diff --git a/includes/menu.inc b/includes/menu.inc index 0f38d6f5088..4a79861b815 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -1500,13 +1500,25 @@ function menu_tree_check_access(&$tree, $node_links = array()) { $nids = array_keys($node_links); $select = db_select('node', 'n'); $select->addField('n', 'nid'); - $select->condition('n.status', 1); + // When a menu administrator who we know has permission to see unpublished + // nodes is administering the menu, included the unpublished nodes in the + // tree, with a special flag so that the Menu module can label them. + // Otherwise, exclude these nodes from the tree. + if (!empty($GLOBALS['menu_admin']) && user_access('bypass node access')) { + $select->addField('n', 'status'); + } + else { + $select->condition('n.status', 1); + } $select->condition('n.nid', $nids, 'IN'); $select->addTag('node_access'); - $nids = $select->execute()->fetchCol(); - foreach ($nids as $nid) { - foreach ($node_links[$nid] as $mlid => $link) { - $node_links[$nid][$mlid]['access'] = TRUE; + $node_objects = $select->execute()->fetchAll(); + foreach ($node_objects as $node_object) { + foreach ($node_links[$node_object->nid] as $mlid => $link) { + $node_links[$node_object->nid][$mlid]['access'] = TRUE; + if (isset($node_object->status)) { + $node_links[$node_object->nid][$mlid]['node_unpublished'] = !$node_object->status; + } } } } diff --git a/modules/menu/menu.admin.inc b/modules/menu/menu.admin.inc index a24703c9fcd..e4d24a697dc 100644 --- a/modules/menu/menu.admin.inc +++ b/modules/menu/menu.admin.inc @@ -100,12 +100,7 @@ function _menu_overview_tree_form($tree) { $form[$mlid]['#item'] = $item; $form[$mlid]['#attributes'] = $item['hidden'] ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled')); $form[$mlid]['title']['#markup'] = l($item['title'], $item['href'], $item['localized_options']); - if ($item['hidden']) { - $form[$mlid]['title']['#markup'] .= ' (' . t('disabled') . ')'; - } - elseif ($item['link_path'] == 'user' && $item['module'] == 'system') { - $form[$mlid]['title']['#markup'] .= ' (' . t('logged in users only') . ')'; - } + menu_add_link_labels($form[$mlid]['title']['#markup'], $item); $form[$mlid]['hidden'] = array( '#type' => 'checkbox', diff --git a/modules/menu/menu.module b/modules/menu/menu.module index 27b1675a39e..5bbee69d047 100644 --- a/modules/menu/menu.module +++ b/modules/menu/menu.module @@ -401,6 +401,9 @@ function menu_parent_options_js() { * Helper function to get the items of the given menu. */ function _menu_get_options($menus, $available_menus, $item) { + global $menu_admin; + $menu_admin = TRUE; + // If the item has children, there is an added limit to the depth of valid parents. if (isset($item['parent_depth_limit'])) { $limit = $item['parent_depth_limit']; @@ -417,6 +420,8 @@ function _menu_get_options($menus, $available_menus, $item) { _menu_parents_recurse($tree, $menu_name, '--', $options, $item['mlid'], $limit); } } + + $menu_admin = FALSE; return $options; } @@ -431,9 +436,7 @@ function _menu_parents_recurse($tree, $menu_name, $indent, &$options, $exclude, } if ($data['link']['mlid'] != $exclude && $data['link']['hidden'] >= 0) { $title = $indent . ' ' . truncate_utf8($data['link']['title'], 30, TRUE, FALSE); - if ($data['link']['hidden']) { - $title .= ' (' . t('disabled') . ')'; - } + menu_add_link_labels($title, $data['link']); $options[$menu_name . ':' . $data['link']['mlid']] = $title; if ($data['below']) { _menu_parents_recurse($data['below'], $menu_name, $indent . '--', $options, $exclude, $depth_limit); @@ -442,6 +445,27 @@ function _menu_parents_recurse($tree, $menu_name, $indent, &$options, $exclude, } } +/** + * Adds labels to the title of a hidden, unpublished or logged-in menu link. + * + * @param string $title + * The title of the menu link. This will be modified as necessary to add the + * appropriate label in parentheses at the end. + * @param array $item + * An array representing the menu link item. + */ +function menu_add_link_labels(&$title, $item) { + if ($item['hidden']) { + $title .= ' (' . t('disabled') . ')'; + } + elseif (!empty($item['node_unpublished'])) { + $title .= ' (' . t('unpublished') . ')'; + } + elseif ($item['link_path'] == 'user' && $item['module'] == 'system') { + $title .= ' (' . t('logged in users only') . ')'; + } +} + /** * Reset a system-defined menu link. */ diff --git a/modules/menu/menu.test b/modules/menu/menu.test index bb792ee8edf..af0d09591e7 100644 --- a/modules/menu/menu.test +++ b/modules/menu/menu.test @@ -604,6 +604,50 @@ class MenuTestCase extends DrupalWebTestCase { $this->assertText(t('Menus'), 'Add menu node was displayed'); } } + + /** + * Tests that menu admin lists can include menu items for unpublished nodes. + */ + function testUnpublishedNodeMenuItem() { + // Log in as an administrator who can view unpublished nodes. + $menu_and_node_admin_user = $this->drupalCreateUser(array( + 'bypass node access', + 'administer menu', + )); + $this->drupalLogin($menu_and_node_admin_user); + + // Create an unpublished node with a menu link. + $title = $this->randomName(); + $node = $this->drupalCreateNode(array( + 'type' => 'article', + 'title' => $title, + 'status' => NODE_NOT_PUBLISHED, + )); + $edit = array( + 'link_path' => 'node/' . $node->nid, + 'link_title' => $title, + 'description' => '', + 'enabled' => TRUE, + 'expanded' => TRUE, + 'parent' => 'navigation:0', + 'weight' => '0', + ); + $this->drupalPost('admin/structure/menu/manage/navigation/add', $edit, t('Save')); + + // Verify that the administrator can see the menu link (with a label + // indicating that it is unpublished) on the menu management page. + $this->drupalGet('admin/structure/menu/manage/navigation'); + $this->assertText($title . ' (unpublished)', 'Menu link to unpublished node is visible to users with "bypass node access" permission.'); + + // Verify that a user who cannot view unpublished nodes does not see the + // menu link on the menu management page. + $menu_admin_user = $this->drupalCreateUser(array('administer menu')); + $this->drupalLogin($menu_admin_user); + $this->drupalGet('admin/structure/menu/manage/navigation'); + $this->assertResponse(200); + $this->assertNoText($title, 'Menu link to unpublished node is not visible to users without the "bypass node access" permission.'); + } + } /** @@ -758,4 +802,5 @@ class MenuNodeTestCase extends DrupalWebTestCase { $options = $this->xpath('//select[@id=:id]//option[@value=:option]', array(':id' => $id, ':option' => $option)); return $this->assertTrue(isset($selects[0]) && !isset($options[0]), $message ? $message : t('Option @option for field @id does not exist.', array('@option' => $option, '@id' => $id)), t('Browser')); } + }