The Flexibility of Drupal 8

DCN Lights 2017

Mike Miles

Genuine (wearegenuine.com)

Dev(up); podcast (developingup.com)

All the internet places: mikemiles86

Flexiblity

TYPES OF FLEXIBILITIES AND CLASSIFICATION OF FLEXIBLE MANUFACTURING SYSTEMS

"Expansion Flexibility - The capability of building a system, and expanding it as needed, easily and modularly."
- Jim Browne, 1984

What Makes Drupal Flexible

  • Modular design
  • Decoupled systems
  • Open Source nature
The brain of a Drupalist bit.ly/DrupalBrain

The brain of a Drupalist is split into many skillsets, which can all be leveraged.

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

Along comes the client...

"Could you change the menu things on the homepage?"

The "Homepage"

Plain Drupal 8 site before manipulations

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

Focus of this Session

  • To prove the flexiblity of Drupal
  • To demostrate abilities of all skillsets
  • To discuss considerations and limitations

#1 Drupal Core

Using Drupal core to edit a main menu link Using Drupal core to edit a main menu link

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

The first menu link has been altered using only Drupal core

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

#2 Modules

Look on drupal.org for modules that meet your needs

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.

Use drupal core to enable module. User drupal core to enable module.

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

More editable attributes for a menu link More editable attributes for a menu link

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

Menu Link Attributes require technical knowledge to change.

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


              attributes:
  class:
    label: ''
    description: ''
  target:
    label: ''
    description: ''
    options:
      _blank: 'New window (_blank)'
      _self: 'Same window (_self)'
  style:
    label: ''
    description: ''
_core:
  default_config_hash: 9nRDOclwSlz2Os9mJXM1LXNbV2q-bADV0zipiWPXymk

            

Add a new configurable 'style' attribute (lines 11-13) to the YAML

Now able to add inline style to menu link Now able to add inline style to menu link

After saving configuration, now able to add inline style to menu links

Main menu link altered using a module.

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

#3 Twig Templates

Use debug tools to learn which templates to alter.

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


               <!-- THEME DEBUG -->




<!-- END OUTPUT from 'core/themes/classy/templates/navigation/menu.html.twig'
            

Twig debug tells the available template names to override current template.

Create a custom theme to override template

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


{# ... #}
  {% if items %}
    {# ... #}
    {% for item in items %}
      {# ... #}
      <li{{ item.attributes.addClass(classes) }}>
        {% if item.title == 'Twig' %}
          {% set style = 'background:#0F0;color:#F00' %}
          {{ link(item.title ~ ' Alt', item.url, { 'style': style }) }}
        {% else %}
          {{ link(item.title, item.url) }}
        {% endif %}
        {# ... #}
      </li>
    {% endfor %}
    </ul>
  {% 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.

Menu link altered using a custom template

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

#4 CSS

Using a custom theme for styling

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


.menu--main .menu li:nth-child(5) a {
    background: #0000FF;
    color: #FFF;
}
            themes/flex_theme/css/menu_alter.css 

Use custom CSS to target the 5th item in the main menu


              menu-alter:
  version: VERSION
  css:
    component:
      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.


              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.

Altered menu link using custom CSS in a custom library.

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

#5 JavaScript

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


              (function ($, Drupal) {
  "use strict";
  Drupal.behaviors.flexThemeMenuAlterMain = {
    attach: function (context) {
      $('.menu--main ul.menu li a').each(function(){
        if ($(this).attr('href') == '/node/5') {
          $(this).addClass('yellow-menu');
          $(this).attr('style', 'color: #000;');
          $(this).attr('target', '_blank');
          $(this).text($(this).text() + Drupal.t(' Alt'));
        }
      });
    }
  }
})(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.


              .yellow-menu {
    background: #FFFF00;
}
            themes/flex_theme/css/menu_alter_main.css 

Add some basic CSS for to a custom class name.


              menu-alter:
  version: VERSION
  css:
    component:
      css/menu_alter.css: {}
menu-alter-main:
  version: VERSION
  css:
    component:
      css/menu_alter_main.css: {}
  js:
    js/menu_alter_main.js: {}
  dependencies:
    - core/jquery
    - core/jquery.once
    - 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.


{{ attach_library('flex_theme/menu-alter-main') }}
{# ... #}
  {% if items %}
    {# ... #}
    {% for item in items %}
      {# ... #}
      <li{{ item.attributes.addClass(classes) }}>
        {% if item.title == 'Twig' %}
          {% set style = 'background:#0F0;color:#F00' %}
          {{ link(item.title ~ ' Alt', item.url, { 'style': style }) }}
        {% else %}
          {{ link(item.title, item.url) }}
        {% endif %}
        {# ... #}
            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.

Result of using custom JavaScrupt to alter menu item.

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

#6 Hooks

Using Twig debug to learn which hooks affect the menu

Can use Twig debug to learn naming convention for hooks


              <!-- THEME DEBUG -->




<!-- END OUTPUT from 'themes/flex_theme/templates/menu--main.html.twig'
            

Twig debug information informs that theme hooks should contain 'menu__main' (line 2)

Create a custom module to implement hooks.

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


              // Implements hook_preprocess_HOOK().
function flex_module_preprocess_menu__main(&$variables) {
  // Loop through all menu tabs.
  foreach ($variables['items'] as &$menu_tab) {
    // Current tab pointing to node/6 ?
    if ($menu_tab['url']->toString() == '/node/6') {
      // Alter Title
      $menu_tab['title'] .= ' Alt';
      // Existing attributes?
      $attributes = $menu_tab['url']->getOption('attributes');
      // Add custom styling.
      $attributes['style'] .= 'color:#FFF;background:#F00;';
      // Add back modified attributes.
      $menu_tab['url']->setOption('attributes', $attributes);
    }
  }
}
            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

enable custom module using Drush enable custom module using Drush

Can enable modules from command line using Drush.

Result of altering menu item with hooks

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

#7 Services

PHP files adding to custom module.

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


              namespace Drupal\flex_module;

use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Drupal\Core\DependencyInjection\ContainerBuilder;

class FlexModuleServiceProvider extends ServiceProviderBase {
  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container) {
    // Override menu_link_tree class with custom.
    $definition = $container->getDefinition('menu.link_tree');
    $definition->setClass('Drupal\flex_module\FlexModuleMenuLinkTree');
  }
}
            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)


              namespace Drupal\flex_module;
use Drupal\Core\Menu\MenuLinkTree;

class FlexModuleMenuLinkTree extends MenuLinkTree {
  // Overrides \Drupal\Core\Menu\MenuLinkTree::build().
  public function build(array $tree) {
    $build = parent::build($tree);
    if (isset($build['#items']) && $build['#theme'] == 'menu__main') {
      $n = 0;
      foreach ($build['#items'] as &$item ) {
        if (++$n == 8) {
          // Change Title, path and add styling.
          $item['title'] .= ' Alt';
          $item['url']->setOption('attributes', array(
            'style' => 'color:#00F;background:#FFA500;',
          ));
        }
      }
    }
    return $build;
  }
}
            modules/custom/flex_module/src/FlexModuleMenuLinkTree.php 

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.

Result of using a custom service

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

Along comes the client...

"Could you change the menu things on the homepage?"

"Could you make Drupal (8) do X, Y and Z?"

Yes. Yes I can.

...but I need more details

What did we Learn?

  • Drupal can do "that"
  • No "right way", just "right for me way"

Resources

bit.ly/DCN17Flex

This presentation


bit.ly/DCN17FlexSlides

Annotated Slides


bit.ly/DCN17FlexCode

Demo code (theme and module)


bit.ly/DrupalBrain

Drupal Brain Diagram


developingup.com

My podcast

Feedback

@mikemiles86

#DCNLights

Thank You!

Questions?