Inheritance rules

Before divulging into the various callbacks, we shall know the simple but very powerful inheritance rules. We are using the parents of a given path for this, for example the parents of node/%/view are:
node/%
node

If a page callback is NOT defined for a path, then we look at the closest parent which has one and use it. If the page callback is inherited from a parent, then the page arguments, the file and the file path are inherited from the parent as a whole, but can be overwritten. Most of the time, is only required to overwrite the page arguments and nothing else.

If the page callback is defined for a given path, then there is not inheritance at all and the page arguments, file, and file path must be defined if they are required.

For example:

<?php
  $items
['admin/user/roles'] = array(
   
'title' => 'Roles',
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('user_admin_new_role'),
   
'file' => 'user.admin.inc'
 
);
 
$items['admin/user/roles/edit'] = array(
   
'title' => 'Edit role',
   
'page arguments' => array('user_admin_role'),
  );
?>

The above is a shorthand for:
<?php
  $items
['admin/user/roles'] = array(
   
'title' => 'Roles',
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('user_admin_new_role'),
   
'file' => 'user.admin.inc'
 
);
 
$items['admin/user/roles/edit'] = array(
   
'title' => 'Edit role',
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('user_admin_role'),
   
'file' => 'user.admin.inc',
  );
?>

Note that the 'page callback' and the 'file' are inherited from the parent whilst the 'page arguments' is defined (overwritten) for this path.

If you would have:

<?php
  $items
['admin/user/roles/edit'] = array(
   
'title' => 'Edit role',
  );
?>

then it would be a shorthand for:
<?php
  $items
['admin/user/roles/edit'] = array(
   
'title' => 'Edit role',
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('user_admin_new_role'),
   
'file' => 'user.admin.inc',
  );
?>

In this case the callback, the arguments and the file are inherited.

If you would have:

<?php
  $items
['admin/user/rules'] = array(
   
'title' => 'Access rules',
   
'page callback' => 'user_admin_access',
   
'file' => 'user.admin.inc',
  );
 
$items['admin/user/rules/edit'] = array(
   
'title' => 'Edit rule',
   
'page callback' => 'user_admin_access_edit',
   
'file' => 'user.admin.inc',
  );
?>

In this case there is not inheritance beacuse a 'page callback' is defined for the 'admin/user/rules/edit' path, so if the 'page arguments', 'file', and 'file path' are required, must defined in the menu item definition.

Inheritance for access callbacks was supported the same way as with page callbacks before Drupal 6.2. Since Drupal 6.2 however, access callbacks are only inherited for default local tasks, and not inherited otherwise (neither the callback nor the arguments). Drupal 6.2 and later requires you to provide access callbacks and arguments on all menu items except default local tasks, which should be the same as the parent anyway.

To see how inheritance is built check the implementation of _menu_router_build

Just to clarify the default access behaviour

gpk - May 29, 2008 - 12:15

In the general case (i.e. all cases except default local tasks), if neither 'access callback' nor 'access arguments' is set then access will be denied (the 'access callback' will be set to 0). If 'access callback' is not set but 'access arguments' is then http://api.drupal.org/api/function/user_access/6 *will* be used as the 'access callback', i.e. you don't have to provide the access callback on all menu items - only on those that need to use something other than the default user_access(). If 'access callback' is set but 'access arguments' is not then 'access arguments' defaults to the empty array.

So this statement is slightly misleading:

Drupal 6.2 and later requires you to provide access callbacks and arguments on all menu items except default local tasks

gpk
----
www.alexoria.co.uk

paths do not nest when no inheritance

Dave Cohen - June 14, 2008 - 19:35

It's worth noting that when menu items define page callbacks, this disables inheritance, and it also disables any nesting that you might expect based on paths. In the last example above, the two menu items 'Access rules' (admin/user/rules) and 'Edit rule' (admin/user/rules/edit) will be peers in the Navigation menu, rather than one being nested under the other (as, I personally would have expected).

I can't tell if this is a feature or a bug, in Drupal 6.2.

 
 

Drupal is a registered trademark of Dries Buytaert.