Drupal 8 Theme System: The Backend of Frontend
-
Upload
acquia -
Category
Technology
-
view
709 -
download
0
Transcript of Drupal 8 Theme System: The Backend of Frontend
Drupal 8 Theme SystemThe Backend of Frontend
Scott Reeves (Cottser)
Scott Reeves - @CottserTeam Lead at Digital EchidnaDrupal 8 theme systemand Stable co-maintainerDrupal 8 provisional core committer
Drupal 8 theme layer
changes
Theme functionsare gone!
Libraries
Template process layeris gone!
Theme suggestion hooksDrupal 7:
/** * 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:
/** * 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'; }
Goodbye theme(), hello render arrays
Drupal 7:
$variables['list'] = theme('item_list', array( 'items' => $items, ));
Drupal 8:
$variables['list'] = [ '#theme' => 'item_list', '#items' => $items, ];
AttributesAll the HTML attributes:
<div{{ attributes }}>
Please don't do this, you will end up with yucky whitespace:
<div✖{{ attributes }}>
More attributesClass manipulation:
<div{{ attributes.addClass('hello').removeClass('goodbye') }}>
Testing:
{% if attributes.hasClass('field-label-inline') %} {# Do something special here. #} {% endif %}
Even more attributesSet attribute:
<div{{ attributes.setAttribute('id', 'eye-d') }}>
Remove attribute:
<div{{ attributes.removeAttribute('id') }}>
Print what you want,when you want
Drupal 7: Drupal 8:
// We hide the comments and links // to print them later. hide($content['comments']); hide($content['links']); print render($content); // Render calls show() on the element. print render($content['links']); // To get back links with the content. show($content['links']); // Prints content with links yet // without comments :( print render($content);
{# Print without comments and links #} {{ content|without('comments', 'links') }} {# Print only links #} {{ content.links }} {# Print everything without comment! #} {{ content|without('comments') }} {# Print everything #} {{ content }}
Oh yeah, and Twig!
services.yml:
parameters: twig.config: debug: true
Example output:
<!-- THEME DEBUG --> <!-- THEME HOOK: '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/themes/bartik/templates/block.html.twig' --> <div id="block-bartik-powered" role="complementary" class="block block-system block-system-powered-by-block <div class="content"> <span>Powered by <a href="http://drupal.org">Drupal</a></span> </div> </div> <!-- END OUTPUT from 'core/themes/bartik/templates/block.html.twig' -->
Drupal 7.33+settings.php:
$conf['theme_debug'] = TRUE;
Example output:
<!-- THEME DEBUG --> <!-- CALL: theme('block') --> <!-- FILE NAME SUGGESTIONS: * block--system--powered-by.tpl.php * block--system.tpl.php * block--footer.tpl.php x block.tpl.php --> <!-- BEGIN OUTPUT from 'modules/block/block.tpl.php' --> <div id="block-system-powered-by" class="block block-system"> <div class="content"> <span>Powered by <a href="https://www.drupal.org">Drupal</a></span> </div> </div> <!-- END OUTPUT from 'modules/block/block.tpl.php' -->
Sandwiches.https://github.com/DrupalTwig/sandwich
De�ne with hook_theme()/** * Implements hook_theme(). */ function sandwich_theme() { return [ 'sandwich' => [ 'variables' => [ 'attributes' => [], 'name' => '', 'bread' => '', 'cheese' => '', 'veggies' => [], 'protein' => '', 'condiments' => [], ], ], ]; }
Build your render array data/** * Builds a sandwich. */ public function build() { return [ '#theme' => 'sandwich', '#name' => $this->t('Chickado'), '#attributes' => [ 'id' => 'best-sandwich', 'style' => 'float: left;', 'class' => ['left', 'clearfix'], ], '#bread' => $this->t('Sourdough'), '#cheese' => $this->t('Gruyère'), '#veggies' => [$this->t('Avocado'), $this->t('Red onion'), $this->t('Romaine')], '#protein' => $this->t('Chicken'), '#condiments' => [$this->t('Mayo'), $this->t('Dijon')], ]; }
Pass in variables using #-pre�xed keys.
Markup your Twig template<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>Veggies:</strong> <ul> {% for veg in veggies %} <li>{{ veg }}</li> {% endfor %}
Voilà!
Overview of Drupal 7rendering �ow
1. drupal_render()
2. #pre_render
3. theme()4. Preprocess functions (and suggestions)
5. Template/theme function is rendered
7. #post_render
Overview of Drupal 8rendering �ow
1. \Drupal::service('renderer')->render()
2. #pre_render
3. \Drupal::theme()->render()4. Theme suggestion hooks
5. Preprocess functions
6. Template is rendered
7. #post_render
Twig magic{{ sandwich.cheese }}
// Array key.
$sandwich['cheese'];
// Object property.
$sandwich->cheese;
// Also works for magic get (provided you implement magic isset).
$sandwich->__isset('cheese'); && $sandwich->__get('cheese');
// Object method.
$sandwich->cheese();
// Object get method convention.
$sandwich->getCheese();
// Object is method convention.
$sandwich->isCheese();
// Method doesn't exist/dynamic method.
$sandwich->__call('cheese');
Autoescape $user->field_first_name = "<script>alert('XSS')</script>";
Drupal 7:
Drupal 8:
BAD <?php print $user->field_first_name; ?>
GOOD <?php print check_plain($user->field_first_name); ?>
GOOD {{ user.field_first_name }}
BAD {{ user.field_first_name|raw }}
Thanks!Questions?