You are here

Plugin API in Drupal 9

Same name and namespace in other branches
  1. 8 core/core.api.php \plugin_api

Using the Plugin API

Overview and terminology

The basic idea of plugins is to allow a particular module or subsystem of Drupal to provide functionality in an extensible, object-oriented way. The controlling module or subsystem defines the basic framework (interface) for the functionality, and other modules can create plugins (implementing the interface) with particular behaviors. The controlling module instantiates existing plugins as needed, and calls methods to invoke their functionality. Examples of functionality in Drupal Core that use plugins include: the block system (block types are plugins), the entity/field system (entity types, field types, field formatters, and field widgets are plugins), the image manipulation system (image effects and image toolkits are plugins), and the search system (search page types are plugins).

Plugins are grouped into plugin types, each generally defined by an interface. Each plugin type is managed by a plugin manager service, which uses a plugin discovery method to discover provided plugins of that type and instantiate them using a plugin factory.

Some plugin types make use of the following concepts or components:

  • Plugin derivatives: Allows a single plugin class to present itself as multiple plugins. Example: the Menu module provides a block for each defined menu via a block plugin derivative.
  • Plugin mapping: Allows a plugin class to map a configuration string to an instance, and have the plugin automatically instantiated without writing additional code.
  • Plugin collections: Provide a way to lazily instantiate a set of plugin instances from a single plugin definition.

There are several things a module developer may need to do with plugins:

See https://www.drupal.org/developing/api/8/plugins for more detailed documentation on the plugin system. There are also topics for a few of the many existing types of plugins:

Defining a new plugin type

To define a new plugin type:

Plugin discovery

Plugin discovery is the process your plugin manager uses to discover the individual plugins of your type that have been defined by your module and other modules. Plugin discovery methods are classes that implement \Drupal\Component\Plugin\Discovery\DiscoveryInterface. Most plugin types use one of the following discovery mechanisms:

  • Annotation: Plugin classes are annotated and placed in a defined namespace subdirectory. Most Drupal Core plugins use this method of discovery.
  • Hook: Plugin modules need to implement a hook to tell the manager about their plugins.
  • YAML: Plugins are listed in YAML files. Drupal Core uses this method for discovering local tasks and local actions. This is mainly useful if all plugins use the same class, so it is kind of like a global derivative.
  • Static: Plugin classes are registered within the plugin manager class itself. Static discovery is only useful if modules cannot define new plugins of this type (if the list of available plugins is static).

It is also possible to define your own custom discovery mechanism or mix methods together. And there are many more details, such as annotation decorators, that apply to some of the discovery methods. See https://www.drupal.org/developing/api/8/plugins for more details.

The remainder of this documentation will assume Annotation-based discovery, since this is the most common method.

Defining a plugin manager class and service

To define an annotation-based plugin manager:

  • Choose a namespace subdirectory for your plugin. For example, search page plugins go in directory Plugin/Search under the module namespace.
  • Define an annotation class for your plugin type. This class should extend \Drupal\Component\Annotation\Plugin, and for most plugin types, it should contain member variables corresponding to the annotations plugins will need to provide. All plugins have at least $id: a unique string identifier.
  • Define an alter hook for altering the discovered plugin definitions. You should document the hook in a *.api.php file.
  • Define a plugin manager class. This class should implement \Drupal\Component\Plugin\PluginManagerInterface; most plugin managers do this by extending \Drupal\Core\Plugin\DefaultPluginManager. If you do extend the default plugin manager, the only method you will probably need to define is the class constructor, which will need to call the parent constructor to provide information about the annotation class and plugin namespace for discovery, set up the alter hook, and possibly set up caching. See classes that extend DefaultPluginManager for examples.
  • Define a service for your plugin manager. See the Services topic for more information. Your service definition should look something like this, referencing your manager class and the parent (default) plugin manager service to inherit constructor arguments:

  plugin.manager.mymodule:
    class: Drupal\mymodule\MyPluginManager
    parent: default_plugin_manager
  
  • If your plugin is configurable, you will also need to define the configuration schema and possibly a configuration entity type. See the Configuration API topic for more information.

Defining a plugin collection

Some configurable plugin types allow administrators to create zero or more instances of each plugin, each with its own configuration. For example, a single block plugin can be configured several times, to display in different regions of a theme, with different visibility settings, a different title, or other plugin-specific settings. To make this possible, a plugin type can make use of what's known as a plugin collection.

A plugin collection is a class that extends \Drupal\Component\Plugin\LazyPluginCollection or one of its subclasses; there are several examples in Drupal Core. If your plugin type uses a plugin collection, it will usually also have a configuration entity, and the entity class should implement \Drupal\Core\Entity\EntityWithPluginCollectionInterface. Again, there are several examples in Drupal Core; see also the Configuration API topic for more information about configuration entities.

Creating a plugin of an existing type

Assuming the plugin type uses annotation-based discovery, in order to create a plugin of an existing type, you will be creating a class. This class must:

  • Implement the plugin interface, so that it has the required methods defined. Usually, you'll want to extend the plugin base class, if one has been provided.
  • Have the right annotation in its documentation header. See the Annotation topic for more information about annotation.
  • Be in the right plugin namespace, in order to be discovered.

Often, the easiest way to make sure this happens is to find an existing example of a working plugin class of the desired type, and copy it into your module as a starting point.

You can also create a plugin derivative, which allows your plugin class to present itself to the user interface as multiple plugins. To do this, in addition to the plugin class, you'll need to create a separate plugin derivative class implementing \Drupal\Component\Plugin\Derivative\DerivativeInterface. The classes \Drupal\system\Plugin\Block\SystemMenuBlock (plugin class) and \Drupal\system\Plugin\Derivative\SystemMenuBlock (derivative class) are a good example to look at.

Performing tasks involving plugins

Here are the steps to follow to perform a task that involves plugins:

  • Locate the machine name of the plugin manager service, and instantiate the service. See the Services topic for more information on how to do this.
  • On the plugin manager class, use methods like getDefinition(), getDefinitions(), or other methods specific to particular plugin managers to retrieve information about either specific plugins or the entire list of defined plugins.
  • Call the createInstance() method on the plugin manager to instantiate individual plugin objects.
  • Call methods on the plugin objects to perform the desired tasks.

See also

Annotations

File

core/core.api.php, line 1292
Documentation landing page and topics, plus core library hooks.

Classes

Namesort descending Location Description
Condition core/lib/Drupal/Core/Condition/Annotation/Condition.php Defines a condition plugin annotation object.
ConditionManager core/lib/Drupal/Core/Condition/ConditionManager.php A plugin manager for condition plugins.
ConditionPluginBase core/lib/Drupal/Core/Condition/ConditionPluginBase.php Provides a basis for fulfilling contexts for condition plugins.
DefaultPluginManager core/lib/Drupal/Core/Plugin/DefaultPluginManager.php Base class for plugin managers.
LazyPluginCollection core/lib/Drupal/Component/Plugin/LazyPluginCollection.php Defines an object which stores multiple plugin instances to lazy load them.
Plugin core/lib/Drupal/Component/Annotation/Plugin.php Defines a Plugin annotation object.
PluginBase core/lib/Drupal/Core/Plugin/PluginBase.php Base class for plugins supporting metadata inspection and translation.

Interfaces

Namesort descending Location Description
ConditionInterface core/lib/Drupal/Core/Condition/ConditionInterface.php An interface for condition plugins.
ConfigurableInterface core/lib/Drupal/Component/Plugin/ConfigurableInterface.php Provides an interface for a configurable plugin.
ContextAwarePluginInterface core/lib/Drupal/Core/Plugin/ContextAwarePluginInterface.php An override of ContextAwarePluginInterface for documentation purposes.
ContextAwarePluginInterface core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php Interface for defining context aware plugins.
DependentPluginInterface core/lib/Drupal/Component/Plugin/DependentPluginInterface.php Provides an interface for a plugin that has dependencies.
DeriverInterface core/lib/Drupal/Component/Plugin/Derivative/DeriverInterface.php Provides additional plugin definitions based on an existing definition.
DiscoveryInterface core/lib/Drupal/Component/Plugin/Discovery/DiscoveryInterface.php An interface defining the minimum requirements of building a plugin discovery component.
EntityWithPluginCollectionInterface core/lib/Drupal/Core/Entity/EntityWithPluginCollectionInterface.php Provides an interface for an object using a plugin collection.
ExecutableInterface core/lib/Drupal/Core/Executable/ExecutableInterface.php An interface for executable plugins.
ObjectWithPluginCollectionInterface core/lib/Drupal/Core/Plugin/ObjectWithPluginCollectionInterface.php Provides an interface for an object using a plugin collection.
PluginFormInterface core/lib/Drupal/Core/Plugin/PluginFormInterface.php Provides an interface for an embeddable plugin form.
PluginInspectionInterface core/lib/Drupal/Component/Plugin/PluginInspectionInterface.php Plugin interface for providing some metadata inspection.
PluginManagerInterface core/lib/Drupal/Component/Plugin/PluginManagerInterface.php Interface implemented by plugin managers.

Traits

Namesort descending Location Description
ContextAwarePluginTrait core/lib/Drupal/Core/Plugin/ContextAwarePluginTrait.php Provides a trait to add context-aware functionality to plugins.