Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.255.2.31 diff -u -p -r1.255.2.31 menu.inc --- includes/menu.inc 27 Apr 2009 12:50:13 -0000 1.255.2.31 +++ includes/menu.inc 16 Aug 2009 01:44:56 -0000 @@ -1891,7 +1891,12 @@ function menu_link_save(&$item) { $existing_item = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['mlid'])); } - if (isset($item['plid'])) { + // If no explicit plid is defined as parent, then the the re-parenting process + // is always invoked, since there is no guarantee that a plid of 0 is not + // caused by a re-parenting process that went wrong previously. For example, + // local tasks may be re-parented to the top-level (0) when tab_root points to + // an item of type MENU_CALLBACK. + if (!empty($item['plid'])) { $parent = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['plid'])); } else { @@ -1918,6 +1923,14 @@ function menu_link_save(&$item) { $parent = db_fetch_array(db_query("SELECT * FROM {menu_links} ". $where, $parent_path, $arg2)); } } while ($parent === FALSE && $parent_path); + + // Whenever we retrieve a menu link for a router item from the database, we + // need to update the menu link properties according to the new router item. + // Otherwise, the re-parenting process gets stuck on the menu router data + // that was stored in {menu_links} in the previous rebuild. + if ($parent && !empty($parent['router_path']) && isset($menu[$parent['router_path']])) { + $parent = array_merge($parent, _menu_link_build($parent)); + } } if ($parent !== FALSE) { $item['menu_name'] = $parent['menu_name'];