The collection tag.
One tag reads the site database from inside a template. It queries posts, products, users, orders, bits and more, with a shared vocabulary of filters, sorting and paging, and it returns a plain array you can loop.
Syntax
{% collection <source>, <variable>, <key>: <value>, <key>: <value> %}The first argument is the source, the second is the variable name the results land in, and the rest are parameters. Parameters accept either key: value or key=value. If you pass a name: parameter it becomes the variable name instead. A value can be a literal, a quoted string, or a context variable.
{% collection products, items, limit: 8, order: inserted_at desc %}
{% collection blogs, articles, tag: 'news', limit: 5 %}
{% collection users, sellers, type: 'seller' %}When the source is a content type (products, blogs, events and the other plural aliases) it resolves to a posts query filtered to that type. The raw sources users, leads, orders, subscriptions and variants are queried directly. The full list is on the Data sources page.
The result
The variable is an array of entries, so you loop it directly. It also carries a pagination object and an entries alias, and the tag sets a variable and a paginate object.
{% collection blogs, posts, limit: 10 %}
{% for post in posts %}
> href="{{ post.permalink }}">{{ post.title }}> >
{% endfor %}
>Page {{ posts.pagination.page }} of {{ posts.pagination.total_pages }}
>
>{{ blogs_count }} shown
>Printing the variable directly ({{ posts }}) outputs the whole result as JSON, entries and pagination together.
Filtering
Posts and products accept a wide set of filters. The most common:
| Parameter | Effect |
|---|---|
type / types | Filter by one type or several (comma separated). |
status | Post status. Defaults to published. status: any removes the filter. |
category | A category id. |
tag / tags | One tag, or several that must all be present. |
q | Text search across title, body and tags. |
label | Match a label. |
author | Filter by author id. |
exclude / id_in / uid | Exclude an id, restrict to a set of ids, or match one uid. |
price_greater_than / price_less_than | Price bounds. |
date, date_min, date_max | Filter by created date. |
data_ / meta_ | Match a value in the post's data or meta object. |
distinct | Return one row per value of a column. |
The JSON filters have a small grammar: data_x: v matches equal, data_not_x: v matches not-equal, and data_null_x / data_not_null_x test for presence.
Sorting and paging
Sort with order: ". Posts default to id desc; users, leads, orders and subscriptions default to inserted_at desc. Posts can sort by a data_ value.
Page with limit (or page_size) and page. The default page size is 20 (variants default to 27).
{% collection products, items, order: price asc, limit: 12, page: params.page %}Parameters from the URL
Unless you set exclude_params: true, query-string parameters are merged onto the collection, so a search page can pass ?q= and ?page= straight through. Your template's own parameters always win over the URL.
Visitor-supplied parameters are constrained. Privilege and identity parameters are never taken from the URL, and a visitor's ?limit= is capped at 100. A visitor cannot widen a query past what your template allows.
What the query hides by default
- Only published posts appear, unless a signed-in user is viewing their own, or the template asks for another status.
- Private posts are hidden from anonymous visitors.
- Posts by banned or deleted users are excluded.
- System records (site configuration and domain rows) never appear in a posts query.
- An entry's
authoris a safe subset of user fields. Passwords, tokens and payment ids are never exposed, even when you print an entry as JSON.
For the complete list of sources and their visibility, see Data sources.