diff --git a/scheduler.module b/scheduler.module index 9f86b4d..502a4cf 100644 --- a/scheduler.module +++ b/scheduler.module @@ -72,6 +72,18 @@ function scheduler_form_node_form_alter(&$form, FormStateInterface $form_state) $publishing_enabled = $type->getThirdPartySetting('scheduler', 'publish_enable', $config->get('default_publish_enable')); $unpublishing_enabled = $type->getThirdPartySetting('scheduler', 'unpublish_enable', $config->get('default_unpublish_enable')); + /* @var $node \Drupal\node\NodeInterface */ + $node = $form_state->getFormObject()->getEntity(); + if (\Drupal::moduleHandler()->moduleExists('scheduler_content_moderation_integration')) { + /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */ + $moderation_info = \Drupal::service('content_moderation.moderation_information'); + if ($moderation_info->isModeratedEntity($node)) { + // If no moderation transitions are available, hide the scheduling. + $publishing_enabled = $publishing_enabled && !empty($form['publish_state']['widget'][0]['#options']); + $unpublishing_enabled = $unpublishing_enabled && !empty($form['unpublish_state']['widget'][0]['#options']); + } + } + // If neither publishing nor unpublishing are enabled for this node type then // the only thing to do is remove the fields from the form, then exit. if (!$publishing_enabled && !$unpublishing_enabled) { @@ -82,9 +94,6 @@ function scheduler_form_node_form_alter(&$form, FormStateInterface $form_state) $date_only_allowed = $config->get('allow_date_only'); - /* @var $node \Drupal\node\NodeInterface */ - $node = $form_state->getFormObject()->getEntity(); - // A publish_on date is required if the content type option is set and the // node is being created or it currently has a scheduled publishing date. $publishing_required = $type->getThirdPartySetting('scheduler', 'publish_required', $config->get('default_publish_required')) @@ -362,6 +371,9 @@ function scheduler_node_presave(EntityInterface $node) { } $node->publish_on->value = NULL; $node->setPublished(TRUE); + if (\Drupal::moduleHandler()->moduleExists('scheduler_content_moderation_integration')) { + $node->set('moderation_state', $node->publish_state->getValue()); + } // Trigger the PUBLISH_IMMEDIATELY event so that modules can react after // the node has been published. diff --git a/scheduler.services.yml b/scheduler.services.yml index 00ab742..6874c41 100644 --- a/scheduler.services.yml +++ b/scheduler.services.yml @@ -1,7 +1,7 @@ services: scheduler.manager: class: Drupal\scheduler\SchedulerManager - arguments: ['@date.formatter', '@logger.channel.scheduler', '@module_handler', '@entity.manager', '@config.factory' ] + arguments: ['@date.formatter', '@logger.channel.scheduler', '@module_handler', '@entity.manager', '@config.factory', '@?content_moderation.moderation_information'] logger.channel.scheduler: class: Drupal\Core\Logger\LoggerChannel factory: logger.factory:get diff --git a/src/SchedulerManager.php b/src/SchedulerManager.php index de17b18..dc00379 100644 --- a/src/SchedulerManager.php +++ b/src/SchedulerManager.php @@ -2,6 +2,7 @@ namespace Drupal\scheduler; +use Drupal\content_moderation\ModerationInformationInterface; use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Datetime\DateFormatter; use Drupal\Core\Entity\EntityManager; @@ -39,6 +40,13 @@ class SchedulerManager { */ protected $moduleHandler; + /** + * The scheduler_content_moderation_integration module status. + * + * @var bool + */ + protected $schedulerModerationEnabled; + /** * Entity Manager service object. * @@ -46,6 +54,13 @@ class SchedulerManager { */ protected $entityManager; + /** + * Moderation information service. + * + * @var \Drupal\content_moderation\ModerationInformationInterface + */ + protected $moderationInfo; + /** * Config Factory service object. * @@ -56,12 +71,14 @@ class SchedulerManager { /** * Constructs a SchedulerManager object. */ - public function __construct(DateFormatter $dateFormatter, LoggerInterface $logger, ModuleHandler $moduleHandler, EntityManager $entityManager, ConfigFactory $configFactory) { + public function __construct(DateFormatter $dateFormatter, LoggerInterface $logger, ModuleHandler $moduleHandler, EntityManager $entityManager, ConfigFactory $configFactory, ModerationInformationInterface $moderationInformation = NULL) { $this->dateFormatter = $dateFormatter; $this->logger = $logger; $this->moduleHandler = $moduleHandler; $this->entityManager = $entityManager; $this->configFactory = $configFactory; + $this->moderationInfo = $moderationInformation; + $this->schedulerModerationEnabled = $this->moduleHandler->moduleExists('scheduler_content_moderation_integration'); } /** @@ -93,6 +110,7 @@ class SchedulerManager { ->exists('publish_on') ->condition('publish_on', REQUEST_TIME, '<=') ->condition('type', $scheduler_enabled_types, 'IN') + ->latestRevision() ->sort('publish_on') ->sort('nid'); // Disable access checks for this query. @@ -192,8 +210,28 @@ class SchedulerManager { ]; $this->logger->notice('@type: scheduled publishing of %title.', $logger_variables); - // Use the actions system to publish the node. - $this->entityManager->getStorage('action')->load('node_publish_action')->getPlugin()->execute($node); + // If scheduler_content_moderation_integration is enabled, set to + // published state. + if ($this->schedulerModerationEnabled && $this->moderationInfo->isModeratedEntity($node)) { + $state = $node->publish_state->value; + $node->publish_state->value = NULL; + + /** @var \Drupal\content_moderation\Plugin\WorkflowType\ContentModerationInterface $type_plugin */ + $type_plugin = $this->moderationInfo->getWorkflowForEntity($node)->getTypePlugin(); + try { + // If transition is not valid, throw exception. + $type_plugin->getTransitionFromStateToState($node->moderation_state->value, $state); + $node->set('moderation_state', $state); + } + catch (\InvalidArgumentException $exception) { + $node->save(); + continue; + } + } + else { + // Use the actions system to publish the node. + $this->entityManager->getStorage('action')->load('node_publish_action')->getPlugin()->execute($node); + } // Invoke the event to tell Rules that Scheduler has published the node. if ($this->moduleHandler->moduleExists('scheduler_rules_integration')) { @@ -242,6 +280,7 @@ class SchedulerManager { ->exists('unpublish_on') ->condition('unpublish_on', REQUEST_TIME, '<=') ->condition('type', $scheduler_enabled_types, 'IN') + ->latestRevision() ->sort('unpublish_on') ->sort('nid'); // Disable access checks for this query. @@ -341,8 +380,28 @@ class SchedulerManager { ]; $this->logger->notice('@type: scheduled unpublishing of %title.', $logger_variables); - // Use the actions system to publish the node. - $this->entityManager->getStorage('action')->load('node_unpublish_action')->getPlugin()->execute($node); + // If scheduler_content_moderation_integration is enabled, set to + // unpublished state. + if ($this->schedulerModerationEnabled && $this->moderationInfo->isModeratedEntity($node)) { + $state = $node->unpublish_state->value; + $node->unpublish_state->value = NULL; + + /** @var \Drupal\content_moderation\Plugin\WorkflowType\ContentModerationInterface $type_plugin */ + $type_plugin = $this->moderationInfo->getWorkflowForEntity($node)->getTypePlugin(); + try { + // If transition is not valid, throw exception. + $type_plugin->getTransitionFromStateToState($node->moderation_state->value, $state); + $node->set('moderation_state', $state); + } + catch (\InvalidArgumentException $exception) { + $node->save(); + continue; + } + } + else { + // Use the actions system to publish the node. + $this->entityManager->getStorage('action')->load('node_unpublish_action')->getPlugin()->execute($node); + } // Invoke event to tell Rules that Scheduler has unpublished this node. if ($this->moduleHandler->moduleExists('scheduler_rules_integration')) {