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:
- Define an interface for the plugin. This describes the common set of behavior, and the methods you will call on each plugin class that is instantiated. Usually this interface will extend one or more of the following interfaces:
- (optional) Create a base class that provides a partial implementation of the interface, for the convenience of developers wishing to create plugins of your type. The base class usually extends , or one of the base classes that extends this class.
- Choose a method for plugin discovery, and define classes as necessary. See Plugin discovery below.
- Create a plugin manager/factory class and service, which will discover and instantiate plugins. See Defining a plugin manager class and service below.
- Use the plugin manager to instantiate plugins. Call methods on your plugin interface to perform the tasks of your plugin type.
- (optional) If appropriate, define a plugin collection. See Defining a plugin collection below for more information.
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 . 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 , 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 ; most plugin managers do this by extending . 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:
- 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 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 . 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 . The classes (plugin class) and (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