Working with Twig Templates in Drupal 8

drupal.org: mikeker

"Dude, where's my car file?"

http://slides.com/mikeker/twig-templates-in-d8

Me: circa 2013

Debugging

# Uncomment these lines in settings.php
if (file_exists(__DIR__ . '/settings.local.php')) {
  include __DIR__ . '/settings.local.php';
}
# Change this is sites/default/services.yml
parameters:
  twig.config:
    # @default false
    debug: true
$ cp sites/example.settings.local.php ↵ 
 sites/default/settings.local.php
$ drush cache-rebuild  # alias: drush cr
# Uncomment the following line in settings.local.php
$settings['cache']['bins']['render'] = 'cache.backend.null';

https://www.flickr.com/photos/tsevis/

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'field' -->
<!-- FILE NAME SUGGESTIONS:
   * field--node--body--page.html.twig
   * field--node--body.html.twig
   * field--node--page.html.twig
   * field--body.html.twig
   x field--text-with-summary.html.twig
   * field.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/classy/templates/↵
 field/field--text-with-summary.html.twig' -->

... Template output goes here ...

<!-- END OUTPUT from 'core/themes/classy/templates/↵
 field/field--text-with-summary.html.twig' -->

Drupal Template Helper

https://github.com/arshad/drupal-template-helper

Template file location

-core
-modules
-themes
  |-contrib
  |-custom
     |-example_theme
       |-...
       |-templates
          |-field.html.twig
          |-field--field-custom-field.html.twig
          |-node.html.twig
          |-node--article.html.twig
          |-...
       
-core
-modules
-themes
  |-contrib
  |-custom
     |-example_theme
       |-...
       |-templates
          |-fields
            |-field.html.twig
            |-field--field-custom-field.html.twig
          |-nodes
            |-node.html.twig
            |-node--article.html.twig
          |-...
       

Theme suggestions

// Drupal 7 version
function HOOK_preprocess_views_view(&$variables) {
  if ($variables['name'] == 'my_view') {
    $variables['theme_hook_suggestions'][] =
     'my_view_template';
  }
}
// No more singular -- this does not work in Drupal 8:
$variables['theme_hook_suggestion'] = 
  'node__' . 'use_this_one';

In Drupal 8 we have:

  1. hook_theme_suggestions_alter()
  2. hook_theme_suggestions_HOOK()
  3. hook_theme_suggestions_HOOK_alter()

 

hook_theme_suggestions_alter

function MYTHEME_theme_suggestions_alter(array &$suggestions, ↵
array $variables, $hook) {
  if (\Drupal::currentUser()->isAuthenticated() && 
    in_array($hook, array('node', 'taxonomy_term'))) {

    $suggestions[] = $hook . '__' . 'logged_in';

  }
}

Views, as an example

https://www.drupal.org/node/2118743

Adding Options

function MYTHEME_theme_suggestions_views_view_alter ↩
(array &$suggestions, array $variables) {

  $display = $variables['view']->getDisplay()->getPluginId();
  $view = $variables['view']->id();
  $suggestions[] = "views_view__$view";
  $suggestions[] = "views_view__$display";
  $suggestions[] = "views_view__$view" . "__$display";
}

Preprocessing

         Template: field.html.twig
mytheme_preprocess_field(&$variables)

         Template: field--field-name.html.twig
mytheme_preprocess_field__field_name(&$variables)

         Template: node--node-type--view-mode.html.twig
mytheme_preprocess_node__node_type__view_mode(&$variables)

Template Reuse

The old way

{# You could do this in each field template override... #}
{# File: templates/field--field-list.html.twig #}
<div{{ attributes }}>
  <ul class="{{ classes |  join(' ') }}">
    {% for item in items %}
      <li>{{ item }}</li>
    {% endfor %}
  </ul>
</div>

A better way...

{# Super simplified list example #}
{# File: templates/list.twig #}
{% set listType = listType ?? 'ul' %}
{% set classes = classes ?? ['default', 'classes'] %}
<div{{ attributes }}>
  <{{ listType }} class="{{ classes |  join(' ') }}">
    {% for item in items %}
      <li>{{ item }}</li>
    {% endfor %}
  </{{ listType }}>
</div>
{# File: templates/field--field-name.html.twig #}
{% include '@theme_name/lists.twig' %}

A better way, continued...

 

{# File: templates/field--field-name.html.twig #}
{% include '@test/lists.twig' with {
  listType: 'ol',
  classes: ['my', 'new', 'classes'],
}%}

Why?

{# File: template/lists.twig #}
{% set listType = listType ?? 'ul' %}
{% set classes = classes ?? ['default', 'classes'] %}
<div{{ attributes }}>
  {% if items | length == 1 %}
    {{ items }}
  {% else %}
    <{{ listType }} class="{{ classes |  join(' ') }}">
      {% for item in items %}
        <li>{{ item }}</li>
      {% endfor %}
    </{{ listType }}>
  {% endif %}
</div>

Any questions?

Working with Twig Templates in Drupal 8

By Mike Keran

Working with Twig Templates in Drupal 8

  • 1,267