Workflows, together with Content Moderation modules landed in Drupal 8 core as part of a workflow suite. The path of these moderation-related modules to Drupal core is a long one. Historically, Drupal has had a built-in concept of versioning of posts or nodes. Different contributed modules, e.g., Revisioning and Workbench moderation have built solutions on this feature to enhance the moderation of content over different stages managed, perhaps, by different members of an editorial team. In fact, Workbench moderation was changed into Content moderation for this inclusion in core.

Workflows does nothing by itself. Another module must leverage the available APIs. An example of this implementation is the Content moderation, which should be studied after this article.

This module allows you to build and manage state machines for different content types called workflows. Such a workflow or state machine comprises of defined states and all the supported transitions between them. Other properties essential to the function of the system may be added to the workflows.

States

These are some examples of possible states that a piece of content can be in:

  1. Editorial workflow:

    • Draft
    • Published
    • Archived
  2. Legal document:

    • Drafted
    • Reviewed
    • Validated
    • Approved
  3. Order checkout:

    • Cart
    • Addressing
    • Shipping
    • Payment
    • Completed

These states are defined by modules implementing workflows. There may be multiple workflows depending on the diversity of content types on a single site. For example on an e-commerce site, there may be a workflow type for news articles describing the items on sale ("Editorial workflow") and a second one for what happens to orders from the moment an item is added to the shopping basket to order completion ("Order checkout").

Transitions

These describe all the allowed changes in the state of an entity that is in a given workflow or state machine. For a news article in the first example above, these may be the available transitions:

  • DRAFT > DRAFT
  • PUBLISHED > DRAFT
  • DRAFT > PUBLISHED
  • PUBLISHED > PUBLISHED
  • PUBLISHED > ARCHIVED
  • ARCHIVED > DRAFT
  • ARCHIVED > PUBLISHED

Each transition may then be placed under access control as different people with different levels of authority may be responsible for applying specific transitions to news articles. An editor role may be assigned permissions to work on drafts only while the moderator reviews all changes and approves them for publication. Until a post under moderation is published, it may be viewed by any roles with the right permission too.

This is a massive improvement on the previous published and unpublished states we have had in Drupal. Previously, only the author or super administrator (uid: 1) was able to view any unpublished content.

Type settings

Often, state machines include callbacks, i.e., what should happen to an entity under moderation before or after each transition. There are no explicit callbacks in the Workflows module, but when configuring workflows, any number of type settings may be added. These are properties that play an important role when acting on appropriate entities later. This satisfies the concept of callbacks in similar programming contexts that implement state machines.

These three components, states, transitions, and type settings make up workflows. Taken together, they are referred to as a workflow (or graph). In Drupal 8, they are defined as configuration entities, which have to be fully defined by modules implementing them for any content types they want to control.

How it works

This module provides the blueprint for other modules that want to leverage the functionality of workflows. It does nothing by itself.

Workflow type plugin

A workflow type needs to be provided as a plugin object. The annotation for this object is in core/modules/workflows/src/Annotation/WorkflowType.php

   <?php

    namespace Drupal\workflows\Annotation;
    
    use Drupal\Component\Annotation\Plugin;
    
    /**
     * Defines an Workflow type annotation object.
     */
    class WorkflowType extends Plugin {
    
      /**
       * The plugin ID.
       *
       * @var string
       */
      public $id;
    
      /**
       * The label of the workflow.
       *
       * Describes how the plugin is used to apply a workflow to something.
       *
       * @var \Drupal\Core\Annotation\Translation
       *
       * @ingroup plugin_translatable
       */
      public $label = '';
    
      /**
       * States required to exist.
       *
       * Normally supplied by WorkflowType::defaultConfiguration().
       *
       * @var array
       */
      public $required_states = [];
    
    }

A module that wants to expose its workflow type needs to create a plugin class under src\Plugin\WorkflowType\PLUGIN_CLASSNAME.php. The @WorkflowType annotation must define the keys matching the names of the properties of the annotation class above, i.e., id, label and required_states.

Workflows module comes with a base class for plugins with some common methods so that other plugin classes can simply extend and get those methods for free. For example:

<?php

/**
 * Defines the LegalDocument.
 * 
 * @WorkflowType(
 *   id = "legal_document",
 *   label = @Translation("Legal Document"),
 *   required_states = {
 *     "drafted",
 *     "approved",
 *   },
 * )
 */
class LegalDocument extends WorkflowBase {
        
}             

When building the administration UI, the workflows module will ask other modules for these WorkflowType plugins so that content types will have an opportunity to declare their participation in any of them.

More states can be added to the default ones as provided by the plugin. Also, all possible transitions between the states can be configured.

Workflow configuration entity

As the Workflows module also manages workflows (or graphs) as configuration entities, it defines the schema for them. Here it is:

# core/modules/content_moderation/config/schema/content_moderation.schema.yml 

workflows.workflow.*:
  type: config_entity
  label: 'Workflow'
  mapping:
    id:
      type: string
      label: 'ID'
    label:
      type: label
      label: 'Label'
    type:
      type: string
      label: 'Workflow type'
    type_settings:
      type: workflow.type_settings.[%parent.type]
      label: 'Custom settings for workflow type'
    states:
      type: sequence
      label: 'States'
      sequence:
        type: mapping
        label: 'State'
        mapping:
          label:
            type: label
            label: 'Label'
          weight:
            type: integer
            label: 'Weight'
    transitions:
      type: sequence
      label: 'Transitions'
      sequence:
        type: mapping
        label: 'Transition from state to state'
        mapping:
          label:
            type: label
            label: 'Transition label'
          from:
            type: sequence
            label: 'From state IDs'
            sequence:
              type: string
              label: 'From state ID'
          to:
            type: string
            label: 'To state ID'
          weight:
            type: integer
            label: 'Weight'

In effect, this is the template for any modules that want to implement workflows. The configuration entities they create must be based on this template.

Conclusion

Workflows module has no UI and does not do much on its own. It lays down guidelines for other modules that want to implement different states for content or moderation.