Preparing for use of Twig 2 in Drupal 9

Last updated on
20 July 2023

The update from Drupal 8 to Drupal 9 includes updating the Twig dependency from Twig 1 to Twig 2. Unfortunately due to how composer dependencies work for Drupal 8 sites, we cannot update Drupal 8 to optionally allow Twig 2 support, even though the API is fully ready for that. So these changes can only be made currently in your Drupal 9 environment.

Use Upgrade Status 8.x-2.x either on the UI or via Drush to check your Twig files for deprecated syntax use. Fortunately, the changes from Twig 1 to Twig 2 should be manageable for most users, and many projects will not require any changes. 

Template-facing Twig 2 changes

Twig 2 has a few small changes that impact the template level language (i.e. the language used in .html.twig files):

  • As of Twig 2.0, macros imported in a file are no longer available in child templates anymore (via an includecall for instance). Macros must now be explicitly imported in each file they are used.

  • Silent display of undefined blocks is deprecated since version 1.29 and will throw an exception in 2.0. This can be addressed by wrapping potentially-undefined blocks in conditionals that verify they are defined before attempting to display them. 

    {% if block('potentially-undefined-block') is defined %}
      {{ block('potentially-undefined-block') }} 
    {% endif %} 
  • Using an if condition on for tags is deprecated since Twig 2.10.0, use a filter filter or an if condition inside the for body instead (if your condition depends on a variable updated inside the loop).

    <ul>
        {% for user in users if user.active %}
            <li>{{ user.username|e }}</li>
        {% endfor %}
    </ul>

    can be replaced with:

    <ul>
        {% for user in users|filter(user => user.active) %}
            <li>{{ user.username|e }}</li>
        {% endfor %}
    </ul>

    or

    <ul>
        {% for user in users %}
            {% if user.active %}
                <li>{{ user.username|e }}</li>
            {% endif %}
        {% endfor %}
    </ul>

    And if you are filtering against the key.

    <ul>
    {% for key, item in items if key|first != '#' %}
       {{ link(item.title, item.url) }}
    {% endfor %}
    <ul>

    can be replaced with:

    <ul>
    {% for key, item in items|filter((value, key) => key|first != '#') %}
       {{ link(item.title, item.url) }}
    {% endfor %}
    <ul>
  • As of Twig 2.7, the spaceless tag is deprecated. Use the spaceless filter instead or {% apply spaceless %}

    -  {% spaceless %}
    +  {% apply spaceless %}
         {{ element_to_be_spaceless }}
    -  {% endspaceless %}
    +  {% endapply %}
  • As of Twig 1.x, the raw tag is deprecated in favor of verbatim

  • The sameas and divisibleby tests are deprecated in favor of same as and divisible by respectively.

  • As of Twig 1.x, using the _self global variable to access to the current \Twig\Template instance is deprecated. In Twig 2.0, the output of _self is the current template name, so instances of {{ _self.templateName }} should be replaced with {{ _self }}. Note that _self can still be used to access macros - e.g. {{ _self.macro_name() }} is still valid.

Changes affecting module developers

Changes affecting module developers can also be detected using the Upgrade status module.

Major changes include:

  • As of Twig 1.x, the ability to remove an extension is deprecated and the \Twig\Environment::removeExtension() method will be removed in 2.0.
  • As of Twig 1.x, use \Twig\TwigFunction to add a function. The following classes and interfaces will be removed in 2.0:
    • Twig_FunctionInterface
    • Twig_FunctionCallableInterface
    • Twig_Function
    • Twig_Function_Function
    • Twig_Function_Method
    • Twig_Function_Node
  • As of Twig 1.x, use \Twig\TwigFilter to add a filter. The following classes and interfaces will be removed in 2.0:
    • Twig_FilterInterface
    • Twig_FilterCallableInterface
    • Twig_Filter
    • Twig_Filter_Function
    • Twig_Filter_Method
    • Twig_Filter_Node

Additional information on the change from Twig 1 to Twig 2

Help improve this page

Page status: No known problems

You can: