TIP: dealing with Drupal (menu) paths, path arguments, and path wildcards

HOT TIP: this content is flagged as highly recommended !

This zone is about programmatic argument extraction, when dealing with Views it has its own very clever and handy ways of extracting arguments from invoked paths.

Your first step is to read (very carefully) every single word (from top to bottom) of the entire documentation to hook_menu(). You haven't a hope in hell of understanding how Drupal paths and path arguments work without it.

Pay special attention to the section on _to_arg() function patterns, which are the easiest way to extract, for example, the uid from paths like /user/%uid/edit, as illustrated by user_uid_optional_to_arg($arg).

Being Drupal, you also have to be wary of functions like drupal_lookup_path($action, $path = '', $path_language = NULL) that still haven't decided yet what they are supposed to be doing:

Given an alias, return its Drupal system URL if one exists. Given a Drupal system URL return one of its aliases if such a one exists. Otherwise, return FALSE.

Well of course, why have two clearly documents functions with dedicated purpose when you can do sneaky things "the Drupal way" and have one that does the opposite of itself sometimes ?

That's it ! I'll make a fortune with a new kind of ice-cream van that takes away (one of) your ice-cream(s) from you and gives you your money back (but only when the moon is full).

Another thing to be careful of when extracting path arguments is whether you are working with the underlying Drupal path or the path alias.

You can get the current real "external" path as called using $_SERVER['REQUEST_URI']. But often you want to be working with the underlying (internal) path, for which you need arg($index = NULL, $path = NULL), which:

Returns a component of the current Drupal path.

It is instructive to inspect the difference between these (and also to browse and actual menu_router table):

- menu_get_item($path = NULL, $router_item = NULL):

Gets a router item.


$path: The path; for example, 'node/5'. The function will find the corresponding node/% item and return that.

$router_item: Internal use only.

Return value

The router item or, if an error occurs in _menu_translate(), FALSE. A router item is an associative array corresponding to one row in the menu_router table. The value corresponding to the key 'map' holds the loaded objects. The value corresponding to the key 'access' is TRUE if the current user can access this page. The values corresponding to the keys 'title', 'page_arguments', 'access_arguments', and 'theme_arguments' will be filled in based on the database values and the objects loaded.

- menu_get_object($type = 'node', $position = 1, $path = NULL):

Gets a loaded object from a router item.

menu_get_object() provides access to objects loaded by the current router item. For example, on the page node/%node, the router loads the %node object, and calling menu_get_object() will return that. Normally, it is necessary to specify the type of object referenced, however node is the default. The following example tests to see whether the node being displayed is of the "story" content type:

$node = menu_get_object();
$story = $node->type == 'story';


$type: Type of the object. These appear in hook_menu definitions as %type. Core provides aggregator_feed, aggregator_category, contact, filter_format, forum_term, menu, menu_link, node, taxonomy_vocabulary, user. See the relevant {$type}_load function for more on each. Defaults to node.

$position: The position of the object in the path, where the first path segment is 0. For node/%node, the position of %node is 1, but for comment/reply/%node, it's 2. Defaults to 1.

$path: See menu_get_item() for more on this. Defaults to the current path.

There is also a good explanation of these in the answers on this forum.

Visit also