Drupal 8 Frontend (for backenders) – Lauri Eskola – Drupal 8 ships with simplified theme layer



Drupal 8 Frontend (for backenders) – Lauri Eskola – Drupal 8 ships with simplified theme layer

0 0


theme-system-dcbaltics-2015


On Github lauriii / theme-system-dcbaltics-2015

Drupal 8 Frontend (for backenders)

28.08.2015 Lauri Eskola

Lauri Eskola

  • Front and Back End Developer
  • Drupal Theme System maintainer
  • Working for Druid
  • I like kittens (added 43 of them to Drupal 8 core and counting...)
  • and I like to break Bartik.

@lauriii

@laurii1

Topics

Theme system Twig Autoescape Demo

Drupal 8 ships with simplified theme layer

Drupal 7 theme layer - WTF?

Template process layer ...is gone!

hook_page_alter ...is gone!

Theme functions

...are being converted to Twig templates..

154 vs 8 theme functions

Goodbye theme(), hello render arrays

Drupal 7

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

Drupal 8

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

Drupal 8 theme layer - FTW!

Theme suggestion hooks

Theme suggestion hooks

Drupal 7

              
  <?php
  /**
   * Implements hook_preprocess_HOOK() for node templates.
   */
  function MYTHEME_preprocess_node(&$variables) {
    $variables['theme_hook_suggestions'][] = 'node__' . 'first_suggestion';
    $variables['theme_hook_suggestions'][] = 'node__' . '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__' . 'first_suggestion';
    $suggestions[] = 'node__' . 'more_specific_suggestion';
  }
              
            

Preprocess hooks & missing process functions

Specific preprocess functions

              
 <?php

 /**
  * Implements hook_preprocess_node().
  */
  function hook_preprocess_node(&$variables) {
    // This will be run as first.
  }

  /**
   * Implements hook_preprocess_node__article().
   */
   function hook_preprocess_node__article(&$variables) {
     // This will be run as second.
   }
              
            

Attributes

              
 <?php
 /**
  * Implements hook_preprocess_node().
  */
 function hook_preprocess_node(&$variables) {
   // Add new class.
   $attributes->addClass('my-own-class');
   // Remove elements default class.
   $attributes->removeClass('default-class');
   // Set elements id to kitten.
   $attributes->setAttribute('id', 'kitten');
 }
              
            

Attributes

Twig

              
 <div{{ attributes }}>
              
            
Not like this:
                  
   <div {{ attributes }}>
                  
                
                  
   <div✖{{ attributes }}>
                  
                

Attributes

              
 {%
   set classes [
     'a-lot-of',
     'classes-needed',
     'for-this-element'
   ]
 %}
 <div{{ attributes.removeClass('my-own-class').addClass('better-class', classes) }}>
              
            

Twig

Crash course for backenders

Twig magic

{{ sandwich.cheese }}

Same in PHP

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

Print what you want, when you want

Drupal 7

              
  <?php
  // We hide the comments and links now so that we can render them later.
  hide($content['comments']);
  hide($content['links']);
  print render($content);
              
            

Drupal 8

              
 {# We give you what you ask for. #}
 {{ content|without('comments', 'links') }}
              
            

Twig filters

Meant to manipulate content. Simply takes the first parameter from a variable or inline string and returns it in different format.

Example

              
  {% set name = 'Lauri' %}
  {# Print varibale using lenght filter. #}
  {{ name|length }}
              
            

Returns

              
  5
              
            

Twig functions

More viable functions with multiple parameters meant to create simple front-end logic

              
 {{ dump() }}
              
            

This magic is built in Twig

However I'm going to show you how to add these by your self!

1. Add a Twig extension class

              
  <?php
  /**
   * A class providing my own Twig extension.
   */
  class TrimString extends \Twig_Extension {
    /**
     * {@inheritdoc}
     */
    public function getFilters() {
      return [
        new \Twig_SimpleFilter('trim_string', array($this, 'trimString')),
      ];
    }

    public function trimString($string, $length = 10) {
      return strpos($string, 0, $length);
    }
  }
              
            

2. Inject your class using services container

 
              
  services:
    trim_string.twig.trimstring:
      class: Drupal\trim_string\TwigExtension\TrimString
      arguments: ['@renderer']
      tags:
        - { name: twig.extension }
              
            
trim_string.services.yml

3. Profit!

              
  {% set variable = 'my text' %}
  {{ variable|trim_string(2) }}
              
            
              
  my
              
            

Adding Twig functions

              
  <?php
  /**
   * A class providing my own Twig extension.
   */
  class MyTwigExtension extends \Twig_Extension {

    /**
     * {@inheritdoc}
     */
    public function getFunctions() {
      return [
        new \Twig_SimpleFunction('url', [$this, 'getUrl'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']),
      ];
    }
  }
              
            

Example:

https://github.com/lauriii/trim-string

"I don't want to learn anything new!"

"I don't like Twig!"

Solution!

              
      # engine: phptemplate
              
            
themename.info.yml

Autoescape

Markup should live inside a Twig template. Not in PHP!

What is Autoescaping?

              
    <?php

    print drupal_render([
      '#markup' => '<script>alert('xss')</script>',
    ]);
              
            
Will print as:
    <script>alert('xss')</script>
            

Outputting markup from code

              
    <?php

    $render = [
      '#markup' => '<em>some markup</em>',
      '#allowed_tags' => ['em'],
    ];

              
            

With possibly unsafe variables:

              
    <?php

    $possible_unsafe_var = 'some markup';
    $render = [
      '#type' => 'inline_template',
      '#template' => '<em>{{ var }}</em>',
      '#context' => [
        'var' => $possible_unsafe_var,
      ],
    ];
              
            

Sandwiches demo!

https://github.com/DrupalTwig/sandwich