6 This section describes how to extends Twig for versions **older than
7 1.12**. If you are using a newer version, read the :doc:`newer<advanced>`
10 Twig can be extended in many ways; you can add extra tags, filters, tests,
11 operators, global variables, and functions. You can even extend the parser
12 itself with node visitors.
16 The first section of this chapter describes how to extend Twig easily. If
17 you want to reuse your changes in different projects or if you want to
18 share them with others, you should then create an extension as described
19 in the following section.
23 When extending Twig by calling methods on the Twig environment instance,
24 Twig won't be able to recompile your templates when the PHP code is
25 updated. To see your changes in real-time, either disable template caching
26 or package your code into an extension (see the next section of this
29 Before extending Twig, you must understand the differences between all the
30 different possible extension points and when to use them.
32 First, remember that Twig has two main language constructs:
34 * ``{{ }}``: used to print the result of an expression evaluation;
36 * ``{% %}``: used to execute statements.
38 To understand why Twig exposes so many extension points, let's see how to
39 implement a *Lorem ipsum* generator (it needs to know the number of words to
42 You can use a ``lipsum`` *tag*:
48 That works, but using a tag for ``lipsum`` is not a good idea for at least
51 * ``lipsum`` is not a language construct;
52 * The tag outputs something;
53 * The tag is not flexible as you cannot use it in an expression:
57 {{ 'some text' ~ {% lipsum 40 %} ~ 'some more text' }}
59 In fact, you rarely need to create tags; and that's good news because tags are
60 the most complex extension point of Twig.
62 Now, let's use a ``lipsum`` *filter*:
68 Again, it works, but it looks weird. A filter transforms the passed value to
69 something else but here we use the value to indicate the number of words to
70 generate (so, ``40`` is an argument of the filter, not the value we want to
73 Next, let's use a ``lipsum`` *function*:
79 Here we go. For this specific example, the creation of a function is the
80 extension point to use. And you can use it anywhere an expression is accepted:
84 {{ 'some text' ~ ipsum(40) ~ 'some more text' }}
86 {% set ipsum = ipsum(40) %}
88 Last but not the least, you can also use a *global* object with a method able
89 to generate lorem ipsum text:
95 As a rule of thumb, use functions for frequently used features and global
96 objects for everything else.
98 Keep in mind the following when you want to extend Twig:
100 ========== ========================== ========== =========================
101 What? Implementation difficulty? How often? When?
102 ========== ========================== ========== =========================
103 *macro* trivial frequent Content generation
104 *global* trivial frequent Helper object
105 *function* trivial frequent Content generation
106 *filter* trivial frequent Value transformation
107 *tag* complex rare DSL language construct
108 *test* trivial rare Boolean decision
109 *operator* trivial rare Values transformation
110 ========== ========================== ========== =========================
115 A global variable is like any other template variable, except that it's
116 available in all templates and macros::
118 $twig = new Twig_Environment($loader);
119 $twig->addGlobal('text', new Text());
121 You can then use the ``text`` variable anywhere in a template:
123 .. code-block:: jinja
125 {{ text.lipsum(40) }}
130 A filter is a regular PHP function or an object method that takes the left
131 side of the filter (before the pipe ``|``) as first argument and the extra
132 arguments passed to the filter (within parentheses ``()``) as extra arguments.
134 Defining a filter is as easy as associating the filter name with a PHP
135 callable. For instance, let's say you have the following code in a template:
137 .. code-block:: jinja
141 When compiling this template to PHP, Twig looks for the PHP callable
142 associated with the ``lower`` filter. The ``lower`` filter is a built-in Twig
143 filter, and it is simply mapped to the PHP ``strtolower()`` function. After
144 compilation, the generated PHP code is roughly equivalent to:
146 .. code-block:: html+php
148 <?php echo strtolower('TWIG') ?>
150 As you can see, the ``'TWIG'`` string is passed as a first argument to the PHP
153 A filter can also take extra arguments like in the following example:
155 .. code-block:: jinja
157 {{ now|date('d/m/Y') }}
159 In this case, the extra arguments are passed to the function after the main
160 argument, and the compiled code is equivalent to:
162 .. code-block:: html+php
164 <?php echo twig_date_format_filter($now, 'd/m/Y') ?>
166 Let's see how to create a new filter.
168 In this section, we will create a ``rot13`` filter, which should return the
169 `rot13`_ transformation of a string. Here is an example of its usage and the
172 .. code-block:: jinja
176 {# should displays Gjvt #}
178 Adding a filter is as simple as calling the ``addFilter()`` method on the
179 ``Twig_Environment`` instance::
181 $twig = new Twig_Environment($loader);
182 $twig->addFilter('rot13', new Twig_Filter_Function('str_rot13'));
184 The second argument of ``addFilter()`` is an instance of ``Twig_Filter``.
185 Here, we use ``Twig_Filter_Function`` as the filter is a PHP function. The
186 first argument passed to the ``Twig_Filter_Function`` constructor is the name
187 of the PHP function to call, here ``str_rot13``, a native PHP function.
189 Let's say I now want to be able to add a prefix before the converted string:
191 .. code-block:: jinja
193 {{ "Twig"|rot13('prefix_') }}
195 {# should displays prefix_Gjvt #}
197 As the PHP ``str_rot13()`` function does not support this requirement, let's
198 create a new PHP function::
200 function project_compute_rot13($string, $prefix = '')
202 return $prefix.str_rot13($string);
205 As you can see, the ``prefix`` argument of the filter is passed as an extra
206 argument to the ``project_compute_rot13()`` function.
208 Adding this filter is as easy as before::
210 $twig->addFilter('rot13', new Twig_Filter_Function('project_compute_rot13'));
212 For better encapsulation, a filter can also be defined as a static method of a
213 class. The ``Twig_Filter_Function`` class can also be used to register such
214 static methods as filters::
216 $twig->addFilter('rot13', new Twig_Filter_Function('SomeClass::rot13Filter'));
220 In an extension, you can also define a filter as a static method of the
223 Environment aware Filters
224 ~~~~~~~~~~~~~~~~~~~~~~~~~
226 The ``Twig_Filter`` classes take options as their last argument. For instance,
227 if you want access to the current environment instance in your filter, set the
228 ``needs_environment`` option to ``true``::
230 $filter = new Twig_Filter_Function('str_rot13', array('needs_environment' => true));
232 Twig will then pass the current environment as the first argument to the
235 function twig_compute_rot13(Twig_Environment $env, $string)
237 // get the current charset for instance
238 $charset = $env->getCharset();
240 return str_rot13($string);
246 If automatic escaping is enabled, the output of the filter may be escaped
247 before printing. If your filter acts as an escaper (or explicitly outputs html
248 or javascript code), you will want the raw output to be printed. In such a
249 case, set the ``is_safe`` option::
251 $filter = new Twig_Filter_Function('nl2br', array('is_safe' => array('html')));
253 Some filters may need to work on input that is already escaped or safe, for
254 example when adding (safe) html tags to originally unsafe output. In such a
255 case, set the ``pre_escape`` option to escape the input data before it is run
256 through your filter::
258 $filter = new Twig_Filter_Function('somefilter', array('pre_escape' => 'html', 'is_safe' => array('html')));
263 .. versionadded:: 1.5
264 Dynamic filters support was added in Twig 1.5.
266 A filter name containing the special ``*`` character is a dynamic filter as
267 the ``*`` can be any string::
269 $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
271 function twig_path($name, $arguments)
276 The following filters will be matched by the above defined dynamic filter:
281 A dynamic filter can define more than one dynamic parts::
283 $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
285 function twig_path($name, $suffix, $arguments)
290 The filter will receive all dynamic part values before the normal filters
291 arguments. For instance, a call to ``'foo'|a_path_b()`` will result in the
292 following PHP call: ``twig_path('a', 'b', 'foo')``.
297 A function is a regular PHP function or an object method that can be called from
300 .. code-block:: jinja
302 {{ constant("DATE_W3C") }}
304 When compiling this template to PHP, Twig looks for the PHP callable
305 associated with the ``constant`` function. The ``constant`` function is a built-in Twig
306 function, and it is simply mapped to the PHP ``constant()`` function. After
307 compilation, the generated PHP code is roughly equivalent to:
309 .. code-block:: html+php
311 <?php echo constant('DATE_W3C') ?>
313 Adding a function is similar to adding a filter. This can be done by calling the
314 ``addFunction()`` method on the ``Twig_Environment`` instance::
316 $twig = new Twig_Environment($loader);
317 $twig->addFunction('functionName', new Twig_Function_Function('someFunction'));
319 You can also expose extension methods as functions in your templates::
321 // $this is an object that implements Twig_ExtensionInterface.
322 $twig = new Twig_Environment($loader);
323 $twig->addFunction('otherFunction', new Twig_Function_Method($this, 'someMethod'));
325 Functions also support ``needs_environment`` and ``is_safe`` parameters.
330 .. versionadded:: 1.5
331 Dynamic functions support was added in Twig 1.5.
333 A function name containing the special ``*`` character is a dynamic function
334 as the ``*`` can be any string::
336 $twig->addFunction('*_path', new Twig_Function_Function('twig_path'));
338 function twig_path($name, $arguments)
343 The following functions will be matched by the above defined dynamic function:
348 A dynamic function can define more than one dynamic parts::
350 $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
352 function twig_path($name, $suffix, $arguments)
357 The function will receive all dynamic part values before the normal functions
358 arguments. For instance, a call to ``a_path_b('foo')`` will result in the
359 following PHP call: ``twig_path('a', 'b', 'foo')``.
364 One of the most exciting feature of a template engine like Twig is the
365 possibility to define new language constructs. This is also the most complex
366 feature as you need to understand how Twig's internals work.
368 Let's create a simple ``set`` tag that allows the definition of simple
369 variables from within a template. The tag can be used like follows:
371 .. code-block:: jinja
373 {% set name = "value" %}
377 {# should output value #}
381 The ``set`` tag is part of the Core extension and as such is always
382 available. The built-in version is slightly more powerful and supports
383 multiple assignments by default (cf. the template designers chapter for
386 Three steps are needed to define a new tag:
388 * Defining a Token Parser class (responsible for parsing the template code);
390 * Defining a Node class (responsible for converting the parsed code to PHP);
392 * Registering the tag.
394 Registering a new tag
395 ~~~~~~~~~~~~~~~~~~~~~
397 Adding a tag is as simple as calling the ``addTokenParser`` method on the
398 ``Twig_Environment`` instance::
400 $twig = new Twig_Environment($loader);
401 $twig->addTokenParser(new Project_Set_TokenParser());
403 Defining a Token Parser
404 ~~~~~~~~~~~~~~~~~~~~~~~
406 Now, let's see the actual code of this class::
408 class Project_Set_TokenParser extends Twig_TokenParser
410 public function parse(Twig_Token $token)
412 $lineno = $token->getLine();
413 $name = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue();
414 $this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, '=');
415 $value = $this->parser->getExpressionParser()->parseExpression();
417 $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
419 return new Project_Set_Node($name, $value, $lineno, $this->getTag());
422 public function getTag()
428 The ``getTag()`` method must return the tag we want to parse, here ``set``.
430 The ``parse()`` method is invoked whenever the parser encounters a ``set``
431 tag. It should return a ``Twig_Node`` instance that represents the node (the
432 ``Project_Set_Node`` calls creating is explained in the next section).
434 The parsing process is simplified thanks to a bunch of methods you can call
435 from the token stream (``$this->parser->getStream()``):
437 * ``getCurrent()``: Gets the current token in the stream.
439 * ``next()``: Moves to the next token in the stream, *but returns the old one*.
441 * ``test($type)``, ``test($value)`` or ``test($type, $value)``: Determines whether
442 the current token is of a particular type or value (or both). The value may be an
443 array of several possible values.
445 * ``expect($type[, $value[, $message]])``: If the current token isn't of the given
446 type/value a syntax error is thrown. Otherwise, if the type and value are correct,
447 the token is returned and the stream moves to the next token.
449 * ``look()``: Looks a the next token without consuming it.
451 Parsing expressions is done by calling the ``parseExpression()`` like we did for
456 Reading the existing ``TokenParser`` classes is the best way to learn all
457 the nitty-gritty details of the parsing process.
462 The ``Project_Set_Node`` class itself is rather simple::
464 class Project_Set_Node extends Twig_Node
466 public function __construct($name, Twig_Node_Expression $value, $lineno, $tag = null)
468 parent::__construct(array('value' => $value), array('name' => $name), $lineno, $tag);
471 public function compile(Twig_Compiler $compiler)
474 ->addDebugInfo($this)
475 ->write('$context[\''.$this->getAttribute('name').'\'] = ')
476 ->subcompile($this->getNode('value'))
482 The compiler implements a fluid interface and provides methods that helps the
483 developer generate beautiful and readable PHP code:
485 * ``subcompile()``: Compiles a node.
487 * ``raw()``: Writes the given string as is.
489 * ``write()``: Writes the given string by adding indentation at the beginning
492 * ``string()``: Writes a quoted string.
494 * ``repr()``: Writes a PHP representation of a given value (see
495 ``Twig_Node_For`` for a usage example).
497 * ``addDebugInfo()``: Adds the line of the original template file related to
498 the current node as a comment.
500 * ``indent()``: Indents the generated code (see ``Twig_Node_Block`` for a
503 * ``outdent()``: Outdents the generated code (see ``Twig_Node_Block`` for a
506 .. _creating_extensions:
508 Creating an Extension
509 ---------------------
511 The main motivation for writing an extension is to move often used code into a
512 reusable class like adding support for internationalization. An extension can
513 define tags, filters, tests, operators, global variables, functions, and node
516 Creating an extension also makes for a better separation of code that is
517 executed at compilation time and code needed at runtime. As such, it makes
520 Most of the time, it is useful to create a single extension for your project,
521 to host all the specific tags and filters you want to add to Twig.
525 When packaging your code into an extension, Twig is smart enough to
526 recompile your templates whenever you make a change to it (when the
527 ``auto_reload`` is enabled).
531 Before writing your own extensions, have a look at the Twig official
532 extension repository: http://github.com/fabpot/Twig-extensions.
534 An extension is a class that implements the following interface::
536 interface Twig_ExtensionInterface
539 * Initializes the runtime environment.
541 * This is where you can load some file that contains filter functions for instance.
543 * @param Twig_Environment $environment The current Twig_Environment instance
545 function initRuntime(Twig_Environment $environment);
548 * Returns the token parser instances to add to the existing list.
550 * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
552 function getTokenParsers();
555 * Returns the node visitor instances to add to the existing list.
557 * @return array An array of Twig_NodeVisitorInterface instances
559 function getNodeVisitors();
562 * Returns a list of filters to add to the existing list.
564 * @return array An array of filters
566 function getFilters();
569 * Returns a list of tests to add to the existing list.
571 * @return array An array of tests
576 * Returns a list of functions to add to the existing list.
578 * @return array An array of functions
580 function getFunctions();
583 * Returns a list of operators to add to the existing list.
585 * @return array An array of operators
587 function getOperators();
590 * Returns a list of global variables to add to the existing list.
592 * @return array An array of global variables
594 function getGlobals();
597 * Returns the name of the extension.
599 * @return string The extension name
604 To keep your extension class clean and lean, it can inherit from the built-in
605 ``Twig_Extension`` class instead of implementing the whole interface. That
606 way, you just need to implement the ``getName()`` method as the
607 ``Twig_Extension`` provides empty implementations for all other methods.
609 The ``getName()`` method must return a unique identifier for your extension.
611 Now, with this information in mind, let's create the most basic extension
614 class Project_Twig_Extension extends Twig_Extension
616 public function getName()
624 Of course, this extension does nothing for now. We will customize it in
627 Twig does not care where you save your extension on the filesystem, as all
628 extensions must be registered explicitly to be available in your templates.
630 You can register an extension by using the ``addExtension()`` method on your
631 main ``Environment`` object::
633 $twig = new Twig_Environment($loader);
634 $twig->addExtension(new Project_Twig_Extension());
636 Of course, you need to first load the extension file by either using
637 ``require_once()`` or by using an autoloader (see `spl_autoload_register()`_).
641 The bundled extensions are great examples of how extensions work.
646 Global variables can be registered in an extension via the ``getGlobals()``
649 class Project_Twig_Extension extends Twig_Extension
651 public function getGlobals()
654 'text' => new Text(),
664 Functions can be registered in an extension via the ``getFunctions()``
667 class Project_Twig_Extension extends Twig_Extension
669 public function getFunctions()
672 'lipsum' => new Twig_Function_Function('generate_lipsum'),
682 To add a filter to an extension, you need to override the ``getFilters()``
683 method. This method must return an array of filters to add to the Twig
686 class Project_Twig_Extension extends Twig_Extension
688 public function getFilters()
691 'rot13' => new Twig_Filter_Function('str_rot13'),
698 As you can see in the above code, the ``getFilters()`` method returns an array
699 where keys are the name of the filters (``rot13``) and the values the
700 definition of the filter (``new Twig_Filter_Function('str_rot13')``).
702 As seen in the previous chapter, you can also define filters as static methods
703 on the extension class::
705 $twig->addFilter('rot13', new Twig_Filter_Function('Project_Twig_Extension::rot13Filter'));
707 You can also use ``Twig_Filter_Method`` instead of ``Twig_Filter_Function``
708 when defining a filter to use a method::
710 class Project_Twig_Extension extends Twig_Extension
712 public function getFilters()
715 'rot13' => new Twig_Filter_Method($this, 'rot13Filter'),
719 public function rot13Filter($string)
721 return str_rot13($string);
727 The first argument of the ``Twig_Filter_Method`` constructor is always
728 ``$this``, the current extension object. The second one is the name of the
731 Using methods for filters is a great way to package your filter without
732 polluting the global namespace. This also gives the developer more flexibility
733 at the cost of a small overhead.
735 Overriding default Filters
736 ..........................
738 If some default core filters do not suit your needs, you can easily override
739 them by creating your own extension. Just use the same names as the one you
742 class MyCoreExtension extends Twig_Extension
744 public function getFilters()
747 'date' => new Twig_Filter_Method($this, 'dateFilter'),
752 public function dateFilter($timestamp, $format = 'F j, Y H:i')
754 return '...'.twig_date_format_filter($timestamp, $format);
757 public function getName()
763 Here, we override the ``date`` filter with a custom one. Using this extension
764 is as simple as registering the ``MyCoreExtension`` extension by calling the
765 ``addExtension()`` method on the environment instance::
767 $twig = new Twig_Environment($loader);
768 $twig->addExtension(new MyCoreExtension());
773 Adding a tag in an extension can be done by overriding the
774 ``getTokenParsers()`` method. This method must return an array of tags to add
775 to the Twig environment::
777 class Project_Twig_Extension extends Twig_Extension
779 public function getTokenParsers()
781 return array(new Project_Set_TokenParser());
787 In the above code, we have added a single new tag, defined by the
788 ``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is
789 responsible for parsing the tag and compiling it to PHP.
794 The ``getOperators()`` methods allows to add new operators. Here is how to add
795 ``!``, ``||``, and ``&&`` operators::
797 class Project_Twig_Extension extends Twig_Extension
799 public function getOperators()
803 '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
806 '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
807 '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
818 The ``getTests()`` methods allows to add new test functions::
820 class Project_Twig_Extension extends Twig_Extension
822 public function getTests()
825 'even' => new Twig_Test_Function('twig_test_even'),
835 .. versionadded:: 1.10
836 Support for functional tests was added in Twig 1.10.
841 You can create functional tests for extensions simply by creating the
842 following file structure in your test directory::
856 The ``IntegrationTest.php`` file should look like this::
858 class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
860 public function getExtensions()
863 new Project_Twig_Extension1(),
864 new Project_Twig_Extension2(),
868 public function getFixturesDir()
870 return dirname(__FILE__).'/Fixtures/';
874 Fixtures examples can be found within the Twig repository
875 `tests/Twig/Fixtures`_ directory.
880 Testing the node visitors can be complex, so extend your test cases from
881 ``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository
882 `tests/Twig/Node`_ directory.
884 .. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register
885 .. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php
886 .. _`tests/Twig/Fixtures`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Fixtures
887 .. _`tests/Twig/Node`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Node