Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.335
diff -u -9 -p -r1.335 menu.inc
--- includes/menu.inc	19 Aug 2009 23:29:13 -0000	1.335
+++ includes/menu.inc	22 Aug 2009 01:51:18 -0000
@@ -1937,29 +1937,37 @@ function _menu_link_build($item) {
   return $item;
 }
 
 /**
  * Helper function to build menu links for the items in the menu router.
  */
 function _menu_navigation_links_rebuild($menu) {
   // Add normal and suggested items as links.
   $menu_links = array();
+  $menu_links_again = array();
   foreach ($menu as $path => $item) {
     if ($item['_visible']) {
-      $menu_links[$path] = $item;
+      $menu_links[] = $item;
       $sort[$path] = $item['_number_parts'];
+      // An item that explicitly refer to its parent must be processed after
+      // the parent, but it must also be processed before its own children, so
+      // process it in the normal order as determined by $item['_number_parts']
+      // and then again when all other items has been processed.
+      if (isset($item['parent path'])) {
+        $menu_links_again[] = $item;
+      }
     }
   }
   if ($menu_links) {
     // Make sure no child comes before its parent.
     array_multisort($sort, SORT_NUMERIC, $menu_links);
 
-    foreach ($menu_links as $item) {
+    foreach (array_merge($menu_links, $menu_links_again) as $item) {
       $existing_item = db_select('menu_links')
         ->fields('menu_links', array(
           'mlid',
           'menu_name',
           'plid',
           'customized',
           'has_children',
           'updated',
         ))
@@ -2122,19 +2130,22 @@ function menu_link_save(&$item) {
     'updated' => 0,
   );
   $existing_item = FALSE;
   if (isset($item['mlid'])) {
     if ($existing_item = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $item['mlid']))->fetchAssoc()) {
       $existing_item['options'] = unserialize($existing_item['options']);
     }
   }
 
-  if (isset($item['plid'])) {
+  if (isset($item['parent path'])) {
+    $parent = db_query("SELECT * FROM {menu_links} WHERE link_path = :link_path", array(':link_path' => $item['parent path']))->fetchAssoc();
+  }
+  elseif (isset($item['plid'])) {
     if ($item['plid']) {
       $parent = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $item['plid']))->fetchAssoc();
     }
     else {
       // Don't bother with the query - mlid can never equal zero..
       $parent = FALSE;
     }
   }
   else {
Index: modules/menu/menu.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.api.php,v
retrieving revision 1.9
diff -u -9 -p -r1.9 menu.api.php
--- modules/menu/menu.api.php	11 Jul 2009 13:56:21 -0000	1.9
+++ modules/menu/menu.api.php	22 Aug 2009 01:51:18 -0000
@@ -29,19 +29,19 @@
  *   - "title callback": Function to generate the title, defaults to t().
  *     If you require only the raw string to be output, set this to FALSE.
  *   - "title arguments": Arguments to send to t() or your custom callback.
  *   - "description": The untranslated description of the menu item.
  *   - "page callback": The function to call to display a web page when the user
  *     visits the path. If omitted, the parent menu item's callback will be used
  *     instead.
  *   - "page arguments": An array of arguments to pass to the page callback
  *     function. Integer values pass the corresponding URL component (see arg()).
- *   - "access callback": A  function returning a boolean value that determines
+ *   - "access callback": A function returning a boolean value that determines
  *     whether the user has access rights to this menu item. Defaults to
  *     user_access() unless a value is inherited from a parent menu item.
  *   - "access arguments": An array of arguments to pass to the access callback
  *     function. Integer values pass the corresponding URL component.
  *   - "file": A file that will be included before the callbacks are accessed;
  *     this allows callback functions to be in separate files. The file should
  *     be relative to the implementing module's directory unless otherwise
  *     specified by the "file path" option.
  *   - "file path": The path to the folder containing the file specified in
@@ -54,18 +54,21 @@
  *     arguments. There are also two "magic" values: "%index" will correspond
  *     to the URL index where the object's load function is specified; "%map"
  *     will correspond to the full menu map, passed in by reference to the
  *     load function.
  *   - "weight": An integer that determines relative position of items in the
  *     menu; higher-weighted items sink. Defaults to 0. When in doubt, leave
  *     this alone; the default alphabetical order is usually best.
  *   - "menu_name": Optional. Set this to a custom menu if you don't want your
  *     item to be placed in Navigation.
+ *   - "parent path": Optional. The path of the menu item's parent. This
+ *      overrides the default parent and allows a menu item to use a path that
+ *      begins with a different string than the parent path.
  *   - "type": A bitmask of flags describing properties of the menu item.
  *     Many shortcut bitmasks are provided as constants in menu.inc:
  *     - MENU_NORMAL_ITEM: Normal menu items show up in the menu tree and can be
  *       moved/hidden by the administrator.
  *     - MENU_CALLBACK: Callbacks simply register a path so that the correct
  *       function is fired when the URL is accessed.
  *     - MENU_SUGGESTED_ITEM: Modules may "suggest" menu items that the
  *       administrator may enable.
  *     - MENU_LOCAL_TASK: Local tasks are rendered as tabs by default.
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1104
diff -u -9 -p -r1.1104 node.module
--- modules/node/node.module	21 Aug 2009 14:27:45 -0000	1.1104
+++ modules/node/node.module	22 Aug 2009 01:51:19 -0000
@@ -1757,24 +1757,28 @@ function node_menu() {
     $items['node/add/' . $type_url_str] = array(
       'title' => $type->name,
       'title callback' => 'check_plain',
       'page callback' => 'node_add',
       'page arguments' => array(2),
       'access callback' => 'node_access',
       'access arguments' => array('create', $type->type),
       'description' => $type->description,
     );
+    // Do not use the admin/structure/types prefix in order to avoid conflicts
+    // e.g. with admin/structure/types/add for a node type whose machine name
+    // is "add".
     $items['admin/structure/node-type/' . $type_url_str] = array(
       'title' => $type->name,
       'page callback' => 'drupal_get_form',
       'page arguments' => array('node_type_form', $type),
       'access arguments' => array('administer content types'),
       'type' => MENU_CALLBACK,
+      'parent' => 'admin/structure/types',
     );
     $items['admin/structure/node-type/' . $type_url_str . '/edit'] = array(
       'title' => 'Edit',
       'type' => MENU_DEFAULT_LOCAL_TASK,
     );
     $items['admin/structure/node-type/' . $type_url_str . '/delete'] = array(
       'title' => 'Delete',
       'page arguments' => array('node_type_delete_confirm', $type),
       'access arguments' => array('administer content types'),
Index: modules/simpletest/tests/menu.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/menu.test,v
retrieving revision 1.13
diff -u -9 -p -r1.13 menu.test
--- modules/simpletest/tests/menu.test	14 Jul 2009 20:53:16 -0000	1.13
+++ modules/simpletest/tests/menu.test	22 Aug 2009 01:51:19 -0000
@@ -97,21 +97,25 @@ class MenuIncTestCase extends DrupalWebT
   }
 
   /**
    * Tests for menu hiearchy.
    */
   function testMenuHiearchy() {
     $parent_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent'))->fetchAssoc();
     $child_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent/child'))->fetchAssoc();
     $unattached_child_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent/child2/child'))->fetchAssoc();
+    $stepchild_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent2/stepchild'))->fetchAssoc();
+    $stepchild_child_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent2/stepchild/child'))->fetchAssoc();
 
     $this->assertEqual($child_link['plid'], $parent_link['mlid'], t('The parent of a directly attached child is correct.'));
     $this->assertEqual($unattached_child_link['plid'], $parent_link['mlid'], t('The parent of a non-directly attached child is correct.'));
+    $this->assertEqual($stepchild_link['plid'], $parent_link['mlid'], t('The parent of a stepchild is correct.'));
+    $this->assertEqual($stepchild_child_link['plid'], $stepchild_link['mlid'], t("The parent of a stepchild's child is correct."));
   }
 
   /**
    * Test menu_set_item().
    */
   function testMenuSetItem() {
     $item = menu_get_item('node');
 
     $this->assertEqual($item['path'], 'node', t("Path from menu_get_item('node') is equal to 'node'"), 'menu');
Index: modules/simpletest/tests/menu_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/menu_test.module,v
retrieving revision 1.6
diff -u -9 -p -r1.6 menu_test.module
--- modules/simpletest/tests/menu_test.module	14 Jul 2009 20:53:16 -0000	1.6
+++ modules/simpletest/tests/menu_test.module	22 Aug 2009 01:51:19 -0000
@@ -38,18 +38,27 @@ function menu_test_menu() {
   );
   $items['menu-test/hierarchy/parent/child'] = array(
     'title' => 'Child menu router',
     'page callback' => 'node_page_default',
   );
   $items['menu-test/hierarchy/parent/child2/child'] = array(
     'title' => 'Unattached subchild router',
     'page callback' => 'node_page_default',
   );
+  $items['menu-test/hierarchy/parent2/stepchild'] = array(
+    'title' => 'Stepchild menu router',
+    'page callback' => 'node_page_default',
+    'parent path' => 'menu-test/hierarchy/parent',
+  );
+  $items['menu-test/hierarchy/parent2/stepchild/child'] = array(
+    'title' => 'Child of stepchild menu router',
+    'page callback' => 'node_page_default',
+  );
   return $items;
 }
 
 /**
  * Dummy callback for hook_menu() to point to.
  *
  * @return
  *  A random string.
  */
