diff --git includes/menu.inc includes/menu.inc index 3519636..c793ae3 100644 --- includes/menu.inc +++ includes/menu.inc @@ -1092,6 +1092,10 @@ function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) { * The named menu links to return. * @param $max_depth * (optional) The maximum depth of links to retrieve. + * @param $only_active_trail + * (optional) Whether to only return the links in the active trail (TRUE) + * instead of all links on every level of the menu link tree (FALSE). Defaults + * to FALSE. Internally used for breadcrumbs only. * * @return * An array of menu links, in the order they should be rendered. The array @@ -1100,7 +1104,7 @@ function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) { * submenu below the link if there is one, and it is a subtree that has the * same structure described for the top-level array. */ -function menu_tree_page_data($menu_name, $max_depth = NULL) { +function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail = FALSE) { $tree = &drupal_static(__FUNCTION__, array()); // Load the menu item corresponding to the current page. @@ -1110,6 +1114,17 @@ function menu_tree_page_data($menu_name, $max_depth = NULL) { } // Generate a cache ID (cid) specific for this page. $cid = 'links:' . $menu_name . ':page:' . $item['href'] . ':' . $GLOBALS['language']->language . ':' . (int) $item['access'] . ':' . (int) $max_depth; + // If we are asked for the active trail only, and $menu_name has not been + // built and cached for this page yet, then this likely means that it + // won't be built anymore, as this function is invoked from + // template_preprocess_page(). So in order to not build a giant menu tree + // that needs to be checked for access on all levels, we simply check + // whether we have the menu already in cache, or otherwise, build a minimum + // tree containing the breadcrumb/active trail only. + // @see menu_set_active_trail() + if (!isset($tree[$cid]) && $only_active_trail) { + $cid .= ':trail'; + } if (!isset($tree[$cid])) { // If the static variable doesn't have the data, check {cache_menu}. @@ -1146,13 +1161,18 @@ function menu_tree_page_data($menu_name, $max_depth = NULL) { $active_trail[$active_link['p' . $i]] = $active_link['p' . $i]; } } + // If we are asked to build links for the active trail only, skip + // the entire 'expanded' handling. + if ($only_active_trail) { + $tree_parameters['only_active_trail'] = TRUE; + } } } $parents = $active_trail; $expanded = variable_get('menu_expanded', array()); // Check whether the current menu has any links set to be expanded. - if (in_array($menu_name, $expanded)) { + if (!$only_active_trail && 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 { @@ -1202,9 +1222,12 @@ function menu_tree_page_data($menu_name, $max_depth = NULL) { * (optional) An associative array of build parameters. Possible keys: * - expanded: An array of parent link ids to return only menu links that are * children of one of the plids in this list. If empty, the whole menu tree - * is built. + * is built, unless 'only_active_trail' is TRUE. * - active_trail: An array of mlids, representing the coordinates of the * currently active menu link. + * - only_active_trail: Whether to only return links that are in the active + * trail. This option is ignored, if 'expanded' is non-empty. Internally + * used for breadcrumbs only. * - min_depth: The minimum depth of menu links in the resulting tree. * Defaults to 1, which is the default to build a whole tree for a menu, i.e. * excluding menu container itself. @@ -1282,6 +1305,9 @@ function _menu_build_tree($menu_name, array $parameters = array()) { if (!empty($parameters['expanded'])) { $query->condition('ml.plid', $parameters['expanded'], 'IN'); } + elseif (!empty($parameters['only_active_trail'])) { + $query->condition('ml.mlid', $parameters['active_trail'], 'IN'); + } $min_depth = (isset($parameters['min_depth']) ? $parameters['min_depth'] : 1); if ($min_depth != 1) { $query->condition('ml.depth', $min_depth, '>='); @@ -2171,7 +2197,10 @@ function menu_set_active_trail($new_trail = NULL) { // There is a link for the current path. if ($preferred_link) { - $tree = menu_tree_page_data($preferred_link['menu_name']); + // Pass TRUE for $only_active_trail to make menu_tree_page_data() build + // a stripped down menu tree containing the active trail only, in case + // the given menu has not been built in this request yet. + $tree = menu_tree_page_data($preferred_link['menu_name'], NULL, TRUE); list($key, $curr) = each($tree); } // There is no link for the current path. diff --git includes/theme.inc includes/theme.inc index 658128c..b2e34bc 100644 --- includes/theme.inc +++ includes/theme.inc @@ -2257,7 +2257,6 @@ function template_preprocess_page(&$variables) { $variables['base_path'] = base_path(); $variables['front_page'] = url(); - $variables['breadcrumb'] = theme('breadcrumb', array('breadcrumb' => drupal_get_breadcrumb())); $variables['feed_icons'] = drupal_get_feeds(); $variables['language'] = $GLOBALS['language']; $variables['language']->dir = $GLOBALS['language']->direction ? 'rtl' : 'ltr'; @@ -2269,6 +2268,11 @@ function template_preprocess_page(&$variables) { $variables['site_name'] = (theme_get_setting('toggle_name') ? filter_xss_admin(variable_get('site_name', 'Drupal')) : ''); $variables['site_slogan'] = (theme_get_setting('toggle_slogan') ? filter_xss_admin(variable_get('site_slogan', '')) : ''); $variables['tabs'] = theme('menu_local_tasks'); + // Build the breadcrumb last, so as to increase the chance of being able to + // re-use the cache of an already rendered menu containing the active link + // for the current page. + // @see menu_tree_page_data() + $variables['breadcrumb'] = theme('breadcrumb', array('breadcrumb' => drupal_get_breadcrumb())); $variables['title'] = drupal_get_title(); if ($node = menu_get_object()) {