Drupal Tutorial: Plugins

Plugins in Drupal are used to extend and customise the functionality of the platform by providing reusable code that can be extended by other plugins or modules. This article covers the basics of creating plugins for Drupal core.

Drupal core comes with various plugin types used to manage different aspects of the platform, some of the most common plugin types are:

  1. Block plugins: These are used to create blocks that can be assigned to different regions of a page.
  2. Field plugins: These are used to create custom fields that can be added to content entities such as nodes and users.
  3. Views plugins: These are used to define functionality for Views such as custom filters or custom content for Views header and footer areas.

Plugin annotations are used to define the properties and behaviour of a plugin. Annotations are a way of adding metadata to a class, method, or property, which can be used by Drupal to understand how the plugin works. The annotations used in Drupal are defined using PHPDoc syntax and are placed directly above the plugin class or method. 

Note: if you are coding to PHPCS Drupal standards then be careful when auto-formatting plugin annotations as this can lead to serious issues when an annotation becomes broken due to bad formatting.

Here is an example of a plugin annotation for a block plugin:

/**
* Provides a 'Example Custom Block' block.
*
* @Block(
*   id = "example_custom_block",
*   admin_label = @Translation("Example Custom Block")
* )
*/

This simple plugin annotation provides metadata about a block plugin called "Example Custom Block". The "id" property specifies the unique identifier for the plugin that can be called programmatically when loading a plugin, and the "admin_label" property provides a label that is used in the Drupal administration interface.

Annotations provide a number of benefits when developing with Drupal, including:

  • Standardisation: Annotations provide a standardised way of defining plugins, making it easier for developers to understand the properties of a plugin.
  • Extensibility: Annotations make it possible to extend the behaviour of plugins by adding new properties or behaviours.

To provide a working example of a Drupal plugin class, let's use the example custom block annotation to create a custom block that displays a list of recent articles on a Drupal site. The plugin will extend the functionality of Drupal by adding a new block that can be placed on any page of the site.

The directory structure we will be using is as follows:

  • example_custom_module
    • src
      • Plugin
namespace Drupal\example_custom_module\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* Provides a 'Recent articles' block.
*
* @Block(
*   id = "recent_articles_block",
*   admin_label = @Translation("Recent articles"),
*   category = @Translation("Custom")
* )
*/
class RecentArticlesBlock extends BlockBase {
}

In this example, we are defining a block plugin with the id "recent_articles_block" and an admin label "Recent articles". We have also specified that this block belongs to a custom category named "Custom".

Next, we will define the build method that is used to generate the content for the block, the finished block class looks like this:

<?php

namespace Drupal\example_custom_module\Plugin\Block;

use Drupal\node\Entity\Node;
use Drupal\Core\Block\BlockBase;

/**
 * Provides a 'Recent articles' block.
 *
 * @Block(
 *   id = "recent_articles_block",
 *   admin_label = @Translation("Recent articles"),
 *   category = @Translation("Custom")
 * )
 */
class RecentArticlesBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build(): array {
    // Get the 3 most recent articles.
    $query = \Drupal::entityQuery('node')
      ->condition('type', 'article')
      ->condition('status', 1)
      ->sort('created', 'DESC')
      ->range(0, 3);
    $nids = $query->execute();
    // Load the node entities and build a list of titles and links.
    $nodes = Node::loadMultiple($nids);
    $items = [];
    foreach ($nodes as $node) {
      $items[] = [
        '#type' => 'link',
        '#title' => $node->getTitle(),
        '#url' => $node->toUrl(),
      ];
    }
    // Return a render array with the list of titles and links.
    return [
      '#theme' => 'item_list',
      '#items' => $items,
      '#title' => $this->t('Recent articles'),
      '#wrapper_attributes' => [
        'class' => ['recent-articles'],
      ],
    ];
  }

}

In the build method we are using the Drupal entity query system to retrieve the 3 most recent articles that have the published status of 1 - this means only published articles will be displayed. We then load the node entities and build a list of titles and links for each article. Finally, we return a render array that contains the list of titles and links, along with a title for the block and some wrapper attributes such as the CSS class assigned to the list wrapper.

This block plugin can now be enabled in Drupal's admin interface and added to any region of the site and configured using the default plugin methods provided by the Block base class. 

By using plugins Drupal can be extended to provide custom functionality that is easy to maintain, and provides developers and site owners a flexible solution when working on bespoke platform features.