Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Drupal 8: Theming

1,857 views

Published on

Drupal 8: Theming

  1. 1. Drupal 8: ThemingDrupal 8: Theming Theming basics & TWIG for Drupal 8 modulesTheming basics & TWIG for Drupal 8 modules Drupal Meetup StuttgartDrupal Meetup Stuttgart 07/02/2015
  2. 2. 1. Introduction:1. Introduction: Template EnginesTemplate Engines
  3. 3. 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 logic Hardly to be overwritten
  4. 4. 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)
  5. 5. 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 overwritten And maybe use CSS, not markup or inline styles...
  6. 6. Voilá, a Template Engine!Voilá, a Template Engine! (aka Theme Engine) Drupal 4.7 / 5 / 6 / 7: PHPTemplate Drupal 8: TWIG Variables
  7. 7. What's wrong with PHPTemplate?What's wrong with PHPTemplate? Drupal proprietary stuff Requires PHP knowledge Hard to read Potentially insecure, e.g. printing malicous strings Empowers business logic, e.g. DB queries One typo can take your site offline Sooo old-style So Drupal 8 goesSo Drupal 8 goes PHPTemplatePHPTemplate SmartySmarty PHPTALPHPTAL TWIGTWIG
  8. 8. 2. Building a Drupal 82. Building a Drupal 8 ThemeTheme
  9. 9. 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.twig logo.svg screenshot.png mytheme.breakpoints.yml mytheme.info.yml mytheme.libraries.yml mytheme.theme /themes/custom/mytheme/
  10. 10. Tell Drupal about your themeTell Drupal about your theme name: 'My theme' type: theme description: 'Just a sample theme for Drupal 8.' package: Custom core: 8.x libraries: - mytheme/global stylesheets-remove: - core/assets/vendor/normalize-css/normalize.css regions: header: Header content: Content sidebar_first: 'Sidebar first' footer: Footer /themes/custom/mytheme/mytheme.info.yml
  11. 11. 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 pages global: 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
  12. 12. 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!
  13. 13. Specify breakpoints, if neededSpecify breakpoints, if needed mytheme.mobile: label: mobile mediaQuery: '' weight: 2 multipliers: - 1x mytheme.narrow: label: narrow mediaQuery: 'all and (min-width: 560px) and (max-width: 850px)' weight: 1 multipliers: - 1x mytheme.wide: label: wide mediaQuery: 'all and (min-width: 851px)' weight: 0 multipliers: - 1x /themes/custom/mytheme/mytheme.breakpoints.yml
  14. 14. Add the remaining stuff...Add the remaining stuff... Templates Scripts Stylesheets Images Logo Screenshot ...
  15. 15. 3. Theming basics for3. Theming basics for modulesmodules
  16. 16. Good News!Good News! Not so many changesNot so many changes Main difference: no more theme() functions!
  17. 17. 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
  18. 18. 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 template folder (/modules/custom/mymodule/templates)
  19. 19. 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, ...)
  20. 20. 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
  21. 21. 4. TWIG Basics:4. TWIG Basics: SyntaxSyntax
  22. 22. Print / Output: {{ some content }}{{ some content }} Comments: {# this is a comment #}{# this is a comment #} Execute statements: {% expression %}{% expression %}
  23. 23. 5. TWIG Basics:5. TWIG Basics: VariablesVariables
  24. 24. Accessing variablesAccessing variables Simple 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 %}
  25. 25. 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
  26. 26. 6. TWIG Basics:6. TWIG Basics: Control structuresControl structures
  27. 27. {% 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
  28. 28. 7. TWIG Basics:7. TWIG Basics: Filters & FunctionsFilters & Functions
  29. 29. {{ 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 filters Translate: <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
  30. 30. {{ max(1, 3, 2) }} {{ random(['apple', 'orange', 'citrus']) }} More examples: http://twig.sensiolabs.org/doc/functions/index.html General Twig functions Drupal specific functions Url: <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
  31. 31. 8. TWIG Basics:8. TWIG Basics: InheritanceInheritance
  32. 32. <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%}
  33. 33. 9. TWIG Basics:9. TWIG Basics: ExampleExample
  34. 34. {# /** * @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
  35. 35. Thank You!Thank You! http://slides.com/drubb http://slideshare.net/drubb

×