Theming in Drupal 8 - alles neu mit Twig? (Teil 2)

Nachdem der erste Teil der Blogpostreihe eher allgemein auf Twig eingegangen ist, soll im zweiten Teil der Syntax anhand von Codebeispielen näher erklärt werden. Um die Unterschiede besser aufzuzeigen, stelle ich im Blogpost die uns bekannte Syntax direkt in den Vergleich zur neuen Twig-Syntax. Alle hier gezeigten Beispiele basieren auf dem aktuellen Entwicklungsstand der Drupal 8 Twig-Sandbox.


Der Themer sollte sich im Normalfall eigentlich nur noch um die Ausgabe vordefinierten Variablen (Platzhalter) oder einfacher Kontrollstrukturen (if-Abfragen oder for-Schleifen, die bspw. in Listen verwendet werden) kümmern müssen. Komplexere eigene Logik sollte man nicht in Templates hinterlegen - hier hat sich sicherlich jeder mal ausgetobt, um im Template 'eben mal schnell' noch einen View zu laden oder einzelne Felder benutzerdefiniert auszugeben. Dies führte am Ende meist zu recht komplexen und unübersichtlichen Templates, die nach einer gewissen Zeit eher schlecht wartbar wurden. Dies lag vor allem an der Tatsache, dass in PHP alle Möglichkeiten offenstanden und diese dann auch ausgiebig genutzt wurden.

Ausgabe von Variablen

Beispiel für die Ausgabe von Variablen und einer einfachen if-Anweisung in PHPTemplate:

  1. <div id="taxonomy-term-<?php print $term->tid; ?>">
  2.   <?php if (!$page): ?>
  3.     <h2><?php print $term_name; ?></h2>
  4.   <?php endif; ?>
  5.   <div class="content">
  6.    <?php print render($content); ?>
  7.   </div>
  8. </div>

Beispiel für die Ausgabe von Variablen und einer einfachen if-Anweisung in Twig:

  1. <div id="taxonomy-term-{{ term.tid }}"{{ attributes }}>
  2.   {% if not page %}
  3.     <h2>{{ term_name }}</h2>
  4.   {% endif %}
  5.   <div class="content">
  6.     {{ content }}
  7.   </div>
  8. </div>

Im gezeigten Beispiel sieht man schon die Unterschiede - statt der PHP-Funktionen print bzw. der Drupal eigenen render-Funktion wird in Zukunft zur Ausgabe nur noch {{ name_der_variable }} verwendet. Auch der Zugriff auf Array bzw. Objekt-Konstrukte innerhalb der Templates wurde vereinfacht. Hier setzt man nun auf eine konsistente Syntax, die nun - wie im Beispiel zu sehen - auf eine Punkt-Syntax setzt. Dabei spielt es keine Rolle, ob man auf Arrayelemente oder Objektelemente zugreifen möchte.

Beispiel aus einem Views-Exposed-Filter in PHPTemplate:

  1. <div class="custom-wrapper">
  2.   <label for="<?php print $widgets['filter-myfield']->id; ?>">
  3.     <?php print $widgets['filter-myfield']->label ?>
  4.   </label>
  5.   <?php print $widgets['filter-myfield']->widget ?>
  6. </div>

Beispiel aus einem Views-Exposed-Filter in Twig:

  1. <div class="custom-wrapper">
  2.   <label for="{{ widgets.filter-myfield.id }}">{{ widgets.filter-myfield.label }}</label>
  3.   {{ widgets.filter-myfield.widget }}
  4. </div>

Kontrollstrukturen

Neben der oben schon gezeigten if-Abfrage, gibt es noch die Möglichkeit zur Nutzung von for-Schleifen in den Templates innerhalb von {% %} Zeichen.

Beispiel für for-Schleife in PHPTemplate

  1. <?php foreach ($book_menus as $book_id => $menu): ?>
  2.   <div id="book-block-menu-<?php print $book_id; ?>" class="book-block-menu">
  3.     <?php print render($menu); ?>
  4.   </div>
  5. <?php endforeach; ?>

Beispiel für for-Schleife in Twig

  1. {% for book_id, menu in book_menus %}
  2.   <nav id="book-block-menu-{{ book_id }}" class="book-block-menu">
  3.     {{ menu }}
  4.   </nav>
  5. {% endfor %}

Wie auch schon in den früheren Drupal-Versionen, sollten wir direkt auf Theme-Ebene vermeiden, zu viel Logik in die Templates zu packen. Hierfür stehen uns weiterhin die preprocess-Funktionen zur Verfügung.Neben der neuen {% %} Syntax im Template sieht man hier auch die Nutzung des neuen nav-Elements aus dem HTML5-Standard, der somit auch in andere Twig-Templates Einzug gehalten hat.

Kommentare in Templates

Für die Dokumentation innerhalb von Templates wird in Twig die {# #}-Syntax verwendet.

Beispiel für Kommentar in PHPTemplate (phpdoc-Style):

  1. <?php
  2. // Hier steht ein einzeiliger Kommentar.
  3. /*
  4.  * Hier steht ein mehrzeiliger Kommentar
  5.  * mit weiteren Informationen zur Funktionsweise des Templates.
  6.  */
  7. ?>

Beispiel für Kommentar in Twig:

  1. {# Hier steht ein einzeiliger Kommentar #}
  2.  
  3. {# Hier steht ein mehrzeiliger Kommentar
  4.    mit weiteren Informationen zur Funktionsweise des Templates.
  5. #}

Wiederverwendbarkeit von Templates über Includes

Obwohl auch in PHPTemplate durch PHP schon die Nutzung der include bzw. include_once möglich gewesen wäre, fand diese nur sehr selten Einsatz in den Templates. In Twig werden Includes nun aber häufiger anzutreffen sein. Ein gutes Beispiel hierfür liefert das image-Modul - hier wird je nach übergebenem Imagestyle ein eigenes Template über die include eingebunden.

  1. <figure class="{{ item.attributes.class }}"{{ item.attributes }}>
  2.   {% if style %}
  3.     {% include 'core/themes/stark/templates/image/image_style.html.twig' with {image: item.image } %}
  4.   {% else %}
  5.     {% include 'core/themes/stark/templates/theme.inc/image.html.twig' with {image: item.image } %}
  6.   {% endif %}
  7.   {% if item.caption %}
  8.     <figcaption>
  9.       {{ item.caption }}
  10.     </figcaption>
  11.   {% endif %}
  12. </figure>
  13.  
Den inkludierten Daten lassen sich dann über den Parameter with auch direkt Variablen aus dem übergeordnetem Template mitgeben.

Verwendung von Filtern

Über Filter lässt sich die Ausgabe von Variablen auf Theme-Ebene beeinflussen. Beispielhaft zu den Möglichkeiten von Filtern möchte ich hier die Twig-Alternativen zur t-Funktion und der check_plain-Funktion zeigen.

Übersetzungen in Templates

Beispiel für eine Übersetzung in PHPTemplate:

  1. <div class="poll">
  2.   <div class="title"><?php print $title ?></div>
  3.   <?php print $results ?>
  4.   <div class="total">
  5.     <?php print t('Total votes: @votes', array('@votes' => $votes)); ?>
  6.   </div>
  7. </div>
  8. <div class="links"><?php print $links; ?></div>
Beispiel für eine Übersetzung in Twig:
  1. {{ name }} <small>{{ '(Machine name: @type)'|t({ '@type': type }) }}</small>
  2. <div class="description">{{ description }}</div>
Wie auch in der t-Funktion kann man auch in Twig über Platzhalter etwas mehr Dynamik in die zu übersetzenden Zeichenketten bringen. Im Beispiel wird die übergebene Variable $votes bzw. type bei Ausgabe in der Zeichenkette ersetzt.

Sonderzeichen maskieren

Mithilfe von check_plain konnte man in den vorherigen Drupal-Versionen in Text enthaltene Sonderzeichen in HTML umwandeln. 

Beispiel in PHPTemplate:

  1. <?php
  2.   echo check_plain($title);
  3. ?>

Beispiel in Twig:

Der escape-Filter kann auch über den Alias e verwendet werden und unterstützt über einen Parameter verschiedene escape-Möglichkeiten: 

  • html: Maskieren von Zeichen im HTML-Kontext
  • js: Maskieren von Zeichen im Javascript-Kontext
  • css: Maskieren von Zeichen im CSS-Kontext
  • url: Maskieren von Zeichen für URI-Kontext oder für URL-Parameter
  • html_attr: Maskieren von Zeichen im HTML-Attribut-Kontext

Weitere Informationen über die in Twig zur Verfügung stehenden Filter kann man in der Dokumentation nachlesen.

Steffen Rühlmann
  • Senior-Drupal-Entwickler

Steffen macht nun schon seit zwanzig Jahren Dinge mit Webseiten. Er ist ein Drupal-Allrounder und Acquia Certified Developer seit 2014, der sich sowohl in der Modul-Programmierung als auch bei Theming oder Sitebuilding sicher bewegt. An Remote Work im eigenen Haus mag er den Ausblick auf die Felder. Wenn er nicht gerade arbeitet, wird er von seinen Kindern auf Trab gehalten und ist gerne in der Natur.