Liquid tags
The available tags, the layout, block and include rules, what is rejected, and the stateful-tag warning inside sections.
On this page
Dukkan's engine runs LiquidJS with its standard tags and hardened options. This page collects what you need to know about tags without repeating the general Liquid documentation.
Hardened options#
| Option | Effect |
|---|---|
| strict filters | an unknown filter is a render error |
| own properties only | only what an object actually owns resolves; no constructor, no prototype chain |
| JavaScript truthiness | "", 0, null and false are all falsy; use != blank and size > 0 deliberately |
| output escaping | every {{ }} is escaped except the output of safe filters |
| no relative references | include only by full path inside the bundle |
| limits | see Limits |
layout and block#
{% layout 'layout/theme.liquid' %}
{% block content %}
<h1>{{ category.name }}</h1>
{% endblock %}{% layout %}must be the first tag in the template, with the full path.- The layout declares blocks with
{% block NAME %}…{% endblock %}and their default content inside; the template fills them by the same name. - A layout may declare more than one block (
head_extra,content); whatever the template does not fill keeps the layout's default. - There is no variable for the template's content inside the layout;
{% block %}is the only path.
include#
{% include 'snippets/product-card.liquid' %}
{% include 'snippets/pager.liquid', pager_base: category.url %}
{% assign icon = 'cart' %}{% include 'snippets/icons.liquid' %}- The path is full from the bundle root with the extension; a missing file fails the render with
template not found. - The snippet shares the variable scope with its includer (
includesemantics, notrender), and accepts named arguments that become variables. - Including
assets/theme.cssinside<style>is the supported way to ship CSS.
Control flow and loops#
if/elsif/else/unless, case/when, for with forloop, break/continue, limit/offset/reversed, tablerow, assign, capture, comment, liquid, echo: all available as in LiquidJS.
{% for product in products limit: 8 %}
{% if forloop.first %}<ul>{% endif %}
<li>{{ product.name }}</li>
{% if forloop.last %}</ul>{% endif %}
{% endfor %}increment, decrement and cycle#
Warning
These tags keep state across calls. Inside section bodies every body renders twice (capture, then emit), so their counters and cycles drift. Never use them in snippets/section-body.liquid or anything it includes. Use forloop.index and assign instead.
raw (the tag)#
{% raw %}…{% endraw %} is the standard tag for emitting text that contains Liquid braces literally; it is allowed, because it is escaped like any text. Do not confuse it with the neutralized | raw filter.
Rejected at push#
Any non-JSON-LD <script>, inline event handlers, javascript:, data:text/html, <iframe>, the | raw filter, and section wrapper markers. The list with its strings is in Theme validation.