Skip to content

Instantly share code, notes, and snippets.

@raphaellarrinaga
Last active July 20, 2023 21:21
Show Gist options
  • Star 52 You must be signed in to star a gist
  • Fork 27 You must be signed in to fork a gist
  • Save raphaellarrinaga/c1d71f69873c967ff74f8ec09cbdf9e1 to your computer and use it in GitHub Desktop.
Save raphaellarrinaga/c1d71f69873c967ff74f8ec09cbdf9e1 to your computer and use it in GitHub Desktop.
[Drupal 8 Twig cheatsheet] #tags: drupal8, twig, cheatsheet

Drupal 8 Twig cheatsheet

Please note I created that sheet as a personal side note/draft and not everything is fully tested. There could be errors or better things to do. So if you spot something wrong or something that can be improved, feel free to comment below and I will do the changes.

Getting Drupal 8 field values in Twig

Image path: {{ file_url(content.field_name['#items'].entity.uri.value) }}

Image title text: {{ node.field_name.title }}

Entity Reference path: {{ content.field_tags[0]['#url'] }}

@see https://blog.usejournal.com/getting-drupal-8-field-values-in-twig-22b80cb609bd

Check if field is filled

{% if not node.field_name.isEmpty() %}

Old solution below (does not work), will be true most of the time since the render array is not empty (e.g. gets #cache or #weight rows).

  {% if content.field_image|length %}
  <div class="banner">{{ content.field_image[0] }}</div>
  {% endif %}

Credit @lincoln-chawora 🙏

Check for some content existence

Those solutions are not perfect. @see https://www.drupal.org/project/drupal/issues/953034?page=1

  • e.g. for a region or a field that contains text content.field_fee|render|striptags|trim
  • e.g. for a field image using field value module content.header.field_image|field_value

Custom date format

{% set date = node.createdtime|format_date('long') %}

@see http://agileadam.com/2017/08/drupal-8-formatting-a-date-field-in-twig/

Use Twig date filter + a defined Drupal date format

{{ node.field_blog_date.value|date('U')|format_date('short_mdyyyy') }}

Use Twig date filter

{{ node.field_blog_date.value|date('n/j/Y') }}

Set variables in a translated twig variable

<p class="submitted">{{ "Submitted by !author on @date"|t({ '!author': author, '@date': date }) }}</p>

or

  {% set front_uri = path('<front>') %}
  {% set search_uri = path('view.solr_search_content.page_1') %}
  <p>{% trans %}Return to the <a href="{{ front_uri }}">homepage</a> or <a href="{{ search_uri }}">search articles</a>.{% endtrans %}</p>
  <p>{{ 'Return to the <a href="@front">homepage</a> or <a href="@search">search articles</a>.'|t({'@front': front_uri, '@search': search_uri}) }}</p>

or

{% set  url_1 = path('entity.node.canonical', {'node': 1050}) %}
{% set  url_2 = path('entity.node.canonical', {'node': 2010}) %}
{% trans %}I will have <a href="{{ url_1 }}">one link</a> and <a href="{{ url_2 }}">a second link.</a>{% endtrans %}

@see - more on twig translation https://getlevelten.com/blog/mark-carver/drupal-8-twig-templates-and-translations

Create a link

<a href="{{ path('contact.site_page') }}">{{ 'Contact'|t }}</a>    
<a href="{{ url('contact.site_page') }}">{{ 'Contact'|t }}</a>
{{ link('Contact'|t, 'base:contact', { 'class':[] }) }}

@see - https://drupal.stackexchange.com/a/208107/30331

Render a field to use it eg, in a translated string

{% set number = "Duo @number"|t({ '@number': number|render|striptags }) %}

@see https://www.drupal.org/project/drupal/issues/2728915#comment-11208967

Loop through child elements in Twig like Element::children()

! First @see https://www.drupal.org/node/2776307 And https://www.drupal.org/project/twig_extender

{% for key, child in parent if key|first != '#' %}
  {{ child }}
{% endfor %}

@see https://drupal.stackexchange.com/questions/174742/loop-through-child-elements-in-twig-like-elementchildren/174743

or

{% for key, item in items %}
  {% if key matches '/^\\d+$/' %}
    {{ item }}
  {% endif %}
{% endfor %}

Be carreful, this bypasses theme and will print without template and any html field wrappers @see https://www.drupal.org/forum/support/theme-development/2015-12-16/entity-reference-values-in-twig-template#comment-10900706

Merge arrays

That synthax avoid errors if classes is initialy empty.

{% set classes = { 'class' : 'teaser' }|merge({ (classes) : classes }) %}
<article class="{{ classes|join(' ') }}" role="article">

Override custom layout templates (eg for a specific node)

  1. Be carreful to set
et_twocols_hero:
  class: '\Drupal\ds\Plugin\DsLayout'
  1. Also name the template as the machine name otherwise suggestions provided by DS will not follow the same convention bu the one from machine name then Entity, bundle, view mode
et_twocols_hero:
  template: templates/et-twocols-hero

Provide splited views More link and title vars

/**
 * Implements template_preprocess_views_view()
 * @param array $variables
 */
function hook_preprocess_views_view(&$variables){
  $view = $variables['view'];

  $variables['more_url'] = $variables['more']['#url'];
  $variables['more_text'] = $variables['more']["#title"];

  // @todo see usage of `title`, maybe combined with twig if on default template
  $variables['custom_title'] = [
    '#markup' => $view->getTitle(),
  ];
}

Provide block classes from id

  • plugin_id : unique identifier provided for all blocks (duplicated one, displayed by context module)
  • elements['#id'] : unique identifier depending on block id defined via block layout UI, NULL is returned by context module
{%
  set classes = [
    'block-' ~ plugin_id|clean_class,
    'block--' ~ (elements['#id'] ? elements['#id']|clean_class),
  ]
%}

Provide Custom block bundle templates / or classes (block types from custom block library)

use \Drupal\block_content\BlockContentInterface;

/**
 * Implements hook_theme_suggestions_block_alter().
 */
function hops_theme_suggestions_block_alter(array &$suggestions, array $variables) {
  $content = $variables['elements']['content'];
  if (isset($content['#block_content']) and $content['#block_content'] instanceof BlockContentInterface) {
    $bundle = $content['#block_content']->bundle();
    $view_mode = $content['#view_mode'];
    $suggestions[] = 'block__' . $bundle;
    $suggestions[] = 'block__' . $view_mode;
    $suggestions[] = 'block__' . $bundle . '__' . $view_mode;
  }
}

Display a block entity reference field

{% block content %}
  {% set node_1_teaser = content.field_node_reference.0|merge({'#view_mode': 'compact'}) %}
  {% set node_2_teaser = content.field_node_reference.1|merge({'#view_mode': 'compact'}) %}
  {{ node_1_teaser }}
  <a href="{{ path('entity.node.canonical', {'node': content.field_node_reference.0['#node'].id}) }}">{{ 'Learn more'|t }}</a>
  {{ node_2_teaser }}
  <a href="{{ path('entity.node.canonical', {'node': content.field_node_reference.1['#node'].id}) }}">{{ 'Learn more'|t }}</a>
{% endblock %}

Render referenced entity field as text

Example here for a referenced paragraph but could work with a node with tab['#node'].

{% for key, tab in content.field_reference_tab if key|first != '#' %}
  {% set body = {
    '#type': 'processed_text',
    '#text': tab['#paragraph'].get('field_body').getValue.0.value,
    '#format': tab['#paragraph'].get('field_body').getValue.0.format,
  } %}
  {{ body }}
{% endfor %}
@cnochx
Copy link

cnochx commented Aug 15, 2020

super great !

@RobertCastro
Copy link

😍 Thank you

@lincoln-chawora
Copy link

To check if a field value has value i tend to go with: {% if not node.field_name.isEmpty() %} and that works pretty well, if it's a paragraph field then you’d replace node with paragraph.

@raphaellarrinaga
Copy link
Author

To check if a field value has value i tend to go with: {% if not node.field_name.isEmpty() %} and that works pretty well, if it's a paragraph field then you’d replace node with paragraph.

Thanks a lot, I will check and update.

@KenKodz
Copy link

KenKodz commented Sep 8, 2021

It's amazing how hard it is to find some of the things you have in here. Thank you for compiling all of this!

@raphaellarrinaga
Copy link
Author

To check if a field value has value i tend to go with: {% if not node.field_name.isEmpty() %} and that works pretty well, if it's a paragraph field then you’d replace node with paragraph.

@lincoln-chawora Finally tested and updated, thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment