Skip to content
Quilium Docs
Back to site
Reference

Variables and context

Every object Quilium injects into a Liquid template at render time, what each one holds, and how to read it.

Quilium renders Liquid server-side. At render time the engine injects a fixed set of context objects. A template reads them; it never fetches data itself. Dynamic data comes from queries declared on the page-type (route-aware, exposed as page.custom.<key>) and from content-block fields (content.custom.<field>).

Context objects

All field, section, and query keys are camelCase. Query results are always arrays, even at limit: 1; guard with and <expr>.size > 0 before indexing.

Object Access Holds
page page.contents['<section>'], page.custom.<queryKey>, page.metas.{title,description,robots}, page.title, page.id The current page. page.contents['main'] is the array of blocks dropped in the main section.
page.custom page.custom.<queryKey> (array) Route-aware query results declared on the page-type. Each key is one query field. Always an array, so guard before [0].
content content.custom.<field>, content.custom.<query>, content.id, content.template, content.form.<field>.errors Inside an element template: the current content block. content.id is the block id (form target value); content.template is its element path.
content.custom content.custom.<field> The block's own fields. Idiom: {% assign c = content.custom %} then c.title. A content-type may carry its own query, read at content.custom.<query>.
content.form content.form.<field>.errors Per-field validation errors after a POST, as an object {rule: message}. Empty before submission.
globals globals.<fieldKey> Global fields, flat: the tabset key is dropped from the path. Schema tabsets.infos.fields.copyright reads as globals.copyright, never globals.infos.copyright. Field keys must be unique across all tabsets.
request request.body.<field>, request.query, request.path, request.cookies The incoming request. request.body.<field> holds submitted form values, used to prefill on re-render.
request.body request.body.<field> Posted form values, keyed by field name.
route route.<param> QUERY-ONLY. Valid only inside a page-type query config (e.g. where: { '&=': { slug: '{{route.article.slug}}' } }). It does not exist in a template. Templates read the resolved result at page.custom.<key>. See Routing and URLs.
query query.page QUERY-ONLY. The URL query string inside a query config. {{query.page}} substitutes (pagination); {{query.limit}} does not substitute.
now now, now.year, now.month, now.day, now.hour, now.datetime, now.timestamp, now.timezone Server time. Format with `{{ now
locale locale.slug The current locale. Use for <html lang="{{ locale.slug }}">. See the multilingual model.
locales loc.slug, loc.url (per item) Every locale. loc.url is this page in that locale. Iterate for a language switcher.
sitemap sitemap.<nav>.children → item.url, item.navTitle, item.active Navigation trees. item.url is already locale-aware; do not re-prefix it.
route and query are query-only. Both exist solely inside a page-type's query configuration. A template that reads route.* or query.* directly gets nothing. The page-type resolves {{route.article.slug}} into page.custom.article; the template reads page.custom.article[0].

Reading a query result

Queries are arrays. Always test size before indexing.

{% assign source = page.custom.latest %}
{% if source and source.size > 0 %}
  {% for a in source %}{% include '_articleCard', art: a %}{% endfor %}
{% else %}
  <p>{{ 'Aucun article pour le moment.' | _ }}</p>
{% endif %}

A current-item join (limit 1) reads index [0] behind the same guard:

{% if page.custom.author and page.custom.author.size > 0 %}
  {% assign au = page.custom.author[0] %}
  <h2>{{ au.nom }}</h2>
{% endif %}

Function-form helpers are inert in Liquid

The render payload also carries function-form helpers, url, redirect, responseCode, setCookie, and _. They are leftovers from the engine that preceded Liquid and are inert in Liquid. In a Liquid template you use the filter forms instead ('article' | url: …, 'msgid' | _). See Liquid filters for every filter signature.

Globals are flat. The tabset key never appears in the path. A field copyright under tabset infos is globals.copyright. Because of this, every global field key must be unique across all tabsets, or one shadows the other.

Last updated September 6, 2026.