You are here

workflow_extensions.module in Workflow Extensions 7

Same filename and directory in other branches
  1. 6 workflow_extensions.module

UI-related improvements to the Workflow module and tokens for Rules.

1a) Replaces the traditional workflow radio-buttons by either a drop-down or single-action buttons featuring context-sensitive labels (using replacement tokens) for a more intuitive user experience. See also the discussion on intelligent buttons at drupal.org/node/282122. All three UI styles (radio, drop-down or single-action) are available as a block. 1b) Suppresses the workflow schedule transition form if not selected by the user. 2) The module also defines tokens which when used with Rules allow you to more easily invoke actions when something did NOT happen for some time.

Re 1a) Let's say we have a basic workflow with states "draft", "review" and "live". Traditionally authors and moderators must select the next state by pressing the correct radio-button and clicking submit. Experience from the field suggests that not everybody finds this intuitive. Rather than having to think in terms of state transitions, users prefer to press a button with a an explanatory label that clearly expresses what is going to happen. Using this module authors will find on the edit form a couple of clearly labeled buttons: "Save as draft, don't submit" and "Submit for publication". In old workflow-speak the latter action is represented by radio buttons plus a submit button and read less intuitively as: transition workflow state from "draft" to "review". Similarly, with this module a moderator will see on their edit form buttons like "Reject and return to author John" (i.e. "review -> draft") and "Publish this" ("review -> live"). The alternative buttons appear on: a) the node edit form (node/%/edit) b) the comment edit form, if enabled c) the workflow tab, if enabled (node/%/workflow)

Re 2) This module defines a replacement token [node:workflow-state-age], which when used in a scheduled rule set, make it easier to invoke actions when a workflow state was NOT changed after a specified elapsed time. See drupal.org/project/workflow_extensions for full instructions on how to do this using Rules.

File

workflow_extensions.module
View source
<?php

/**
 *  @file
 *  UI-related improvements to the Workflow module and tokens for Rules.
 *
 *  1a) Replaces the traditional workflow radio-buttons by either a drop-down or
 *  single-action buttons featuring context-sensitive labels (using replacement
 *  tokens) for a more intuitive user experience.
 *  See also the discussion on intelligent buttons at drupal.org/node/282122.
 *  All three UI styles (radio, drop-down or single-action) are available as a
 *  block.
 *  1b) Suppresses the workflow schedule transition form if not selected by the
 *  user.
 *  2) The module also defines tokens which when used with Rules allow you to
 *  more easily invoke actions when something did NOT happen for some time.
 *
 *  Re 1a)
 *  Let's say we have a basic workflow with states "draft", "review" and "live".
 *  Traditionally authors and moderators must select the next state by pressing
 *  the correct radio-button and clicking submit. Experience from the field
 *  suggests that not everybody finds this intuitive. Rather than having to
 *  think in terms of state transitions, users prefer to press a button with a
 *  an explanatory label that clearly expresses what is going to happen.
 *  Using this module authors will find on the edit form a couple of clearly
 *  labeled buttons: "Save as draft, don't submit" and "Submit for publication".
 *  In old workflow-speak the latter action is represented by radio buttons plus
 *  a submit button and read less intuitively as: transition workflow state
 *  from "draft" to "review".
 *  Similarly, with this module a moderator will see on their edit form buttons
 *  like "Reject and return to author John" (i.e. "review -> draft") and
 *  "Publish this" ("review -> live").
 *  The alternative buttons appear on:
 *  a) the node edit form (node/%/edit)
 *  b) the comment edit form, if enabled
 *  c) the workflow tab, if enabled (node/%/workflow)
 *
 *  Re 2)
 *  This module defines a replacement token [node:workflow-state-age], which
 *  when used in a scheduled rule set, make it easier to invoke actions when
 *  a workflow state was NOT changed after a specified elapsed time.
 *  See drupal.org/project/workflow_extensions for full instructions on
 *  how to do this using Rules.
 */
define('WORKFLOW_EXTENSIONS_UI_RADIOS', 1);

// the original Workflow style
define('WORKFLOW_EXTENSIONS_UI_BUTTONS', 2);

// single-action buttons
define('WORKFLOW_EXTENSIONS_UI_DROPDOWN', 3);

// dropdown selector + update

/**
 * Implements hook_permission().
 */
function workflow_extensions_permission() {
  return array(
    'change workflow state via node edit form' => array(
      'title' => t('change workflow state via node edit form'),
      'description' => t(''),
    ),
    'edit workflow log' => array(
      'title' => t('edit workflow log'),
      'description' => t(''),
    ),
    'view workflow state change block even when state cannot be changed' => array(
      'title' => t('view workflow state change block even when state cannot be changed'),
      'description' => t(''),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function workflow_extensions_menu() {
  $items = array();
  $items['workflow-log/%workflow_state_transition_record'] = array(
    // maps to function workflow_state_transition_record_load()
    'title' => 'Edit workflow log comment',
    'description' => 'Edit workflow state transition comment.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'workflow_extensions_workflow_comment_edit_form',
      1,
    ),
    'access arguments' => array(
      'edit workflow log',
    ),
  );
  $items['admin/config/workflow/workflow_extensions'] = array(
    'title' => 'Workflow extensions',
    'description' => 'Configure workflow form style (buttons and labels).',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'workflow_extensions_admin_configure',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'file' => 'workflow_extensions.admin.inc',
  );
  return $items;
}

/**
 * Load function belonging to the above menu option 'workflow-log/%workflow-state-transition-record'.
 * Maps to this function just like 'node/%node' maps to node_load().
 *
 * @param $hid
 *   The ID of the workflow state transition record to load.
 * @return
 *   object representing one row from the {workflow_node_history} table
 */
function workflow_state_transition_record_load($hid) {
  $result = db_query('SELECT * FROM {workflow_node_history} WHERE hid = :hid', array(
    ':hid' => $hid,
  ));
  $workflow_state_transition_record = $result
    ->fetchObject();
  return $workflow_state_transition_record;
}

/**
 * Display a text area populated with the selected workflow log comment and
 * allow the user to modify and save it.
 */
function workflow_extensions_workflow_comment_edit_form($form, $form_state, $workflow_state_transition_record) {
  $form = array();
  $form['hid'] = array(
    '#type' => 'value',
    '#value' => $workflow_state_transition_record->hid,
  );
  $form['nid'] = array(
    '#type' => 'value',
    '#value' => $workflow_state_transition_record->nid,
  );
  $form['workflow']['workflow_comment'] = array(
    '#type' => 'textarea',
    '#title' => t('Comment'),
    '#description' => t('Modify this workflow state transition comment and press submit.'),
    '#default_value' => $workflow_state_transition_record->comment,
    '#rows' => 2,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}

/**
 * Submit handler for the workflow transition comment edit form.
 *
 * @see workflow_extensions_workflow_comment_edit_form()
 */
function workflow_extensions_workflow_comment_edit_form_submit($form, &$form_state) {
  $hid = $form_state['values']['hid'];
  $comment = $form_state['values']['workflow_comment'];

  /* db_query("UPDATE {workflow_node_history} SET comment = '%s' WHERE hid = %d", $comment, $hid) */
  db_update('workflow_node_history')
    ->fields(array(
    'comment' => $comment,
  ))
    ->condition('hid', $hid)
    ->execute();
  $nid = $form_state['values']['nid'];

  // Whatever is set here, is overriden by the "?destination=..." parameter, if present
  $form_state['redirect'] = module_exists('views') && views_get_view('workflow_history') ? "workflow-history/{$nid}" : (workflow_node_tab_access(node_load($nid)) ? "node/{$nid}/workflow" : "node/{$nid}");
}

/**
 * Implements hook_form_alter().
 *
 * 1) Remove the Workflow radio buttons and replace each state transition by a
 * submit button with a configurable, explanatory label.
 * To allow saving of edits to the node without a state transition, display
 * an additional button "Save, don't submit" (or similar).
 * 2) If on the create/edit form suppress the workflow fieldset if the user
 * does not have the relevant permission
 * 3) If the schedule state transition form is enabled, suppress it until the
 * user clicks the radio button to reveal it.
 * 4) Add an (extra) form validator
 */
function workflow_extensions_form_alter(&$form, &$form_state, $form_id) {

  // If there's no Workflow fieldset, then we have nothing further to do.
  if (!isset($form['#wf'])) {

    // was $form['workflow'] but need to exclude content type edit form
    return;
  }

  // 4) Add form validator
  if (empty($form['#validate'])) {
    $form['#validate'] = array();
  }
  elseif (!is_array($form['#validate'])) {
    $form['#validate'] = array(
      $form['#validate'],
    );
  }
  $form['#validate'][] = 'workflow_extensions_workflow_form_validate';
  if (isset($form['workflow']['workflow_comment']) && !variable_get('workflow_extensions_allow_blank_comments', TRUE)) {
    $form['workflow']['workflow_comment']['#required'] = TRUE;
  }

  // 2) Suppress Workflow fieldset on the create/edit form if not permitted.
  if (isset($form['#node_edit_form']) && !user_access('change workflow state via node edit form')) {
    unset($form['workflow']);
    return;
  }

  // The next if-statement implements point 3) above
  if (variable_get('workflow_extensions_display_schedule_toggle', TRUE)) {
    $path = drupal_get_path('module', 'workflow_extensions');
    drupal_add_js($path . '/workflow_schedule.js');
  }

  // The rest of this function implements point 1)
  $workflow_name = workflow_extensions_extract_workflow_name($form);
  $workflow_radios = $form['workflow'][$workflow_name];
  if (is_array($workflow_radios) && isset($workflow_radios['#options'])) {

    // Use the form to work out the potential state transitions for this user.
    $states = $workflow_radios['#options'];

    // $states will be empty when creating node
    if (!empty($states)) {
      $title = variable_get('workflow_extensions_change_state_form_title', '');
      if (!empty($title)) {
        if (trim($title) == '<none>') {
          $form['workflow'][$workflow_name]['#title'] = '';
        }
        else {
          $form['workflow'][$workflow_name]['#title'] = workflow_extensions_replace_tokens_raw($title);
        }
      }
      if (empty($form['#submit'])) {
        @(include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'workflow') . '/workflow.pages.inc');
        $form['#submit'] = array(
          'workflow_extensions_form_submit',
          'workflow_tab_form_submit',
        );
      }
      switch (variable_get('workflow_extensions_ui_style', WORKFLOW_EXTENSIONS_UI_BUTTONS)) {
        case WORKFLOW_EXTENSIONS_UI_BUTTONS:
          if (count($states) > 1) {
            _workflow_extensions_replace_with_buttons($form, $workflow_name);
          }
          break;
        case WORKFLOW_EXTENSIONS_UI_DROPDOWN:
          _workflow_extensions_replace_with_dropdown($form, $workflow_name);

        // no break;
        default:

          // dropdown and radios
          $form['#submit'][] = 'workflow_extensions_form_redirect';
          if (isset($form['submit'])) {
            $submit_label = variable_get('workflow_extensions_change_state_button_label', '');
            if (!empty($submit_label)) {
              $form['submit']['#value'] = workflow_extensions_replace_tokens_raw($submit_label);
            }
          }
          break;
      }
    }
  }
}

/**
 * Implements hook_forms().
 *
 * Called as a result of the fact that there are no form handlers for the
 * unique form_id's generated in workflow_extensions_change_state_form().
 * Here we map these form_id's back to the same 'workflow_tab_form'. This
 * allows us to have multiple copies of the same form on the same page.
 * Note: first of the args is typically the node object.
 */
function workflow_extensions_forms($form_id, $args) {
  if (function_exists('workflow_forms')) {
    return array();
  }
  if (strpos($form_id, 'workflow_tab_form_nid') === 0) {
    $form = array(
      $form_id => array(
        'callback' => 'workflow_tab_form',
        'callback arguments' => array(),
      ),
    );
    return $form;
  }
}

/**
 * Validate the workflow form, in particular the state transition comment and
 * the scheduled state transition time (the date is a drop-down so requires no
 * validation).
 */
function workflow_extensions_workflow_form_validate($form, &$form_state) {
  $nid = substr($form['#id'], strrpos($form['#id'], '-') + 1);
  $title = isset($form_state['values']['title']) ? $form_state['values']['title'] : (isset($form_state['values']['node']) ? $form_state['values']['node']->title : t('Content form'));
  if (!empty($form_state['values']['workflow_scheduled_hour'])) {
    if (!strtotime($form_state['values']['workflow_scheduled_hour'])) {
      form_set_error(is_numeric($nid) ? "workflow_scheduled_hour_{$nid}" : 'workflow_scheduled_hour', t('%title: scheduled time is not in the correct format.', array(
        '%title' => $title,
      )));
    }
  }
  if (!variable_get('workflow_extensions_allow_blank_comments', TRUE)) {
    if (!isset($form_state['values']['nid']) && !isset($form_state['values']['node'])) {

      // Bypass node creation
      return;
    }
    $comment = $form_state['values']['workflow_comment'];
    if (!trim($comment)) {
      form_set_error(is_numeric($nid) ? "workflow_comment_{$nid}" : 'workflow_comment', t('%title: please enter a non-blank comment for the workflow log.', array(
        '%title' => $title,
      )));
    }
  }
}

/**
 * Handler for the edit form.
 */
function workflow_extensions_form_submit($form, &$form_state) {

  // In the original form_submit handler that we pass control to next, the
  // selected workflow state is taken from form_state['values']['workflow']. So
  // that's the entry we need to set here in accordance with the clicked button.
  // See workflow_tab_form_submit() for the Workflow tab.
  if (isset($form_state['clicked_button']['#to_state'])) {
    $form_state['values']['workflow'] = $form_state['clicked_button']['#to_state'];
  }

  // workflow_tab_form_submit() requires the node to be present on $form_state.
  if (isset($form['#node'])) {
    $form_state['values']['node'] = $form['#node'];
  }

  // [#1786346]
  form_load_include($form_state, 'inc', 'workflow', 'workflow.pages');
}

/**
 * If the workflow state was NOT transitioned via the node View, Edit or
 * Workflow tabs, then redirect to the original page.
 * @todo: make this configurabele
 */
function workflow_extensions_form_redirect($form, &$form_state) {
  if (arg(0) != 'node') {
    $path = variable_get('workflow_extensions_redirect_page', '');

    // @todo: make this a UI config option
    $form_state['redirect'] = empty($path) ? $_GET['q'] : $path;

    // @todo: save query-string too (Views pager)
  }
}
function _workflow_extensions_replace_with_buttons(&$form, $workflow_name) {
  $current_sid = $form['workflow'][$workflow_name]['#default_value'];
  $current_state_name = workflow_get_workflow_states_by_sid($current_sid)->state;

  // We need a node-context for token replacement. When on the Workflow tab
  // form, the node object will already have been loaded on the form.
  // When creating content (node/add/<type>) we only have limited data. In
  // the remaining cases we load the node from the cache based on the nid
  // found on the form.
  $form_id = $form['form_id']['#value'];
  if (strpos($form_id, 'workflow_tab_form') === 0) {
    $node = $form['node']['#value'];
  }
  elseif (is_numeric($nid = $form['nid']['#value'])) {
    $node = node_load($nid);
  }
  else {

    // Creating new content, nid not yet known
    $node = $form['#node'];
  }
  $states = $form['workflow'][$workflow_name]['#options'];
  $submit_handlers = _workflow_extensions_assign_handlers($form);
  $form['workflow']['buttons'] = array(
    '#prefix' => '<div class="workflow-buttons">',
    '#suffix' => '</div>',
  );
  foreach ($states as $sid => $to_state_name) {
    if ($sid != $current_sid) {

      // Create button for transition from current_sid to destination state.
      $button = array();
      $button['#value'] = workflow_extensions_get_transition_label($form['#wf']->wid, $current_state_name, workflow_get_workflow_states_by_sid($sid)->state, $node);
      $button['#type'] = 'submit';
      $button['#to_state'] = $sid;
      if (isset($form['buttons']['submit']['#weight'])) {

        // node form
        $button['#weight'] = $form['buttons']['submit']['#weight'] + 1;
      }
      elseif (isset($form['submit']['#weight'])) {

        // comment form
        $button['#weight'] = $form['submit']['#weight'];
      }
      $button['#submit'] = $submit_handlers;
      $form['workflow']['buttons']["submit_to_{$to_state_name}"] = $button;
    }
  }
  $form['workflow'][$workflow_name]['#type'] = 'markup';
  $form['workflow'][$workflow_name]['#markup'] = '<h3>' . $form['workflow'][$workflow_name]['#title'] . '</h3>';

  // With the existing Save button now impotent to submit a workflow
  // transition, we can re-purpose it for saving all other edits to the
  // node without changing the workflow state.
  // This does not make sense for the Workflow tab form though, as there is
  // nothing to save but a state change. In this case we simply remove the
  // Save button.
  if ($form_id == 'comment_form') {
    $form['actions']['submit'] = $form['submit'];

    // ???
    $form['actions']['submit']['#submit'] = $form['#submit'];
    $form['actions']['submit']['#weight']--;

    // left-most
  }
  if (strpos($form_id, 'workflow_tab_form') !== 0 && ($label = variable_get('workflow_extensions_default_save_button_label', ''))) {
    $form['actions']['submit']['#value'] = workflow_extensions_replace_state_name_tokens($label, $current_state_name);
  }
  unset($form['submit']);

  // remove submit button...

  //unset($form['#submit']); // ... but don't remove handler, [#1097328]
}
function _workflow_extensions_replace_with_dropdown(&$form, $workflow_name) {
  if ($form['workflow'][$workflow_name]['#type'] != 'value') {
    $form['workflow'][$workflow_name]['#type'] = 'select';
    $form['workflow'][$workflow_name]['#name'] = 'workflow';
  }
}

/**
 * Implements hook_block_info().
 */
function workflow_extensions_block_info() {
  if (!module_exists('workflow')) {
    return array();
  }
  $block[0]['info'] = t('Workflow state change form');
  return $block;
}

/**
 * Implements hook_block_view().
 */
function workflow_extensions_block_view($delta) {
  if (arg(0) == 'node') {
    $node = node_load(arg(1));
    $block['content'] = workflow_extensions_change_state_form($node);
    if ($block['content']) {
      $workflow = workflow_get_workflow_type_map_by_type($node->type);
      $workflow = workflow_get_workflows_by_wid($workflow->wid);
      $block['subject'] = t('Current state: @state', array(
        '@state' => $node->workflow_state_name,
      ));
    }
    return $block;
  }
}

/**
 * Use this function in a code-snippet to output a workflow state change form
 * on any page. May be used multiple times on the same page (for different
 * nodes), e.g. using the 'Views PHP' module, as a unique form_id is generated
 * for each occurrence of the form.
 *
 * @param $node
 */
function workflow_extensions_change_state_form($node) {
  if (empty($node)) {
    return '';
  }
  $workflow_type = workflow_get_workflow_type_map_by_type($node->type);
  if (empty($workflow_type)) {
    return '';
  }
  $wid = $workflow_type->wid;
  $choices = workflow_field_choices($node);
  if (count($choices) == 1) {
    if (user_access('view workflow state change block even when state cannot be changed')) {

      // Generate single-option form without Submit button
      $workflow = workflow_get_workflows_by_wid($wid);
      return drupal_get_form('workflow_extensions_single_state_form', $workflow->name, $choices);
    }
    return '';

    // not allowed to view workflow state
  }
  $result = db_query("SELECT sid, state FROM {workflow_states} WHERE status = :status ORDER BY sid", array(
    ':status' => 1,
  ));
  while ($row = $result
    ->fetchObject()) {
    $workflow_states[$row->sid] = check_plain(t($row->state));
  }
  $sid_current = workflow_node_current_state($node);
  @(include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'workflow') . '/workflow.pages.inc');
  $form = drupal_get_form('workflow_tab_form_nid_' . $node->nid, $node, $wid, $workflow_states, $sid_current);
  return $form;
}

/**
 * Form used to display the current state, without a submit button to change it.
 * @param $form_state
 * @param $workflow_name
 * @param $current_state, an array of one element, indexed by its sid
 */
function workflow_extensions_single_state_form($form, $form_state, $workflow_name, $current_state) {
  $sids = array_keys($current_state);
  $form['workflow']['#title'] = $workflow_name;
  $form['workflow'][$workflow_name] = array(
    '#type' => 'radios',
    // may be overridden by workflow_extensions_form_alter()
    '#options' => $current_state,
    '#default_value' => $sids[0],
  );
  return $form;
}
function workflow_extensions_extract_workflow_name($form) {

  // Current and allowed next states for this user and node live in
  // $form['workflow'][$workflow_name]['#options'].
  // At the time of writing, the workflow.module (6.x.1-4) contained a bug that
  // resulted in the $workflow_name being passed as blank. Luckily we can work
  // around this and also be compatible with later versions that don't have the
  // bug.
  if (isset($form['workflow'][''])) {
    return '';
  }
  return isset($form['#wf']->name) ? $form['#wf']->name : $form['workflow']['#title'];
}

/**
 * Sets up an array of handlers appropriate for the form we're on.
 *
 * Called only from _workflow_extensions_replace_with_buttons().
 * Add 'workflow_tab_form_submit' if is not a handler for the form already.
 * Also make sure we go through 'workflow_extensions_form_submit' first.
 *
 * @param array $form
 *   the form
 * 
 * @return array
 *   an arrray of form handler functions
 */
function _workflow_extensions_assign_handlers($form) {
  $handlers = empty($form['#submit']) ? array() : $form['#submit'];
  if (isset($form['#node']) && !in_array('node_form_submit', $handlers)) {
    $handlers[] = 'node_form_submit';
  }
  if (!in_array('workflow_tab_form_submit', $handlers)) {

    // We arrive here, for instance, when the Locale modules is enabled.
    $handlers[] = 'workflow_tab_form_submit';
  }
  if (!in_array('workflow_extensions_form_submit', $handlers)) {
    array_unshift($handlers, 'workflow_extensions_form_submit');
  }

  // Append a redirect handler. It will not affect the original redirection
  // when on /node/%/..., but will redirect back to the original page if on any
  // other page.
  $handlers[] = 'workflow_extensions_form_redirect';
  return $handlers;
}

/**
 * Implements hook_token_list().
 *
 * Note: [workflow-new-state-name] is in fact a pseudo-token, but the user
 * doesn't have to know that!
 */
function workflow_extensions_token_list($context = 'all') {
  if (module_exists('workflow') && in_array($context, array(
    'workflow',
    'node',
    'all',
  ))) {
    $tokens['workflow']['workflow-new-state-name'] = 'New state of content';
    $tokens['workflow']['workflow-state-age'] = 'Seconds elapsed since last state change';
  }
  if ($context == 'node' || $context == 'all') {
    $tokens['node']['mod-since-seconds'] = 'Seconds elapsed since last modification';
  }
  return $tokens;
}

/**
 * Implements hook_token_values().
 *
 * Returning [workflow-state-age] for both node and workflow contexts as there
 * seems to be an issue with using Workflow state as the data type argument in
 * a Rule set. Such a Rule set won't show as available in a scheduled triggered
 * rule. The Content (ie node) data type must be used instead.
 */
function workflow_extensions_token_values($context, $object = NULL) {
  $values = array();
  switch ($context) {
    case 'node':
    case 'workflow':
      if (isset($object)) {
        $node = (object) $object;
        if (module_exists('workflow')) {
          $stamp = db_query_range("SELECT stamp FROM {workflow_node_history} WHERE nid = :nid ORDER BY stamp DESC", array(
            ':nid' => $node->nid,
          ))
            ->fetchField();
          $values['workflow-state-age'] = $stamp ? REQUEST_TIME - $stamp : 0;
        }
        $values['mod-since-seconds'] = $node->changed ? REQUEST_TIME - $node->changed : 0;
      }
      break;
  }
  return $values;
}

/**
 * Return the name for the workflow transition identified by the supplied
 * from-state and to-state names.
 *
 * @param int $wid, workflow identifier, maybe NULL (but then the combination
 *  of $from_state_name and $to_state_name must be unique across all workflows)
 * @param string $from_state_name
 * @param string $to_state_name
 * @param object $node, context for token replacement; if omitted an attempt
 *   will be made to load the node based on the nid in the URL. This will fail
 *   when creating new content, in which case a partial node must be supplied.
 */
function workflow_extensions_get_transition_label($wid, $from_state_name, $to_state_name, $node = NULL) {
  if (module_exists('workflow_named_transitions')) {
    $transitions = workflow_named_transitions_get_transitions($wid);
    foreach ($transitions as $transition) {
      if ($transition->from_state == $from_state_name && $transition->to_state == $to_state_name) {
        return workflow_extensions_replace_state_name_tokens($transition->label, $to_state_name, $node);
      }
    }

    // No label defined, fall through as if module 'workflow_named_transitions'
    // wasn't installed
  }
  $tokenized_label = variable_get('workflow_extensions_change_state_button_label', '');

  // Don't think we need to check_markup(). Only users with 'administer site
  // configuration' permission can set the label pattern, so it's up to them to
  // use or not use HTML and/or javascript.
  return workflow_extensions_replace_state_name_tokens($tokenized_label, $to_state_name, $node);
}
function workflow_extensions_replace_state_name_tokens($tokenized_label, $to_state_name = NULL, $node = NULL) {
  if (empty($tokenized_label)) {
    return t('Move to "@state_name"', array(
      '@state_name' => $to_state_name,
    ));
  }
  $label = workflow_extensions_replace_tokens_raw($tokenized_label, $node);
  if (!empty($to_state_name)) {

    // Once the real tokens have been replaced, replace the pseudo-token
    // [workflow:workflow-new-state-name]
    $label = str_replace('[workflow:workflow-new-state-name]', $to_state_name, $label);
  }
  return $label;
}
function workflow_extensions_replace_tokens_raw($tokenized_label, $node = NULL) {
  if (module_exists('token')) {
    global $user;
    $objects['global'] = NULL;
    $objects['user'] = $user;
    if ($node == NULL && arg(0) == 'node' && is_numeric(arg(1))) {
      $node = node_load(arg(1));

      // node/%
    }
    $objects['node'] = $objects['workflow'] = $node;
    return token_replace($tokenized_label, $objects);
  }
  return $tokenized_label;
}

/**
 * Implements hook_views_api().
 */
function workflow_extensions_views_api() {
  return array(
    'api' => views_api_version(),
    'path' => drupal_get_path('module', 'workflow_extensions') . '/views',
  );
}

Functions

Namesort descending Description
workflow_extensions_block_info Implements hook_block_info().
workflow_extensions_block_view Implements hook_block_view().
workflow_extensions_change_state_form Use this function in a code-snippet to output a workflow state change form on any page. May be used multiple times on the same page (for different nodes), e.g. using the 'Views PHP' module, as a unique form_id is generated for each…
workflow_extensions_extract_workflow_name
workflow_extensions_forms Implements hook_forms().
workflow_extensions_form_alter Implements hook_form_alter().
workflow_extensions_form_redirect If the workflow state was NOT transitioned via the node View, Edit or Workflow tabs, then redirect to the original page. @todo: make this configurabele
workflow_extensions_form_submit Handler for the edit form.
workflow_extensions_get_transition_label Return the name for the workflow transition identified by the supplied from-state and to-state names.
workflow_extensions_menu Implements hook_menu().
workflow_extensions_permission Implements hook_permission().
workflow_extensions_replace_state_name_tokens
workflow_extensions_replace_tokens_raw
workflow_extensions_single_state_form Form used to display the current state, without a submit button to change it.
workflow_extensions_token_list Implements hook_token_list().
workflow_extensions_token_values Implements hook_token_values().
workflow_extensions_views_api Implements hook_views_api().
workflow_extensions_workflow_comment_edit_form Display a text area populated with the selected workflow log comment and allow the user to modify and save it.
workflow_extensions_workflow_comment_edit_form_submit Submit handler for the workflow transition comment edit form.
workflow_extensions_workflow_form_validate Validate the workflow form, in particular the state transition comment and the scheduled state transition time (the date is a drop-down so requires no validation).
workflow_state_transition_record_load Load function belonging to the above menu option 'workflow-log/%workflow-state-transition-record'. Maps to this function just like 'node/%node' maps to node_load().
_workflow_extensions_assign_handlers Sets up an array of handlers appropriate for the form we're on.
_workflow_extensions_replace_with_buttons
_workflow_extensions_replace_with_dropdown

Constants

Namesort descending Description
WORKFLOW_EXTENSIONS_UI_BUTTONS
WORKFLOW_EXTENSIONS_UI_DROPDOWN
WORKFLOW_EXTENSIONS_UI_RADIOS @file UI-related improvements to the Workflow module and tokens for Rules.