7 system.api.php hook_action_info()
6 core.php hook_action_info()

Declares information about actions.

Any module can define actions, and then call actions_do() to make those actions happen in response to events. The trigger module provides a user interface for associating actions with module-defined triggers, and it makes sure the core triggers fire off actions when their events happen.

An action consists of two or three parts:

  • an action definition (returned by this hook)
  • a function which performs the action (which by convention is named MODULE_description-of-function_action)
  • an optional form definition function that defines a configuration form (which has the name of the action function with '_form' appended to it.)

The action function takes two to four arguments, which come from the input arguments to actions_do().

Return value

An associative array of action descriptions. The keys of the array are the names of the action functions, and each corresponding value is an associative array with the following key-value pairs:

  • 'type': The type of object this action acts upon. Core actions have types 'node', 'user', 'comment', and 'system'.
  • 'label': The human-readable name of the action, which should be passed through the t() function for translation.
  • 'configurable': If FALSE, then the action doesn't require any extra configuration. If TRUE, then your module must define a form function with the same name as the action function with '_form' appended (e.g., the form for 'node_assign_owner_action' is 'node_assign_owner_action_form'.) This function takes $context as its only parameter, and is paired with the usual _submit function, and possibly a _validate function.
  • 'triggers': An array of the events (that is, hooks) that can trigger this action. For example: array('node_insert', 'user_update'). You can also declare support for any trigger by returning array('any') for this value.
  • 'behavior': (optional) A machine-readable array of behaviors of this action, used to signal additionally required actions that may need to be triggered. Currently recognized behaviors by Trigger module:

    • 'changes_property': If an action with this behavior is assigned to a trigger other than a "presave" hook, any save actions also assigned to this trigger are moved later in the list. If no save action is present, one will be added. Modules that are processing actions (like Trigger module) should take special care for the "presave" hook, in which case a dependent "save" action should NOT be invoked.

Related topics

6 functions implement hook_action_info()

Note: this list is generated by pattern matching, so it may include some functions that are not actually implementations of this hook.

actions_loop_test_action_info in modules/simpletest/tests/actions_loop_test.module
Implements hook_action_info().
comment_action_info in modules/comment/comment.module
Implements hook_action_info().
node_action_info in modules/node/node.module
Implements hook_action_info().
system_action_info in modules/system/system.module
Implements hook_action_info().
trigger_test_action_info in modules/trigger/tests/trigger_test.module
Implements hook_action_info().

... See full list

1 invocation of hook_action_info()
actions_list in includes/actions.inc
Discovers all available actions by invoking hook_action_info().


modules/system/system.api.php, line 3985
Hooks provided by Drupal core and the System module.


function hook_action_info() {
  return array(
    'comment_unpublish_action' => array(
      'type' => 'comment',
      'label' => t('Unpublish comment'),
      'configurable' => FALSE,
      'behavior' => array('changes_property'),
      'triggers' => array('comment_presave', 'comment_insert', 'comment_update'),
    'comment_unpublish_by_keyword_action' => array(
      'type' => 'comment',
      'label' => t('Unpublish comment containing keyword(s)'),
      'configurable' => TRUE,
      'behavior' => array('changes_property'),
      'triggers' => array('comment_presave', 'comment_insert', 'comment_update'),
    'comment_save_action' => array(
      'type' => 'comment',
      'label' => t('Save comment'),
      'configurable' => FALSE,
      'triggers' => array('comment_insert', 'comment_update'),


I used this hook in Drupal 7 to create a custom action, after added I cannot see the option in the operation' selector.
Each new action generate a new permission, the administrator has to define which roles has access to the new operation, without this even if the action is added in mass action, will not be able for users.
And setup the permission to my new actions, and voila! It's working right now!

I don't see the generated permissions... how are they named?

When I created my custom action called "Add servers", then I went to permission page (admin/people/permissions)
under category "Actions permissions (VBO)" and I found the new permission called "Execute Add servers", this permission was generated automatically.

It means the new action will have a permission with the same name of your action, with a prefix "Execute ".

Thank you, I hadn't Actions permissions (VBO) module enabled first, then I had to configure my view of users to activate the display of the newly created action in the mass operation field.

The behaviour section could use more clarifications. This attribute defines what access permissions are required for users to be able to run this action. This may not be entirely clear, as there are cases where an access failure results in a no-notification action failure.

Under common implementations you will find the following connections:
'views_property' => view access for the entity
'changes_property' => update access for the entity
'creates_property' => create access for the entity type
'deletes_property' => delete access for the entity

The vbo operations are run past this access check method:

function _views_bulk_operations_entity_access($operation, $entity_type, $entity, $account = NULL) {
  $access_ops = array(
    VBO_ACCESS_OP_VIEW => 'view',
    VBO_ACCESS_OP_UPDATE => 'update',
    VBO_ACCESS_OP_CREATE => 'create',
    VBO_ACCESS_OP_DELETE => 'delete',

The base vbo module defines the following permissions:

define('VBO_ACCESS_OP_VIEW',      0x01);
define('VBO_ACCESS_OP_UPDATE',    0x02);
define('VBO_ACCESS_OP_CREATE',    0x04);
define('VBO_ACCESS_OP_DELETE',    0x08);

The situation can be clarified by examining the VBO action class, in either the base class or the child action class.

If you examine the plugins/operations_types/base.plugin.php file in the ViewsBulkOperationsBaseOperation class you will see that the getAccessMask method defines that the only permission requires is VBO_ACCESS_OP_UPDATE

If you exam the action.class.php include, in the ViewsBulkOperationsAction class, you will find the method getAccessMask(), which connects these behaviours to entity_access permissions you see a more complex relationship of:

    if (in_array('views_property', $this->operationInfo['behavior'])) {
      $mask |= VBO_ACCESS_OP_VIEW;
    if (in_array('changes_property', $this->operationInfo['behavior'])) {
      $mask |= VBO_ACCESS_OP_UPDATE;
    if (in_array('creates_property', $this->operationInfo['behavior'])) {
      $mask |= VBO_ACCESS_OP_CREATE;
    if (in_array('deletes_property', $this->operationInfo['behavior'])) {
      $mask |= VBO_ACCESS_OP_DELETE;

Set configurable to TRUE in your info hook and define the following functions.

function my_action_form($context);
function my_action_validate($form, &$form_state);   // Optional validator.
function my_action_submit($form, &$form_state);

Whatever the return value of my_action_submit() is will be appended to the $context array and accessible in your action callback. For example you could return the form values like:

return array('form_values' => $form_state['values']);

Then you can access $context['form_values'] in your action callback.