It's really neat how views can be set up to display a path like '$args/foo/bar', but sometimes it's helpful to be able to do up your own pages with the argument in the front or middle of the path. It may be because views isn't able to handle the strange tangle of tables that the modules you are using installed, or it may be because you need to relentlessly optimize a query for the page. In either case, it's time to hack hook_menu(), and in fact, we're going to cheat a little while we're doing it.
The standard texts and pages, or at least the ones I found, were pretty mum on this topic, but a hint pointed me to the user_menu() of the user module, and there I found my solution. Say you've got it set up so that the path should be '$args/foo/bar', '$args/foo/baz', or $args/foo/ban'. Open up your module and scroll down to where you're using hook_menu, or set it up yourself, and enter the following:
<?php
function example_menu($may_cache) {
$items = array();
if (!$may_cache) {
$types = array('bar', 'baz', 'ban');
if (arg(1) == 'foo' && in_array(arg(2), $types)) {
foreach($types as $type) {
$items[] = array(
'path' => arg(0) .'/foo/'. $type,
'callback' => '_example_show_page_callback',
'access' => user_access('access content'),
'callback arguments' => array(arg(0), $type),
'type' => MENU_CALLBACK,
);
}
}
}
return $items;
}
?>Do you see what we're doing here? We're checking the arg() function to test if the parts of the path we're expecting – the 'foo' and the 'bar/baz/ban' – are where we want them, and then if they are then we add in the items to hook_menu() along with whatever the heck is in arg(0) – we don't care what it is at this point. We just pass it along as a callback argument to our event handler, which is hopefully set up somewhere at
_example_show_page_callback($something, $type) {}.
If it turns out we're wrong - if the foo and the bar/baz/ban aren't where we're looking for them, then there's no harm - we just skip right over the code, and no funky new paths are added to hook_menu(). Technically, you only need to add the item into the menu array for the specific arg(2) that you're using this time, but it's just as easy to throw it all in a loop and get them all done at once, and it's a little more clear to future programmers maintaining your code that all three elements in the array are valid options for hook_menu.








Comments
AjK writes:
Here's a slightly different way to do it (this is for Drupal 5):-
<?phpfunction example_menu($may_cache) {
$items = array();
if (!$may_cache) {
$items[] = array(
'path' => arg(0) .'/foo',
'type' => MENU_CALLBACK,
'callback' => '_example_router',
);
}
return $items;
}
function
_example_router() {$args = func_get_args();
if (!
count($args)) {drupal_not_found();
}
else {
switch (array_shift($args)) {
case 'bar':
return _example_bar_handler($args);
break;
case 'baz':
return _example_baz_handler($args);
break;
case 'ban':
return _example_ban_handler($args);
break;
default:
drupal_not_found();
}
}
return;
?>}