Drupal 7 to 8 Migration: Themes and Modules

Dealing With Custom Themes

Themes at their core use the Module API, so everything said below also applies to themes (i.e., read the rest of this page, even if you aren't planning to write any custom modules).  In addition, be aware that:

  • Page templates are now done using the Twig language

  • Best practice is to create a sub-theme of a core Drupal 8 theme (stark or classy) and then add your customizations to that sub-heme

Dealing With Custom Modules

Drupal 8 moved to class based programing style based on Symfony, which makes it much harder for a module maintainer to port modules to Drupal 8

Some custom module rebuild options include:

  • Port it yourself (you'll need some good PHP coding experience)

  • Get co-workers, interns, student assistants, etc. to port it (you'll need $$ and talent)

  • Pay an outside development company to port it (you'll need $$$)

  • Find an alternative module that does roughly the same thing

    • Note that you may lose data this way, or have to manually migrate your data

Porting Your Custom Modules: API Changes

  • Config files are now written in YAML

  • Many hook_* API calls are gone

  • Blocks, filters, etc. are now written into autoloader class files

  • Plan on it taking a while to port a module to Drupal 8

Porting Your Custom Modules: API Changes (Gotchas)

  • All output must be returned as a render array

  • Plain HTML can be sent as #markup, but it will be filtered to protect against XSS vulnerabilities

  • So, you may need to whitelist additional HTML tags and/or enable additional URL protocols

    • Here's how to whitelist HTML tags in your module output that are normally stripped out by the XSS filter:

          $tagList = array('input');
          return array(
            '#markup' => $buffer,
            '#allowed_tags' => array_merge(\Drupal\Component\Utility\Xss::getAdminTagList(), $tagList),
    • Here's how to allow data URLs in your module output for displaying images with data that you've already pulled in from a data source:

          \Drupal\Component\Utility\URLHelper::setAllowedProtocols(array('http', 'https', 'data'));
    • There is no way (I know of) to whitelist additional HTML element properties.  So, even though you can allow form elements (e.g. INPUT, SELECT, BUTTON), you'll have to give them unique IDs and then use Javascript that runs at load time to find those elements and attach Javascript actions to them (i.e. you can't use onChange, onClick, etc.).  You also cannot use any inline styles, so all styles will have to be provided by CSS classes.
  • Twig based rendering is recommended, but not required, and it has its own quirks.

    • All data values passed to a Twig template are sanitized, and there is no known way to disable this or alter the rulesets.  So, if you have preformatted content coming from an outside source, your only choice is to use the #markup option for now.  (If anyone finds a way to alter the way that Twig sanitizes data values in Drupal 8, please let me know -- Twig itself supports custom rules, but those options don't appear to be exposed to custom modules in Drupal).