Last updated June 5, 2012. Created by fago on August 16, 2010.
Edited by wizonesolutions, hansfn, mitchell, Paul Simard. Log in to edit this page.

Modules may add further events, for which actions and conditions may be configured by either the UI or modules.

To do so, you need to implement hook_rules_event_info(). You may put the implementation in your module's MODULE.rules.inc file.

Consider the events provided for the comment module as example:

<?php
/**
* Implements hook_rules_event_info().
*/
function comment_rules_event_info() {
 
$defaults = array(
   
'group' => t('comment'),
   
'module' => 'comment',
   
'access callback' => 'rules_comment_integration_access',
  );
  return array(
   
'comment_insert' => $defaults + array(
     
'label' => t('After saving a new comment'),
     
'variables' => array(
       
'comment' => array('type' => 'comment', 'label' => t('created comment')),
      ),
    ),
   
'comment_update' => $defaults + array(
     
'label' => t('After updating an existing comment'),
     
'variables' => array(
       
'comment' => array('type' => 'comment', 'label' => t('updated comment')),
      ),
    ),
   
'comment_presave' => $defaults + array(
     
'label' => t('Before saving a comment'),
     
'variables' => array(
       
'comment' => array('type' => 'comment', 'label' => t('saved comment'), 'skip save' => TRUE),
       
'comment_unchanged' => array('type' => 'comment', 'label' => t('unchanged comment'), 'handler' => 'rules_events_entity_unchanged'),
      ),
    ),
   
'comment_view' => $defaults + array(
     
'label' => t('A comment is viewed'),
     
'variables' => array(
       
'comment' => array('type' => 'comment', 'label' => t('viewed comment')),
      ),
     
'help' => t("Note that if drupal's page cache is enabled, this event won't be generated for pages served from cache."),
    ),
   
'comment_delete' => $defaults + array(
     
'label' => t('After deleting a comment'),
     
'variables' => array(
       
'comment' => array('type' => 'comment', 'label' => t('deleted comment')),
      ),
    ),
  );
}
?>

As seen, you have to describe the variables you provide for the event. When invoking the event, you have to pass the variables. For the comment module, the event invocations look like this:

<?php
function rules_comment_view($comment) {
 
rules_invoke_event('comment_view', $comment);
}
function
rules_comment_presave($comment) {
 
rules_invoke_event('comment_presave', $comment);
}
function
rules_comment_update($comment) {
 
rules_invoke_event('comment_update', $comment);
}
function
rules_comment_insert($comment) {
 
rules_invoke_event('comment_insert', $comment);
}
function
rules_comment_delete($comment) {
 
rules_invoke_event('comment_delete', $comment);
}
?>

Usually one also provides a hook for modules - in that case first invoke the hook, then the rules event.

Note that you may also pass an array of variable values, with the variable names as keys. This is done by the rules_invoke_event_by_args function. Example:

<?php
function rules_comment_delete($comment) {
 
rules_invoke_event_by_args('comment_delete', array('comment' => $comment));
}
?>

Lazy-loading entites / variables

If you want to pass an entity, you may pass an EntityMetadataWrapper object to Rules. In case you do so, Rules uses the passed wrapper instead of creating its own. Passing the wrapper has the benefit, that you may create it with the entity type + id only, thus the entity is lazy loaded on demand.

E.g.:

<?php
// Create a wrapper and pass it to Rules.
$comment = entity_metadata_wrapper('comment', $comment_id);
rules_invoke_event('comment_delete', $comment);
?>

Rules also supports lazy-loading variables via a specified handler. For that specify a callback for lazy-loading the variable using the 'handler' key and implement it like this:

<?php
function rules_events_variable_foo_load($arguments, $variable_name, $variable_info) {
 
// Arguments is the array of variables already passed to the event.
 
return $variable;
}
?>

Providing unchanged entities

Rules provides the handler rules_events_entity_unchanged which may be used for providing variables for the unchanged version of an entity that is changed. For using it, just specify the variable for the unchanged entity using the handler and make sure its name matches the name of the updated entity but has '_unchanged' appended. Thus 'comment' would be the updated entity, 'comment_unchanged' the unchanged. Rules implements the logic for keeping track of unchanged entities, such that the handler works for all entities automatically. But note that this handler only works properly if the updated entity has not been saved yet *or* the entity has been loaded with entity_load() before it is saved. Thus in the case the updated entity has been already saved (hook_entity_update/insert) and a module serializes an entity and saves it afterwards on another page load, the handler would fail.

Passing variables by reference

Passing variables by reference is not supported by Rules 2.x - however with PHP 5 this does not matter much for objects. In case you want to allow modifications of an array structure, you need to wrap it manually before passing to rules - use the EntityMetadataArrayObject for that.

Changing variables itself (e.g. changing the the whole object) is not supported for reaction rules / events, but is possible for components. Thus if you need a way for users to alter or even provide a specific variable, consider using a component (e.g. a rule set) for that.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

To anyone wondering how to trigger the event:
There is no callback or anything of the sort, the event is triggered wherever you call rules_invoke_event()

If you for instance defined an event you want triggered on every pageview, implement hook_rules_event_info() as described using 'every_damn_pageview' as the array-key for your event and then do

<?php
 
function MYMODULE_init(){
   
rules_invoke_event('every_damn_pageview');
  }
?>

This may be better:

<?php
 
function MYMODULE_init(){
   
module_invoke('rules', 'invoke_event', 'every_damn_pageview');
  }
?>

Doing it this way you do not need to check if Rules is enabled, thus you do not risk to break your site if the module is disabled.

Of course, this advice is valid if your module is a general one, which should work with or without Rules. If you can control the environment around (e.g. "rules" is listed in your module dependencies), then you'd better to invoke Rules directly, as pointed by phryk.

Flávio