diff --git a/workbench_moderation.api.php b/workbench_moderation.api.php
index 7dc8b9c..974f2f8 100644
--- a/workbench_moderation.api.php
+++ b/workbench_moderation.api.php
@@ -26,3 +26,19 @@ function hook_workbench_moderation_access_alter(&$access, $op, $node) {
     $access = FALSE;
   }
 }
+
+/**
+ * Allows modules to respond to state transitions.
+ *
+ * @param $node
+ *  The node that is being transitioned.
+ *
+ * @param $previous_state
+ *  The state of the revision before the transition occurred.
+ *
+ * @param $new_state
+ *  The new state of the revision.
+ */
+function hook_workbench_moderation_transition($node, $previous_state, $new_state) {
+  // Your code here.
+}
diff --git a/workbench_moderation.module b/workbench_moderation.module
index 2cc5ea6..6676dbe 100644
--- a/workbench_moderation.module
+++ b/workbench_moderation.module
@@ -1466,6 +1466,9 @@ function workbench_moderation_moderate($node, $state) {
   if (!empty($node->workbench_moderation['published'])) {
     drupal_register_shutdown_function('workbench_moderation_store', $node);
   }
+
+  // Notify other modules that the state was changed.
+  module_invoke_all('workbench_moderation_transition', $node, $old_revision->state, $state);
 }
 
 /**
@@ -1840,3 +1843,151 @@ function workbench_moderation_workbench_block() {
 
   return $output;
 }
+
+/**
+ * Implementation of hook_workbench_moderation_transition().
+ */
+function workbench_moderation_workbench_moderation_transition($node, $previous_state, $new_state) {
+  if (module_exists('trigger')) {
+    workbench_moderation_trigger_transition($node, $previous_state, $new_state);
+  }
+
+  if (module_exists('rules')){
+    rules_invoke_event('workbench_moderation_after_moderation_transition', $node, $previous_state, $new_state);
+  }
+}
+
+/**
+ * Implements hook_trigger_info().
+ *
+ * Creates a trigger for each transition.
+ */
+function workbench_moderation_trigger_info() {
+
+  $output = array(
+    'workbench_moderation' => array(
+      'workbench_moderation_transition' => array(
+        'label' => t('After any transition between states occurs.'),
+      ),
+    ),
+  );
+
+  // Get all transitions.
+  $transitions = workbench_moderation_transitions();
+
+  // Add a trigger for each transition.
+  foreach ($transitions as $transition_definition) {
+    $transition_string = 'wmt_' . $transition_definition->from_name . '__' . $transition_definition->to_name;
+    // Hash this string if it's longer than the db field size
+    if (strlen($transition_string) > 32) {
+      $transition_string = md5($transition_string);
+    }
+
+    $output['workbench_moderation'][$transition_string] = array(
+      'label' => t('Transition from the state %from_name to %to_name occurs.', array('%from_name' => $transition_definition->from_name, '%to_name' => $transition_definition->to_name)),
+    );
+  }
+
+  return $output;
+}
+
+/**
+ * transition trigger: Run actions associated with an arbitrary event.
+ *
+ * This function is executed after a transition takes place.
+ *
+ * @param $node
+ *   The node undergoing the transition.
+ * @param $from_state
+ *   The previous workbench moderation state.
+ * @param $state
+ *   The new workbench moderation state.
+ */
+function workbench_moderation_trigger_transition($node, $from_state, $state, $a3 = NULL, $a4 = NULL) {
+  // Ask the trigger module for all actions enqueued for the 'transition' trigger.
+  $aids = trigger_get_assigned_actions('workbench_moderation_transition');
+  // prepare a basic context, indicating group and "hook", and call all the
+  // actions with this context as arguments.
+  $context = array(
+    'group' => 'workbench_moderation',
+    'hook' => 'transition',
+    'from_state' => $from_state,
+    'state' => $state,
+  );
+  actions_do(array_keys($aids), $node, $context, $a3, $a4);
+
+
+  // Ask the trigger module for all actions enqueued for this specific transition.
+  $transition_string = 'wmt_' . $from_state . '__' . $state;
+  // Hash this string if it's longer than the db field size
+  if (strlen($transition_string) > 32) {
+    $transition_string = md5($transition_string);
+  }
+  $aids = trigger_get_assigned_actions($transition_string);
+  $context['hook'] = $transition_string;
+
+  actions_do(array_keys($aids), $node, $context, $a3, $a4);
+}
+
+/**
+ * Implements hook_action_info().
+ */
+function workbench_moderation_action_info() {
+  $info = array();
+
+  $info['workbench_moderation_set_state_action'] = array(
+    'type' => 'node',
+    'label' => t('Set moderation state'),
+    'configurable' => TRUE,
+    'behavior' => array('changes_property'),
+    'triggers' => array('node_presave', 'node_insert', 'node_update', 'workbench_moderation_transition'),
+  );
+
+  // Get all workbench transitions.
+  $transitions = workbench_moderation_transitions();
+
+  // Add a trigger for each transition.
+  foreach ($transitions as $transition_definition) {
+    $transition_string = 'wmt_' . $transition_definition->from_name . '__' . $transition_definition->to_name;
+    // Hash this string if it's longer than the db field size
+    if (strlen($transition_string) > 32) {
+      $transition_string = md5($transition_string);
+    }
+
+    $info['workbench_moderation_set_state_action']['triggers'][] = $transition_string;
+  }
+
+  return $info;
+}
+
+/**
+ * Form builder; Prepare a form for possible moderation states.
+ */
+function workbench_moderation_set_state_action_form($context) {
+  $form = array();
+
+  $form['state'] = array(
+    '#type' => 'select',
+    '#options' => workbench_moderation_state_labels(),
+    '#default_value' => isset($context['state']) ? $context['state'] : '',
+  );
+
+  return $form;
+}
+
+/**
+ * Process workbench_moderation_set_state_action_form form submissions.
+ */
+function workbench_moderation_set_state_action_submit($form, $form_state) {
+  return array('state' => $form_state['values']['state']);
+}
+
+/**
+ * Changes the moderation state for a given node.
+ */
+function workbench_moderation_set_state_action($node, $context) {
+  if (!empty($context['state']) && _workbench_moderation_moderate_access($node, $context['state'])) {
+    workbench_moderation_moderate($node, $context['state']);
+    watchdog('action', 'Change node %nid moderation state to %state.', array('%nid' => $node->nid, '%state' => $context['state']));
+  }
+}
