On Github DrupalTwig / ThemeSystemAustin2014
1:30 - 5:00
Now we can hit 'B' and gauge the personas in the audience. Ask people to raise their hand if they are:
…is gone!
5:00 - 8:00
…are being converted to Twig templates.
8:00 - 11:00
Theme functions are so Drupal 7 (effectively deprecated, people will yell at you) Markup belongs in templates, not in PHP strings. Your IDE/Text Editor will reward you by syntax highlighting markup and much less string concatenation and quote escaping is needed.Drupal 7:
<?php /** * Implements hook_preprocess_HOOK() for node templates. */ function MYTHEME_preprocess_node(&$variables) { $variables['theme_hook_suggestions'][] = 'node__' . 'my_first_suggestion'; $variables['theme_hook_suggestions'][] = 'node__' . 'my_second_more_specific_suggestion'; }
Drupal 8:
<?php /** * Implements hook_theme_suggestions_HOOK_alter() for node templates. */ function MYTHEME_theme_suggestions_node_alter(array &$suggestions, array $variables) { $suggestions[] = 'node__' . 'my_first_suggestion'; $suggestions[] = 'node__' . 'my_second_suggestion'; }
11:00 - 14:00
In Drupal 7 you could manipulate theme suggestions during preprocess, but by this point it might already be too late, or you've already done unnecessary preprocessing. Drupal 8 splits out the manipulation of theme hook (template) suggestions into separate hooks. You can see template suggestions in action when we talk about Twig debug in a few minutes.<?php $variables['list'] = theme('item_list', array( 'items' => $items, ));
<?php $variables['list'] = array( '#theme' => 'item_list', '#items' => $items, );
14:00 - 16:00
Instead of the list variable being a flat string of HTML, it's a render array that gets passed to the template and rendered from there.
16:00 - 18:00
settings.php:
$settings['twig_debug'] = TRUE;
Example output:
<!-- THEME DEBUG --> <!-- CALL: _theme('block') --> <!-- FILE NAME SUGGESTIONS: * block--bartik-powered.html.twig * block--system-powered-by-block.html.twig * block--system.html.twig x block.html.twig --> <!-- BEGIN OUTPUT from 'core/modules/block/templates/block.html.twig' --> <div class="block block-system contextual-region" id="block-bartik-powered" role="complementary"> <div data-contextual-id="block:block=bartik_powered:"></div> <div class="content"> <span>Powered by <a href="http://drupal.org">Drupal</a></span> </div> </div> <!-- END OUTPUT from 'core/modules/block/templates/block.html.twig' -->
18:00 - 20:00
https://github.com/DrupalTwig/sandwich
20:00 - 21:00
We were hungry when we came up with this example.
<?php /** * Implements hook_theme(). */ function sandwich_theme() { return array( 'sandwich' => array( 'variables' => array( 'attributes' => array(), 'name' => '', 'bread' => '', 'cheese' => '', 'veggies' => array(), 'protein' => '', 'condiments' => array(), ), 'template' => 'sandwich', ), ); }
<?php /** * Builds a sandwich. */ public function build() { return array( '#theme' => 'sandwich', '#name' => $this->t('Chickado'), '#attributes' => array( 'id' => 'best-sandwich', 'style' => 'float: left;', 'class' => array('left', 'clearfix'), ), '#bread' => $this->t('Sourdough'), '#cheese' => $this->t('Gruyère'), '#veggies' => array($this->t('Avocado'), $this->t('Red onion'), $this->t('Romain')), '#protein' => $this->t('Chicken'), '#condiments' => array($this->t('Mayo'), $this->t('Dijon')), ); }
Pass in variables using #-prefixed keys.
- 24:00
<section{{ attributes }}> <h2>{{ name }}</h2> {% if bread %} <p><strong>Bread:</strong> {{ bread }}</p> {% endif %} {% if protein %} <p><strong>Protein:</strong> {{ protein }}</p> {% endif %} {% if cheese %} <p><strong>Cheese:</strong> {{ cheese }}</p> {% endif %} {% if veggies %} <strong>Vegetables:</strong> <ul> {% for veg in veggies %} <li>{{ veg }}</li> {% endfor %} </ul> {% endif %} {% if condiments %} <strong>Condiments:</strong> <ul> {% for condiment in condiments %} <li>{{ condiment }}</li> {% endfor %} </ul> {% endif %} </section>
That's the bare minimum for most practical use cases. But what if you need to do more, or if you're altering themeable output that someone else has defined? Let's dig a bit deeper.
Don't make a template for condiments. Real life example: toolbar.
28:00 - 33:00
drupal_render() is called on the render array. Any defined #pre_render callbacks are called. drupal_render() calls the now internal _theme() function.
After _theme() does its thing, #post_render callbacks can massage the resulting string.
{{ sandwich.cheese }}
// Array key. $sandwich['cheese']; // Object property. $sandwich->cheese; // Object method. $sandwich->cheese(); // Object get method convention. $sandwich->getCheese(); // Object is method convention. $sandwich->isCheese(); // Object dynamic object property is set and get property. $sandwich->__isset('cheese'); $sandwich->__get('cheese');
33:00 - 35:00
<div{{ attributes }}>
<div class="myclass {{ attributes.class }}"{{ attributes|without('class') }}>
35:00 - 38:00
@Cottser
@joelpittet
IRC: #drupal-twig
Twitter: #drupaltwig