0

I have a View listing pending node revisions (using Revisioning). I have several actions, like changing the node author, which are executed using Views Bulk Operations. Executing, for example, the "Change author" action should update the author, but keep the revision in pending state. However, the revision gets published, and becomes the new, current revision.

Anyone else run into this issue? I've been digging around both VBO and Revisionings source code, but I cannot find out which one is to "blame". VBO is correctly loading the pending revision, and executing the action on it. Revisioning's node hooks are correctly invoked as well. Auto-publishing is disabled, and Revisioning does not get into that code flow (I put tracer code in there to make sure it doesn't). So this leads me to think VBO or Entity are at fault, but I can't put my finger on it.

1 Answer 1

0

So, I found out where the issue is coming from.

Basically, Revisioning works as follows:

  1. A node gets saved by Drupal. Drupal doesn't care much about the status. If the node is published, it remains published. It is important to realize that, when using Revisioning, if a node has a published revision, for Drupal the node has a status of 1, regardless of the pending, unpublished revision. Upon saving, Drupal simply stores a new revision, and updates the node database row, pointing the revision ID to this new revision.
  2. Revisioning kicks in, with revisioning_node_update(). It checks the revision_operation property. Based on its value, it "reverts" what Drupal just did, setting the revision ID in the node table back to the previous revision. This is what keeps the published revision one step behind the pending revision.

Now, this revision_operation property is only set when in context of a node form. When using VBO (or any way to trigger actions, for that matter), Revisioning doesn't see the revision_operation property, and revisioning_node_update() doesn't revert the revision ID.

We could patch this in Revisioning, but the project hasn't received much attention lately (for the D7 version). So this is how I solved it (I have several actions, but I'll give the example of the node_assign_owner_action action):

/**
 * Implements hook_action_info().
 */
function mymodule_action_info() {
  return array(
    'mymodule_assign_to_user_action' => array(
      'type' => 'node',
      'label' => t("Assign to user (Revisioning compatible)"),
      'configurable' => TRUE,
      'behavior' => array('changes_property'),
      'triggers' => array('node_presave'),
    ),
  );
}

/**
 * Assign a node to a user.
 *
 * We need a custom action for this, as actions are not entirely compatible with
 * Revisioning. We need to tweak the node a bit to force a pending revision to
 * stay that way. node_assign_owner_action() does not allow this. See
 * _mymodule_actions_reset_revision_operation() for an explanation on why we
 * need this.
 *
 * @see node_assign_owner_action()
 * @see node_action_info()
 */
function mymodule_assign_to_user_action($node, $context = array()) {
  // Simply proxy to node_assign_owner_action().
  node_assign_owner_action($node, $context);

  // Make sure the revision_operation property is correctly set.
  _mymodule_actions_reset_revision_operation($node);
}

/**
 * Configuration form for mymodule_assign_to_user_action().
 *
 * @see mymodule_assign_to_user_action()
 * @see node_assign_owner_action_form()
 */
function mymodule_assign_to_user_action_form($context = array()) {
  return node_assign_owner_action_form($context);
}

/**
 * Validation callback for mymodule_assign_to_user_action_form().
 *
 * @see mymodule_assign_to_user_action()
 * @see node_assign_owner_action_validate()
 */
function mymodule_assign_to_user_action_validate($form, $form_state) {
  node_assign_owner_action_validate($form, $form_state);
}

/**
 * Submission callback for mymodule_assign_to_user_action_form().
 *
 * @see mymodule_assign_to_user_action()
 * @see node_assign_owner_action_submit()
 */
function mymodule_assign_to_user_action_submit($form, $form_state) {
  return node_assign_owner_action_submit($form, $form_state);
}

/**
 * Set the correct node revision_operation property.
 *
 * @param object $node
 *    The node on which the action is performed.
 */
function _mymodule_actions_reset_revision_operation($node) {
  module_load_include('inc', 'revisioning', 'revisioning_api');

  $is_moderated_content = isset($node->revision_moderation) ?
    $node->revision_moderation :
    revisioning_content_is_moderated($node->type, $node);

  $node->revision_operation = (int) $node->is_pending + (int) $is_moderated_content;
}

Thanks to this, we can still use actions provided by core or other modules, but we need to wrap them in another, Revisioning compatible action. When calling _mymodule_actions_reset_revision_operation(), we use the same logic as Revisioning is using when altering the node form.

It now works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.