Drupal 8 Theming – Lauri Eskola – Drupal 7 Front-end Sucks!



Drupal 8 Theming – Lauri Eskola – Drupal 7 Front-end Sucks!

0 0


twig-slides


On Github lauriii / twig-slides

Drupal 8 Theming

7.10.2014 Lauri Eskola

Me:

Lauri Eskola

@lauriii

@laurii1

Drupal 7 Front-end Sucks!

Why?

What's changed for Drupal 8?

HTML5

HTML5

              
      <header role="banner">
        <h1>Dries FTW!</h1>
        <nav>
          <a href="/">home</a> | <a href="/info">info</a>
        </nav>
      </header>
      <main>
        <aside>
          ...
        </aside>
        <div>
          ... 
        </div>    
      </main>
      <footer role="">
      </footer>
              
            

So Drupal 8 WON'T support

ie 6

ie 7

ie 8

Drupal CSS

Drupal 7

              
      <body class="html drupal7 is-awesome wtf not-logged-in no-sidebars page-node page-node- page-node-274 node-type-page">
              
            

Drupal 8

              
      <body>
              
            

CSS build on SMACSS and BEM

More from #1887918

CSS

              
      .field {
        margin: 6px 9px;
      }
      .field.field--name {
        color: pink; 
      }
              
            

HTML

              
      <div class="field field--name" />
              
            

Seven CSS file structure

Removing CSS files

Drupal 8 File structure

No more

sites/all/where/the/f*ck/is/my/themes

Templates in template folder!

AND!

Templates are auto-loaded with hook_theme implementation key!

.php vs .twig

Drupal 7

55 templates

154 functions

Drupal 8

21 functions

149 templates

Completely new theme layer!

Drupal 7 theme layer - WTF?

Drupal 8 theme layer - FTW!

Twig

Almost impossible in Twig

              
      <?php

      db_query('
        DROP DATABASE;
        ROLLBACK;
      ');

      $frontend_developers = 'rule';
              
            

Basics in under 5 minutes

This is Twig, no Drupal!

Comments & Vars

PHP:

              
      <?php

      // My test variable
      print $variable;
              
            

Twig:

              
      {# My test variable #}
      {{ variable }}
              
            

Set variables

              
      {% set variable = 'result' %}
              
            
            
      {%
        set array = [
          'foo',
          'bar',
        ]
      %}
              
            

Arrays

PHP:

              
      <?php

      // WTF?!
      print $hamburger['sandwich']['und']->content['meat']['bacon']['stuff'] ?>
              
            

Twig:

              
      {{ hamburger.sandwich.content.meat.bacon.stuff }}
              
            

Finding stuff in Twig

To print all available variables:

              
        {{ dump() }}
              
            

To print content of specific variable:

              
        {{ dump(foo) }}
              
            

Loops

              
      <h2>Team Awesome</h2>
      <ul>
        {% for user in users %}
          <li>{{ user.username}}</li>
        {% endfor %}
      </ul>
              
            
              
        <h2>Team Awesome</h2>
        <ul>
          <li>cottser</li>        
          <li>joel</li>
          <li>david</li>
          <li>mark carver</li>        
          <li>mortendk</li>
        </ul>
              
            

Loop stuff

              
      {{ loop.length }}    

      {{ loop.first }}

      {{ loop.last }}
     
      {{ loop.index }}

      {% if loop.first %}
        ...  
      {% elseif loop.index == 2 %}
        ...
      {% elseif loop.last %}
          ...
      {% endif %}
              
            

Loop with empty text

              
      <h2>Team Awesome</h2>
      <ul>
        {% for user in users %}
          <li>{{ user.username}}</li>
        {% else %}
          <li>no results found</li>
        {% endfor %}
      </ul>
              
            

Filter

              
      <p>
        {% filter upper %}
          uppercase for the win
        {% endfilter %}
      </p>
              
            

|Filter

              
      {% set name = 'Lauri' %}
      <span>           
        {{ name|length }}
      </span>
              
            

Returns:

              
      <span>
        5
      </span>
              
            
  • |abs
  • |batch
  • |capitalize
  • |covert_encoding
  • |date
  • |date_modify
  • |default
  • |escape
  • |first
  • |format
  • |join
  • |json_encode
  • |keys
  • |last
  • |length
  • |lower
  • |nl2br
  • |number_format
  • |merge
  • |upper
  • |raw
  • |replace
  • |reverse
  • |round
  • |slice
  • |sort
  • |split
  • |striptags
  • |title
  • |trim
  • |url_encode

Twig blocks

page.html.twig
              
      {% block headerblock %}
        <h2>This block needs more kittens!</h2>
      {% endblock %}
              
            
page--front.html.twig
              
      {% extends "page.html.twig" %}
      {% block headerblock %}
        {{ parent() }}
        <h4>Kitten!</h4>
      {% endblock %}
              
            

More stuff?

Twig documentation: http://twig.sensiolabs.org/

You no like it?

Solution!

              
      # engine: phptemplate
              
            
themename.info

Drupal specific Twig functionalities

This is Drupal!

Filters

              
      {% set class_name = 'lauri/druid' %}

      {%
        set contributors = [
          'rteijeiro',
          'joelpittet',
          'Cottser',
          'lauriii',
          'Dries',
        ]
      %}

      {{ class_name|clean_class }}
      {{ contributors|without('lauriii') }},
      {{ stuff|placeholder('kitten') }}
              
            

Returns

              
      lauri-druid
      rteijeiro,joelpittet,Cottser,Dries,
      kitten
          

HTML Attributes

Not ready yet, more info #2325517

Preprocess:

              
      <?php
        function template_preprocess_username(&$variables) {
          $variables['attributes'] = new Attribute();
        }
      ?>
              
            

Template:

              
      <div{{ attributes.setAttribute('id', 'kitten').setAttribute('I-Love', 'Dries') }}>

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

Add class

More information #2325067

              
      <div{{ attributes.addClass('field-item-' ~ name|clean_class) }}>
              
            

Remove class

              
  <?php
  
  function node_preprocess_node(&$variables) {
    $variables['attributes']->addClass(['carrot', 'potato']);
  }
              
            
              
  <div{{ attributes.removeClass('carrot', 'potato').addClass('bacon', 'beef') }}>
              
            

Translate

              
      {{ 'Author: @username'| t({'@username':username}) }}
              
            

Or:

              
      {% trans %}
        Author {{ username }}
      {% endtrans %}
              
            

Twig debug

No more guessing!

              
    <!-- THEME DEBUG -->
    <!-- CALL: _theme('page') -->
    <!-- FILE NAME SUGGESTIONS:
       * page--front.html.twig
       * page--node.html.twig
       x page.html.twig
    -->
    <!-- BEGIN OUTPUT from 'core/themes/bartik/templates/page.html.twig' -->
              
            

Want this to D7?

Do it! #2307505

Deep template clean up

We've made even @mortendk rock while theming

pager.html.twig
menu.html.twig

Autoescape

Context-Aware Auto-Escaping

Basic idea: everytime variable goes to template run appropriate escaping function!

Different Escape functions

              
      <?php

      Drupal\Component\Utility\SafeMarkup::isSafe();
      Drupal\Component\Utility\SafeMarkup::escape();
      Drupal\Component\Utility\SafeMarkup::checkAdminXss();

              
            

How it works?

    <?php

    public static function escape($string) {
      return static::isSafe($string) ? $string : String::checkPlain($string);
    }
                
            

Consensus banana

Steps:

  • Phase 1. Move all the classes to templates ✓ done!
  • Phase 2. Classy <- we are here!

Phase 1:

Move classes from preprocess to templates

node.html.twig

              
  {%
    set classes = [
      'node',
      'node--type-' ~ node.bundle|clean_class,
      node.isPromoted() ? 'node--promoted',
      node.isSticky() ? 'node--sticky',
      not node.isPublished() ? 'node--unpublished',
      view_mode ? 'node--view-mode-' ~ view_mode|clean_class,
      'clearfix',
    ]
  %}
  <article{{ attributes.addClass(classes) }}>
   {{ content }}
  </article>

              
            

Phase 2:

New theme: Classy

What will this change?

Move all the class logic to Classy - so no classes from core (even automated tests uses now Classy)

Simplify core markup even more! (removing all unnecessary divs & other elements)

Creating new theme?

Remember to extend Classy!

Bonus!

No more hardcoded menu...

...or logo!

Want to help?

RC1 means markup freeze...

... so there's plenty of time still!

Sprints tomorrow!

More info: http://ghent2014.drupalcamp.be/sprints

Frontend United BOF right after this session