In implementing hook_menu for a module, I am trying to put some items into a submenu.
So far I have something like this
$items['MyModule'] = array(
//...
'page callback' => 'system_admin_menu_block_page',
'file' => 'system.admin.inc',
'file path' => drupal_get_path('module','system'),
);
$items['MyModule/MenuItem1'] = array(
//...
);
$items['MyModule/SubMenu'] = array(
//...
'page callback' => 'system_admin_menu_block_page',
'file' => 'system.admin.inc',
'file path' => drupal_get_path('module','system'),
);
$items['MyModule/SubMenu/SubMenuItem1'] = array(
//...
);
I expect the SubMenu
to appear as, well, a submenu to the MyModule
menu, and for the SubMenuItems
to appear under that submenu. This is the default behaviour described at the Drupal API documentation.
However, all items appear under the MyModule
menu.
- MyModule
- MenuItem1
- SubMenuItem1
- SubMenu
What am I doing wrong?
*EDIT: A typo (which I have fixed) caused SubMenu
to be a separate element rather than a child element of MyModule
. I still don't understand why SubMenuItem1
does not render under the SubMenu
, though.
I can not reproduce your problem - using your menu hierarchy, all entries appear under the navigation menu in the expected order and nesting.
Have you (re)tried from a clean state (that is, with your module uninstalled and the menu entries gone)? To explain why I ask this, I have to elaborate a bit:
Drupal 6 split the menu definition storage in two tables. There is the menu_router
table, which stores the path<>callback relations defined via hook_menu()
. This does not define any 'real' menu entry (as in menu menu, e.g. the navigation menu). It does only define the Drupal internal menu structure, which has nothing to do with the displayed menus, but only with the internal hierarchy of mapping paths to callback functions!
Then there is the menu_links
table, which stores the 'real' menu entries as they appear under the various displayable menus (e.g. navigation, primary links, etc.). The entries there also define the nesting order by storing a 'parent menu id' (plid) for each entry, pointing to the parent entry, or 0 for a top level entry.
Now whenever you define path/callback combinations via hook_menu()
, Drupal just puts that entry into the menu_router
table. If you define them as MENU_NORMAL_ITEM
or MENU_SUGGESTED_ITEM
, Drupal will additionally try to create an entry in the menu_links
table. If an entry for that path already exists, Drupal will not alter its placement in the hierarchy, as it assumes that a user moved it on purpose. You should think of this menu_link
entry creation by hook_menu()
as a convenience add on that can save you the trouble off explicitly adding them via the functions mentioned below, but the mechanism is not very flexible and tries not to interfere with existing configurations (otherwise a manually edited menu would constantly get reordered on every rebuilding of the menu cache).
So you should try again while making sure that none of your paths have an existing entry in the `menu_links' table.
For your goal of providing a proper default menu on install of your module (and for more control over whats happening), you should take a look into the menu_link_save()
and menu_link_maintain()
functions. You might also want to read When and how to use menu_links.
hook_menu isn't really the place to set weighting, I'm sure it can be done there but you'll find that just creating a normal menu item and dragging it into place in the admin's Menus dialogue will save you a ton of hassle and pain.
The reason, as I understand it, is that menu hierarchy is determined in part through a weighting system rather than by the path you set. Convention certainly dictates how people set their path, but just making a normal menu item at admin/monkey does not put a monkey item into the admin menus automagically.