Array filters
Filters for ordering, transforming, and querying lists — including the microdata items a resource binding yields. Standard Shopify Liquid unless marked extension.
Filters that walk a whole list — sort, sort_natural, uniq, where, find, reject, map, group_by and their relatives — are subject to your request's time limit while they run, not only before they start. A filter applied to a very large list can therefore stop partway and fail the request with a time-limit error, where it would previously have run to completion. If you hit this, the fix is to narrow the list before the expensive filter rather than to raise the limit.
Ordering and elements
first
The first element of an array (or first character of a string). nil if empty.
{{ items | first }}
last
The last element of an array (or last character of a string).
{{ items | last }}
reverse
Reverses the array.
{{ "a,b,c" | split: "," | reverse | join: "," }} <!-- c,b,a -->
sort
Sorts the array. With a field name, sorts an array of objects by that field.
{{ "banana,apple,cherry" | split: "," | sort | join: ", " }} <!-- apple, banana, cherry -->
{% assign newest = posts | sort: "date" %}
Items that have nothing to sort on go to the end. Sorting people by nickname puts everyone who has one first, in order, then everyone who does not. An empty nickname is a value, not a missing one, so it sorts with the text.
A list holding a mix of things that cannot be compared with each other — some numbers and some words — comes back grouped by kind rather than interleaved. Each kind is in order within its group. There is no meaningful answer to "is 2 before apple", so the filter gives a predictable one instead of an arbitrary one.
sort_natural
Case-insensitive lexical sort. Because it compares text rather than numbers,
"10" sorts before "9" — use sort when you want numeric order. As with
sort, items with nothing to sort on go to the end.
{{ "b,A,c" | split: "," | sort_natural | join: "" }} <!-- Abc -->
uniq
Removes duplicate elements, preserving order.
{{ "a,b,a,c" | split: "," | uniq | join: "," }} <!-- a,b,c -->
compact
Removes nil elements.
{{ list | compact | join: ", " }}
Transforming and joining
map
Extracts a field from every object in the array.
{{ people | map: "name" | join: ", " }}
join
Joins the elements into a string with a separator (default a space).
{{ tags | join: ", " }}
concat
Concatenates a second array onto the input.
{% assign all = drafts | concat: published %}
Querying an array of objects
These operate on an array of objects and let a template filter, find, and test them without a {% for %} loop.
Each takes a field name and an optional expected value: array | filter: "field", value matches items whose field equals value; with the value omitted, array | filter: "field" matches items whose field is truthy. Non-object elements never match. For a full expression rather than field equality, see the expression-variant filters.
where
The sub-array of matching items. (Standard Liquid.)
{{ people | where: "role", "admin" | map: "name" | join: ", " }}
reject
(extension) The sub-array of non-matching items — the inverse of where.
{% assign active = users | reject: "suspended", true %}
find
(extension) The first matching element (or nil).
{{ products | find: "sku", "A-1" | map: "title" }}
find_index
(extension) The index of the first matching element (or nil).
{{ products | find_index: "sku", "A-1" }} <!-- 0 -->
has
(extension) A boolean — whether any element matches.
{% if products | has: "onsale", true %}Sale on now!{% endif %}
group_by
(extension) Groups the array by a field, returning an array of { name, items } objects in first-seen key order.
{% assign by_year = posts | group_by: "year" %}
{% for group in by_year %}
<h2>{{ group.name }}</h2>
<ul>{% for post in group.items %}<li>{{ post.title }}</li>{% endfor %}</ul>
{% endfor %}
sum
(extension) Totals the array. With no argument it sums the array's numbers; with a field name it sums that property across an array of objects. Non-numeric values count as 0; the result is an integer when whole, otherwise a float.
{{ prices | sum }} <!-- total of the numbers -->
{{ line_items | sum: "price" }} <!-- total of each item's price -->
Mutation
Each returns a new array — the input is never mutated — so they compose in a pipeline or an {% assign %}. All are extensions.
push
(extension) Appends a value, returning a new array. Standard Liquid has no array-append filter — concat only joins two arrays — so push fills the gap. The input is coerced to an array first: an array is appended to; nothing (an unassigned variable) becomes a one-element array; any other single value is promoted to a one-element array first.
Pushing onto an unassigned variable is the idiomatic way to build a list in a loop:
{% for term in terms %}
{% assign wanted = wanted | push: term %}
{% endfor %}
{{ wanted | join: ", " }}
wanted is never assigned before the loop, so on the first iteration it is nil and push returns a one-element array; each later iteration appends. This avoids a common footgun: {% assign a = "" | split: "," %} does not produce an empty array — it produces [""].
unshift
(extension) Prepends a value, returning a new array. LiquidJS-compatible.
{% assign crumbs = crumbs | unshift: "Home" %}
pop
(extension) Returns a new array without the last element. LiquidJS-compatible.
{% assign rest = items | pop %}
shift
(extension) Returns a new array without the first element. LiquidJS-compatible.
{% assign tail = items | shift %}
See also
- Expression-variant array filters — query by a full expression, not just field equality
- String filters · Number filters
- When a filter errors