Expressions & Syntax
This page is the full reference for Unblock's expression syntax — operators, filters, literals, and functions.
Unblock uses Twig expression syntax. Based on Twig and Timber, this syntax is widely used and well-documented.
The Basics
These patterns cover 90% of real-world usage.
Accessing Data
Use dot notation to access properties:
{{ post.title }}
{{ post.author.name }}
{{ site.name }}
Bracket Notation
Access array elements or dynamic properties:
{{ array[0] }}
{{ array['key'] }}
{{ post.meta('field_name') }}
Optional Chaining
Safely access properties that might be null:
{{ post.author?.name }}
{{ post.thumbnail?.src }}
Method Calls
Call methods with arguments:
{{ post.date('F j, Y') }}
{{ post.excerpt({words: 25}) }}
{{ user.avatar(96) }}
{{ post.meta('price') }}
Function Calls
Call built-in functions directly in expressions:
{{ min(1, 2, 3) }}
{{ max(prices) }}
{{ random() }}
{{ range(1, 10) }}
{{ html_classes('btn', {active: is_active}) }}
WordPress functions return provider objects, so you can chain property access:
{{ get_post(42).title }}
{{ get_term(5).name }}
{{ get_image(thumbnail_id).src('medium') }}
{{ get_posts({post_type: 'page', posts_per_page: 5}) }}
See Functions for the complete list.
Filters
Transform values using the pipe (|) operator:
{{ value|filter }}
{{ value|filter(argument) }}
{{ value|filter(arg1, arg2) }}
Chaining Filters
Apply multiple filters in sequence:
{{ post.title|lower|slug }}
{{ post.content|striptags|truncate(150) }}
{{ post.date|date_modify('+1 day')|date('F j, Y') }}
See Filters for the complete list.
Conditional Logic
Ternary Operator
{{ condition ? 'yes' : 'no' }}
{{ post.thumbnail ? 'Has image' : 'No image' }}
{{ user.logged_in ? user.name : 'Guest' }}
Short syntax (returns empty if false):
{{ user.logged_in ? 'Welcome!' }}
Fallback Operators
| Operator | Name | Returns fallback when | Example |
|---|---|---|---|
?? | Null coalescing | Value is null | {{ post.subtitle ?? 'No subtitle' }} |
?: | Elvis (falsy coalescing) | Value is falsy (null, false, 0, '', []) | {{ post.views ?: 0 }} |
{{ post.subtitle ?? 'No subtitle' }}
{{ post.image ?? post.thumbnail ?? '/default.jpg' }}
{{ post.views ?: 0 }}
Comparison: ?? vs ?: vs |default
| Value | ?? returns | ?: returns | |default returns |
|---|---|---|---|
'text' | 'text' | 'text' | 'text' |
null | fallback | fallback | fallback |
false | false | fallback | fallback |
0 | 0 | fallback | 0 |
'' | '' | fallback | fallback |
[] | [] | fallback | fallback |
??— returns fallback only whennull. Preservesfalse,0,'',[].?:— returns fallback when falsy (null,false,0,'',[]).|default— returns fallback when empty (like?:but preserves0).
Text Operations
Concatenation
Use + or ~ to concatenate strings:
{{ 'Hello, ' + user.name + '!' }}
{{ post.title + ' - ' + site.name }}
{{ 'Hello ' ~ user.name }}
Note: + auto-detects: it concatenates when either side is a string, otherwise it adds numbers. ~ always concatenates by casting both sides to strings.
Testing Strings
{{ post.title starts with 'Hello' }}
{{ post.slug ends with '-draft' }}
Containment
{{ 'a' in ['a', 'b'] }}
{{ 'c' not in ['a', 'b'] }}
{{ post.status in ['publish', 'future'] }}
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
| Operator | Description | Example |
|---|---|---|
~ | Concatenation | {{ 'Hello ' ~ name }} |
starts with | Starts with test | {{ post.title starts with 'Hello' }} |
ends with | Ends with test | {{ post.slug ends with '-draft' }} |
Containment
| Operator | Description | Example |
|---|---|---|
in | Contains | {{ 'a' in ['a', 'b'] }} |
not in | Not contains | {{ 'c' not in ['a', 'b'] }} |
Operator Precedence
From lowest to highest priority:
?— Ternaryor— Logical OR??,?:— Fallbackand— Logical AND|— Filter==,!=,===,!==,<,>,<=,>=,<=>,in,not in,starts with,ends with— Comparison..— Range+,-,~— Addition / Concatenation*,/,%,//— Multiplication / Division**— Power (right-associative)not— Logical NOT
Use parentheses to control evaluation order:
{{ (a + b) * c }}
{{ (value ?? 'default')|upper }}
{{ (post.views ?: 0) + 1 }}
Literals
Strings
{{ 'single quotes' }}
{{ "double quotes" }}
Numbers
{{ 42 }}
{{ 3.14 }}
{{ -10 }}
Booleans
{{ true }}
{{ false }}
Null
{{ null }}
Arrays
{{ [1, 2, 3] }}
{{ ['a', 'b', 'c'] }}
Objects
{{ {key: 'value'} }}
{{ {name: 'John', age: 30} }}
Variables
Use the Variable block to store and reuse values. Create a variable with a name and an expression, then reference it anywhere in child blocks:
{{ my_price|number_format(2) }}
{{ display_title }}
See Variables for full documentation.
Arrow Functions
Used with higher-order filters like map, filter, sort, reduce, and find:
Single Parameter
{{ items|map(p => p.name) }}
{{ items|filter(p => p.active) }}
{{ items|find(p => p.id == 5) }}
{{ items|sort(p => p.date) }}
Multiple Parameters
{{ items|sort((a, b) => a.date <=> b.date) }}
{{ items|reduce((carry, item) => carry + item.price, 0) }}
Complex Expressions
{{ posts|filter(p => p.status == 'publish' and p.author.id == user.id) }}
{{ products|map(p => p.price * 1.2) }}
See Array Filters for all available higher-order filters.
Escaping & Output
Auto-Escaping
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
Comments are not rendered in the output:
{# This is a comment #}
Reserved Keywords
The following cannot be used as variable names:
true,falsenull,noneand,or,notinif,else
Error Handling
Missing Properties
Missing properties return an empty string — no errors:
{{ post.nonexistent }} <!-- Returns '' -->
Safe Navigation
Properties are safely navigated — no errors on null:
{{ post.author.name }} <!-- Safe even if author is null -->
Default Values
{{ value|default('fallback') }}
{{ value ?? 'fallback' }}