Skip to main content

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

OperatorNameReturns fallback when
??Null coalescingValue is null
?:ElvisValue is falsy (null, false, 0, '', [])
|defaultDefault filterValue 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'
nullfallbackfallbackfallback
falsefalsefallbackfallback
00fallback0
''''fallbackfallback
[][]fallbackfallback

Operators

Arithmetic

OperatorDescriptionExample
+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

OperatorDescriptionExample
==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

OperatorDescriptionExample
andLogical AND{{ a and b }}
orLogical OR{{ a or b }}
notLogical NOT{{ not a }}

String & Containment

OperatorDescriptionExample
~Concatenation (cast to string){{ 'Hello ' ~ name }}
+Concatenation (auto-detect){{ post.title + ' - ' + site.name }}
starts withStarts with test{{ post.title starts with 'Hello' }}
ends withEnds with test{{ post.slug ends with '-draft' }}
inContains{{ 'a' in ['a', 'b'] }}
not inNot 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:

  1. ? — Ternary
  2. or — Logical OR
  3. ??, ?: — Fallback
  4. and — Logical AND
  5. ==, !=, <, >, <=, >=, <=>, in, not in, starts with, ends with — Comparison
  6. .. — Range
  7. +, -, ~ — Addition / Concatenation
  8. *, /, %, // — Multiplication / Division
  9. ** — Power (right-associative)
  10. not — Logical NOT
  11. | — 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 like post.link use esc_url, and HTML fields like post.content are already processed by WordPress.
  • Context-aware: expressions in HTML attributes are escaped with esc_attr (or esc_url for URL attributes like href and src), 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 -->
Common mistake

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