如何在Drupal 8中通过Rules模块实现Workbench Moderation状态变更邮件通知?
我之前在Drupal 8项目里刚好实现过这个需求,确实不像D7那样开箱即用就能搞定,不过有几个靠谱的方案,我给你拆解一下:
方案1:自定义模块+事件订阅(推荐,灵活可控)
Drupal 8的事件系统是处理这类状态变更触发操作的最佳实践,Workbench Moderation刚好提供了状态转换的事件,我们可以通过自定义模块监听这个事件,然后实现发邮件逻辑。
步骤1:创建基础自定义模块
先创建一个名为moderation_notifications的模块,核心文件包括:
moderation_notifications.info.yml:模块声明
name: Moderation Notifications type: module description: Sends email notifications when content moderation state transitions occur. core_version_requirement: ^8 || ^9 dependencies: - workbench_moderation:workbench_moderation
moderation_notifications.services.yml:注册事件订阅服务
services: moderation_notifications.subscriber: class: Drupal\moderation_notifications\EventSubscriber\ModerationNotificationSubscriber arguments: ['@plugin.manager.mail', '@entity_type.manager'] tags: - { name: event_subscriber }
步骤2:编写事件订阅类
在src/EventSubscriber/ModerationNotificationSubscriber.php里创建订阅类,监听状态转换事件并处理邮件发送:
<?php namespace Drupal\moderation_notifications\EventSubscriber; use Drupal\workbench_moderation\Event\WorkbenchModerationEvents; use Drupal\workbench_moderation\Event\StateTransitionEvent; use Drupal\Core\Mail\MailManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Event subscriber for moderation state transitions. */ class ModerationNotificationSubscriber implements EventSubscriberInterface { use StringTranslationTrait; /** * The mail manager. * * @var \Drupal\Core\Mail\MailManagerInterface */ protected $mailManager; /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * Constructs a new ModerationNotificationSubscriber object. * * @param \Drupal\Core\Mail\MailManagerInterface $mail_manager * The mail manager. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. */ public function __construct(MailManagerInterface $mail_manager, EntityTypeManagerInterface $entity_type_manager) { $this->mailManager = $mail_manager; $this->entityTypeManager = $entity_type_manager; } /** * {@inheritdoc} */ public static function getSubscribedEvents() { $events[WorkbenchModerationEvents::STATE_TRANSITION][] = ['onStateTransition']; return $events; } /** * React to moderation state transition. * * @param \Drupal\workbench_moderation\Event\StateTransitionEvent $event * The state transition event. */ public function onStateTransition(StateTransitionEvent $event) { // 过滤目标状态转换:仅处理从Draft到Needs Review的情况 $fromStateId = $event->getFromState()->id(); $toStateId = $event->getToState()->id(); if ($fromStateId !== 'draft' || $toStateId !== 'needs_review') { return; } $entity = $event->getEntity(); // 仅处理节点类型(如果需要支持其他实体,可以扩展这里) if ($entity->getEntityTypeId() !== 'node') { return; } // 获取Content Approver角色下的所有用户 $roleStorage = $this->entityTypeManager->getStorage('user_role'); $approverRole = $roleStorage->load('content_approver'); if (!$approverRole) { return; } $userStorage = $this->entityTypeManager->getStorage('user'); $approvers = $userStorage->loadByProperties(['roles' => $approverRole->id()]); if (empty($approvers)) { return; } // 准备邮件参数 $nodeUrl = $entity->toUrl('canonical', ['absolute' => TRUE])->toString(); $mailParams = [ 'subject' => $this->t('New content needs review: @title', ['@title' => $entity->getTitle()]), 'message' => $this->t( 'The content "@title" has been submitted for review. You can view and moderate it here: @url', ['@title' => $entity->getTitle(), '@url' => $nodeUrl] ), ]; // 给每个审批者发送邮件 foreach ($approvers as $user) { $this->mailManager->mail( 'moderation_notifications', 'review_request', $user->getEmail(), $user->getPreferredLangcode(), $mailParams, NULL, // 发件人邮箱,留空用系统默认 TRUE // 是否立即发送 ); } } }
步骤3:实现邮件模板钩子
在moderation_notifications.module文件里添加hook_mail()来定义邮件内容:
<?php /** * Implements hook_mail(). */ function moderation_notifications_mail($key, &$message, $params) { switch ($key) { case 'review_request': $message['subject'] = $params['subject']; $message['body'][] = $params['message']; break; } }
最后一步:启用模块
在后台启用Moderation Notifications模块,之后当节点从Draft转为Needs Review时,Content Approver角色的用户就会收到通知邮件了。
这个方案的优势是完全自定义,你可以轻松扩展逻辑(比如仅针对特定内容类型发送、调整邮件模板、添加抄送等),而且不依赖第三方模块的维护状态。
方案2:社区模块组合(少代码方案)
如果不想写代码,可以尝试使用社区模块workbench_moderation_rules_integration,它为Rules模块添加了Workbench Moderation相关的事件和条件。
操作步骤:
- 安装并启用
Rules和workbench_moderation_rules_integration模块 - 进入Rules配置页面,创建新规则:
- 触发事件选择“After a moderation state has been changed”
- 添加条件:检查原状态是Draft,目标状态是Needs Review,且实体类型是节点
- 添加动作:选择“Send email to users with role”,选择Content Approver角色,配置邮件主题和内容
注意:这个方案依赖社区模块,需要确认模块是否兼容你的Drupal 8版本,部分老版本可能存在兼容性问题。
方案3:Hook实现(备选)
如果不想用事件订阅,也可以通过实体更新的Hook来实现,不过这不是Drupal 8的最佳实践,但作为备选方案也可行:
在moderation_notifications.module里添加:
<?php use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Mail\MailManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Implements hook_entity_update(). */ function moderation_notifications_entity_update(EntityInterface $entity) { // 仅处理节点且有 moderation_state 字段的情况 if ($entity->getEntityTypeId() !== 'node' || !$entity->hasField('moderation_state')) { return; } // 获取原状态和当前状态 $originalState = $entity->original->get('moderation_state')->target_id; $currentState = $entity->get('moderation_state')->target_id; // 过滤目标转换 if ($originalState !== 'draft' || $currentState !== 'needs_review') { return; } // 以下发邮件逻辑和方案1中的代码一致,这里不再重复 // ... }
内容的提问来源于stack exchange,提问作者Juhani

