Changing the Default Content Moderation State in Drupal 8

I have been working with the Content Moderation module in Drupal 8 and one slight niggle we came across was the default option for the Moderation state.

If the current state was In Review we would like the Change to option to also be In Review rather than Draft.

Current default moderation state

The desired default state option

This means the default is to keep the entity in it’s current state rather than switching to a new state. Switching to a new state is then an active task for the editor.

I did this by implementing hook_form_alter() in a custom module.

/**
 * Implements hook_form_alter().
 */
function my_module_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {

if ( array_key_exists('moderation_state', $form) ) {

$node = $form_state->getFormObject()->getEntity();

$moderationState = $node->get('moderation_state')->getValue('state');

if (isset($moderationState[0]['value'])) {
 $form['moderation_state']['widget'][0]['state']['#default_value'] = $moderationState[0]['value'];
 }

}

}

In this function we first check if the form contains the moderation_state key.

Next we load the node so we can access it’s properties.

The moderation state is then retrieved from the node.

The last part is to check if the moderation state has a value. If we are creating a node this will not be set.

In the if statement we then set the default value to the current state.

Drupal 8 Workflow Notifications with Rules Part 2

In my previous post I talked through setting up Content Moderation with a review state. In this post we will complete the process by sending email notifications via the Rules module when the moderation state is changed.

Install Rules

To enable the Rules module we first need to require it via Composer. Run the following from the command line in the root of your project
composer require drupal/rules

Once this has run you can return to the Extend page and enable the Rules module.

Create the First Rule

By the end we will have three rules for different states and transitions. The first rule will handle the creation of content the state is set straight to Review.

To create a rule navigate to Manage -> Configuration -> Rules (/admin/config/workflow/rules)

Once on that page click on the Add a reaction rule button. Fill in the details with the following.

Label: Notify reviewers of content created for review

React on event: After saving new content moderation state

Selecting React on event: After saving new content moderation state

We now need to add a condition so click the Add condition button.

From the select box choose Data Comparison from under Data and then click Continue

Selecting Data Comparison condition

When adding our condition it is useful to Switch to data selection for the Data selector input. This will help us drill down into the available data.

Using data selection to find the required selector

The Data selector we want is content_moderation_state.moderation_state.value

Leave the Operator as ==

Set the Data value to review. This is the machine name of our state that was created in the Editorial Workflow.

Completed data comparison condition

We can now save our condition.

Adding an Action

Before we create our action to send the email we need to make the node available to our rule so we can use it’s title and ID in the email body.

Click Add action and then choose Fetch entity by id under the Entity section.

Adding a fetch entity by id action

On the next screen set the Entity Type value to node and then for the Identifier we will again switch to data selection.

Using the autocomplete we set the Identifier value to content_moderation_state.content_entity_id.value

Completed fetch entity by id action

Sending the email

We can now add an action for sending the email. Click the Add action button and choose Send email from the System section of the dropdown.

Choosing the send email action

For the Send To we use an email address that will forward to all reviewers, e.g. reviewers@example.com

For the Subject we use Item Ready For Review.

For the body we want to provide some information for our reviewers so we set it to

Please review {{ entity_fetched.title.value }} at https://example.com/node/{{ entity_fetched.nid.value }}

The two parts in curly brackets are tokens from our fetched entity, node, that we performed earlier.

When the email sends the body would would look something like

Please review My New Page at https://example.com/node/12

In the next part we will create two more rules to handle updating the moderation state.

Drupal 8 Workflow Notifications with Rules Part 1

For Drupal projects I’ve always used the comprehensive suite of tools provided by Workbench. But when I started a new project and saw that Workflow is hopefully making it’s way into core it felt like a good time to try it out. One part of the project was the addition of notifications when Workflow states were changed. With the Rules module also receiving lots of attention I decided combining the two modules was the best approach.

The following example was made using Drupal 8.4.4

Enable the Modules

First of all we have to enable the Workflows module and the Content Moderation module. Click on Extend form the admin menu or go to /admin/modules and find these two modules.

When enabling Content Moderation you will be warned that it is an experimental module. https://www.drupal.org/core/experimental

Edit the Workflow

If you go to /admin/config/workflow/workflows you will see we have one workflow called Editorial.

List of available Workflows

Click the Edit button to go to /admin/config/workflow/workflows/manage/editorial

States in the Editorial Workflow

We currently have three states but we want to add a new one for Review. Click the Add a new state link. On the Add state page all we need to enter is a label of Review and then click Save.

Adding a new Workflow state

Back on the Edit Editorial Workflow page drag the Review state to in between Draft and Published and then click the Save button at the bottom of the page.

Reordering the Workflow States

We now need to edit the transitions to allow the flow between draft, review and publish. This is how the transitions look by default. We need to enable a draft to be become a review and a review to become published. We want to cut out the draft to published transition.

Below are the default transitions, we’ll first add our new ones and then modify the existing ones.

List of the Editorial Workflow transitions

Click the Add a new transition link and you will be on a page with options for Label, From and To. Set the Label to Review, From to Draft and To as Review then click Save.

Adding a new Workflow transition

Back on the main page drag the new Review transition up so it is between Create New Draft and Publish and then click Save.

Reordering the Workflow transitions

We now need to update the existing transitions. Change the Create New Draft From value. It is currently Draft, Published and we need it to be Draft, Review.

Lastly for transitions change the Publish transitions’s From value to Review, Publish. This means a node has to go from Draft to Review before it can be published.

The completed transitions

Add The Workflow to Entities

The last part of the workflow setup is to enable it for any required content types or entities. At the bottom of the page there is the section This Workflow Applies To. In this example we will enable this workflow for Basic Pages.

Click the Select button beside Content types, select Basic Page from the overlay and then click Save. Now If you go to add a Basic Page you will see at the bottom there is a select where you can choose the State of you node.

Available Workflow states when saving a node

In the next part we will look at sending email notifications when the Workflow state changes using the Rules module.

Drupal 7 Views Sort by Two Date Fields

To achieve this you will need to implement hook_views_query_alter() in a custom module. I did not do this in Views UI.

A recent project at Headscape required me to build view listing two different content types that would use two different date fields to sort by. For examples I’ll use the default basic page and article content types.

The Problem

Some content types need to be sorted on the node created date and others on the display date field.

Trying to use the Views UI to add the two sort fields would result in first ordering by node created, then ordering by display date which is not the result we were after.

The Solution

First we need to add a new field that we can sort by. This field will have the alias order_date.

To create it we check if the display date field is null, if it is order_date gets the node created timestamp. If display date has a value we convert it to a Unix timestamp and that value is assigned to order_date.

In hook_views_query_alter we need this code

$query->fields[] = array(
  'field' => 'IFNULL (UNIX_TIMESTAMP(field_data_field_display_date.field_display_date_value), node.created)',
  'alias' => 'order_date'
);

Next we need to add the order by clause. As this is the only field we want to order by we completley over write the order by array.

$query->orderby = array(
  array(
    'field' => 'order_date',
    'direction' => 'DESC',
  )
);

Put together hook_views_query_alter will look like this.

/**
 * Implements hook_views_query_alter().
 */
function MYMODULE_views_query_alter(&$view, &$query) {

if ($view->name == 'YOUR_VIEW_NAME') {

  $query->fields[] = array(
    'field' => 'IFNULL (UNIX_TIMESTAMP(field_data_field_display_date.field_display_date_value), node.created)',
    'alias' => 'order_date'
  );

  $query->orderby = array(
    array(
      'field' => 'order_date',
      'direction' => 'DESC',
    )
  );

 }

}

Stepping back to move forward with ReactJS

I’ve been using ReactJS as I have been exploring Headless / Decoupled Drupal and have so far found it to be very nice to work with. However, as I am not overly familar with it I’ve found myself looking up lots of things to ensure I’m doing it “the React way”. This has meant I’ve been doing more React learning than I have Drupal learning.

My solution is to go back to an existing Drupal 7 project where I have a custom piece of search functionality and replicate it using JSON feeds provided by Drupal and a ReactJS frontend.

This has been really beneficial in my learning as I have very clea objectivies and expectations. It also means I am only focussed on learning one thing at time so I don’t skip around between documentation and tutorials.

If you ae just starting with ReactJS, or any othe JavaScript famework, and Drupal I would highly reccomend this approach to get a taste of what this decoupled appoach can bring to your skill set.

Drupal 6 num_rows

I’ve been working on a site powered by Drupal and needed to find the number of rows a database query returned. Simple enough and quite common procedure. But, the Drupal database API no longer offers the db_num_rows() function.

I had a quick Google around and the answered seemed to be to run the query twice but the second time using a count query. Two calls to the database when only one is necessary? Not on my watch. The piece of code is to appear on the home page so it will be called upon frequently.

My solution was too loop through the results set and add the formatted HTML to an array. Then check if there are any items in the array, if so loop through it an output them if not display the message that there are currently no results.

I know it’s still doubling up but I think it is a slightly more elegant solution than the double database call.