Issue #460408 by marthinal, dww, David_Rothstein, gpk, joelpittet, markie, aerozeppelin, byronveale, Cottser, david_garcia, acbramley, jojonaloha, nerdcore, gnindl, dotton, girishmuraly, umar-ahmad, joseph.olstad, Webrotta, btopro, wizonesolutions, andrewmacpherson, Bojhan, catch: Cannot administer menu item/link if it points to an unpublished node

merge-requests/756/head
mcdruid 2021-05-27 13:37:52 +01:00
parent 021554e94d
commit f4515a59ea
4 changed files with 90 additions and 14 deletions

View File

@ -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;
}
}
}
}

View File

@ -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',

View File

@ -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.
*/

View File

@ -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'));
}
}