Expression-variant array filters
The array query filters match on a single field equality. The _exp variants instead take an item-variable name and a predicate expression evaluated for each element, so the test can be any Liquid expression — comparisons, boolean logic, property paths, even nested filters. All are Pagelove/LiquidJS extensions.
Signature: collection | filter_exp: "<var>", "<expression>". The element is bound to <var> for the expression (as a {% for %}-loop variable would be), and the expression is a Liquid expression string.
Nested expression filters are supported and terminate normally, so a predicate may itself query a collection:
{{ groups | where_exp: "g", "g.items | has_exp: 'i', 'i.active'" }}
One limit applies: expression-filter evaluation may nest at most 32 levels deep. Beyond that the filter reports an error rather than continuing.
The limit exists because a predicate is re-resolved each time it is evaluated, so a predicate that refers to itself would otherwise recurse forever:
{% assign pred = "users | where_exp: 'x', pred" %}
{{ users | where_exp: "u", pred }}
That is refused. Ordinary nesting is nowhere near the limit — one or two levels is typical — so a template that hits it is almost certainly self-referential.
Where the error appears depends on context, as it does for every Liquid error:
inside {{ }} output the page still renders and the failure appears in
place as an error item; inside {% assign %} the error stops the render, so
the page does not appear at all.
where_exp
The sub-array of items whose expression is truthy.
{{ users | where_exp: "u", "u.age >= 18" | map: "name" | join: ", " }}
reject_exp
The sub-array of items whose expression is falsy — the inverse of where_exp.
{% assign upcoming = events | reject_exp: "e", "e.cancelled" %}
find_exp
The first item whose expression is truthy (or nil).
{{ products | find_exp: "p", "p.price < 10" | map: "title" }}
find_index_exp
The index of the first item whose expression is truthy (or nil).
{{ steps | find_index_exp: "s", "s.done == false" }}
has_exp
A boolean — whether any item's expression is truthy.
{% if events | has_exp: "e", "e.starts > now" %}Upcoming events{% endif %}
group_by_exp
Groups by the value of the expression, returning { name, items } objects in first-seen key order. Because the key is an expression, you can group by a computed value — here, the year of each order:
{% assign by_year = orders | group_by_exp: "o", "o.date | date: '%Y'" %}
{% for group in by_year %}
<h3>{{ group.name }}</h3>
<ul>{% for order in group.items %}<li>{{ order.ref }}</li>{% endfor %}</ul>
{% endfor %}
See also
- Array filters — the single-field query filters these extend
- When a filter errors