Skip navigation


6 core.php hook_menu()
7 system.api.php hook_menu()

Define menu items and page callbacks.

This hook enables modules to register paths in order to define how URL requests are handled. Paths may be registered for URL handling only, or they can register a link to be placed in a menu (usually the Navigation menu). A path and its associated information is commonly called a "menu router item". This hook is rarely called (for example, when modules are enabled), and its results are cached in the database.

hook_menu() implementations return an associative array whose keys define paths and whose values are an associative array of properties for each path. (The complete list of properties is in the return value section below.)

The definition for each path may include a page callback function, which is invoked when the registered path is requested. If there is no other registered path that fits the requested path better, any further path components are passed to the callback function. For example, your module could register path 'abc/def':

  function mymodule_menu() {
    $items['abc/def'] = array(
      'page callback' => 'mymodule_abc_view',
    return $items;

  function mymodule_abc_view($ghi = 0, $jkl = '') {
    // ...

When path 'abc/def' is requested, no further path components are in the request, and no additional arguments are passed to the callback function (so $ghi and $jkl would take the default values as defined in the function signature). When 'abc/def/123/foo' is requested, $ghi will be '123' and $jkl will be 'foo'. Note that this automatic passing of optional path arguments applies only to page and theme callback functions.

In addition to optional path arguments, the page callback and other callback functions may specify argument lists as arrays. These argument lists may contain both fixed/hard-coded argument values and integers that correspond to path components. When integers are used and the callback function is called, the corresponding path components will be substituted for the integers. That is, the integer 0 in an argument list will be replaced with the first path component, integer 1 with the second, and so on (path components are numbered starting from zero). To pass an integer without it being replaced with its respective path component, use the string value of the integer (e.g., '1') as the argument value. This substitution feature allows you to re-use a callback function for several different paths. For example:

  function mymodule_menu() {
    $items['abc/def'] = array(
      'page callback' => 'mymodule_abc_view',
      'page arguments' => array(1, 'foo'),
    return $items;

When path 'abc/def' is requested, the page callback function will get 'def' as the first argument and (always) 'foo' as the second argument.

If a page callback function uses an argument list array, and its path is requested with optional path arguments, then the list array's arguments are passed to the callback function first, followed by the optional path arguments. Using the above example, when path 'abc/def/bar/baz' is requested, mymodule_abc_view() will be called with 'def', 'foo', 'bar' and 'baz' as arguments, in that order.

Special care should be taken for the page callback drupal_get_form(), because your specific form callback function will always receive $form and &$form_state as the first function arguments:

  function mymodule_abc_form($form, &$form_state) {
    // ...
    return $form;

See Form API documentation for details.

Wildcards within paths also work with integer substitution. For example, your module could register path 'my-module/%/edit':

  $items['my-module/%/edit'] = array(
    'page callback' => 'mymodule_abc_edit',
    'page arguments' => array(1),

When path 'my-module/foo/edit' is requested, integer 1 will be replaced with 'foo' and passed to the callback function.

Registered paths may also contain special "auto-loader" wildcard components in the form of '%mymodule_abc', where the '%' part means that this path component is a wildcard, and the 'mymodule_abc' part defines the prefix for a load function, which here would be named mymodule_abc_load(). When a matching path is requested, your load function will receive as its first argument the path component in the position of the wildcard; load functions may also be passed additional arguments (see "load arguments" in the return value section below). For example, your module could register path 'my-module/%mymodule_abc/edit':

  $items['my-module/%mymodule_abc/edit'] = array(
    'page callback' => 'mymodule_abc_edit',
    'page arguments' => array(1),

When path 'my-module/123/edit' is requested, your load function mymodule_abc_load() will be invoked with the argument '123', and should load and return an "abc" object with internal id 123:

  function mymodule_abc_load($abc_id) {
    return db_query("SELECT * FROM {mymodule_abc} WHERE abc_id = :abc_id", array(':abc_id' => $abc_id))->fetchObject();

This 'abc' object will then be passed into the page callback function mymodule_abc_edit() to replace the integer 1 in the page arguments.

You can also make groups of menu items to be rendered (by default) as tabs on a page. To do that, first create one menu item of type MENU_NORMAL_ITEM, with your chosen path, such as 'foo'. Then duplicate that menu item, using a subdirectory path, such as 'foo/tab1', and changing the type to MENU_DEFAULT_LOCAL_TASK to make it the default tab for the group. Then add the additional tab items, with paths such as "foo/tab2" etc., with type MENU_LOCAL_TASK. Example:

// Make "Foo settings" appear on the admin Config page
$items['admin/config/foo'] = array(
  'title' => 'Foo settings',
  'type' => MENU_NORMAL_ITEM,
  // Page callback, etc. need to be added here.
// Make "Global settings" the main tab on the "Foo settings" page
$items['admin/config/foo/global'] = array(
  'title' => 'Global settings',
  // Access callback, page callback, and theme callback will be inherited
  // from 'admin/config/foo', if not specified here to override.
// Make an additional tab called "Node settings" on "Foo settings"
$items['admin/config/foo/node'] = array(
  'title' => 'Node settings',
  'type' => MENU_LOCAL_TASK,
  // Page callback and theme callback will be inherited from
  // 'admin/config/foo', if not specified here to override.
  // Need to add access callback or access arguments.

Return value

An array of menu items. Each menu item has a key corresponding to the Drupal path being registered. The corresponding array value is an associative array that may contain the following key-value pairs:

  • "title": Required. The untranslated title of the menu item.
  • "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, with path component substitution as described above.
  • "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, with path component substitution as described above.
  • "delivery callback": The function to call to package the result of the page callback function and send it to the browser. Defaults to drupal_deliver_html_page() unless a value is inherited from a parent menu item. Note that this function is called even if the access checks fail, so any custom delivery callback function should take that into account. See drupal_deliver_html_page() for an example.
  • "access callback": A function returning TRUE if the user has access rights to this menu item, and FALSE if not. It can also be a boolean constant instead of a function, and you can also use numeric values (will be cast to boolean). Defaults to user_access() unless a value is inherited from the parent menu item; only MENU_DEFAULT_LOCAL_TASK items can inherit access callbacks. To use the user_access() default callback, you must specify the permission to check as 'access arguments' (see below).
  • "access arguments": An array of arguments to pass to the access callback function, with path component substitution as described above. If the access callback is inherited (see above), the access arguments will be inherited with it, unless overridden in the child menu item.
  • "theme callback": (optional) A function returning the machine-readable name of the theme that will be used to render the page. If not provided, the value will be inherited from a parent menu item. If there is no theme callback, or if the function does not return the name of a current active theme on the site, the theme for this page will be determined by either hook_custom_theme() or the default theme instead. As a general rule, the use of theme callback functions should be limited to pages whose functionality is very closely tied to a particular theme, since they can only be overridden by modules which specifically target those pages in hook_menu_alter(). Modules implementing more generic theme switching functionality (for example, a module which allows the theme to be set dynamically based on the current user's role) should use hook_custom_theme() instead.
  • "theme arguments": An array of arguments to pass to the theme callback function, with path component substitution as described above.
  • "file": A file that will be included before the page callback is called; this allows page 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. Does not apply to other callbacks (only page callback).
  • "file path": The path to the directory containing the file specified in "file". This defaults to the path to the module implementing the hook.
  • "load arguments": An array of arguments to be passed to each of the wildcard object loaders in the path, after the path argument itself. For example, if a module registers path node/%node/revisions/%/view with load arguments set to array(3), the '%node' in the path indicates that the loader function node_load() will be called with the second path component as the first argument. The 3 in the load arguments indicates that the fourth path component will also be passed to node_load() (numbering of path components starts at zero). So, if path node/12/revisions/29/view is requested, node_load(12, 29) will be called. There are also two "magic" values that can be used in load arguments. "%index" indicates the index of the wildcard path component. "%map" indicates the path components as an array. For example, if a module registers for several paths of the form 'user/%user_category/edit/*', all of them can use the same load function user_category_load(), by setting the load arguments to array('%map', '%index'). For instance, if the user is editing category 'foo' by requesting path 'user/32/edit/foo', the load function user_category_load() will be called with 32 as its first argument, the array ('user', 32, 'edit', 'foo') as the map argument, and 1 as the index argument (because %user_category is the second path component and numbering starts at zero). user_category_load() can then use these values to extract the information that 'foo' is the category being requested.
  • "weight": An integer that determines the relative position of items in the menu; higher-weighted items sink. Defaults to 0. Menu items with the same weight are ordered alphabetically.
  • "menu_name": Optional. Set this to a custom menu if you don't want your item to be placed in Navigation.
  • "context": (optional) Defines the context a tab may appear in. By default, all tabs are only displayed as local tasks when being rendered in a page context. All tabs that should be accessible as contextual links in page region containers outside of the parent menu item's primary page context should be registered using one of the following contexts:

    • MENU_CONTEXT_PAGE: (default) The tab is displayed as local task for the page context only.
    • MENU_CONTEXT_INLINE: The tab is displayed as contextual link outside of the primary page context only.

    Contexts can be combined. For example, to display a tab both on a page and inline, a menu router item may specify:

  • "tab_parent": For local task menu items, the path of the task's parent item; defaults to the same path without the last component (e.g., the default parent for 'admin/people/create' is 'admin/people').
  • "tab_root": For local task menu items, the path of the closest non-tab item; same default as "tab_parent".
  • "position": Position of the block ('left' or 'right') on the system administration page for this item.
  • "type": A bitmask of flags describing properties of the menu item. Many shortcut bitmasks are provided as constants in

    • 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 information is generated when the path is accessed.
    • MENU_SUGGESTED_ITEM: Modules may "suggest" menu items that the administrator may enable.
    • MENU_LOCAL_ACTION: Local actions are menu items that describe actions on the parent item such as adding a new user or block, and are rendered in the action-links list in your theme.
    • MENU_LOCAL_TASK: Local tasks are menu items that describe different displays of data, and are generally rendered as tabs.
    • MENU_DEFAULT_LOCAL_TASK: Every set of local tasks should provide one "default" task, which should display the same page as the parent item.

    If the "type" element is omitted, MENU_NORMAL_ITEM is assumed.

  • "options": An array of options to be passed to l() when generating a link from this menu item.

For a detailed usage example, see page_example.module. For comprehensive documentation on the menu system, see

Related topics

88 functions implement hook_menu()

2 invocations of hook_menu()


drupal/modules/system/system.api.php, line 1179
Hooks provided by Drupal core and the System module.


function hook_menu() {
  $items['blog'] = array(
    'title' => 'blogs', 
    'page callback' => 'blog_page', 
    'access arguments' => array('access content'), 
    'type' => MENU_SUGGESTED_ITEM,
  $items['blog/feed'] = array(
    'title' => 'RSS feed', 
    'page callback' => 'blog_feed', 
    'access arguments' => array('access content'), 
    'type' => MENU_CALLBACK,

  return $items;