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