Twig

The flexible, fast, and secure
template engine for PHP

a Symfony Product
Docs Tags macro
You are reading the documentation for Twig 3.x. Switch to the documentation for Twig 1.x, 2.x.

Questions & Feedback

License

Twig documentation is licensed under the new BSD license.

macro

Macros are comparable with functions in regular programming languages. They are useful to reuse template fragments to not repeat yourself.

Macros are defined in regular templates.

Imagine having a generic helper template that define how to render HTML forms via macros (called forms.twig):

1
2
3
4
5
6
7
{% macro input(name, value, type = "text", size = 20) %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}"/>
{% endmacro %}

{% macro textarea(name, value, rows = 10, cols = 40) %}
    <textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols }}">{{ value|e }}</textarea>
{% endmacro %}

Each macro argument can have a default value (here text is the default value for type if not provided in the call).

Macros differ from native PHP functions in a few ways:

  • 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.

Tip

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

Importing Macros

There are two ways to import macros. You can import the complete template containing the macros into a local variable (via the import tag) or only import specific macros from the template (via the from tag).

To import all macros from a template into a local variable, use the import tag:

1
{% import "forms.twig" as forms %}

The above import call imports the forms.twig file (which can contain only macros, or a template and some macros), and import the macros as attributes of the forms local variable.

The macros can then be called at will in the current template:

1
2
3
4
<p>{{ forms.input('username') }}</p>
<p>{{ forms.input('password', null, 'password') }}</p>
{# You can also use named arguments #}
<p>{{ forms.input(name: 'password', type: 'password') }}</p>

Alternatively you can import names from the template into the current namespace via the from tag:

1
2
3
4
5
{% from 'forms.twig' import input as input_field, textarea %}

<p>{{ input_field('password', '', 'password') }}</p>
<p>{{ input_field(name: 'password', type: 'password') }}</p>
<p>{{ textarea('comment') }}</p>

Caution

As macros imported via from are called like functions, be careful that they shadow existing functions:

1
2
3
4
{% from 'forms.twig' import input as include %}

{# include refers to the macro and not to the built-in "include" function #}
{{ include() }}

Tip

When macro usages and definitions are in the same template, you don't need to import the macros as they are automatically available under the special _self variable:

1
2
3
4
5
<p>{{ _self.input('password', '', 'password') }}</p>

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

Macros Scoping

The scoping rules are the same whether you imported macros via import or from.

Imported macros are always local to the current template. It means that macros are available in all blocks and other macros defined in the current template, but they are not available in included templates or child templates; you need to explicitly re-import macros in each template.

Imported macros are not available in the body of embed tags, you need to explicitly re-import macros inside the tag.

When calling import or from from a block tag, the imported macros are only defined in the current block and they shadow macros defined at the template level with the same names.

Checking if a Macro is defined

You can check if a macro is defined via the defined test:

1
2
3
4
5
6
7
8
9
10
11
{% import "macros.twig" as macros %}

{% from "macros.twig" import hello %}

{% if macros.hello is defined -%}
    OK
{% endif %}

{% if hello is defined -%}
    OK
{% endif %}

Named Macro End-Tags

Twig allows you to put the name of the macro after the end tag for better readability (the name after the endmacro word must match the macro name):

1
2
3
{% macro input() %}
    ...
{% endmacro input %}