diff --git a/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutPublishNode.php b/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutPublishNode.php
index e3563ae4402e822642954c91e70e0b02f47c74af..b2d85335aacd64964efcf6022ddd94f408bd78bc 100644
--- a/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutPublishNode.php
+++ b/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutPublishNode.php
@@ -53,23 +53,14 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function access($entity, AccountInterface $account = NULL, $return_as_object = FALSE) {
+    /** @var \Drupal\node\NodeInterface $entity */
     if ($entity && $this->moderationInfo->isModeratedEntity($entity)) {
-      drupal_set_message($this->t('One or more entities were skipped as they are under moderation and may not be directly published or unpublished.'));
-      return;
+      drupal_set_message($this->t("@bundle @label were skipped as they are under moderation and may not be directly published.", ['@bundle' => node_get_type_label($entity), '@label' => $entity->getEntityType()->getPluralLabel()]), 'warning');
+      $result = AccessResult::forbidden();
+      return $return_as_object ? $result : $result->isAllowed();
     }
-
-    parent::execute($entity);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
-    $result = parent::access($object, $account, TRUE)
-      ->andif(AccessResult::forbiddenIf($this->moderationInfo->isModeratedEntity($object))->addCacheableDependency($object));
-
-    return $return_as_object ? $result : $result->isAllowed();
+    return parent::access($entity, $account, $return_as_object);
   }
 
 }
diff --git a/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutUnpublishNode.php b/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutUnpublishNode.php
index 28b968991a35d33e1ab4b76fd99c0c7718afc972..ee36169468d57e8baaeb86fb36a5a33f666811bb 100644
--- a/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutUnpublishNode.php
+++ b/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutUnpublishNode.php
@@ -53,23 +53,14 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function access($entity, AccountInterface $account = NULL, $return_as_object = FALSE) {
+    /** @var \Drupal\node\NodeInterface $entity */
     if ($entity && $this->moderationInfo->isModeratedEntity($entity)) {
-      drupal_set_message($this->t('One or more entities were skipped as they are under moderation and may not be directly published or unpublished.'));
-      return;
+      drupal_set_message($this->t("@bundle @label were skipped as they are under moderation and may not be directly unpublished.", ['@bundle' => node_get_type_label($entity), '@label' => $entity->getEntityType()->getPluralLabel()]), 'warning');
+      $result = AccessResult::forbidden();
+      return $return_as_object ? $result : $result->isAllowed();
     }
-
-    parent::execute($entity);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
-    $result = parent::access($object, $account, TRUE)
-      ->andif(AccessResult::forbiddenIf($this->moderationInfo->isModeratedEntity($object))->addCacheableDependency($object));
-
-    return $return_as_object ? $result : $result->isAllowed();
+    return parent::access($entity, $account, $return_as_object);
   }
 
 }
diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationActionsTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationActionsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..32d10fa045cba5cf0faa663b59d5ca30ae2d8962
--- /dev/null
+++ b/core/modules/content_moderation/tests/src/Functional/ModerationActionsTest.php
@@ -0,0 +1,137 @@
+<?php
+
+namespace Drupal\Tests\content_moderation\Functional;
+
+use Drupal\node\Entity\Node;
+use Drupal\simpletest\ContentTypeCreationTrait;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\workflows\Entity\Workflow;
+
+/**
+ * Test the content moderation actions.
+ *
+ * @group content_moderation
+ */
+class ModerationActionsTest extends BrowserTestBase {
+
+  use ContentTypeCreationTrait;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'content_moderation',
+    'node',
+    'views',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $moderated_bundle = $this->createContentType(['type' => 'moderated_bundle']);
+    $moderated_bundle->save();
+    $standard_bundle = $this->createContentType(['type' => 'standard_bundle']);
+    $standard_bundle->save();
+
+    $workflow = Workflow::load('editorial');
+    $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'moderated_bundle');
+    $workflow->save();
+
+    $admin = $this->drupalCreateUser([
+      'access content overview',
+      'administer nodes',
+      'bypass node access',
+    ]);
+    $this->drupalLogin($admin);
+  }
+
+  /**
+   * Test the node status actions report moderation status to users correctly.
+   *
+   * @dataProvider nodeStatusActionsTestCases
+   */
+  public function testNodeStatusActions($action, $bundle, $warning_appears, $starting_status, $final_status) {
+    // Create and run an action on a node.
+    $node = Node::create([
+      'type' => $bundle,
+      'title' => $this->randomString(),
+      'status' => $starting_status,
+    ]);
+    if ($bundle == 'moderated_bundle') {
+      $node->moderation_state->value = $starting_status ? 'published' : 'draft';
+    }
+    $node->save();
+
+    $this->drupalPostForm('admin/content', [
+      'node_bulk_form[0]' => TRUE,
+      'action' => $action,
+    ], 'Apply to selected items');
+
+    if ($warning_appears) {
+      if ($action == 'node_publish_action') {
+        $this->assertSession()
+          ->elementContains('css', '.messages--warning', node_get_type_label($node) . ' content items were skipped as they are under moderation and may not be directly published.');
+      }
+      else {
+        $this->assertSession()
+          ->elementContains('css', '.messages--warning', node_get_type_label($node) . ' content items were skipped as they are under moderation and may not be directly unpublished.');
+      }
+    }
+    else {
+      $this->assertSession()->elementNotExists('css', '.messages--warning');
+    }
+
+    // Ensure after the action has run, the node matches the expected status.
+    $node = Node::load($node->id());
+    $this->assertEquals($node->isPublished(), $final_status);
+  }
+
+  /**
+   * Test cases for ::testNodeStatusActions.
+   *
+   * @return array
+   *   An array of test cases.
+   */
+  public function nodeStatusActionsTestCases() {
+    return [
+      'Moderated bundle shows warning (publish action)' => [
+        'node_publish_action',
+        'moderated_bundle',
+        TRUE,
+        // If the node starts out unpublished, the action should not work.
+        FALSE,
+        FALSE,
+      ],
+      'Moderated bundle shows warning (unpublish action)' => [
+        'node_unpublish_action',
+        'moderated_bundle',
+        TRUE,
+        // If the node starts out published, the action should not work.
+        TRUE,
+        TRUE,
+      ],
+      'Normal bundle works (publish action)' => [
+        'node_publish_action',
+        'standard_bundle',
+        FALSE,
+        // If the node starts out unpublished, the action should work.
+        FALSE,
+        TRUE,
+      ],
+      'Normal bundle works (unpublish action)' => [
+        'node_unpublish_action',
+        'standard_bundle',
+        FALSE,
+        // If the node starts out published, the action should work.
+        TRUE,
+        FALSE,
+      ],
+    ];
+  }
+
+}