Event-driven bulk updates using VBO and Rules

Here's the situation: when a change occurs on a node, you want to modify a bunch of related nodes accordingly. On my site, when a Job's state moves from "accepting proposals" to "in progress", I want to change all pending Job Offers (those that haven't been accepted yet) to "closed". Here's how to do it without coding, using VBO and Rules (and Workflow in this example):

  • Ensure that you have an action that performs your needed function: in my example, I create an advanced action out of "Change workflow state of post to new state" with the proper "closed" Job Offer state as parameter.
  • Create a new VBO where the only available action is the one created above. This view will return Job Offer nodes that relate to a given Job node, so I configure the view argument to accept the Job node, and filter the view by Job Offer nodes that have the "open" workflow state. Test the view by previewing it with a Job argument, then save it.
  • Create a new rule on event "Workflow state has changed", with the condition "Check workflow transition" from "accepting proposals" state to "in progress".
  • To this rule, add the action "Execute a VBO programmatically on node". Select the view you created above, then the sole operation in that view, and enter the following code in the "View arguments" that corresponds to the argument that your view expects:
return array($object->nid);
  • Assuming the operation you need takes arguments, you have 3 options:
    • Pre-create an action with filled-in argument values. To do so, go to admin/settings/actions/manage and locate your desired action in the drop-down "Make a new advanced action available". Click "Create" and fill in the arguments form, then give this action a new name and save it. Next time you visit the VBO settings page, you will be able to find and select this new action.
    • When you select an operation, the page is refreshed to show the action's argument form. You can fill your argument values right there.
    • If the argument values depend on the actual parent node, then you need to fill in these arguments in the "Operation arguments" field using PHP code. This requires that you know the names of the arguments used by this action. To find the argument names, you need to manually inspect the action_submit($form, $form_state) function for the chosen action and note each entry in the return array. For example, the action "Change the author of a post" (node_assign_owner_action) is located in node.module. The function node_assign_owner_action_submit looks like this:
<?php
// @file node.module

function node_assign_owner_action_submit($form, $form_state) {
 
// Username can change, so we need to store the ID, not the username.
 
$uid = db_result(db_query("SELECT uid from {users} WHERE name = '%s'", $form_state['values']['owner_name']));
  return array(
'owner_uid' => $uid);
}
?>

The sole argument for this action is therefore owner_uid which expects a uid value.

Conclusion

As you see, creating such functionality through configuration is not significantly simpler than coding it. And there's no reason why it should be, really: we're just substituting one form of programming (through code) with another (through configuration). The underlying function is as complex.

NOTE: At the time of writing, you will need a dev release of VBO to use this functionality. It will be generally available as of VBO-6.x-1.10.

Comments

The latest beta version of VBO 1.10 features a simpler way to specify operation arguments for "Execute a VBO programmatically on node". The form has been enhanced to display the chosen operation's form via AJAX, so you can just specify the arguments right there. The PHP script area is still there if you have more complex requirements.

Overall the above is clear and this idea is really simple. (powerful!) But I keep getting this error.

rules_core_action_execute() expected to be a reference

It is a simple VBO that searches for unpublished nodes and choosed the one canned option to delete them. Then when I run this via rules/cron it gives that error in the logs file.

Please post your issue to the VBO issue queue. We'll be better able to track it and solve it there. Thanks!

it worked out, I just was not passing the argument correctly. I made a function to output the args and ran drush at the command line and it all worked out. Thanks though for your post.

I've updated the post with a discussion on operation arguments, following a new support request in VBO's issue queue.

I understood the example up until the last bit where you add the return array command. What does that do and why is it needed? If we're performing a different action do we use a different return command? etc.

Remember how the view that we created takes a node ID as argument? When we execute that VBO programmatically, we still need to pass that argument to the view, because otherwise the view might return all nodes - and you've just messed up your database badly :-) So this return array is an array of arguments that will be passed to the view. It should contain as many elements as there are arguments in your view.