DEV Community

Cover image for Drupal 8/9 - Additional routes using custom module
Edoardo Cordani
Edoardo Cordani

Posted on

Drupal 8/9 - Additional routes using custom module

Drupal is a really powerful CMS and it offers a lot of extendibility out of the box, mainly thanks to Symfony. One of the basic tasks we can archive is the creation of custom endpoints associated to a controller, in addition to the system ones generated by the definition and creation of content. The controller can then provide a response in different formats (HTML markup, JSON, Twig, etc.).
For the first step we need to create a new module and define a MY_MODULE.routing.yml file in which specify the url, the name of the controller and the access permissions.

Module creation

We use drupal console command in order to create a new module:

drupal generate:module
Enter fullscreen mode Exit fullscreen mode

After answering the questions (use all the defaults, except the unit test class creation), these files will be generated in the folder modules/custom/MACHINE_NAME_MY_MODULE (composer.json is optional):

├── MACHINE_NAME_MY_MODULE.info.yml
├── MACHINE_NAME_MY_MODULE.module
├── composer.json
└── templates
    └── MACHINE_NAME_MY_MODULE.html.twig
Enter fullscreen mode Exit fullscreen mode

It is also possible to run the command without wizard by passing directly the options. Refer to the guide generate:module | Drupal Console

Module installation

At this point we install the new module with the command:

drupal module:install MACHINE_NAME_MY_MODULE
Enter fullscreen mode Exit fullscreen mode

Alternatively we can use the Drupal admin UI at /admin/modules.

Controller creation

To create the controller associated to the module, use the command:

drupal generate:controller
Enter fullscreen mode Exit fullscreen mode

Answer the questions:

  1. module name (enter the one previously created)
  2. controller class name
  3. controller method title
  4. action method name
  5. route path (related to the point 4)

Points from 3 to 5 are repeated until you leave a blank method title (so you can add several methods/routes in one shot).
At the end of the procedure these files will be generated:

├── MACHINE_NAME_MY_MODULE.routing.yml
└── src
    └── Controller
        └── CONTROLLER_NAME.php
Enter fullscreen mode Exit fullscreen mode

Also in this case it is possible to run the command without a wizard.
Refer to the guide generate:controller | Drupal Console

Output data with Twig

If you visit the url set in the controller you will receive as response the default output generated by the generate:controller command.

Implement method: METHOD_NAME
Enter fullscreen mode Exit fullscreen mode

To render the Twig template already present in the templates subdirectory of the module, you have to modify the method created in the controller like this (in this example the method name created in the previous step is content)

from this:

public function content() {
  return [
    '#type' => 'markup',
    '#markup' => $this->t('Implement method: content')
  ];
}
Enter fullscreen mode Exit fullscreen mode

to this:

public function content() {
  return [
    '#theme' => 'MACHINE_NAME_MY_MODULE'
  ];
}
Enter fullscreen mode Exit fullscreen mode

Passing variables to the template

If you want to pass variables from the controller to the Twig template, you must edit the MACHINE_NAME_MY_MODULE.module file to list the variables you want to use, for example like this:

function MACHINE_NAME_MY_MODULE_theme() {
  return [
    'MACHINE_NAME_MY_MODULE' => [
      'render element' => 'children',
      'variables' => [
        'var1' => '',
        'items' => []
      ]
    ],
  ];
}
Enter fullscreen mode Exit fullscreen mode

Then in the controller content method we go to value the two variables var1 and items:

  public function content() {
    $var1 = 'Hello world!';
    $array1 = [1, 2, 3, 4];

    return [
      '#theme' => 'MACHINE_NAME_MY_MODULE',
      '#var1' => $var1,
      '#items' => $array1,
    ];
  }
Enter fullscreen mode Exit fullscreen mode

Finally clean up the cache with the command:

drupal cc
Enter fullscreen mode Exit fullscreen mode

Now we have access to the var1 and items variables directly in the Twig template, as in the following example:

<div>
  <p>{{ var1 }}</p>
  {% for item in items %}
    {{ item }}
  {% endfor %}
</div>
Enter fullscreen mode Exit fullscreen mode

Change access role

Using the controller generation command, default access is allowed to all users via this rule in the MACHINE_NAME_MY_MODULE.routing.yml file:

requirements:
  _permission: 'access content'
Enter fullscreen mode Exit fullscreen mode

For example, if we want to restrict access to authenticated users only, we have to edit the content of the file as follows:

requirements:
  _permission: 'access content'
  _role: 'authenticated'
Enter fullscreen mode Exit fullscreen mode

It is possible to specify multiple values using "," as a separator if you want to use AND logic, otherwise use "+" for OR logic, as in the following example:

requirements:
  _permission: 'access content'
  _role: 'authenticated, editor'
Enter fullscreen mode Exit fullscreen mode

Change caching option

Starting from Drupal 8.9, the output of the views of a custom module is automatically cached. If you want to disable this behavior, for example if your content is dynamic, add the no_cache option in the MY_MODULE.routing.yml file:

requirements:
  _permission: 'access content'
  _role: 'authenticated'
options:
  no_cache: TRUE
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
tejicit profile image
tejicit

Great post! When it comes to adding additional routes using a custom module in Drupal 8/9, it can significantly extend the functionality of a site by creating new paths and custom controllers. If anyone is looking to enhance their Drupal platform or needs expert help with custom Drupal development, check out Custom Drupal Development for tailored solutions and top-tier development services in the USA