--- menu_block.module.orig 2009-08-14 09:26:33.000000000 -0700 +++ menu_block.module 2009-12-27 17:17:49.443829889 -0800 @@ -164,7 +164,7 @@ function _menu_block_block_view($delta) } else { // Get the tree pruned for just the active trail. - $tree = menu_tree_page_data($menu_name); + $tree = menu_block_tree_page_data($menu_name); } // Allow other modules to alter the tree before we begin operations on it. @@ -281,7 +281,7 @@ function menu_block_set_title($item = NU function menu_tree_add_active_path(&$tree) { // Grab any menu item to find the menu_name for this tree. $menu_item = current($tree); - $tree_with_trail = menu_tree_page_data($menu_item['link']['menu_name']); + $tree_with_trail = menu_block_tree_page_data($menu_item['link']['menu_name']); // To traverse the original tree down the active trail, we use a pointer. $subtree_pointer =& $tree; @@ -518,3 +518,119 @@ function menu_block_tree_output(&$tree) } return $output ? theme('menu_tree', $output) : ''; } + +/** + * Modified menu_tree_page_data() keeps active path for map/href discrepencies. + * + * 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. + * + * @param $menu_name + * The named menu links to return + * @return + * 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. + */ +function menu_block_tree_page_data($menu_name = 'navigation') { + static $tree = array(); + // Load the menu item corresponding to the current page. + if ($item = menu_get_item()) { + // Generate a cache ID (cid) specific for this page. + $cid = 'links:'. $menu_name .':page-cid:'. $item['href'] .':'. (int)$item['access']; + + if (!isset($tree[$cid])) { +/* we can't use the main menu caching system with our hack @TODO fix this + // 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; + } + } +*/ +$data = NULL; // End short-circuiting of caching. @TODO find way to keep. + // 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. + // Create the real href from the map if it is simple Views provided + // and not the crazy thing nodes give. This is likely very brittle. + $href = (isset($item['map']) && is_string($item['map'][1])) ? implode('/', $item['map']) : $item['href']; + $args = array($menu_name, $href); + $placeholders = "'%s'"; + if (drupal_is_front_page()) { + $args[] = ''; + $placeholders .= ", '%s'"; + } + $parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE menu_name = '%s' AND link_path IN (". $placeholders .") ORDER BY depth DESC LIMIT 1", $args)); + 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_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s'", $menu_name, $item['tab_root'])); + } + // 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)); + $placeholders = implode(', ', array_fill(0, count($args), '%d')); + $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_query("SELECT mlid FROM {menu_links} WHERE menu_name = '%s' AND expanded = 1 AND has_children = 1 AND plid IN (". $placeholders .') AND mlid NOT IN ('. $placeholders .')', array_merge(array($menu_name), $args, $args)); + $num_rows = FALSE; + while ($item = db_fetch_array($result)) { + $args[] = $item['mlid']; + $num_rows = TRUE; + } + $placeholders = implode(', ', array_fill(0, count($args), '%d')); + } while ($num_rows); + } + array_unshift($args, $menu_name); + } + else { + // Show only the top-level menu items when access is denied. + $args = array($menu_name, '0'); + $placeholders = '%d'; + $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. + $data['tree'] = menu_tree_data(db_query(" + SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.* + FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path + WHERE ml.menu_name = '%s' AND ml.plid IN (". $placeholders .") + ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $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(); +} +