Drupal 8 Theme System: The Backend of Frontend

25
Drupal 8 Theme System The Backend of Frontend Scott Reeves (Cottser)

Transcript of Drupal 8 Theme System: The Backend of Frontend

Page 1: Drupal 8 Theme System: The Backend of Frontend

Drupal 8 Theme SystemThe Backend of Frontend

Scott Reeves (Cottser)

Page 2: Drupal 8 Theme System: The Backend of Frontend

Scott Reeves - @CottserTeam Lead at Digital EchidnaDrupal 8 theme systemand Stable co-maintainerDrupal 8 provisional core committer

Page 3: Drupal 8 Theme System: The Backend of Frontend

Drupal 8 theme layer

changes

Page 4: Drupal 8 Theme System: The Backend of Frontend

Theme functionsare gone!

Page 5: Drupal 8 Theme System: The Backend of Frontend

Libraries

Page 6: Drupal 8 Theme System: The Backend of Frontend

Template process layeris gone!

Page 7: Drupal 8 Theme System: The Backend of Frontend

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'; }

Page 8: Drupal 8 Theme System: The Backend of Frontend

Goodbye theme(), hello render arrays

Drupal 7:

$variables['list'] = theme('item_list', array( 'items' => $items, ));

Drupal 8:

$variables['list'] = [ '#theme' => 'item_list', '#items' => $items, ];

Page 9: Drupal 8 Theme System: The Backend of Frontend

AttributesAll the HTML attributes:

<div{{ attributes }}>

Please don't do this, you will end up with yucky whitespace:

<div✖{{ attributes }}>

Page 10: Drupal 8 Theme System: The Backend of Frontend

More attributesClass manipulation:

<div{{ attributes.addClass('hello').removeClass('goodbye') }}>

Testing:

{% if attributes.hasClass('field-label-inline') %} {# Do something special here. #} {% endif %}

Page 11: Drupal 8 Theme System: The Backend of Frontend

Even more attributesSet attribute:

<div{{ attributes.setAttribute('id', 'eye-d') }}>

Remove attribute:

<div{{ attributes.removeAttribute('id') }}>

Page 12: Drupal 8 Theme System: The Backend of Frontend

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 }}

Page 13: Drupal 8 Theme System: The Backend of Frontend

Oh yeah, and Twig!

Page 14: Drupal 8 Theme System: The Backend of Frontend

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' -->

Page 15: Drupal 8 Theme System: The Backend of Frontend

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' -->

Page 16: Drupal 8 Theme System: The Backend of Frontend

Sandwiches.https://github.com/DrupalTwig/sandwich

Page 17: Drupal 8 Theme System: The Backend of Frontend

De�ne with hook_theme()/** * Implements hook_theme(). */ function sandwich_theme() { return [ 'sandwich' => [ 'variables' => [ 'attributes' => [], 'name' => '', 'bread' => '', 'cheese' => '', 'veggies' => [], 'protein' => '', 'condiments' => [], ], ], ]; }

Page 18: Drupal 8 Theme System: The Backend of Frontend

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.

Page 19: Drupal 8 Theme System: The Backend of Frontend

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 %}

Page 20: Drupal 8 Theme System: The Backend of Frontend

Voilà!

Page 21: Drupal 8 Theme System: The Backend of Frontend

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

Page 22: Drupal 8 Theme System: The Backend of Frontend

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

Page 23: Drupal 8 Theme System: The Backend of Frontend

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');

Page 24: Drupal 8 Theme System: The Backend of Frontend

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 }}

Page 25: Drupal 8 Theme System: The Backend of Frontend

Thanks!Questions?