Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.431 diff -u -p -r1.431 menu.inc --- includes/menu.inc 4 Jan 2011 06:20:30 -0000 1.431 +++ includes/menu.inc 13 Jan 2011 00:02:14 -0000 @@ -1191,23 +1191,23 @@ function menu_tree_page_data($menu_name, ); // Parent mlids; used both as key and value to ensure uniqueness. // We always want all the top-level links with plid == 0. - $active_trail = array(0 => 0); + $active_trail = $parents = array(0 => 0); // If the item for the current page is accessible, build the tree // parameters accordingly. if ($item['access']) { // Find a menu link corresponding to the current path. - if ($active_link = menu_link_get_preferred()) { + if ($preferred_link = menu_link_get_preferred()) { // The active link may only be taken into account to build the // active trail, if it resides in the requested menu. Otherwise, // we'd needlessly re-run _menu_build_tree() queries for every menu // on every page. - if ($active_link['menu_name'] == $menu_name) { + if ($preferred_link['menu_name'] == $menu_name) { // Use all the coordinates, except the last one because there // can be no child beyond the last column. for ($i = 1; $i < MENU_MAX_DEPTH; $i++) { - if ($active_link['p' . $i]) { - $active_trail[$active_link['p' . $i]] = $active_link['p' . $i]; + if ($preferred_link['p' . $i]) { + $active_trail[$preferred_link['p' . $i]] = $preferred_link['p' . $i]; } } // If we are asked to build links for the active trail only, skip @@ -1217,7 +1217,19 @@ function menu_tree_page_data($menu_name, } } } - $parents = $active_trail; + + // Get all of the active links corresponding to the current path + if ($all_active_links = menu_link_get_active()) { + foreach ($all_active_links as $active_link) { + // Use all the coordinates, except the last one because there + // can be no child beyond the last column. + for ($i = 1; $i < MENU_MAX_DEPTH; $i++) { + if ($active_link['p' . $i]) { + $parents[$active_link['p' . $i]] = $active_link['p' . $i]; + } + } + } + } $expanded = variable_get('menu_expanded', array()); // Check whether the current menu has any links set to be expanded. @@ -2415,6 +2427,79 @@ function menu_link_get_preferred($path = } /** + * Lookup the active menu links for a given system path. + * + * @param $path + * The path, for example 'node/5'. The function will find the corresponding + * menu link ('node/5' if it exists, or fallback to 'node/%'). + * + * @return + * An array of fully translated menu links, or NULL if not matching menu link was + * found. The most specific menu links ('node/5' preferred over 'node/%') is + * returned. + */ +function menu_link_get_active($path = NULL) { + $menu_links = &drupal_static(__FUNCTION__); + + if (!isset($path)) { + $path = $_GET['q']; + } + + if (!isset($menu_links[$path])) { + $menu_links[$path] = FALSE; + + // Look for the correct menu link by building a list of candidate paths, + // which are ordered by priority (translated hrefs are preferred over + // untranslated paths). Afterwards, the most relevant path is picked from + // the menus, ordered by menu preference. + $item = menu_get_item($path); + $path_candidates = array(); + // 1. The current item href. + $path_candidates[$item['href']] = $item['href']; + // 2. The tab root href of the current item (if any). + if ($item['tab_parent'] && ($tab_root = menu_get_item($item['tab_root_href']))) { + $path_candidates[$tab_root['href']] = $tab_root['href']; + } + // 3. The current item path (with wildcards).+ $path_candidates[$item['path']] = $item['path']; + // 4. The tab root path of the current item (if any). + if (!empty($tab_root)) { + $path_candidates[$tab_root['path']] = $tab_root['path']; + } + + $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC)); + $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path'); + $query->fields('ml'); + // Weight must be taken from {menu_links}, not {menu_router}. + $query->addField('ml', 'weight', 'link_weight'); + $query->fields('m'); + $query->condition('ml.link_path', $path_candidates, 'IN'); + + // Sort candidates by link path and menu name. + $candidates = array(); + foreach ($query->execute() as $candidate) { + $candidate['weight'] = $candidate['link_weight']; + $candidates[$candidate['link_path']][] = $candidate; + } + + // Pick the most specific links. + foreach ($path_candidates as $link_path) { + if (!isset($candidates[$link_path])) { + continue; + } + foreach ($candidates[$link_path] as $candidate_item) { + $map = explode('/', $path); + _menu_translate($candidate_item, $map); + if ($candidate_item['access']) { + $menu_links[$path][] = $candidate_item; + } + } + } + } + + return $menu_links[$path]; +} + +/** * Gets the active trail (path to root menu root) of the current page. * * See menu_set_active_trail() for details of return value.