Expressions & Syntax
Full reference for Unblock's expression syntax.
Unblock uses Twig expression syntax — widely used and well-documented.
Accessing Data
Use dot notation to access properties:
{{ post.title }}
{{ post.author.name }}
{{ site.name }}
Bracket notation for array elements or dynamic properties:
{{ array[0] }}
{{ array['key'] }}
Optional chaining for properties that might be null:
{{ post.author?.name }}
{{ post.thumbnail?.src }}
Method calls with arguments:
{{ post.date('F j, Y') }}
{{ user.avatar(96) }}
{{ post.meta('field_name') }}
Conditional Logic
Ternary Operator
{{ condition ? 'yes' : 'no' }}
{{ post.thumbnail ? 'Has image' : 'No image' }}
{{ user.id ? user.name : 'Guest' }}
{{ user.id ? 'Welcome!' }} <!-- Empty if guest -->
Fallback Operators
| Operator | Name | Returns fallback when |
|---|---|---|
?? | Null coalescing | Value is null |
?: | Elvis | Value is falsy (null, false, 0, '', []) |
|default | Default filter | Value is empty (like ?: but preserves 0) |
{{ post.subtitle ?? 'No subtitle' }}
{{ post.image ?? post.thumbnail ?? '/default.jpg' }}
{{ post.views ?: 0 }}
{{ post.subtitle|default('No subtitle') }}
Comparison:
| Value | ?? | ?: | |default |
|---|---|---|---|
'text' | 'text' | 'text' | 'text' |
null | fallback | fallback | fallback |
false | false | fallback | fallback |
0 | 0 | fallback | 0 |
'' | '' | fallback | fallback |
[] | [] | fallback | fallback |
Operators
Arithmetic
| Operator | Description | Example |
|---|---|---|
+ | Addition / Concatenation | {{ 5 + 3 }} → 8 |
- | Subtraction | {{ 10 - 3 }} → 7 |
* | Multiplication | {{ 4 * 5 }} → 20 |
/ | Division | {{ 20 / 4 }} → 5 |
% | Modulo | {{ 17 % 5 }} → 2 |
// | Floor division | {{ 17 // 5 }} → 3 |
** | Power | {{ 2 ** 3 }} → 8 |
.. | Range | {{ 1..5 }} → [1, 2, 3, 4, 5] |
Comparison
| Operator | Description | Example |
|---|---|---|
== | Equal | {{ a == b }} |
!= | Not equal | {{ a != b }} |
=== | Identical | {{ a === b }} |
!== | Not identical | {{ a !== b }} |
< | Less than | {{ a < b }} |
> | Greater than | {{ a > b }} |
<= | Less or equal | {{ a <= b }} |
>= | Greater or equal | {{ a >= b }} |
<=> | Spaceship | {{ a <=> b }} |
Logical
| Operator | Description | Example |
|---|---|---|
and | Logical AND | {{ a and b }} |
or | Logical OR | {{ a or b }} |
not | Logical NOT | {{ not a }} |
String & Containment
| Operator | Description | Example |
|---|---|---|
~ | Concatenation (cast to string) | {{ 'Hello ' ~ name }} |
+ | Concatenation (auto-detect) | {{ post.title + ' - ' + site.name }} |
starts with | Starts with test | {{ post.title starts with 'Hello' }} |
ends with | Ends with test | {{ post.slug ends with '-draft' }} |
in | Contains | {{ 'a' in ['a', 'b'] }} |
not in | Not contains | {{ 'c' not in ['a', 'b'] }} |
+ concatenates when either side is a string, otherwise adds numbers. ~ always concatenates.
Operator Precedence
From lowest to highest priority:
?— Ternaryor— Logical OR??,?:— Fallbackand— Logical AND==,!=,<,>,<=,>=,<=>,in,not in,starts with,ends with— Comparison..— Range+,-,~— Addition / Concatenation*,/,%,//— Multiplication / Division**— Power (right-associative)not— Logical NOT|— Filter
{{ (a + b) * c }}
{{ (value ?? 'default')|upper }}
{{ (post.views ?: 0) + 1 }}
{{ post.title|upper == 'HELLO' }} <!-- Filter binds before comparison -->
Literals
{{ 'single quotes' }} {{ "double quotes" }}
{{ 42 }} {{ 3.14 }} {{ -10 }}
{{ true }} {{ false }} {{ null }}
{{ [1, 2, 3] }} {{ ['a', 'b', 'c'] }}
{{ {key: 'value'} }} {{ {name: 'John', age: 30} }}
Arrow Functions
Used with higher-order filters like map, filter, sort, reduce, and find:
{{ items|map(p => p.name) }}
{{ items|filter(p => p.active) }}
{{ items|find(p => p.id == 5) }}
{{ items|sort((a, b) => a.date <=> b.date) }}
{{ items|reduce((carry, item) => carry + item.price, 0) }}
{{ posts|filter(p => p.status == 'publish' and p.author.id == user.id) }}
Escaping & Output
All output is automatically escaped — you never need to think about it. UnBlock combines two layers of protection:
- Field-aware: each field knows its type. Text fields use
esc_html, URL fields likepost.linkuseesc_url, and HTML fields likepost.contentare already processed by WordPress. - Context-aware: expressions in HTML attributes are escaped with
esc_attr(oresc_urlfor URL attributes likehrefandsrc), regardless of the field used.
{{ post.title }} <!-- esc_html in text, esc_attr in attributes -->
{{ post.link }} <!-- esc_url everywhere -->
{{ post.content }} <!-- Pre-processed HTML, safe to output -->
Comments are not rendered in the output:
{# This is a comment #}
Error Handling
Missing properties return an empty string — no errors. Properties are safely navigated even through null:
{{ post.nonexistent }} <!-- Returns '' -->
{{ post.author.name }} <!-- Safe even if author is null -->
Watch operator precedence when combining filters with fallback operators. {{ value ?? 'default'|upper }} applies upper to 'default' only — not to the whole result. Use parentheses: {{ (value ?? 'default')|upper }}.
Reserved Keywords
Cannot be used as variable names: true, false, null, none, and, or, not, in, if.
Next steps
- Your First Expression — learn the basics step by step
- Providers — all available data fields
- Filters — transform and format data
- Functions — built-in utility and WordPress functions
- Common Patterns — ready-to-use template examples