The menu system introduced in Drupal 6 also supports conditional loading of an extra include file for each menu entry. That allows module developers to separate off their page handler functions to separate files that are loaded only as-needed. In many modules the majority of the code is page handlers, but on any given page request only one page handler is called in all of Drupal. Separating those functions out to conditional files can save a great deal of overhead from parsing functions that will never be used.
Page handler includes
To tell Drupal that a page handler lives in a separate include file, use the "file" array key. For example:
$items['admin'] = array(
'title' => 'Administer',
'access arguments' => array('access administration pages'),
'page callback' => 'system_main_admin_page',
'weight' => 9,
'file' => 'system.admin.inc',
The above directive, taken from
system_menu(), tells Drupal to include the file "system.admin.inc", located in the same directory as the system.module file, before calling
system_main_admin_page(). system_main_admin_page() can then be placed in system.admin.inc, so it never has to be parsed unless it is needed.
Form page handlers
A great many page handlers are actually just calls to
drupal_get_form(), with the ID of the form for that page as a callback argument. That is especially true for system configuration pages. drupal_get_form() is always available, of course, but the form callback function can then be placed in a separate include file. Remember to move the form definition function as well as its validate and submit handlers, since they will only be needed if the page for that form is loaded.
Page handlers provided by other modules
In some cases, you will want to use a page callback provided by a different module. In that case, you will need to also specify a "file path" key, like so (taken from
$items['admin/content'] = array(
'title' => 'Content management',
'description' => "Manage your site's content.",
'position' => 'left',
'weight' => -10,
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array('administer site configuration'),
'file' => 'system.admin.inc',
'file path' => drupal_get_path('module', 'system'),
Drupal will include the file located at "file path"/"file", with the file path based on the Drupal base directory. If no file path is specified, the path of the module defining the callback is used. That is:
$items['example/path'] = array(
'page callback' => 'example_page',
'file' => 'example.pages.inc',
'file path' => drupal_get_path('module', 'example'),
The "file path" key in the above example is unnecessary, as that is what Drupal does by default.
If a menu item does not define a page callback, then it will inherit the callback from its parent. If it does so, it will also inherit the file directives from its parent. Since they define how Drupal should access the callback function, that should make intuitive sense.
Module developers are free to split off page handlers for their modules however they choose. However, the following guidelines and standards are recommended:
- Any module that has more than ~50 lines of code for page handler functions (including form handling functions if applicable) should split them off into a separate file. That reduces the overhead for PHP when loading modules, and therefore speeds up every single request on the site.
- Page include files should be named in the form
key.inc, where "modulename" is the name of the module and "key" is a one-word descriptive term for the types of page handlers it includes.
- For most modules, splitting page handlers into two files -- example.admin.inc (for administrator-only pages) and example.pages.inc (for pages accessible by non-administrator users) -- is sufficient, and is the recommended practice. If a module has no non-administrator pages, it should just have a single example.admin.inc file. If a module has no administrator-only pages, it should just have a single example.pages.inc file.
- Modules that have a large number of page handlers may choose to separate out page handlers even further. If so, each file should be grouped logically by function (for instance, admin pages related to theming, admin pages related to logging, other admin pages, and user-accessible pages) and clearly marked. Remember that splitting the module's page handlers up too far makes maintenance more difficult, and only one page handler include file is ever loaded regardless of how finely-grained the handler functions are separated.