diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 1b1dd79..36fadef 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -282,9 +282,17 @@ function comment_menu() {
     'type' => MENU_LOCAL_TASK,
     'weight' => 0,
   );
-  $items['comment/%/approve'] = array(
+  $items['comment/%/publish'] = array(
     'title' => 'Approve',
-    'page callback' => 'comment_approve',
+    'page callback' => 'comment_publish',
+    'page arguments' => array(1),
+    'access arguments' => array('administer comments'),
+    'file' => 'comment.pages.inc',
+    'weight' => 1,
+  );
+  $items['comment/%/unpublish'] = array(
+    'title' => 'Disapprove',
+    'page callback' => 'comment_unpublish',
     'page arguments' => array(1),
     'access arguments' => array('administer comments'),
     'file' => 'comment.pages.inc',
@@ -333,7 +341,7 @@ function comment_count_unpublished() {
   $count = db_query('SELECT COUNT(cid) FROM {comment} WHERE status = :status', array(
     ':status' => COMMENT_NOT_PUBLISHED,
   ))->fetchField();
-  return t('Unapproved comments (@count)', array('@count' => $count));
+  return t('Unpublished comments (@count)', array('@count' => $count));
 }
 
 /**
@@ -1108,11 +1116,19 @@ function comment_links(Comment $comment, Node $node) {
         'html' => TRUE,
       );
       if ($comment->status == COMMENT_NOT_PUBLISHED) {
-        $links['comment-approve'] = array(
-          'title' => t('approve'),
-          'href' => "comment/$comment->cid/approve",
+        $links['comment-publish'] = array(
+          'title' => t('publish'),
+          'href' => "comment/$comment->cid/publish",
+          'html' => TRUE,
+          'query' => array('token' => drupal_get_token("comment/$comment->cid/publish")),
+        );
+      }
+      else {
+        $links['comment-unpublish'] = array(
+          'title' => t('unpublish'),
+          'href' => "comment/$comment->cid/unpublish",
           'html' => TRUE,
-          'query' => array('token' => drupal_get_token("comment/$comment->cid/approve")),
+          'query' => array('token' => drupal_get_token("comment/$comment->cid/unpublish")),
         );
       }
     }
diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc
index ed91d23..55e8ab0 100644
--- a/core/modules/comment/comment.pages.inc
+++ b/core/modules/comment/comment.pages.inc
@@ -110,12 +110,12 @@ function comment_reply(Node $node, $pid = NULL) {
  *
  * @see comment_menu()
  */
-function comment_approve($cid) {
+function comment_publish($cid) {
   // @todo CSRF tokens are validated in page callbacks rather than access
   //   callbacks, because access callbacks are also invoked during menu link
   //   generation. Add token support to routing: http://drupal.org/node/755584.
   $token = drupal_container()->get('request')->query->get('token');
-  if (!isset($token) || !drupal_valid_token($token, "comment/$cid/approve")) {
+  if (!isset($token) || !drupal_valid_token($token, "comment/$cid/publish")) {
     throw new AccessDeniedHttpException();
   }
 
@@ -123,7 +123,29 @@ function comment_approve($cid) {
     $comment->status = COMMENT_PUBLISHED;
     comment_save($comment);
 
-    drupal_set_message(t('Comment approved.'));
+    drupal_set_message(t('Comment published.'));
+    drupal_goto('node/' . $comment->nid);
+  }
+  throw new NotFoundHttpException();
+}
+
+/**
+ * Menu callback; unpublish specified comment.
+ *
+ * @param $cid
+ *   A comment identifier.
+ */
+function comment_unpublish($cid) {
+  $token = drupal_container()->get('request')->query->get('token');
+  if (!isset($token) || !drupal_valid_token($token, "comment/$cid/unpublish")) {
+    throw new AccessDeniedHttpException();
+  }
+
+  if ($comment = comment_load($cid)) {
+    $comment->status = COMMENT_NOT_PUBLISHED;
+    comment_save($comment);
+
+    drupal_set_message(t('Comment unpublished.'));
     drupal_goto('node/' . $comment->nid);
   }
   throw new NotFoundHttpException();
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php
index 02b3be1..d20ba17 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php
@@ -118,15 +118,28 @@ class CommentApprovalTest extends CommentTestBase {
 
     // Approve comment.
     $this->drupalLogin($this->admin_user);
-    $this->drupalGet('comment/1/approve');
+    $this->drupalGet('comment/1/publish');
     $this->assertResponse(403, t('Forged comment approval was denied.'));
-    $this->drupalGet('comment/1/approve', array('query' => array('token' => 'forged')));
+    $this->drupalGet('comment/1/publish', array('query' => array('token' => 'forged')));
     $this->assertResponse(403, t('Forged comment approval was denied.'));
     $this->drupalGet('node/' . $this->node->nid);
-    $this->clickLink(t('approve'));
+    $this->clickLink(t('publish'));
     $this->drupalLogout();
 
     $this->drupalGet('node/' . $this->node->nid);
     $this->assertTrue($this->commentExists($anonymous_comment4), t('Anonymous comment visible.'));
+
+    // Disapprove comment.
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('comment/1/unpublish');
+    $this->assertResponse(403, t('Forged comment unapproval was denied.'));
+    $this->drupalGet('comment/1/unpublish', array('query' => array('token' => 'forged')));
+    $this->assertResponse(403, t('Forged comment unapproval was denied.'));
+    $this->drupalGet('node/' . $this->node->nid);
+    $this->clickLink(t('unpublish'));
+    $this->drupalLogout();
+
+    $this->drupalGet('node/' . $this->node->nid);
+    $this->assertFalse($this->commentExists($anonymous_comment4), t('Comment was unpublished.'));
   }
 }
