Drupal 8: Theming

35
Drupal 8: Theming Drupal 8: Theming Theming basics & TWIG for Drupal 8 modules Theming basics & TWIG for Drupal 8 modules Drupal Meetup Stuttgart Drupal Meetup Stuttgart 07/02/2015

Transcript of Drupal 8: Theming

Page 1: Drupal 8: Theming

Drupal 8: ThemingDrupal 8: ThemingTheming basics & TWIG for Drupal 8 modulesTheming basics & TWIG for Drupal 8 modules

Drupal Meetup StuttgartDrupal Meetup Stuttgart

07/02/2015

Page 2: Drupal 8: Theming

1. Introduction:1. Introduction:Template EnginesTemplate Engines

Page 3: Drupal 8: Theming

Once upon a time, in a D7 module...Once upon a time, in a D7 module...

function mymodule_block_content() {

$output = '';

$users = mymodule_get_some_users();

$output = '<ul class="list" style="margin-top:10px">'; foreach ($users as $user) { $output .= '<li class="item"><em>' . $user->name . '</em></li>'; } $output .= '</ul>';

return $output

}

Markup and styling mixed with business logicHardly to be overwritten

Page 4: Drupal 8: Theming

We can do this a little bit better:We can do this a little bit better:function mymodule_block_content() { $users = mymodule_get_some_users(); $output = theme('mymodule_block', $users); return $output}

function mymodule_theme() { return array( 'mymodule_block' => array( 'variables' => array('users' => NULL), ), );}

function theme_mymodule_block($variables) { $users = $variables['users']; $output = '<ul class="list" style="margin-top:10px">'; foreach ($users as $user) { $output .= '<li class="item"><em>' . $user->name . '</em></li>'; } $output .= '</ul>'; return $output}

Can be overwritten, in template.php(mytheme_mymodule_block)

Page 5: Drupal 8: Theming

We can do this much more better:We can do this much more better:function mymodule_block_content() { $users = mymodule_get_some_users(); $output = theme('mymodule_block', $users); return $output}

function mymodule_theme() { return array( 'mymodule_block' => array( 'variables' => array('users' => NULL), 'template' => 'mymodule_block' ), );}

and in mymodule_block.tpl.php:

<ul class="list" style="margin-top:10px"><?php foreach ($users as $user) : ?> <li class="item"><em><?php print $user->name; ?></em></li><?php endforeach; ?></ul>

Template file can be copied and overwrittenAnd maybe use CSS, not markup or inline styles...

Page 6: Drupal 8: Theming

Voilá, a Template Engine!Voilá, a Template Engine!(aka Theme Engine)

Drupal 4.7 / 5 / 6 / 7: PHPTemplateDrupal 8: TWIG

Variables

Page 7: Drupal 8: Theming

What's wrong with PHPTemplate?What's wrong with PHPTemplate?

Drupal proprietary stuffRequires PHP knowledgeHard to readPotentially insecure, e.g. printing malicous stringsEmpowers business logic, e.g. DB queriesOne typo can take your site offlineSooo old-style

So Drupal 8 goesSo Drupal 8 goes

PHPTemplatePHPTemplate SmartySmarty PHPTALPHPTAL TWIG TWIG

Page 8: Drupal 8: Theming

2. Building a Drupal 82. Building a Drupal 8ThemeTheme

Page 9: Drupal 8: Theming

Create a theme folder structureCreate a theme folder structure

- config - schema - mytheme.schema- css - base.css - layout.css- images- js - special.js- libraries - flexslider- templates - node.html.twig - page.html.twiglogo.svgscreenshot.pngmytheme.breakpoints.ymlmytheme.info.ymlmytheme.libraries.ymlmytheme.theme

/themes/custom/mytheme/

Page 10: Drupal 8: Theming

Tell Drupal about your themeTell Drupal about your theme

name: 'My theme'type: themedescription: 'Just a sample theme for Drupal 8.'package: Customcore: 8.xlibraries: - mytheme/globalstylesheets-remove: - core/assets/vendor/normalize-css/normalize.cssregions: header: Header content: Content sidebar_first: 'Sidebar first' footer: Footer

/themes/custom/mytheme/mytheme.info.yml

Page 11: Drupal 8: Theming

Tell Drupal about css/js libraries in your themeTell Drupal about css/js libraries in your theme

# This one is specified in mytheme.info.yml and loaded on all pagesglobal: version: VERSION css: theme: css/base.css {} css/layout.css: {}

# Those are needed in some special places and loaded via #attached['library']special: version: VERSION css: theme: css/special.css: {} js: js/special.js: {}flexslider: version: '2.5.0' css: theme: libraries/flexslider/flexslider.css: {} js: libraries/flexslider/jquery.flexslider.js: {} dependencies: - core/jquery

/themes/custom/mytheme/mytheme.libraries.yml

Page 12: Drupal 8: Theming

Add preprocessing stuff, if neededAdd preprocessing stuff, if needed

<?php

/** * Implements hook_element_info_alter(). */function mytheme_element_info_alter(&$type) { // We require Modernizr for button styling. if (isset($type['button'])) { $type['button']['#attached']['library'][] = 'core/modernizr'; }}

/themes/custom/mytheme/mytheme.theme

Formerly known as template.php!

Page 13: Drupal 8: Theming

Specify breakpoints, if neededSpecify breakpoints, if needed

mytheme.mobile: label: mobile mediaQuery: '' weight: 2 multipliers: - 1xmytheme.narrow: label: narrow mediaQuery: 'all and (min-width: 560px) and (max-width: 850px)' weight: 1 multipliers: - 1xmytheme.wide: label: wide mediaQuery: 'all and (min-width: 851px)' weight: 0 multipliers: - 1x

/themes/custom/mytheme/mytheme.breakpoints.yml

Page 14: Drupal 8: Theming

Add the remaining stuff...Add the remaining stuff...TemplatesScriptsStylesheetsImagesLogoScreenshot...

Page 15: Drupal 8: Theming

3. Theming basics for3. Theming basics formodulesmodules

Page 16: Drupal 8: Theming

Good News!Good News!Not so many changesNot so many changesMain difference: no more theme() functions!

Page 17: Drupal 8: Theming

Registering templatesRegistering templates(no more theme functions!)

function mymodule_theme($existing, $type, $theme, $path) { return array( 'mymodule_something' => array( 'variables' => array('something' => NULL, 'otherthing' => NULL), ), );}

hook_theme(), in your module file

Page 18: Drupal 8: Theming

Create a templateCreate a template(*.html.twig, not *.tpl.php)

{% if something %} <p> {{ something }} {{ otherthing }} </p>{% endif %}

mymodule-something.html.twig, in your module's templatefolder (/modules/custom/mymodule/templates)

Page 19: Drupal 8: Theming

Use this somewhereUse this somewhere(using render array, not theme())

...

$output = array( '#theme' => 'mymodule_something', '#something' => 'Something', '#otherthing' => 'Otherthing',);

...

Somewhere in your code (controller, plugin, ...)

Page 20: Drupal 8: Theming

Alter some stuffAlter some stuff(mainly provided by other modules)

/** * Implements hook_preprocess_HOOK(). */function yourmodule_preprocess_mymodule_something(&$variables) {

...

}

In your module file or theme

Page 21: Drupal 8: Theming

4. TWIG Basics:4. TWIG Basics:SyntaxSyntax

Page 22: Drupal 8: Theming

Print / Output:

{{ some content }}{{ some content }} Comments:

{# this is a comment #}{# this is a comment #} Execute statements:

{% expression %}{% expression %}

Page 23: Drupal 8: Theming

5. TWIG Basics:5. TWIG Basics:VariablesVariables

Page 24: Drupal 8: Theming

Accessing variablesAccessing variablesSimple variables (strings, numbers, booleans):{{ foo }}

Complex variables (arrays / objects):

Objects & arrays:{{ foo.bar }}Alternative:{{ attribute(foo, 'bar') }}

Only arrays:{{ foo['bar'] }}

Example from views module:

{% if attributes -%} <div{{ attributes }}>{% endif %} {% if title %} <h3>{{ title }}</h3> {% endif %} <{{ list.type }}{{ list.attributes }}> {% for row in rows %} <li{{ row.attributes }}>{{ row.content }}</li> {% endfor %} </{{ list.type }}>{% if attributes -%} </div>{% endif %}

Page 25: Drupal 8: Theming

Assigning values to variablesAssigning values to variables

{% set foo = 'bar' %}

{% set foo, bar = 'foo', 'bar' %}

{% set foo = [1, 2] %}{% set foo = {'foo': 'bar'} %}{% set foo = 'foo' ~ 'bar' %}

{% set foo %} <div id="pagination"> ... </div>{% endset %}

More examples:

http://twig.sensiolabs.org/doc/tags/set.html

Page 26: Drupal 8: Theming

6. TWIG Basics:6. TWIG Basics:Control structuresControl structures

Page 27: Drupal 8: Theming

{% if ordered_list %} <ol>{% else %} <ul>{% endif %}

IF ... THEN ... ELSE ... ENDIF

{% for item in items %} <li>{{ item }}</li>{% endfor %}

FOR ... ENDFOR

{% include '@mytheme/parts/footer.html.twig' %}

INCLUDE -> fetch another template file

{% block footer %} © Copyright 2015 drubb{% endblock %}

BLOCK -> section that can be repeated, or overwritten by other template files

Page 28: Drupal 8: Theming

7. TWIG Basics:7. TWIG Basics:Filters & FunctionsFilters & Functions

Page 29: Drupal 8: Theming

{{ title|upper|trim('.') }}

{% filter upper %} This text becomes uppercase{% endfilter %}

More examples: abs, first, last, length, lower, reverse, round,...)

http://twig.sensiolabs.org/doc/filters/index.html

General Twig filters

Drupal specific filtersTranslate:<a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home" class="site-logo"></a>

Without:{{ content|without('links') }}

Safe join:{{ items|safe_join(", ") }}

More examples:https://www.drupal.org/node/2357633

Filter: simple transformations on output

Page 30: Drupal 8: Theming

{{ max(1, 3, 2) }}

{{ random(['apple', 'orange', 'citrus']) }}

More examples:

http://twig.sensiolabs.org/doc/functions/index.html

General Twig functions

Drupal specific functionsUrl:<a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home" class="site-logo"></a>

Path:{{ path('entity.node.canonical', {'node': node->id()}) }}

More examples:

https://www.drupal.org/node/2486991

Function: takes arguments to compute output

Page 31: Drupal 8: Theming

8. TWIG Basics:8. TWIG Basics:InheritanceInheritance

Page 32: Drupal 8: Theming

<header> ...</header>

<article> ...</article>

<footer> {% block footer %} <h4>This is the footer coming from Template 1!</h4> {% endblock%}</footer>

Second template (special.html.twig)

First template (default.html.twig)

{% extends "default.html.twig" %}

{% block footer %} {{ parent() }} <h5>But there's a second line now!</h5>{% endblock%}

Page 33: Drupal 8: Theming

9. TWIG Basics:9. TWIG Basics:ExampleExample

Page 34: Drupal 8: Theming

{#/** * @file * Theme override to display a block. * * Available variables: * - ... * * @see template_preprocess_block() */#}{% set classes = [ 'block', 'block-' ~ configuration.provider|clean_class, ]%}<div{{ attributes.addClass(classes) }}> {{ title_prefix }} {% if label %} <h2{{ title_attributes }}>{{ label }}</h2> {% endif %} {{ title_suffix }} {% block content %} {{ content }} {% endblock %}</div>

block.html.twig

Page 35: Drupal 8: Theming

Thank You!Thank You!

http://slides.com/drubbhttp://slideshare.net/drubb