Filters - Modifying Variables In Twig Templates

Last updated on
21 November 2025

Filters in Twig can be used to modify variables. Filters are separated from the variable by a pipe symbol. They may have optional arguments in parentheses. Multiple filters can be chained. The output of one filter is applied to the next.

Example:
{{ content|safe_join(", ")|lower }}

You may have to render an item before you filter it (sometimes even twice) which can fix an InvalidArgumentException: $string ("Array") must be a string error:
{{ item|render|filter }}

Twig comes with many filters built into it. Drupal 11.x and 10.x uses Twig 3.x, Drupal 9.x uses Twig 2.x, and Drupal 8.x uses Twig 1.x. Drupal has a variety of filters native to it.

Drupal Specific Filters

These are declared in TwigExtension::getFilters().

Translation filters

trans

The translation filter will run the variable through the Drupal t() function, which will return a translated string. This filter should be used for any interface text manually placed in the template that will appear for users. Templates can use either the longer filter name of |trans or the shorter filter name |t.

Incorrect example:

<button>Close</button>

Correct example: 

<button>{{ 'Close'|t }}</button>

Sometimes template variables need to be used in the middle of a text that needs translation. This can be achieved with placeholders. See documentation for the placeholderFormat() method for full details.

Incorrect example:

{{ 'Submitted by'|t }} {{ author_name }} {{ 'on'|t }} ({ date }}

Correct example: 

{{ 'Submitted by @author_name on @date' |t({'@author_name': author_name, '@date': date}) }}

In the above example, the value of the author_name variable is inserted in place of @author_name in the translated text.

Alternatively, the trans tag can be used instead of the t filter. The following example is the equivalent of the previous example.

{% trans %}Submitted by {{ author_name }} on {{ date }}{% endtrans %}

In between the starting {% trans %} and the ending {% endtrans %}, text doesn't need to be quoted or use the t filter.

plural

The {% trans %} tag can also be used to format words in their plural form with the use of the {% plural <variable> %} tag inside it.

{% trans %}
  {{ count }} result was found.
{% plural count %}
  {{ count }} results were found.
{% endtrans %}

In the above example, if count is 1, the text before the {% plural count %} tag is used. Otherwise, the text after {% plural count %} is used.

placeholder

This filter escapes content to HTML and formats it using drupal_placeholder(), which makes it display as emphasized text.

Example:

{% trans %}Submitted on {{ date|placeholder }}{% endtrans %}

Unsafe translation

Passing a variable directly to translation is unsafe and should not be used. Doing so not only inflates the list of strings for translation but is exposes a potential security vulnerability, particularly if the variable was created using user input:

Unsafe Translation Examples
{# DO NOT USE THESE UNSAFE METHODS #}
{{ var1|t }}
{{ var1|placeholder }}
{% trans %}{{ var1 }}{% endtrans %}

To summarize, the above are all unsafe, as only strings should be passed to translation functions, not the values of variables.

Additional filters

clean_class

This filter prepares a string for use as a valid HTML class name. See Html::getClass()

clean_id

This filter prepares a string for use as a valid HTML ID. See Html::getID()

format_date

This filter prepares a timestamp for use as a formatted date string. See DateFormatter::format()

  • To format timestamp: {{ created|format_date }}
  • To format using specific date type: {{ created|format_date('short') }}
  • To format using a custom date type with PHP style formatting: {{ created|format_date('custom', 'M j, Y') }}

raw

This filter should be avoided whenever possible, particularly if you're outputting data that could be user-entered. See this page for more information on auto-escape in Drupal 8.

In Drupal 9 Twig 2, the {% raw %} tag is deprecated in favor of {% verbatim %}. (The |raw filter, on the other hand, is not deprecated.)

Example:

{{ content.body|raw }}

render

This filter is a wrapper for the render() function. It takes a render array and outputs rendered HTML markup. This can be useful if you want to apply an additional filter (such as stripping tags), or if you want to make a conditional based on the rendered output (for example, if you have a non-empty render array that returns an empty string). It also can be used on strings and certain objects, mainly those implementing the toString() method.

safe_join

The safe_join filter joins several strings together with a supplied separator. See TwigExtension::safeJoin().

Example:
{{ items|safe_join(', ') }}
This will output each string in the items variable concatenated together with a comma separating each item.

without

The without filter creates a copy of the renderable array and removes child elements by key specified through arguments passed to the filter. The copy can be printed without these elements. The original renderable array is still available and can be used to print child elements in their entirety in the twig template. See twig_without.

Examples:

{{ content|without('links') }}
This prints everything in the content variable except content.links.

{{ content|without('links', 'field_some_data') }}
Example of excluding two elements from display. This will exclude 'links' and 'field_some_data'.

add_suggestion

The add_suggestion filter allows adding a theme suggestion to a render array rendered with #theme. For example, if content.body has a render array with '#theme' => 'field', using the |add_suggestion filter with the variable {{ content.body|add_suggestion('details') }} would allow loading a template field--details.html.twig.

The theme suggestion added with |add_suggestion will have the highest priority, and will take precedence over any pre-existing theme suggestions. This filter requires Drupal version 10.0.0 or higher. 

Example:

{# in the main template #}  
  
{{ content.field_items|add_suggestion('unordered-list') }} 
{# field--unordered-list.html.twig #}

{% extends 'field.html.twig' %}

{% block content %}
  <ul{{ attributes }}>
    {{ parent() }}
  </ul>
{% endblock content %}

{% block item %}
  <li{{ item.attributes }}>{{ parent() }}</li>
{% endblock item %}

More examples can be found in the change record introducing the add_suggestion filter. 

clean_unique_id

A new clean_unique_id Twig filter has been added to Drupal 10.1 and later. This can be used for getting a unique ID. The filter ensures that even if the template rendered multiple times, the ID remains unique for each usage.

Example:

<div{{ attributes.setAttribute('id', 'my-id'|clean_unique_id) }}></div>

add_class

A new add_class Twig filter has been added to Drupal 10.1 and later. This allows for setting CSS classes on field render arrays.

Example:

{{ content.field_body|add_class('my-new-body-class') }} adds the my-new-body-class CSS class to the field template for field_body.

set_attribute

A new set_attribute Twig filter has been added to Drupal 10.1 and later. This allows for setting HTML attributes on field render arrays.

Example:

{{ content.field_image|set_attribute('fetchpriority', 'auto') }} adds the fetchpriority="auto" attribute and value to the field template for field_image.

Help improve this page

Page status: No known problems

You can: