User Docs Developer Docs | |

Tags

Template tags are wrapped in {% %} delimiters. They control layout inheritance, partial inclusion, iteration, and conditionals.

extends

Declares that this template inherits from a layout. Must be the first token in the file.

{% extends "layout.tpl" %}

The layout file path is relative to the active theme's root views directory. The child template must define all content inside {% block %} tags; any content outside blocks is ignored.

block / endblock

Defines a named content region. In a layout file, blocks provide default content (or are empty). In a child template, blocks override the layout's regions.

Layout (layout.tpl):

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}{{ site_name }}{% endblock %}</title>
</head>
<body>
    {% block content %}{% endblock %}
    {% block sidebar %}{% endblock %}
</body>
</html>

Child template:

{% extends "layout.tpl" %}

{% block title %}{{ page_title }} — {{ site_name }}{% endblock %}

{% block content %}
<article>
    <h1>{{ post.title }}</h1>
    {! render_content post !}
</article>
{% endblock %}

include

Injects another template file inline. The included file shares the current template's variable scope.

{% include "partials/author-card.tpl" %}
{% include "partials/pagination.tpl" %}

Path is relative to the active theme's views directory. Widget templates cannot include files from their own directory — includes always resolve against the theme.

for / endfor / empty

Iterates over an array or object collection.

{% for post in posts %}
    <h2>{{ post.title }}</h2>
{% endfor %}

With empty clause (renders when the collection is empty or null):

{% for post in posts %}
    <h2>{{ post.title }}</h2>
{% empty %}
    <p>No posts found.</p>
{% endfor %}

Nested loops:

{% for category in categories %}
    <h3>{{ category.name }}</h3>
    {% for post in category.posts %}
        <p>{{ post.title }}</p>
    {% endfor %}
{% endfor %}

The loop variable (post, category, etc.) is scoped to the loop body. There is no automatic loop.index variable.

if / elif / else / endif

Conditional rendering. Condition is a boolean expression.

{% if post.status == "published" %}
    <span class="badge badge-success">Published</span>
{% elif post.status == "scheduled" %}
    <span class="badge badge-warning">Scheduled</span>
{% else %}
    <span class="badge badge-secondary">Draft</span>
{% endif %}

Supported comparison operators: ==, !=, <, >, <=, >=

Boolean operators: and, or

Negation: not

{% if user and user.is_active %}
    Welcome back, {{ user.username }}!
{% endif %}

{% if not post.is_premium %}
    {! render_content post !}
{% endif %}

Truthiness: empty string, "0", null, empty array, and false are all falsy.