How to Port a Module from Drupal 7 to 8

Drupal 8 is here and is quickly becoming the de facto version to use for Drupal projects. There is a big push by the Drupal community to get contribution modules ported to Drupal 8, the newest iteration of the Drupal open source platform. Let’s take a look at five big changes that a module needs to start making the move so you can prep for the upcoming sprint on January 30-31.

1. The .info.yml file

Before Drupal 8, an .info file was provided to Drupal with metadata about the module. Drupal 8 modules use an .info.yml file instead. This file contains all the same metadata that the .info file does, it’s now just written in YAML format.

Drupal 7 (example.info)

name = Example
description = An example Drupal module.
package = Other
dependencies[] = oauth

Drupal 8 (example.info.yml)

name: Example
description: An example Drupal module.
type: module
package: Other
dependencies:  
  - oauth

This is a critical update to make when porting a module to Drupal 8. Without the .info.yml file Drupal 8 will not recognize that the module exists. Check out the documentation about .info.yml files to learn more about what else has changed.

2. The .routing.yml file

The hooks hook_menu() and hook_menu_alter() have been removed in Drupal 8. URI paths and page callbacks are now managed using a routing system based on the Symfony Routing component. A .routing.yml file is required to tell Drupal 8 about the URI paths and callbacks for a module.

Drupal 7 (example.module)

<?php
// ... 
function example_menu() {  
  return array(    
    ‘example/page’ => array(      
      ‘title’ => ‘Example Page’,      
      ‘page callback’ => ‘example_content’,      
      ‘access arguments’ => array(‘access content’),
     ),
    );
}
// ...

Drupal 8 (example.routing.yml)

example.example_page:  
  path: ‘/example/page’  
  defaults:    
    _title: ‘Example Page’    
    _controller: ‘\Drupal\example\Controller\ExampleController::exampleContent’
  requirements:  
    _permission: ‘access content’

Routes are defined in YAML format and provide the same information as in the past. This includes the URI path, title, callback function (controller) and required permissions. For more information on how routing replaces the menu hooks checkout the documentation.

3. Basic Controller

Modules still need to provide a .module file. The .module file should only contain hook implementations.  The use of global functions in Drupal 8 is bad practice. Most custom functions, such as the page callbacks for routes, should instead be methods of a Controller Class.  For autoloading purposes a module needs to place controller classes in a \src\Controller\ directory. Drupal 8 modules should have a basic Controller class that is named after the module.  

Drupal 7 (example.module)

<?php
//...
function example_content() {  
  return array(    
    ‘#theme’ => ‘example_content’,    
    ‘#my_content’ => example_get_content(),   
  );
}
// ...

Drupal 8 (\src\Controller\ExampleController.php)

<?php
namespace Drupal\example\Controller;
use Drupal\Core\Controller\ControllerBase;
 
class ExampleController extends ControllerBase {
  // ...
  public function exampleContent() {    
    return [      
      ‘#theme’ => ‘example_content’,      
      ‘#my_content’ => $this->getContent(),    
    ];  
  }   
  //...
}

For more on creating the basic controller for a module checkout the documentation. Modules with a lot of utility or faux private functions (beginning with “_”) should also look into how to create custom services.

4. Configuration & State API/Storage Systems

The variable_set() and variable_get() functions are removed from Drupal 8. Modules that used these functions need to instead use the Drupal 8 config API or state API.  Use the Config API for data expected to be editable by users. Use the State API for variables that can be reset or are not expected to be edited by users.

Drupal 7 (example.module)

<?php
// ...
function example_get_content() {  
  return variable_get(‘example_content’, ‘Hello World’);
}
// ...

Drupal 8 (\src\Controller\ExampleController.php)

<?php 
// ...
class ExampleController extends ControllerBase {  
  // ...  
  function getContent() {    
    return \Drupal::state()->get(‘example_content’) ?: ‘Hello World’;  
  }  
  // ...
}

The methods used by the \Drupal::state() object are similar to the functions in the past. Using a set() method to store a value and get() method to retrieve a value.  Using the config API has a few more moving pieces. Checkout the config API and state API documentation pages for more information.

5. Twig Templates

8 uses the Twig templating engine to render content. Modules need to replace any .tpl.php (template) files with .html.twig (twig template) files. The biggest change is that twig template files cannot contain any PHP code. For many modules this may mean refactoring their templates and functions for content output.

Drupal 7 (example-content.tpl.php)

<div class=”example-content”><?php echo $my_content; ?></div>

Drupal 8 (\templates\example-content.html.twig)

<div class=”example-content”>{{ my_content }}</div>

The hook hook_theme() is still used to define theme implementation and has changed little. By default Drupal 8 will look for template files in the \templates directory of a module. For more information on twig templates in drupal, check out the documentation.

These are just five of the many updates a module needs to make to upgrade to Drupal 8. For more information about porting a Drupal 7 module to Drupal 8 checkout the online handbook. The tool Drupal Module Upgrader can also help automate the porting process.

If you are not a module maintainer, there are plenty of ways for you to help port modules to Drupal 8. Check out the Contrib Port Tracker [https://www.drupal.org/project/contrib_tracker] for statuses and open issues of many popular modules. Join the Drupal 8 contrib office hours on IRC to see where you can help or join us at the Genuine office for the New England Drupal Sprint 2016. More information here!

Have Something to Say?

Your email address will not be published. Required fields are marked *

twenty − 14 =

Recent Posts

Recent Comments

Archives

Categories

Meta