Tags

verbatim

The verbatim tag marks sections as being raw text that should not be parsed. For example to put Twig syntax as example into a template you can use this snippet:

{% verbatim %}
    <ul>
    {% for item in seq %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
{% endverbatim %}

The verbatim tag works in the exact same way as the old raw tag, but was renamed to avoid confusion with the raw filter.

use

Template inheritance is one of the most powerful Twig's feature but it is limited to single inheritance; a template can only extend one other template. This limitation makes template inheritance simple to understand and easy to debug:

{% extends "base.html" %}

{% block title %}{% endblock %}
{% block content %}{% endblock %}

Horizontal reuse is a way to achieve the same goal as multiple inheritance, but without the associated complexity:

{% extends "base.html" %}

{% use "blocks.html" %}

{% block title %}{% endblock %}
{% block content %}{% endblock %}

The use statement tells Twig to import the blocks defined in blocks.html into the current template (it's like macros, but for blocks):

{# blocks.html #}

{% block sidebar %}{% endblock %}

In this example, the use statement imports the sidebar block into the main template. The code is mostly equivalent to the following one (the imported blocks are not outputted automatically):

{% extends "base.html" %}

{% block sidebar %}{% endblock %}
{% block title %}{% endblock %}
{% block content %}{% endblock %}

The use tag only imports a template if it does not extend another template, if it does not define macros, and if the body is empty. But it can use other templates.
Because use statements are resolved independently of the context passed to the template, the template reference cannot be an expression.

The main template can also override any imported block. If the template already defines the sidebar block, then the one defined in blocks.html is ignored. To avoid name conflicts, you can rename imported blocks:

{% extends "base.html" %}

{% use "blocks.html" with sidebar as base_sidebar, title as base_title %}

{% block sidebar %}{% endblock %}
{% block title %}{% endblock %}
{% block content %}{% endblock %}

The parent() function automatically determines the correct inheritance tree, so it can be used when overriding a block defined in an imported template:

{% extends "base.html" %}

{% use "blocks.html" %}

{% block sidebar %}
    {{ parent() }}
{% endblock %}

{% block title %}{% endblock %}
{% block content %}{% endblock %}

In this example, parent() will correctly call the sidebar block from the blocks.html template.

spaceless

Use the spaceless tag to remove whitespace between HTML tags, not whitespace within HTML tags or whitespace in plain text:

{% spaceless %}
    <div>
        <strong>foo</strong>
    </div>
{% endspaceless %}

{# output will be <div><strong>foo</strong></div> #}

This tag is not meant to "optimize" the size of the generated HTML content but merely to avoid extra whitespace between HTML tags to avoid browser rendering quirks under some circumstances.

set

Inside code blocks you can also assign values to variables. Assignments use the set tag and can have multiple targets.

{% set foo = 'bar' %}
{# displays bar #}
{{ foo }}
{% set foo = [1, 2] %}
{% set foo = {'foo': 'bar'} %}
{% set foo = 'foo' ~ 'bar' %}
{% set foo, bar = 'foo', 'bar' %}

{# is equivalent to #}

{% set foo = 'foo' %}
{% set bar = 'bar' %}
{% set foo %}
    <div id="pagination">
        ...
    </div>
{% endset %}

macro

Macros are comparable with functions in regular programming languages. They are useful to put often used HTML idioms into reusable elements to not repeat yourself.

{% macro input(name, value, type, size) %}
    <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}

Macros differs from native PHP functions in a few ways:

  • Default argument values are defined by using the default filter in the macro body;
  • Arguments of a macro are always optional.
  • If extra positional arguments are passed to a macro, they end up in the special varargs variable as a list of values.

But as with PHP functions, macros don't have access to the current template variables.

You can pass the whole context as an argument by using the special _context variable.

{% import "forms.html" as forms %}

The above import call imports the "forms.html" file (which can contain only macros, or a template and some macros), and import the functions as items of the forms variable.

<p>{{ forms.input('username') }}</p>
<p>{{ forms.input('password', null, 'password') }}</p>
{% import _self as forms %}

<p>{{ forms.input('username') }}</p>
{% macro input(name, value, type, size) %}
    <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}

{% macro wrapped_input(name, value, type, size) %}
    {% import _self as forms %}

    <div class="field">
        {{ forms.input(name, value, type, size) }}
    </div>
{% endmacro %}

include

{% include 'header.html' %}
    Body
{% include 'footer.html' %}

Included templates have access to the variables of the active context.

If you are using the filesystem loader, the templates are looked for in the paths defined by it.

{# template.html will have access to the variables from the current context and the additional ones provided #}
{% include 'template.html' with {'foo': 'bar'} %}

{% set vars = {'foo': 'bar'} %}
{% include 'template.html' with vars %}
{# only the foo variable will be accessible #}
{% include 'template.html' with {'foo': 'bar'} only %}
{# no variables will be accessible #}
{% include 'template.html' only %}
{% include some_var %}
{% include ajax ? 'ajax.html' : 'not_ajax.html' %}

You can mark an include with ignore missing in which case Twig will ignore the statement if the template to be included does not exist. It has to be placed just after the template name.

{% include 'sidebar.html' ignore missing %}
{% include 'sidebar.html' ignore missing with {'foo': 'bar'} %}
{% include 'sidebar.html' ignore missing only %}
{% include ['page_detailed.html', 'page.html'] %}

If ignore missing is given, it will fall back to rendering nothing if none of the templates exist, otherwise it will throw an exception.

import

Twig supports putting often used code into macros. These macros can go into different templates and get imported from there.

There are two ways to import templates. You can import the complete template into a variable or request specific macros from it.

{% macro input(name, value, type, size) %}
    <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}

{% macro textarea(name, value, rows, cols) %}
    <textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
{% endmacro %}
{% import 'forms.html' as forms %}

<dl>
    <dt>Username</dt>
    <dd>{{ forms.input('username') }}</dd>
    <dt>Password</dt>
    <dd>{{ forms.input('password', null, 'password') }}</dd>
</dl>
<p>{{ forms.textarea('comment') }}</p>
{% from 'forms.html' import input as input_field, textarea %}

<dl>
    <dt>Username</dt>
    <dd>{{ input_field('username') }}</dd>
    <dt>Password</dt>
    <dd>{{ input_field('password', '', 'password') }}</dd>
</dl>
<p>{{ textarea('comment') }}</p>

To import macros from the current file, use the special _self variable for the source.

if

The if statement in Twig is comparable with the if statements of PHP.

{% if online == false %}
    <p>Our website is in maintenance mode. Please, come back later.</p>
{% endif %}
{% if products %}
    <ul>
        {% for product in products %}
            <li>{{ product.title|e }}</li>
        {% endfor %}
    </ul>
{% endif %}
{% if not user.subscribed %}
    <p>You are not subscribed to our mailing list.</p>
{% endif %}
{% if temperature > 18 and temperature < 27 %}
    <p>It's a nice day for a walk in the park.</p>
{% endif %}
{% if kenny.sick %}
    Kenny is sick.
{% elseif kenny.dead %}
    You killed Kenny! You bastard!!!
{% else %}
    Kenny looks okay --- so far
{% endif %}

The rules to determine if an expression is true or false are the same as in PHP; here are the edge cases rules:

Value

Boolean evaluation

empty string

false

numeric zero

false

whitespace-only string

true

empty array

false

null

false

non-empty array

true

object

true

from

The from tag imports macro names into the current namespace. The tag is documented in detail in the documentation for the import tag.

for

<h1>Products</h1>
<ul>
    {% for product in products %}
        <li>{{ product.title|e }}</li>
    {% endfor %}
</ul>
{% for i in 0..10 %}
    * {{ i }}
{% endfor %}

The above snippet of code would print all numbers from 0 to 10.

{% for letter in 'a'..'z' %}
    * {{ letter }}
{% endfor %}
{% for letter in 'a'|upper..'z'|upper %}
    * {{ letter }}
{% endfor %}

The loop variable
Inside of a for loop block you can access some special variables:

Variable

Description

loop.index

The current iteration of the loop. (1 indexed)

loop.index0

The current iteration of the loop. (0 indexed)

loop.revindex

The number of iterations from the end of the loop (1 indexed)

loop.revindex0

The number of iterations from the end of the loop (0 indexed)

loop.first

True if first iteration

loop.last

True if last iteration

loop.length

The number of items in the sequence

loop.parent

The parent context

{% for product in products %}
    {{ loop.index }} - {{ product.title }}
{% endfor %}

Adding a condition
Unlike in PHP, it's not possible to break or continue in a loop. You can however filter the sequence during iteration which allows you to skip items.

<ul>
    {% for product in products if product.type == 3 %}
        <li>{{ product.title|e }}</li>
    {% endfor %}
</ul>

The advantage is that the special loop variable will count correctly thus not counting the users not iterated over. Keep in mind that properties like loop.last will not be defined when using loop conditions.

The else Clause

<ul>
    {% for product in products %}
        <li>{{ product.title|e }}</li>
    {% else %}
        <li><em>no product found</em></li>
    {% endfor %}
</ul>

Iterating over Keys
By default, a loop iterates over the values of the sequence.

<h1>Products</h1>
<ul>
    {% for key in products|keys %}
        <li>{{ key }}</li>
    {% endfor %}
</ul>

Iterating over Keys and Values

<h1>Products</h1>
<ul>
    {% for key, product in products %}
        <li>{{ key }}: {{ product.title|e }}</li>
    {% endfor %}
</ul>

Iterating over a Sublet
You might want to iterate over a subset of values.

<h1>Top Ten Products</h1>
<ul>
    {% for product in products|slice(0, 10) %}
        <li>{{ product.title|e }}</li>
    {% endfor %}
</ul>

flush

{% flush %}

filter

Filter sections allow you to apply regular Twig filters on a block of template data.

{% filter upper %}
    This text becomes uppercase
{% endfilter %}
{% filter lower|escape %}
    <strong>SOME TEXT</strong>
{% endfilter %}

{# outputs "&lt;strong&gt;some text&lt;/strong&gt;" #}

extends

The extends tag can be used to extend a template from another one.

<!DOCTYPE html>
<html>
    <head>
        {% block head %}
            <link rel="stylesheet" href="style.css" />
            <title>{% block title %}{% endblock %} - My Webpage</title>
        {% endblock %}
    </head>
    <body>
        <div id="content">{% block content %}{% endblock %}</div>
        <div id="footer">
            {% block footer %}
                &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
            {% endblock %}
        </div>
    </body>
</html>

In this example, the block tags define four blocks that child templates can fill in.

All the block tag does is to tell the template engine that a child template may override those portions of the template.

Child Template

{% extends "base.html" %}

{% block title %}Index{% endblock %}
{% block head %}
    {{ parent() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
        Welcome on my awesome homepage.
    </p>
{% endblock %}

The extends tag is the key here. It tells the template engine that this template "extends" another template. When the template system evaluates this template, first it locates the parent. The extends tag should be the first tag in the template.

Note that since the child template doesn't define the footer block, the value from the parent template is used instead.

You can't define multiple block tags with the same name in the same template. This limitation exists because a block tag works in "both" directions. That is, a block tag doesn't just provide a hole to fill - it also defines the content that fills the hole in the parent. If there were two similarly-named block tags in a template, that template's parent wouldn't know which one of the blocks' content to use.

<title>{% block title %}{% endblock %}</title>
<h1>{{ block('title') }}</h1>
{% block body %}{% endblock %}

Parent Blocks

{% block sidebar %}
    <h3>Table Of Contents</h3>
    ...
    {{ parent() }}
{% endblock %}

Named Block-End Tags

{% block sidebar %}
    {% block inner_sidebar %}
        ...
    {% endblock inner_sidebar %}
{% endblock sidebar %}

Of course, the name after the endblock word must match the block name.

Block Nesting & Scope

{% for item in seq %}
    <li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}

Block Shortcuts

{% block title %}
    {{ page_title|title }}
{% endblock %}
{% block title page_title|title %}

Conditional Inheritance

{% extends standalone ? "minimum.html" : "base.html" %}

In this example, the template will extend the "minimum.html" layout template if the standalone variable evaluates to true, and "base.html" otherwise.

How do blocks work?
A block provides a way to change how a certain part of a template is rendered but it does not interfere in any way with the logic around it.

{# base.twig #}

{% for post in posts %}
    {% block post %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.body }}</p>
    {% endblock %}
{% endfor %}
{# child.twig #}

{% extends "base.twig" %}

{% block post %}
    <article>
        <header>{{ post.title }}</header>
        <section>{{ post.text }}</section>
    </article>
{% endblock %}
{% for post in posts %}
    <article>
        <header>{{ post.title }}</header>
        <section>{{ post.text }}</section>
    </article>
{% endfor %}
{% if posts is empty %}
    {% block head %}
        {{ parent() }}

        <meta name="robots" content="noindex, follow">
    {% endblock head %}
{% endif %}

Contrary to what you might think, this template does not define a block conditionally; it just makes overridable by a child template the output of what will be rendered when the condition is true.

{% block head %}
    {{ parent() }}

    {% if posts is empty %}
        <meta name="robots" content="noindex, follow">
    {% endif %}
{% endblock head %}

embed

The embed tag combines the behaviour of include and extends. It allows you to include another template's contents, just like include does. But it also allows you to override any block defined inside the included template, like when extending a template.

{% embed "teasers_skeleton.twig" %}
    {# These blocks are defined in "teasers_skeleton.twig" #}
    {# and we override them right here:                    #}
    {% block left_teaser %}
        Some content for the left teaser box
    {% endblock %}
    {% block right_teaser %}
        Some content for the right teaser box
    {% endblock %}
{% endembed %}

The embed tag takes the idea of template inheritance to the level of content fragments. While template inheritance allows for "document skeletons", which are filled with life by child templates, the embed tag allows you to create "skeletons" for smaller units of content and re-use and fill them anywhere you like.

┌─── page layout ─────────────────────┐
│                                     │
│           ┌── block "content" ──┐   │
│           │                     │   │
│           │                     │   │
│           │ (child template to  │   │
│           │  put content here)  │   │
│           │                     │   │
│           │                     │   │
│           └─────────────────────┘   │
│                                     │
└─────────────────────────────────────┘
┌─── page layout ─────────────────────┐
│                                     │
│           ┌── block "content" ──┐   │
│           │ ┌─ block "top" ───┐ │   │
│           │ │                 │ │   │
│           │ └─────────────────┘ │   │
│           │ ┌─ block "bottom" ┐ │   │
│           │ │                 │ │   │
│           │ └─────────────────┘ │   │
│           └─────────────────────┘   │
│                                     │
└─────────────────────────────────────┘
┌─── page layout ─────────────────────┐
│                                     │
│           ┌── block "content" ──┐   │
│           │                     │   │
│           │ ┌ block ┐ ┌ block ┐ │   │
│           │ │"left" │ │"right"│ │   │
│           │ │       │ │       │ │   │
│           │ │       │ │       │ │   │
│           │ └───────┘ └───────┘ │   │
│           └─────────────────────┘   │
│                                     │
└─────────────────────────────────────┘

Without the embed tag, you have two ways to design your templates:

  • Create two "intermediate" base templates that extend the master layout template: one with vertically stacked boxes to be used by the "foo" and "bar" pages and another one with side-by-side boxes for the "boom" and "baz" pages.
  • Embed the markup for the top/bottom and left/right boxes into each page template directly.

These two solutions do not scale well because they each have a major drawback:

  • The first solution may indeed work for this simplified example. But imagine we add a sidebar, which may again contain different, recurring structures of content. Now we would need to create intermediate base templates for all occurring combinations of content structure and sidebar structure... and so on.
  • The second solution involves duplication of common code with all its negative consequences: any change involves finding and editing all affected copies of the structure, correctness has to be verified for each copy, copies may go out of sync by careless modifications etc.

In such a situation, the embed tag comes in handy. The common layout code can live in a single base template, and the two different content structures, let's call them "micro layouts" go into separate templates which are embedded as necessary:

{% extends "layout_skeleton.twig" %}

{% block content %}
    {% embed "vertical_boxes_skeleton.twig" %}
        {% block top %}
            Some content for the top box
        {% endblock %}

        {% block bottom %}
            Some content for the bottom box
        {% endblock %}
    {% endembed %}
{% endblock %}
<div class="top_box">
    {% block top %}
        Top box default content
    {% endblock %}
</div>

<div class="bottom_box">
    {% block bottom %}
        Bottom box default content
    {% endblock %}
</div>

The goal of the vertical_boxes_skeleton.twig template being to factor out the HTML markup for the boxes.

{% embed "base" with {'foo': 'bar'} %}
    ...
{% endembed %}

{% embed "base" with {'foo': 'bar'} only %}
    ...
{% endembed %}

{% embed "base" ignore missing %}
    ...
{% endembed %}

As embedded templates do not have "names", auto-escaping strategies based on the template "filename" won't work as expected if you change the context (for instance, if you embed a CSS/JavaScript template into an HTML one). In that case, explicitly set the default auto-escaping strategy with the autoescape tag.

do

{% do 1 + 2 %}

block

Blocks are used for inheritance and act as placeholders and replacements at the same time. They are documented in detail in the documentation for the extends tag.

Block names should consist of alphanumeric characters, and underscores. Dashes are not permitted.

autoescape

{% autoescape %}
    Everything will be automatically escaped in this block
    using the HTML strategy
{% endautoescape %}

{% autoescape 'html' %}
    Everything will be automatically escaped in this block
    using the HTML strategy
{% endautoescape %}

{% autoescape 'js' %}
    Everything will be automatically escaped in this block
    using the js escaping strategy
{% endautoescape %}

{% autoescape false %}
    Everything will be outputted as is in this block
{% endautoescape %}
{% autoescape %}
    {{ safe_value|raw }}
{% endautoescape %}

Functions returning template data (like macros and parent) always return safe markup.