Action plugins for bulk operations
In this article we are going to describe how to make a bulk action plugin in Drupal 8/9. What do we understand by bulk operation? Well, that operation or event that acts on a certain number of nodes or content entities to perform a specific action, that is, if we want to modify 400 nodes we can do it at once and not having to edit one by one each node in its respective editing form. Surely you have come across them in the admin/content view, they are these:
'Delete content' is a massive operation that will delete from the Drupal site all the nodes that are checked in the checkbox. But, what happens if we have a series of entities with their own particularities and we want to modify values that are not defined in these default actions provided by Drupal?
In this case, we must define our own action plugins.
Let's suppose we have a content type that has a 'Status' field, and we are interested in modifying that field from a large list of nodes, so that we can update that value at once in all of them.
Definition of an Action Plugin:
To create this type of plugin, we will need to define it in:
- Config schema
- Config install
- A custom plugin class
Plugin definition in config/install:
We must generate the file 'system.action.test_action.yml' in the 'config/install' folder of our custom module. The line ‘id: test_action’ is the name of the id of the new plugin we are going to create.
langcode: es
status: true
dependencies:
module:
- node
id: test_action
label: 'Aprobar estado'
type: node
plugin: test_action
configuration: { }
Be careful when generating this file, as its name tends to cause confusion. You should not use the name of the custom module at the beginning, but as mentioned before: system.action.[module_name].
In the Id field we place the same id that we are going to use later in the schema file and in the class definition.
For this example the 'type' parameter is 'node', but for users or taxonomies this value changes, for example a plugin action to massively change users would be type: 'user'.
The label of this field is what will be displayed when we visit /admin/content and click on the 'Action' select.
Plugin definition in config/schema:
Now we must define a new .yml file in the 'config/schema' location of our custom module, like this:
action.configuration.test_action:
type: test_action
label: 'Aprueba el nodo de forma masiva'
The name of this file in our example is test_action.schema.yml. And in type we have used the same Id as in the file 'system.action.test_action.yml'.
With this we have already created the relative files for Drupal to register the new action plugin. Now let's go to the class where its methods define what we are going to do with those nodes, or better said, how we are going to operate with them.
Action Plugin class definition:
Inside our custom module we are going to define in the folder /src/Plugin/Action the new plugin that will extend the ActionBase class. In this example, we will name it ActionTest.php.
We add the namespace, import the classes and interfaces we need, and add in the Annotation the id we registered before:
- Id: test_action
- Label: A description of our plugin.
- Type: the entity on which it operates, in our case "node".
The ActionBase class comes with two methods:
- access: This will allow us to control the access of the user in question in order to reject or allow the action to be taken.
- execute: Method where we can define the action we want to perform on each selected node, in our case we check that it has the field_status defined and we change its value.
<?php
namespace Drupal\test_action\Plugin\Action;
/**
* Action description.
*
* @Action(
* id = "test_action",
* label = @Translation("Test action"),
* type = "node"
* )
*/
class ActionTest extends ActionBase {
use StringTranslationTrait;
/**
* {@inheritdoc}
*/
public function execute($entity = NULL) {
if ($entity->hasField('field_estado')) {
$entity->set('field_estado', '1');
$entity->save();
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
if ($object->getEntityType()->id() === 'node' && $account->hasPermission('access_test')) {
$access = $object->access('update', $account, TRUE)
->andIf($object->status->access('edit', $account, TRUE));
return $return_as_object ? $access : $access->isAllowed();
}
return TRUE;
}
}
Once implemented, the action will be displayed in the /admin/content view.
And as a result of executing the bulk operation:
We can also place it in a view, adding the field 'bulk operations form':
This field can be added as a field in any view we have on nodes and we can also execute mass actions on them.