The Drupal 8 plugin system allows a particular module or subsystem to provide functionality in an extensible, object-oriented way. The controlling module defines the basic framework (interface) for the functionality, and other modules can create plugins (implementing the interface) with particular behaviors. Plugins are grouped into plugin types. 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.
The system aims to make it easy for developers to allow for management of these components via the user interface, giving more flexibility and control to site administrators.
In this tutorial we'll take a high-level look at the problem the Plugin API is solving and provide a starting point for diving deeper into the various components that make up the Plugin API.
What are plugins?
Plugins are a general reusable solution to a recurring problem within a given context. The plugin system isn't a finished chunk of code that can just be transferred directly into your own code; rather, it's a description or template for solving a specific problem that can be used in many different situations. Plugins also include some generalized utility code that demonstrates a pattern. This is meant to assist the developer who can use this utility code as a starting point instead of having to rewrite the boilerplate pieces each time. In software engineering we call this a design pattern. This one just happens to be specific to Drupal.
Plugins are used to solve the problem where you need to allow one or more modules to provide additional "things" that implement the same interface but provide distinctly different functionality. And in most cases, then provide a site administrator with a list of those "things" so she can choose and configure the appropriate functionality for her use-case.
Blocks are the classic example. In Drupal every block consists of essentially the same parts: a label, some content, and various settings related to visibility and cacheability. How that label and content is generated is likely very different from one module to the next, though. A custom block with static content vs. one provided by Views, for example.
Each plugin behaves the same way externally (to any code that's using it) but internally may vary wildly from one to the next, as long as it sticks to the requirements about what its external face should look like as set forth by the plugin type that's being implemented.
Examples of things in Drupal that employ the plugin pattern:
- Render API elements
- Actions which can be triggered on configurable events
- Image manipulation effects
- Field types, field widgets, and field formatters
- Items in a navigation menu
The technical explanation
The Drupal documentation describes plugins as:
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.
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.
When should I employ the plugin pattern?
Anytime you want to provide new functionality for a system that already makes use of the plugin system you'll need to implement a new plugin instance of the given type. For example, if you wanted to add a new block, Render API element, field type, or image effect.
If your module needs to provide users with the ability to choose between one or more units of functionality, and that choice is considered configuration, you'll want to implement the Plugin API and provide a new plugin type, as well as corresponding plugins that provide the units of functionality, and method for determining which of all the available plugins to use.
Example: Voting API module
The Voting API module provides a generic way to store, retrieve, and tabulate votes. The module itself provides 3 different ways that votes can be tallied. However, this is logic that is likely to be customized. Rather than be forced to include use-case specific logic and giant switch statements to try and determine which ones to use, the module maintainers choose to make the tallying functionality support plugins. Now, they can provide a few basic common examples, and you are free to write a new module with a tallying plugin specific to your application, without having to bother the module maintainers.
Learn how to create a new plugin manager, and define your own plugin type.
The Plugin API
The plugin system consists of four major components:
Plugin Types: Plugins that perform similar functionality are of the same plugin type. All blocks, for example, are plugins of the block plugin type. When creating a plugin the interface it will implement, the mechanisms used for discovery and instantiation, and how the plugin is used by the application are all relative to the plugin type. Read more about plugin types.
Plugin Discovery: The process of locating the definition of, and meta-data for, all plugins of a given type. When creating a new plugin type you'll need to define the discovery mechanism. When implementing a plugin you'll need to know which discovery mechanism it's using so you know how to ensure your plugin can be discovered. Learn more about plugin discovery.
Plugin Factory: Responsible for instantiating a specific plugin(s) and returning a usable instance to the code making use of the provided functionality. You'll need to know about plugin factories when defining a new plugin type, and it's helpful to understand how they work but not essential when implementing a plugin. Learn more about plugin instantiation.
Plugins: Individual units of functionality that adhere to a specific plugin type definition. For example, each block available on your site is representative of an individual block plugin. If you want to add new functionality to an existing tool you probably want to implement a new plugin. Learn more about implementing plugins of any type.
There are several things a module developer may need to do with plugins:
- Define a completely new plugin type
- Create a plugin of an existing plugin type
- Use a plugin manager service to perform tasks that involve plugins, like for example instantiating an instance of a specific plugin.
Further your understanding
- Many different parts of Drupal core use plugins to allow module developers to add new functionality. Can you name a few of them?
- Describe an example in which you're developing a new module and it makes sense for you to define a new plugin type.
- Learn about events, another method of extending Drupal