The Flexibility of Drupal 8

A presentation at NYC Drupal Camp in July 2016 in New York, NY, USA by Michael Miles

Slide 1

Slide 1

THE FLEXIBILITY OF DRUPAL 8

Slide 2

Slide 2

MIKE MILES Genuine (wearegenuine.com) All the internet places: mikemiles86

Slide 3

Slide 3

FLEXIBLITY

Slide 4

Slide 4

WHAT MAKES DRUPAL FLEXIBLE Modular design Decoupled systems Open Source nature

Slide 5

Slide 5

WHY FLEXIBLITY IS IMPORTANT Make Drupal do what you want No “right way”, just a “right for me” way Adjust for skillsets, time and budget

Slide 6

Slide 6

THREE AREAS OF FLEXIBILITY The Interface Display Layer Data Layer

Slide 7

Slide 7

FOCUS OF THIS SESSION To prove the flexiblity of Drupal To demostrate abilities of all skillsets To discuss considerations and limitations

Slide 8

Slide 8

THE DEMO Drupal 8.1.3 Standard Install Profile Change menu tabs using 8 different methods

Slide 9

Slide 9

THE BEFORE A plain Drupal 8 install with menu menu links before altering.

Slide 10

Slide 10

THE AFTER Drupal 8 main menu a er altering 8 different ways.

Slide 11

Slide 11

#1 DRUPAL CORE

Slide 12

Slide 12

THE “CLICKING BUTTONS” METHOD “Easy” and “Quick” Little to No dev skills needed Capabilities are limited

Slide 13

Slide 13

Use Drupal core to edit a main menu link. Limited to changing the title and the destination.

Slide 14

Slide 14

The first menu link has been altered using only Drupal core.

Slide 15

Slide 15

#2 MODULES

Slide 16

Slide 16

THE EXTEND CORE METHOD Requires time for research. Can’t find one? Can build your own (Dev skills needed) Requires long term maintence

Slide 17

Slide 17

Look for modules on Drupal.org to see if there is one that meets your needs. Found the Menu Links Attributes module for Drupal 8.

Slide 18

Slide 18

Many ways to download and enable modules. Will use the core interface to enable the Menu Links Attributes module a er downloading.

Slide 19

Slide 19

When editing a menu link, now have more attributes available to set.

Slide 20

Slide 20

Menu Links Attributes module requires some technial (YAML) knowledge to customize

Slide 21

Slide 21

1 attributes: 2 class: 3 label: ” 4 description: ” 5 target: 6 label: ” 7 description: ” 8 options: 9 _blank: ‘New window (_blank)’ 10 _self: ‘Same window (_self)’ 11 style: 12 label: ” 13 description: ” 14 _core: 15 default_config_hash: 9nRDOclwSlz2Os9mJXM1LXNbV2q-bADV0zipiWPXymk Add a new configurable ‘style’ attribute (lines 11-13) to the YAML

Slide 22

Slide 22

A er saving configuration, now able to add inline style to menu links

Slide 23

Slide 23

Using a contrib module allowed for altering the style of the “Modules” main menu link.

Slide 24

Slide 24

#3 TWIG TEMPLATES

Slide 25

Slide 25

THE ALTER MARKUP METHOD Almost everything is templated Need to know HTML and/or Twig Requires a custom theme

Slide 26

Slide 26

Can use Twig debug to learn which template the main menu uses.

Slide 27

Slide 27

1 <!— THEME DEBUG —> 2 <!— THEME HOOK: ‘menu__main’ —> 3 <!— FILE NAME SUGGESTIONS: 4 * menu—main.html.twig 5 x menu.html.twig 6 —> 7 <!— BEGIN OUTPUT from ‘core/themes/classy/templates/navigation/menu.html.twig’ —> 8 <ul class=”clearfix menu”> 9 <!— // … —> 10 <li class=”menu-item”> 11 <a href=”/node/3” data-drupal-link-system-path=”node/3”>Twig</a> 12 </li> 13 <!— // … —> 14 </ul> 15 <!— END OUTPUT from ‘core/themes/classy/templates/navigation/menu.html.twig’ Twig debug tells the available template names to override current template.

Slide 28

Slide 28

Create a custom theme (flex_theme), to override the menu—main.html.twig template.

Slide 29

Slide 29

1 {# … #} 2 {% if items %} 3 {# … #} 4 {% for item in items %} 5 {# … #} 6 <li{{ item.attributes.addClass(classes) }}> 7 {% if item.title == ‘Twig’ %} 8 {% set style = ‘background:#0F0;color:#F00’ %} 9 {{ link(item.title ~ ’ Alt’, item.url, { ‘style’: style }) }} 10 {% else %} 11 {{ link(item.title, item.url) }} 12 {% endif %} 13 {# … #} 14 </li> 15 {% endfor %} 16 </ul> 17 {% endif %} flex_theme/templates/menu—main.html.twig Add logic to twig template (lines 7-12) to check title of current link and alter the styling.

Slide 30

Slide 30

Enabling the new theme as default so that Drupal will use the custom twig template for output.

Slide 31

Slide 31

Result of using a custom theme with template to alter “Twig” menu link.

Slide 32

Slide 32

#4 CSS

Slide 33

Slide 33

THE ALTER DISPLAY METHOD Target any element on the “page” Need to know CSS and how to add a library Requires a custom theme or module

Slide 34

Slide 34

Will add some custom styling to existing custom theme (flex_theme)

Slide 35

Slide 35

1 .menu—main .menu li:nth-child(5) a { 2 background: #0000FF; 3 color: #FFF; 4 } themes/flex_theme/css/menu_alter.css Use custom CSS to target the 5th item in the main menu

Slide 36

Slide 36

1 menu-alter: 2 version: VERSION 3 css: 4 component: 5 css/menu_alter.css: {} themes/flex_theme/flex_theme.libraries.yml Custom CSS and JavaScript need to be added to a custom library. Custom libraries are defined in a *.libraries.yml file.

Slide 37

Slide 37

1 2 3 4 5 6 7 8 9 name: Flex Theme type: theme description: An theme to demo the flexibility of Drupal 8. package: Core version: VERSION core: 8.x base theme: bartik libraries: - flex_theme/menu-alter themes/flex_theme/flex_theme.info.yml Add custom library as a dependency of the theme in the *.info.yml file. Drupal will include this library on any page where this theme is used.

Slide 38

Slide 38

The “CSS” menu link has been altered using custom CSS. Only able to alter the display of menu item.

Slide 39

Slide 39

#5 JAVASCRIPT

Slide 40

Slide 40

THE DOM MANIPULATION METHOD Change based on actions Need to know JavaScript and how to add a library Dependent on client browser, delay in execution

Slide 41

Slide 41

Will add new JavaScript and CSS to custom theme to alter data using custom JavaScript.

Slide 42

Slide 42

1 (function ($, Drupal) { 2 “use strict”; 3 Drupal.behaviors.flexThemeMenuAlterMain = { 4 attach: function (context) { 5 $(‘.menu—main ul.menu li a’).each(function(){ 6 if ($(this).attr(‘href’) == ‘/node/5’) { 7 $(this).addClass(‘yellow-menu’); 8 $(this).attr(‘style’, ‘color: #000;’); 9 $(this).attr(‘target’, ‘_blank’); 10 $(this).text($(this).text() + Drupal.t(’ Alt’)); 11 } 12 }); 13 } 14 } 15 })(jQuery, Drupal); themes/flex_theme/js/menu_alter_main.js Write a Drupal Behaviour that will trigger whenever the DOM loads. Target a specific menu item to change value and add a custom class.

Slide 43

Slide 43

1 .yellow-menu { 2 background: #FFFF00; 3 } themes/flex_theme/css/menu_alter_main.css Add some basic CSS for to a custom class name.

Slide 44

Slide 44

1 menu-alter: 2 version: VERSION 3 css: 4 component: 5 css/menu_alter.css: {} 6 menu-alter-main: 7 version: VERSION 8 css: 9 component: 10 css/menu_alter_main.css: {} 11 js: 12 js/menu_alter_main.js: {} 13 dependencies: 14 - core/jquery 15 - core/jquery.once 16 - core/drupal themes/flex_theme/flex_theme.libraries.yml Add a second library to libraries.yml file. A Liibrary can define both CSS and JS files to include, as well as, any dependencies on other libraries.

Slide 45

Slide 45

1 {{ attach_library(‘flex_theme/menu-alter-main’) }} 2 {# … #} 3 {% if items %} 4 {# … #} 5 {% for item in items %} 6 {# … #} 7 <li{{ item.attributes.addClass(classes) }}> 8 {% if item.title == ‘Twig’ %} 9 {% set style = ‘background:#0F0;color:#F00’ %} 10 {{ link(item.title ~ ’ Alt’, item.url, { ‘style’: style }) }} 11 {% else %} 12 {{ link(item.title, item.url) }} 13 {% endif %} 14 {# … #} themes/flex_theme/templates/menu—main.html.twig Libraries can be attached from within a template files, by using the twig function ‘attach_library’. Attaching new library only when the template menu—main.html.twig is included on page.

Slide 46

Slide 46

The “JavaScript” menu item is altered a er custom JavaScript triggers, changing values and assigning a new class name for syling.

Slide 47

Slide 47

#6 HOOKS

Slide 48

Slide 48

THE ALTER DATA METHOD Provided by core and modules Requires PHP and Drupal skillset Requires custom theme or module

Slide 49

Slide 49

Can use Twig debug to learn naming convention for hooks

Slide 50

Slide 50

1 <!— THEME DEBUG —> 2 <!— THEME HOOK: ‘menu__main’ —> 3 <!— FILE NAME SUGGESTIONS: 4 X menu—main.html.twig 5 X menu—main.html.twig 6 * menu.html.twig 7 —> 8 <!— BEGIN OUTPUT from ‘themes/flex_theme/templates/menu—main.html.twig’ —> 9 <ul class=”clearfix menu”> 10 <!— // … —> 11 </ul> 12 <!— END OUTPUT from ‘themes/flex_theme/templates/menu—main.html.twig’ Twig debug information informs that theme hooks should contain ‘menu__main’ (line 2)

Slide 51

Slide 51

Will create a custom module (flex_module) to implement hooks.

Slide 52

Slide 52

1 // Implements hook_preprocess_HOOK(). 2 function flex_module_preprocess_menu__main(&$variables) { 3 // Loop through all menu tabs. 4 foreach ($variables[‘items’] as &$menu_tab) { 5 // Current tab pointing to node/6 ? 6 if ($menu_tab[‘url’]->toString() == ‘/node/6’) { 7 // Alter Title 8 $menu_tab[‘title’] .= ’ Alt’; 9 // Existing attributes? 10 $attributes = $menu_tab[‘url’]->getOption(‘attributes’); 11 // Add custom styling. 12 $attributes[‘style’] .= ‘color:#FFF;background:#F00;’; 13 // Add back modified attributes. 14 $menu_tab[‘url’]->setOption(‘attributes’, $attributes); 15 } 16 } 17 } module/custom/flex_module/flex_module.module Implement a preprocess hook targeted at the main menu. Loop through all the menu items and alter any that point to node/6

Slide 53

Slide 53

Can enable modules from command line using Drush.

Slide 54

Slide 54

“Hooks” menu item has been altered by using preprocess hook in a custom module

Slide 55

Slide 55

#7 SERVICES

Slide 56

Slide 56

THE REPLACE CORE METHOD Replace/Alter global systems Requires advanced Drupal and OOP skillset Requires a custom module

Slide 57

Slide 57

Using a custom service requires some PHP classes within a custom module.

Slide 58

Slide 58

1 namespace Drupal\flex_module; 2 3 use Drupal\Core\DependencyInjection\ServiceProviderBase; 4 use Drupal\Core\DependencyInjection\ContainerBuilder; 5 6 class FlexModuleServiceProvider extends ServiceProviderBase { 7 /** 8 * {@inheritdoc} 9 */ 10 public function alter(ContainerBuilder $container) { 11 // Override menu_link_tree class with custom. 12 $definition = $container->getDefinition(‘menu.link_tree’); 13 $definition->setClass(‘Drupal\flex_module\FlexModuleMenuLinkTree’); 14 } 15 } modules/custom/flex_module/src/FlexModuleServiceProvider.php Need to create a *ServiceProvider class that extends the ServiceProviderBase class (line 6). Will override the ‘alter’ method (lines 10 -14), and change the PHP class uses for the menu Tree service (lines 12 - 13)

Slide 59

Slide 59

1 namespace Drupal\flex_module; 2 use Drupal\Core\Menu\MenuLinkTree; 3 4 class FlexModuleMenuLinkTree extends MenuLinkTree { 5 // Overrides \Drupal\Core\Menu\MenuLinkTree::build(). 6 public function build(array $tree) { 7 $build = parent::build($tree); 8 if (isset($build[‘#items’]) && $build[‘#theme’] == ‘menu__main’) { 9 $n = 0; 10 foreach ($build[‘#items’] as &$item ) { 11 if (++$n == 8) { 12 // Change Title, path and add styling. 13 $item[‘title’] .= ’ Alt’; 14 $item[‘url’]->setOption(‘attributes’, array( 15 ‘style’ => ‘color:#00F;background:#FFA500;’, 16 )); 17 } 18 } 19 } 20 return $build; modules/custom/flex_module/src/FlexModuleMenuLinkTree.php 21 } Create a new service class that extends the core MenuLinkTree service (line 4). Will override the core ‘build’ method, so that can use custom logic to tartget the 8th main menu item.

Slide 60

Slide 60

Drupal now uses custom menu link tree service to render menu links. Custom logic thus casues the “Services” menu tab to be altered.

Slide 61

Slide 61

#8 COMBINATIONS

Slide 62

Slide 62

THE REAL WORLD METHOD Most control over Drupal Use multiple skillsets Requires more time and effort

Slide 63

Slide 63

1 namespace Drupal\flex_module; 2 use Drupal\Core\Menu\MenuLinkTree; 3 4 class FlexModuleMenuLinkTree extends MenuLinkTree { 5 // Overrides \Drupal\Core\Menu\MenuLinkTree::build(). 6 public function build(array $tree) { 7 $build = parent::build($tree); 8 if (isset($build[‘#items’]) && $build[‘#theme’] == ‘menu__main’) { 9 $n = 0; 10 foreach ($build[‘#items’] as &$item ) { 11 // … 12 if ($item[‘url’]->toString() == ‘/node/8’) { 13 $item[‘title’] .= ’ Alt’; 14 } 15 } 16 } 17 return $build; 18 } 19 } modules/custom/flex_module/src/FlexModuleMenuLinkTree.php Use custom service to alter the Display title of a menu link (lines 12 - 14)

Slide 64

Slide 64

1 // Implements hook_preprocess_HOOK(). 2 function flex_module_preprocess_menu__main(&$variables) { 3 $size = count($variables[‘items’]); 4 $m = 1; 5 // Loop through all menu tabs. 6 foreach ($variables[‘items’] as &$menu_tab) { 7 // Current tab pointing to node/6 ? 8 if ($menu_tab[‘url’]->toString() == ‘/node/6’) { 9 // … 10 } 11 $menu_tab[‘is_combo’] = ($m++ == $size); 12 } 13 } modules/custom/flex_module/flex_module.module Use a preprocess hook in a custom module to target items in main menu. Will add new menu item boolean attribute to check if last item (line #11).

Slide 65

Slide 65

1 (function ($, Drupal) { 2 “use strict”; 3 Drupal.behaviors.flexThemeMenuAlterMain = { 4 attach: function (context) { 5 $(‘.menu—main ul.menu li a’).each(function(){ 6 // … 7 if ($(this).data(‘combo’) == 1) { 8 $(this).addClass(‘combo-item’); 9 } 10 }); 11 } 12 } 13 })(jQuery, Drupal); themes/flex_theme/js/menu_alter_main.js Will use custom JavaScript that is part of a custom library to add the class ‘combo-item’ to any main menu link that has the data-attribute “combo”

Slide 66

Slide 66

1 .menu—main .menu li a.combo-item { 2 color: #000; 3 font-weight: 800; 4 text-shadow: 0 0 #000 !important; 5 background: red; /* not working, let’s see some red */ 6 background: -moz-linear-gradient( top , 7 rgba(255, 0, 0, 1) 0%, 8 rgba(255, 255, 0, 1) 15%, 9 rgba(0, 255, 0, 1) 30%, 10 rgba(0, 255, 255, 1) 50%, 11 rgba(0, 0, 255, 1) 65%, 12 rgba(255, 0, 255, 1) 80%, 13 rgba(255, 0, 0, 1) 100%); 14 background: -webkit-gradient(linear, left top, left bottom, 15 color-stop(0%, rgba(255, 0, 0, 1)), 16 color-stop(15%, rgba(255, 255, 0, 1)), 17 color-stop(30%, rgba(0, 255, 0, 1)), 18 color-stop(50%, rgba(0, 255, 255, 1)), 19 color-stop(65%, rgba(0, 0, 255, 1)), 20 color-stop(80%, rgba(255, 0, 255, 1)), themes/flex_theme/css/menu_alter.css 21 color-stop(100%, rgba(255, 0, 0, 1))); Write a CSS rule to change background color of any menu item with the class ‘combo-item’

Slide 67

Slide 67

1 <ul class=”menu”> 2 {% endif %} 3 {% for item in items %} 4 {# … #} 5 <li{{ item.attributes.addClass(classes) }}> 6 {% if item.title == ‘Twig’ %} 7 {# … #} 8 {% elseif item.is_combo %} 9 {{ link(item.title | reverse, item.url) }} 10 {% else %} 11 {{ link(item.title, item.url) }} 12 {% endif %} 13 {# … #} 14 </li> 15 {% endfor %} 16 </ul> theme/flex_theme/tempplates/menu—main.html.twig Will use a custom templte to build main menu. Will check to see if menu item has attribute ‘is_combo’ and if so, will reverse the menu text.

Slide 68

Slide 68

1 attributes: 2 class: 3 label: ” 4 description: ” 5 target: 6 label: ” 7 description: ” 8 options: 9 _blank: ‘New window (_blank)’ 10 _self: ‘Same window (_self)’ 11 style: 12 label: ” 13 description: ” 14 data-combo: 15 label: ‘Combo Item’ 16 description: ‘Is this a combo menu item?’ 17 options: 18 0: ‘No’ 19 1: ‘Yes’ 20 _core: 21 default_config_hash: 9nRDOclwSlz2Os9mJXM1LXNbV2q-bADV0zipiWPXymk Will update the configuration of Menu Link Attributes module, to include a custom ‘data-combo’ attribute (lines 14-19).

Slide 69

Slide 69

Will use Drupal core to edit menu item and set custom attribute ‘data-combo’ to ‘Yes’

Slide 70

Slide 70

Result of using multiple manipulations methods, the last menu item is greatly altered.

Slide 71

Slide 71

WHAT DID WE LEARN? Drupal is flexible! No “right” way, just “right for me” way

Slide 72

Slide 72

RESOURCES bit.ly/NYC16Flex This presentation bit.ly/NYC16FlexSlides Annotated Slides bit.ly/NYC16FlexCode Demo code (theme and module) mike-miles.com My blog

Slide 73

Slide 73

FEEDBACK @MIKEMILES86

Slide 74

Slide 74

THANK YOU!