Drupal 8 - How To Create A Custom Module (Article)

Submitted by TheMain on Sun, 04/09/2017 - 16:41

How to create a simple module with Drupal 8.

Module folder

Custom and contributed modules are placed in the /modules directory. You can use subdirectories so let’s create a subfolder /modules/custom and put the module there.

mkdir modules/custom
mkdir modules/custom/mymodule

In Drupal 7 /modules directory was reserved for core modules but in Drupal 8 that is used for custom and contributed modules. The old location sites/all/modules still works though. Core modules are now found in the /core directory.

Note: if you create /modules/contrib folder, then Drush will download modules there.

.Info file

.info file provides metadata that can be used elsewhere. It is required for Drupal to know about the module.

Create an info file "modules/custom/mymodule/mymodule.info.yml" with these lines:

name: My Module
description: A simple module.
package: Custom

type: module
core: 8.x

Explanation:

Name is displayed in admin/modules/ (required):

name: My Module

Description is displayed in admin/modules/ (required):

description: A simple module.

You can group modules for easier management (optional):

package: Custom

Type of the extension (module, theme or profile) (required):

type: module

The core version your module is compatible with (required):

core: 8.x

Flush caches and you should see the module in /admin/modules:

My Module

It doesn’t do anything yet.

Routing

Create a routing file "modules/custom/mymodule/mymodule.routing.yml" with these lines:

mymodule.content:
  path: '/mymodule'
  defaults:
    _controller: '\Drupal\mymodule\Controller\MyModuleController::content'
    _title: 'My Module'
  requirements:
    _permission: 'access content'

Explanation:

The route name with module name as prefix:

mymodule.content:

Route URI:

path: '/mymodule': 

Default properties of the route:

defaults:
  _controller: '\Drupal\mymodule\Controller\MyModuleController::content'
  _title: 'My Module'

_controller value is not a path but a namespaced class defined by PSR-4 standards.

This invokes the content method we will define in MyModuleController.php controller and sets page title as 'My Module'.

 

User has to have 'access content' permission to access this route in /mymodule:

requirements:
  _permission: 'access content'

Controller

Controller is used to execute whatever logic is needed.

Create a folder for the controller:

mkdir modules/custom/mymodule/src
mkdir modules/custom/mymodule/src/Controller

Drupal 8 uses PSR-4 standard namespace autoloading. This requires that you use the path /src/Controller.

A module has a namespace derived from its module name. For this it would be Drupal\mymodule. This is mapped to the /mymodule/src/ folder.

Create a controller file "modules/custom/mymodule/src/Controller/MyModuleController.php" with these lines:

<?php

namespace Drupal\mymodule\Controller;
use Drupal\Core\Controller\ControllerBase;

class MyModuleController extends ControllerBase {

  /**
   * Provide markup.
   *
   * @return array
   */
  public function content() {
    return array(
      '#type' => 'markup',
      '#markup' => t('My custom markup.'),
    );
  }
}

Explanation:

Start the file with <?php but don't add the ending tag:

<?php

This maps to /mymodule/src/Controller:

namespace Drupal\mymodule\Controller;

Utility class for controllers:

use Drupal\Core\Controller\ControllerBase;

Our controller class:

class MyModuleController extends ControllerBase 

Function that returns an array with translated string for Drupal to render:

  public function content() {
    return array(
      '#type' => 'markup',
      '#markup' => t('My custom markup.'),
    );
  }

Enable the module and flush caches:

drush -y en mymodule
drush cr

Navigate to /mymodule and you should see this:

My module

So the file:

modules/custom/mymodule/src/Controller/MyModuleController.php

is loaded and it's content method called because of the _controller value in the routing file:

 _controller: '\Drupal\mymodule\Controller\MyModuleController::content'

.module file

You can also add a .module file for hooks. It is a good practice to add at least the help_hook to this file.

Create a file "modules/custom/mymodule/mymodule.module" with these lines:

<?php

/**
 * @file
 * Main hooks for MyModule module.
 */

use Drupal\Core\Routing\RouteMatchInterface;

/**
 * Implements hook_help().
 */
function mymodule_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.mymodule':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Lorem ipsum. For more information, see the online <a href=":url">documentation</a>', array(
          ':url' => 'http://www.wdtutorials.com',
        )) . '</p>';
      return $output;
  }
}

Read more about help hook: https://api.drupal.org/api/drupal/core%21modules%21help%21help.api.php/function/hook_help/

Flush caches.

This will provide a link to the help page:

Help link

Visit admin/help/mymodule to see the help page:

About page

Folder structure

The folder structure should now look like this:

Folder structure

Read more:

Posted by Samuli Natri on 09 April 2017