0

I want to allow authenticated users to fill out a node (Draft) and then, when they are ready, submit the node (to give it the Submitted state). An admin will later decide whether or not to publish the node.

I'm experimenting with the improvements to the Content Moderation module on Drupal 8.4-rc2 (new UI is in the 8.4 series, so 8.3 and before will look different).

I have the following workflow states defined:

  • Draft
  • Submitted
  • Published

There is a transition called Submit to move from the Draft state to the Submitted state. Authenticated users have permission to use this transition.

The problem is that the core UI for this looks very complicated.

This is a node edit page: node_edit

And this is a node view page: node_view

I want to hide this moderation UI and instead provide users with a single button, "Submit for approval."

I hid the moderation and revision UI from auth users (only admin have permission to edit workflows) like this:

function mymodule_form_content_moderation_entity_moderation_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $user = \Drupal::currentUser();
  if ( empty($user) || !($user->hasPermission('administer workflows')) ) {
    $form['#access'] = FALSE;
  }
}

function mymodule_form_node_mycontenttype_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $user = \Drupal::currentUser();
  if ( empty($user) || !($user->hasPermission('administer workflows')) ) {
    $form['revision_information']['#access'] = FALSE;
    $form['moderation_state']['#access'] = FALSE;
  }
}

function mymodule_form_node_mycontenttype_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $user = \Drupal::currentUser();
  if ( empty($user) || !($user->hasPermission('administer workflows')) ) {
    $form['revision_information']['#access'] = FALSE;
    $form['moderation_state']['#access'] = FALSE;
  }
}

So this cleans up the UI and hides all the Content Moderation options.

But how do I create a button to move from one state to another? Specifically, I want the bottom of the form to look like this:

  • Save button (saves the node in the same (Draft) workflow state)
  • New button that saves the node and activates the transition to the Submitted state

This is basically the same thing as what core does when it provides an option to Save as published and a second option to Save as unpublished-- I just want to do this with my workflow states.

  • You could change moderation_state to be hidden and then set a value for the next state if the user is allowed to? $form['moderation_state']['#access'] = TRUE;, $form['moderation_state']['#type'] = 'hidden';, $form['moderation_state']['#value'] = '[NEXT STATE ID]';. Though I would also implement some feedback to indicate the post changed state and was not just saved. – Neograph734 Sep 27 '17 at 9:47
  • @Neograph734 Thanks, I'm actually trying to add two buttons, "Save as Draft" and "Submit for approval," like what Core does when you have the option to "Save as published" or "Save as unpublished." I updated the end of the question to reflect this. – Patrick Kenny Sep 27 '17 at 9:52
1

I think you should be able to do something like this. (But I did not test).

The first code block adds an additional submit button and gives it a custom submit handler. (Button specific submit callbacks should run before form submit callbacks.)

function mymodule_form_TYPE_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  // Add second submit button (Also check if user can see this).
  $form['actions']['submit_publish'] = [
    '#type' => 'submit',
    '#value' => t('Submit for approval'),
    '#submit' => ['mymodule_submit_callback'],
  ];
}

And the submit callback, which simply sets the new value for the moderation state.

/**
 * Submit callback to submit for approval
 */
function mymodule_submit_callback(array &$form, FormStateInterface &$form_state) {
  $form_state->setValue('moderation_state', 'MODERATION STATE ID');
}
  • Thanks, this looks like the right approach, but moderation_state can't be set like that. Followup question here: drupal.stackexchange.com/questions/246794/… – Patrick Kenny Sep 27 '17 at 16:22
  • @Patrick, there is a form element in the form right now... You should be able to provide a value for that field right? – Neograph734 Sep 27 '17 at 18:29
  • SetValue doesn't appear to work because states config entities have a state, not value. – Patrick Kenny Sep 27 '17 at 21:35
  • The idea was that you hide the existing form element and then substitute its value right before form submission. For this I thought $form_state->setValue should be suitable. It should not distinguish between state or value, it should just replace the field value. But I have never tried injecting values like this, so perhaps setValue is indeed not suitable for this (or the key is different). – Neograph734 Sep 28 '17 at 10:08
1

Based on the code from Neograph734, this is the code I actually used (tested and working):

function MYMODULE_form_node_CONTENTTYPE_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  $form['actions']['submit_publish'] = array(
    '#type' => 'submit',
    '#weight' => 999,
    '#button-type' => 'danger',
    '#value' => t('Submit for approval'),
    '#submit' => array_merge($form['actions']['submit']['#submit'], array('MYMODULE_draft2submit_callback')),
  );
}

function MYMODULE_draft2submit_callback(array &$form, FormStateInterface &$form_state) {
  // Getting the entity.
  $entity = $form_state->getFormObject()->getEntity();
  // Changing the moderation state.
  $entity->set('moderation_state', 'submitted');
  // Saving the entity.
  $entity->save();
}

For more info, see this issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.