menu_tree_page_data($menu_name, $max_depth = NULL)Get the data structure representing a named menu tree, based on the current page.
The tree order is maintained by storing each parent in an individual field, see http://drupal.org/node/141866 for more.
$menu_name The named menu links to return
$max_depth Optional maximum depth of links to retrieve.
An array of menu links, in the order they should be rendered. The array is a list of associative arrays -- these have two keys, link and below. link is a menu item, ready for theming as a link. Below represents the submenu below the link if there is one, and it is a subtree that has the same structure described for the top-level array.
includes/menu.inc, line 1074
<?php
function menu_tree_page_data($menu_name, $max_depth = NULL) {
$tree = &drupal_static(__FUNCTION__, array());
// Load the menu item corresponding to the current page.
if ($item = menu_get_item()) {
if (isset($max_depth)) {
$max_depth = min($max_depth, MENU_MAX_DEPTH);
}
// Generate a cache ID (cid) specific for this page.
$cid = 'links:' . $menu_name . ':page-cid:' . $item['href'] . ':' . $GLOBALS['language']->language . ':' . (int)$item['access'] . ':' . (int)$max_depth;
if (!isset($tree[$cid])) {
// If the static variable doesn't have the data, check {cache_menu}.
$cache = cache_get($cid, 'cache_menu');
if ($cache && isset($cache->data)) {
// If the cache entry exists, it will just be the cid for the actual data.
// This avoids duplication of large amounts of data.
$cache = cache_get($cache->data, 'cache_menu');
if ($cache && isset($cache->data)) {
$data = $cache->data;
}
}
// If the tree data was not in the cache, $data will be NULL.
if (!isset($data)) {
// Build and run the query, and build the tree.
if ($item['access']) {
// Check whether a menu link exists that corresponds to the current path.
$args[] = $item['href'];
if (drupal_is_front_page()) {
$args[] = '<front>';
}
$parents = db_select('menu_links')
->fields('menu_links', array(
'p1',
'p2',
'p3',
'p4',
'p5',
'p6',
'p7',
'p8',
))
->condition('menu_name', $menu_name)
->condition('link_path', $args, 'IN')
->execute()->fetchAssoc();
if (empty($parents)) {
// If no link exists, we may be on a local task that's not in the links.
// TODO: Handle the case like a local task on a specific node in the menu.
$parents = db_select('menu_links')
->fields('menu_links', array(
'p1',
'p2',
'p3',
'p4',
'p5',
'p6',
'p7',
'p8',
))
->condition('menu_name', $menu_name)
->condition('link_path', $item['tab_root'])
->execute()->fetchAssoc();
}
// We always want all the top-level links with plid == 0.
$parents[] = '0';
// Use array_values() so that the indices are numeric for array_merge().
$args = $parents = array_unique(array_values($parents));
$expanded = variable_get('menu_expanded', array());
// Check whether the current menu has any links set to be expanded.
if (in_array($menu_name, $expanded)) {
// Collect all the links set to be expanded, and then add all of
// their children to the list as well.
do {
$result = db_select('menu_links', NULL, array('fetch' => PDO::FETCH_ASSOC))
->fields('menu_links', array('mlid'))
->condition('menu_name', $menu_name)
->condition('expanded', 1)
->condition('has_children', 1)
->condition('plid', $args, 'IN')
->condition('mlid', $args, 'NOT IN')
->execute();
$num_rows = FALSE;
foreach ($result as $item) {
$args[] = $item['mlid'];
$num_rows = TRUE;
}
} while ($num_rows);
}
}
else {
// Show only the top-level menu items when access is denied.
$args = array(0);
$parents = array();
}
// Select the links from the table, and recursively build the tree. We
// LEFT JOIN since there is no match in {menu_router} for an external
// link.
$query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC));
$query->addTag('translatable');
$query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
$query->fields('ml');
$query->fields('m', array(
'load_functions',
'to_arg_functions',
'access_callback',
'access_arguments',
'page_callback',
'page_arguments',
'delivery_callback',
'title',
'title_callback',
'title_arguments',
'theme_callback',
'theme_arguments',
'type',
'description',
));
for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
$query->orderBy('p' . $i, 'ASC');
}
$query->condition('ml.menu_name', $menu_name);
$query->condition('ml.plid', $args, 'IN');
if (isset($max_depth)) {
$query->condition('ml.depth', $max_depth, '<=');
}
// Build an ordered array of links using the query result object.
$links = array();
foreach ($query->execute() as $item) {
$links[] = $item;
}
$data['tree'] = menu_tree_data($links, $parents);
$data['node_links'] = array();
menu_tree_collect_node_links($data['tree'], $data['node_links']);
// Cache the data, if it is not already in the cache.
$tree_cid = _menu_tree_cid($menu_name, $data);
if (!cache_get($tree_cid, 'cache_menu')) {
cache_set($tree_cid, $data, 'cache_menu');
}
// Cache the cid of the (shared) data using the page-specific cid.
cache_set($cid, $tree_cid, 'cache_menu');
}
// Check access for the current user to each item in the tree.
menu_tree_check_access($data['tree'], $data['node_links']);
$tree[$cid] = $data['tree'];
}
return $tree[$cid];
}
return array();
}
?>