Use the default_moderation_state instead of getInitialState() to detect transition on new entities

Created on 7 December 2021, about 3 years ago
Updated 4 December 2023, about 1 year ago

Problem/Motivation

Probably the best way to describe this is with an example. Suppose you have a really basic moderation workflow with only two states: "Draft" and "Published", and the default moderation state is Draft. Now imagine you have a notification set up for the transition from draft->published that sends some kind of notification to the user like "Your post was successfully published! See it here... etc.".

Right now, if the user creates a new post, and immediately sets the state to Published, no notification will be sent. But I believe that it should. The idea being that if the default state is Draft, then the draft->published transition should still happen here even though it wasn't technically saved as a draft first.

I think the issue really stems from the getInitialState() method. getInitialState() was designed to figure out the initial state based on the content's current publish status so that it picked the right value on existing entities that didn't already have a state. Ref: #2817835: When enabling moderation apply a relative state . And here's what getInitialState() look like on the ContentModeration WorkflowType plugin:

/**
   * {@inheritdoc}
   */
  public function getInitialState($entity = NULL) {
    // Workflows are not tied to entities, but Content Moderation adds the
    // relationship between Workflows and entities. Content Moderation needs the
    // entity object to be able to determine the initial state based on
    // publishing status.
    if (!($entity instanceof ContentEntityInterface)) {
      throw new \InvalidArgumentException('A content entity object must be supplied.');
    }
    if ($entity instanceof EntityPublishedInterface && !$entity->isNew()) {
      return $this->getState($entity->isPublished() ? 'published' : 'draft');
    }
    return $this->getState(!empty($this->configuration['default_moderation_state']) ? $this->configuration['default_moderation_state'] : 'draft');
  }

Since we're sending notifications on an insert hook, the entity is already saved by the time we call getInitialState(). Using our example above, the entity will be not new, and published so it will just return the hardcoded 'published' state (instead of draft as we had configured).

Steps to reproduce

  • Create a basic content moderation workflow with only two states: 'draft', and 'published'
  • Set the "Default moderation state" to draft
  • Create transitions for: draft->draft, draft->published
  • Add a notification for draft->published
  • Allow a user/role to use both transitions
  • Create a new content entity using this moderation workflow and set the workflow state to published and save
  • No notification will be sent

Proposed resolution

Instead of using getInitialState(), we should just use the default_moderation_state setting to determine the previous state in the case that there is no "last_revision" (i.e. when new entities are created).

Remaining tasks

Review Patch

API changes

One thing to consider with this one is whether or not people were relying previously on notifications not being sent in this type of case.

🐛 Bug report
Status

Needs work

Version

3.0

Component

Code

Created by

🇨🇦Canada drclaw

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024