Newer
Older
Angie Byron
committed
<?php
/**
* @file
* Hooks provided by Drupal core and the System module.
*/
/**
* @addtogroup hooks
* @{
*/
/**
* Defines one or more hooks that are exposed by a module.
*
* Normally hooks do not need to be explicitly defined. However, by declaring a
* hook explicitly, a module may define a "group" for it. Modules that implement
* a hook may then place their implementation in either $module.module or in
* $module.$group.inc. If the hook is located in $module.$group.inc, then that
* file will be automatically loaded when needed.
* In general, hooks that are rarely invoked and/or are very large should be
* placed in a separate include file, while hooks that are very short or very
* frequently called should be left in the main module file so that they are
* always available.
*
* @return
* An associative array whose keys are hook names and whose values are an
* associative array containing:
* - group: A string defining the group to which the hook belongs. The module
* system will determine whether a file with the name $module.$group.inc
* exists, and automatically load it when required.
*
* See system_hook_info() for all hook groups defined by Drupal core.
*
* @see hook_hook_info_alter().
*/
function hook_hook_info() {
$hooks['token_info'] = array(
'group' => 'tokens',
);
$hooks['tokens'] = array(
'group' => 'tokens',
);
return $hooks;
}
/**
* Alter information from hook_hook_info().
*
* @param $hooks
* Information gathered by module_hook_info() from other modules'
* implementations of hook_hook_info(). Alter this array directly.
* See hook_hook_info() for information on what this may contain.
*/
function hook_hook_info_alter(&$hooks) {
// Our module wants to completely override the core tokens, so make
// sure the core token hooks are not found.
$hooks['token_info']['group'] = 'mytokens';
$hooks['tokens']['group'] = 'mytokens';
}
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/**
* Define administrative paths.
*
* Modules may specify whether or not the paths they define in hook_menu() are
* to be considered administrative. Other modules may use this information to
* display those pages differently (e.g. in a modal overlay, or in a different
* theme).
*
* To change the administrative status of menu items defined in another module's
* hook_menu(), modules should implement hook_admin_paths_alter().
*
* @return
* An associative array. For each item, the key is the path in question, in
* a format acceptable to drupal_match_path(). The value for each item should
* be TRUE (for paths considered administrative) or FALSE (for non-
* administrative paths).
*
* @see hook_menu()
* @see drupal_match_path()
* @see hook_admin_paths_alter()
*/
function hook_admin_paths() {
$paths = array(
'mymodule/*/add' => TRUE,
'mymodule/*/edit' => TRUE,
);
return $paths;
}
/**
* Redefine administrative paths defined by other modules.
*
* @param $paths
* An associative array of administrative paths, as defined by implementations
* of hook_admin_paths().
*
* @see hook_admin_paths()
*/
function hook_admin_paths_alter(&$paths) {
// Treat all user pages as administrative.
$paths['user'] = TRUE;
$paths['user/*'] = TRUE;
// Treat the forum topic node form as a non-administrative page.
$paths['node/add/forum'] = FALSE;
}
Angie Byron
committed
/**
* Perform periodic actions.
*
* Modules that require some commands to be executed periodically can
* implement hook_cron(). The engine will then call the hook whenever a cron
* run happens, as defined by the administrator. Typical tasks managed by
* hook_cron() are database maintenance, backups, recalculation of settings
* or parameters, automated mailing, and retrieving remote data.
Angie Byron
committed
*
* Short-running or non-resource-intensive tasks can be executed directly in
* the hook_cron() implementation.
* Long-running tasks and tasks that could time out, such as retrieving remote
* data, sending email, and intensive file tasks, should use the queue API
* instead of executing the tasks directly. To do this, first define one or
catch
committed
* more queues via hook_queue_info(). Then, add items that need to be
* processed to the defined queues.
Angie Byron
committed
*/
function hook_cron() {
// Short-running operation example, not using a queue:
// Delete all expired records since the last cron run.
$expires = variable_get('mymodule_cron_last_run', REQUEST_TIME);
db_delete('mymodule_table')
->condition('expires', $expires, '>=')
->execute();
variable_set('mymodule_cron_last_run', REQUEST_TIME);
Angie Byron
committed
// Long-running operation example, leveraging a queue:
// Fetch feeds from other sites.
Angie Byron
committed
$result = db_query('SELECT * FROM {aggregator_feed} WHERE checked + refresh < :time AND refresh <> :never', array(
':time' => REQUEST_TIME,
':never' => AGGREGATOR_CLEAR_NEVER,
));
$queue = queue('aggregator_feeds');
foreach ($result as $feed) {
$queue->createItem($feed);
Angie Byron
committed
}
}
Dries Buytaert
committed
/**
* Declare queues holding items that need to be run periodically.
*
* While there can be only one hook_cron() process running at the same time,
* there can be any number of processes defined here running. Because of
* this, long running tasks are much better suited for this API. Items queued
* in hook_cron() might be processed in the same cron run if there are not many
* items in the queue, otherwise it might take several requests, which can be
* run in parallel.
Dries Buytaert
committed
*
catch
committed
* You can create queues, add items to them, claim them, etc without declaring
* the queue in this hook if you want, however, you need to take care of
* processing the items in the queue in that case.
*
Dries Buytaert
committed
* @return
* An associative array where the key is the queue name and the value is
* again an associative array. Possible keys are:
* - 'worker callback': The name of the function to call. It will be called
* with one argument, the item created via
* Drupal\Core\Queue\QueueInterface::createItem() in hook_cron().
catch
committed
* - 'cron': (optional) An associative array containing the optional key:
* - 'time': (optional) How much time Drupal cron should spend on calling
* this worker in seconds. Defaults to 15.
* If the cron key is not defined, the queue will not be processed by cron,
* and must be processed by other means.
*
* @see hook_cron()
catch
committed
* @see hook_queue_info_alter()
Dries Buytaert
committed
*/
catch
committed
function hook_queue_info() {
Dries Buytaert
committed
$queues['aggregator_feeds'] = array(
catch
committed
'title' => t('Aggregator refresh'),
Dries Buytaert
committed
'worker callback' => 'aggregator_refresh',
catch
committed
// Only needed if this queue should be processed by cron.
'cron' => array(
'time' => 60,
),
Dries Buytaert
committed
);
return $queues;
}
Dries Buytaert
committed
/**
* Alter cron queue information before cron runs.
*
Dries Buytaert
committed
* Called by drupal_cron_run() to allow modules to alter cron queue settings
Dries Buytaert
committed
* before any jobs are processesed.
*
* @param array $queues
* An array of cron queue information.
*
catch
committed
* @see hook_queue_info()
* @see drupal_cron_run()
Dries Buytaert
committed
*/
catch
committed
function hook_queue_info_alter(&$queues) {
Dries Buytaert
committed
// This site has many feeds so let's spend 90 seconds on each cron run
// updating feeds instead of the default 60.
catch
committed
$queues['aggregator_feeds']['cron']['time'] = 90;
Dries Buytaert
committed
}
Angie Byron
committed
/**
* Allows modules to declare their own Forms API element types and specify their
* default values.
*
* This hook allows modules to declare their own form element types and to
* specify their default values. The values returned by this hook will be
* merged with the elements returned by hook_form() implementations and so
* can return defaults for any Form APIs keys in addition to those explicitly
* mentioned below.
*
* Each of the form element types defined by this hook is assumed to have
* a matching theme function, e.g. theme_elementtype(), which should be
* registered with hook_theme() as normal.
*
* For more information about custom element types see the explanation at
Angie Byron
committed
* http://drupal.org/node/169815.
*
* @return
* An associative array describing the element types being defined. The array
* contains a sub-array for each element type, with the machine-readable type
* name as the key. Each sub-array has a number of possible attributes:
* - "#input": boolean indicating whether or not this element carries a value
* (even if it's hidden).
Dries Buytaert
committed
* - "#process": array of callback functions taking $element, $form_state,
* and $complete_form.
Angie Byron
committed
* - "#after_build": array of callback functions taking $element and $form_state.
* - "#validate": array of callback functions taking $form and $form_state.
* - "#element_validate": array of callback functions taking $element and
* $form_state.
* - "#pre_render": array of callback functions taking $element and $form_state.
* - "#post_render": array of callback functions taking $element and $form_state.
* - "#submit": array of callback functions taking $form and $form_state.
Dries Buytaert
committed
* - "#title_display": optional string indicating if and how #title should be
* displayed, see theme_form_element() and theme_form_element_label().
Dries Buytaert
committed
*
* @see hook_element_info_alter()
* @see system_element_info()
Angie Byron
committed
*/
Dries Buytaert
committed
function hook_element_info() {
$types['filter_format'] = array(
'#input' => TRUE,
);
return $types;
Angie Byron
committed
}
Angie Byron
committed
/**
* Alter the element type information returned from modules.
*
* A module may implement this hook in order to alter the element type defaults
* defined by a module.
*
* @param $type
Dries Buytaert
committed
* All element type defaults as collected by hook_element_info().
Angie Byron
committed
*
Dries Buytaert
committed
* @see hook_element_info()
Angie Byron
committed
*/
function hook_element_info_alter(&$type) {
// Decrease the default size of textfields.
if (isset($type['textfield']['#size'])) {
$type['textfield']['#size'] = 40;
}
}
Angie Byron
committed
/**
* Perform cleanup tasks.
*
* This hook is run at the end of each page request. It is often used for
Dries Buytaert
committed
* page logging and specialized cleanup. This hook MUST NOT print anything.
Angie Byron
committed
*
* Only use this hook if your code must run even for cached page views.
Dries Buytaert
committed
* If you have code which must run once on all non-cached pages, use
* hook_init() instead. That is the usual case. If you implement this hook
Angie Byron
committed
* and see an error like 'Call to undefined function', it is likely that
* you are depending on the presence of a module which has not been loaded yet.
* It is not loaded because Drupal is still in bootstrap mode.
*
* @param $destination
* If this hook is invoked as part of a drupal_goto() call, then this argument
* will be a fully-qualified URL that is the destination of the redirect.
*/
function hook_exit($destination = NULL) {
Dries Buytaert
committed
db_update('counter')
->expression('hits', 'hits + 1')
->condition('type', 1)
->execute();
Angie Byron
committed
}
/**
* Perform necessary alterations to the JavaScript before it is presented on
* the page.
*
* @param $javascript
* An array of all JavaScript being presented on the page.
Dries Buytaert
committed
*
Angie Byron
committed
* @see drupal_add_js()
* @see drupal_get_js()
* @see drupal_js_defaults()
*/
function hook_js_alter(&$javascript) {
// Swap out jQuery to use an updated version of the library.
Nate Lampton
committed
$javascript['core/misc/jquery.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js';
Angie Byron
committed
}
Angie Byron
committed
/**
* Registers JavaScript/CSS libraries associated with a module.
*
* Modules implementing this return an array of arrays. The key to each
* sub-array is the machine readable name of the library. Each library may
* contain the following items:
*
* - 'title': The human readable name of the library.
* - 'website': The URL of the library's web site.
* - 'version': A string specifying the version of the library; intentionally
* not a float because a version like "1.2.3" is not a valid float. Use PHP's
* version_compare() to compare different versions.
* - 'js': An array of JavaScript elements; each element's key is used as $data
* argument, each element's value is used as $options array for
* drupal_add_js(). To add library-specific (not module-specific) JavaScript
* settings, the key may be skipped, the value must specify
* 'type' => 'setting', and the actual settings must be contained in a 'data'
* element of the value.
* - 'css': Like 'js', an array of CSS elements passed to drupal_add_css().
* - 'dependencies': An array of libraries that are required for a library. Each
* element is an array listing the module and name of another library. Note
* that all dependencies for each dependent library will also be added when
* this library is added.
Angie Byron
committed
*
* Registered information for a library should contain re-usable data only.
* Module- or implementation-specific data and integration logic should be added
* separately.
*
* @return
* An array defining libraries associated with a module.
*
* @see system_library_info()
Angie Byron
committed
* @see drupal_add_library()
* @see drupal_get_library()
*/
function hook_library_info() {
Angie Byron
committed
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
// Library One.
$libraries['library-1'] = array(
'title' => 'Library One',
'website' => 'http://example.com/library-1',
'version' => '1.2',
'js' => array(
drupal_get_path('module', 'my_module') . '/library-1.js' => array(),
),
'css' => array(
drupal_get_path('module', 'my_module') . '/library-2.css' => array(
'type' => 'file',
'media' => 'screen',
),
),
);
// Library Two.
$libraries['library-2'] = array(
'title' => 'Library Two',
'website' => 'http://example.com/library-2',
'version' => '3.1-beta1',
'js' => array(
// JavaScript settings may use the 'data' key.
array(
'type' => 'setting',
'data' => array('library2' => TRUE),
),
),
'dependencies' => array(
// Require jQuery UI core by System module.
array('system', 'ui'),
Angie Byron
committed
// Require our other library.
array('my_module', 'library-1'),
// Require another library.
array('other_module', 'library-3'),
),
);
return $libraries;
}
/**
* Alters the JavaScript/CSS library registry.
*
* Allows certain, contributed modules to update libraries to newer versions
* while ensuring backwards compatibility. In general, such manipulations should
* only be done by designated modules, since most modules that integrate with a
* certain library also depend on the API of a certain library version.
*
* @param $libraries
* The JavaScript/CSS libraries provided by $module. Keyed by internal library
* name and passed by reference.
* @param $module
* The name of the module that registered the libraries.
*
* @see hook_library_info()
Angie Byron
committed
*/
function hook_library_info_alter(&$libraries, $module) {
Angie Byron
committed
// Update Farbtastic to version 2.0.
if ($module == 'system' && isset($libraries['farbtastic'])) {
// Verify existing version is older than the one we are updating to.
if (version_compare($libraries['farbtastic']['version'], '2.0', '<')) {
// Update the existing Farbtastic to version 2.0.
$libraries['farbtastic']['version'] = '2.0';
$libraries['farbtastic']['js'] = array(
drupal_get_path('module', 'farbtastic_update') . '/farbtastic-2.0.js' => array(),
);
}
}
}
Dries Buytaert
committed
/**
* Alter CSS files before they are output on the page.
*
* @param $css
* An array of all CSS items (files and inline CSS) being requested on the page.
Dries Buytaert
committed
*
Dries Buytaert
committed
* @see drupal_add_css()
* @see drupal_get_css()
*/
function hook_css_alter(&$css) {
// Remove defaults.css file.
unset($css[drupal_get_path('module', 'system') . '/defaults.css']);
}
* Alter the commands that are sent to the user through the Ajax framework.
*
* @param $commands
* An array of all commands that will be sent to the user.
Dries Buytaert
committed
*
* @see ajax_render()
*/
function hook_ajax_render_alter($commands) {
// Inject any new status messages into the content area.
$commands[] = ajax_command_prepend('#block-system-main .content', theme('status_messages'));
}
Angie Byron
committed
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
/**
* Add elements to a page before it is rendered.
*
* Use this hook when you want to add elements at the page level. For your
* additions to be printed, they have to be placed below a top level array key
* of the $page array that has the name of a region of the active theme.
*
* By default, valid region keys are 'page_top', 'header', 'sidebar_first',
* 'content', 'sidebar_second' and 'page_bottom'. To get a list of all regions
* of the active theme, use system_region_list($theme). Note that $theme is a
* global variable.
*
* If you want to alter the elements added by other modules or if your module
* depends on the elements of other modules, use hook_page_alter() instead which
* runs after this hook.
*
* @param $page
* Nested array of renderable elements that make up the page.
*
* @see hook_page_alter()
* @see drupal_render_page()
*/
function hook_page_build(&$page) {
if (menu_get_object('node', 1)) {
// We are on a node detail page. Append a standard disclaimer to the
// content region.
$page['content']['disclaimer'] = array(
'#markup' => t('Acme, Inc. is not responsible for the contents of this sample code.'),
'#weight' => 25,
);
}
}
Angie Byron
committed
/**
* Alter a menu router item right after it has been retrieved from the database or cache.
*
* This hook is invoked by menu_get_item() and allows for run-time alteration of router
* information (page_callback, title, and so on) before it is translated and checked for
Dries Buytaert
committed
* access. The passed-in $router_item is statically cached for the current request, so this
Angie Byron
committed
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
* hook is only invoked once for any router item that is retrieved via menu_get_item().
*
* Usually, modules will only want to inspect the router item and conditionally
* perform other actions (such as preparing a state for the current request).
* Note that this hook is invoked for any router item that is retrieved by
* menu_get_item(), which may or may not be called on the path itself, so implementations
* should check the $path parameter if the alteration should fire for the current request
* only.
*
* @param $router_item
* The menu router item for $path.
* @param $path
* The originally passed path, for which $router_item is responsible.
* @param $original_map
* The path argument map, as contained in $path.
*
* @see menu_get_item()
*/
function hook_menu_get_item_alter(&$router_item, $path, $original_map) {
// When retrieving the router item for the current path...
if ($path == $_GET['q']) {
// ...call a function that prepares something for this request.
mymodule_prepare_something();
}
}
Angie Byron
committed
/**
* 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':
* @code
* function mymodule_menu() {
* $items['abc/def'] = array(
* 'page callback' => 'mymodule_abc_view',
* );
* return $items;
Angie Byron
committed
* }
*
* function mymodule_abc_view($ghi = 0, $jkl = '') {
* // ...
* }
* @endcode
* 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
Angie Byron
committed
* 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:
Angie Byron
committed
* @code
* function mymodule_menu() {
* $items['abc/def'] = array(
* 'page callback' => 'mymodule_abc_view',
* 'page arguments' => array(1, 'foo'),
* );
* return $items;
Angie Byron
committed
* }
* @endcode
* 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.
Angie Byron
committed
*
* 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:
* @code
* function mymodule_abc_form($form, &$form_state) {
* // ...
* return $form;
* }
* @endcode
* See @link form_api Form API documentation @endlink for details.
*
* Wildcards within paths also work with integer substitution. For example,
* your module could register path 'my-module/%/edit':
* @code
* $items['my-module/%/edit'] = array(
* 'page callback' => 'mymodule_abc_edit',
* 'page arguments' => array(1),
* );
* @endcode
* When path 'my-module/foo/edit' is requested, integer 1 will be replaced
Dries Buytaert
committed
* with 'foo' and passed to the callback function. Note that wildcards may not
* be used as the first component.
Angie Byron
committed
*
* 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':
* @code
* $items['my-module/%mymodule_abc/edit'] = array(
* 'page callback' => 'mymodule_abc_edit',
* 'page arguments' => array(1),
* );
* @endcode
* 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:
* @code
* function mymodule_abc_load($abc_id) {
* return db_query("SELECT * FROM {mymodule_abc} WHERE abc_id = :abc_id", array(':abc_id' => $abc_id))->fetchObject();
* }
* @endcode
Dries Buytaert
committed
* This 'abc' object will then be passed into the callback functions defined
* for the menu item, such as the page callback function mymodule_abc_edit()
* to replace the integer 1 in the argument array. Note that a load function
* should return FALSE when it is unable to provide a loadable object. For
* example, the node_load() function for the 'node/%node/edit' menu item will
* return FALSE for the path 'node/999/edit' if a node with a node ID of 999
* does not exist. The menu routing system will return a 404 error in this case.
Dries Buytaert
committed
*
* You can also define a %wildcard_to_arg() function (for the example menu
* entry above this would be 'mymodule_abc_to_arg()'). The _to_arg() function
* is invoked to retrieve a value that is used in the path in place of the
* wildcard. A good example is user.module, which defines
* user_uid_optional_to_arg() (corresponding to the menu entry
* 'user/%user_uid_optional'). This function returns the user ID of the
* current user.
*
* The _to_arg() function will get called with three arguments:
* - $arg: A string representing whatever argument may have been supplied by
* the caller (this is particularly useful if you want the _to_arg()
* function only supply a (default) value if no other value is specified,
* as in the case of user_uid_optional_to_arg().
* - $map: An array of all path fragments (e.g. array('node','123','edit') for
* 'node/123/edit').
* - $index: An integer indicating which element of $map corresponds to $arg.
*
* _load() and _to_arg() functions may seem similar at first glance, but they
* have different purposes and are called at different times. _load()
* functions are called when the menu system is collecting arguments to pass
* to the callback functions defined for the menu item. _to_arg() functions
* are called when the menu system is generating links to related paths, such
* as the tabs for a set of MENU_LOCAL_TASK items.
Angie Byron
committed
*
* 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:
* @code
* // Make "Foo settings" appear on the admin Config page
Dries Buytaert
committed
* $items['admin/config/system/foo'] = array(
Angie Byron
committed
* 'title' => 'Foo settings',
* 'type' => MENU_NORMAL_ITEM,
* // Page callback, etc. need to be added here.
Angie Byron
committed
* );
Dries Buytaert
committed
* // Make "Tab 1" the main tab on the "Foo settings" page
* $items['admin/config/system/foo/tab1'] = array(
* 'title' => 'Tab 1',
Angie Byron
committed
* 'type' => MENU_DEFAULT_LOCAL_TASK,
* // Access callback, page callback, and theme callback will be inherited
Dries Buytaert
committed
* // from 'admin/config/system/foo', if not specified here to override.
Angie Byron
committed
* );
Dries Buytaert
committed
* // Make an additional tab called "Tab 2" on "Foo settings"
* $items['admin/config/system/foo/tab2'] = array(
* 'title' => 'Tab 2',
Angie Byron
committed
* 'type' => MENU_LOCAL_TASK,
* // Page callback and theme callback will be inherited from
Dries Buytaert
committed
* // 'admin/config/system/foo', if not specified here to override.
* // Need to add access callback or access arguments.
Angie Byron
committed
* );
* @endcode
*
* @return
* 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
Angie Byron
committed
* 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.
Dries Buytaert
committed
* - "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).
Angie Byron
committed
* - "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.
Dries Buytaert
committed
* - "theme callback": (optional) A function returning the machine-readable
Dries Buytaert
committed
* 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.
Angie Byron
committed
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
* - "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:
* @code
* 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
* @endcode
* - "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.inc:
* - 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.
Dries Buytaert
committed
* - "options": An array of options to be passed to l() when generating a link
Dries Buytaert
committed
* from this menu item. Note that the "options" parameter has no effect on
* MENU_LOCAL_TASK, MENU_DEFAULT_LOCAL_TASK, and MENU_LOCAL_ACTION items.
Angie Byron
committed
*
* For a detailed usage example, see page_example.module.
* For comprehensive documentation on the menu system, see
* http://drupal.org/node/102338.
*/
function hook_menu() {
$items['example'] = array(
'title' => 'Example Page',
'page callback' => 'example_page',
Angie Byron
committed
'access arguments' => array('access content'),
'type' => MENU_SUGGESTED_ITEM,
);
$items['example/feed'] = array(
'title' => 'Example RSS feed',
'page callback' => 'example_feed',
Angie Byron
committed
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Alter the data being saved to the {menu_router} table after hook_menu is invoked.
*
* This hook is invoked by menu_router_build(). The menu definitions are passed
* in by reference. Each element of the $items array is one item returned
* by a module from hook_menu. Additional items may be added, or existing items
* altered.
*
* @param $items
* Associative array of menu router definitions returned from hook_menu().
*/
function hook_menu_alter(&$items) {
// Example - disable the page at node/add
$items['node/add']['access callback'] = FALSE;
}
/**
* Alter the data being saved to the {menu_links} table by menu_link_save().
*
* @param $item
* Associative array defining a menu link as passed into menu_link_save().
Dries Buytaert
committed
*
* @see hook_translated_menu_link_alter()
Angie Byron
committed
*/
function hook_menu_link_alter(&$item) {
Dries Buytaert
committed
// Make all new admin links hidden (a.k.a disabled).
Angie Byron
committed
if (strpos($item['link_path'], 'admin') === 0 && empty($item['mlid'])) {
$item['hidden'] = 1;
}
Dries Buytaert
committed
// Flag a link to be altered by hook_translated_menu_link_alter().
Angie Byron
committed
if ($item['link_path'] == 'devel/cache/clear') {
$item['options']['alter'] = TRUE;
}
Dries Buytaert
committed
// Flag a link to be altered by hook_translated_menu_link_alter(), but only
// if it is derived from a menu router item; i.e., do not alter a custom
// menu link pointing to the same path that has been created by a user.
if ($item['link_path'] == 'user' && $item['module'] == 'system') {
$item['options']['alter'] = TRUE;
}
Angie Byron
committed
}
/**
Dries Buytaert
committed
* Alter a menu link after it has been translated and before it is rendered.
*
* This hook is invoked from _menu_link_translate() after a menu link has been
* translated; i.e., after dynamic path argument placeholders (%) have been
* replaced with actual values, the user access to the link's target page has
* been checked, and the link has been localized. It is only invoked if
* $item['options']['alter'] has been set to a non-empty value (e.g., TRUE).
* This flag should be set using hook_menu_link_alter().
*
* Implementations of this hook are able to alter any property of the menu link.
* For example, this hook may be used to add a page-specific query string to all
* menu links, or hide a certain link by setting:
* @code
* 'hidden' => 1,
* @endcode
Angie Byron
committed
*
* @param $item
* Associative array defining a menu link after _menu_link_translate()
* @param $map
* Associative array containing the menu $map (path parts and/or objects).
Dries Buytaert
committed
*
* @see hook_menu_link_alter()
Angie Byron
committed
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
*/
function hook_translated_menu_link_alter(&$item, $map) {
if ($item['href'] == 'devel/cache/clear') {
$item['localized_options']['query'] = drupal_get_destination();
}
}
/**
* Inform modules that a menu link has been created.
*
* This hook is used to notify modules that menu items have been
* created. Contributed modules may use the information to perform
* actions based on the information entered into the menu system.
*
* @param $link
* Associative array defining a menu link as passed into menu_link_save().
*
* @see hook_menu_link_update()
* @see hook_menu_link_delete()
*/
function hook_menu_link_insert($link) {
// In our sample case, we track menu items as editing sections
// of the site. These are stored in our table as 'disabled' items.
$record['mlid'] = $link['mlid'];
$record['menu_name'] = $link['menu_name'];
$record['status'] = 0;
drupal_write_record('menu_example', $record);
}
/**
* Inform modules that a menu link has been updated.
*
* This hook is used to notify modules that menu items have been
* updated. Contributed modules may use the information to perform
* actions based on the information entered into the menu system.
*
* @param $link
* Associative array defining a menu link as passed into menu_link_save().
*
* @see hook_menu_link_insert()
* @see hook_menu_link_delete()
*/
function hook_menu_link_update($link) {
// If the parent menu has changed, update our record.
Angie Byron
committed
$menu_name = db_query("SELECT menu_name FROM {menu_example} WHERE mlid = :mlid", array(':mlid' => $link['mlid']))->fetchField();
Angie Byron
committed
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
if ($menu_name != $link['menu_name']) {
db_update('menu_example')
->fields(array('menu_name' => $link['menu_name']))
->condition('mlid', $link['mlid'])
->execute();
}
}
/**
* Inform modules that a menu link has been deleted.
*
* This hook is used to notify modules that menu items have been
* deleted. Contributed modules may use the information to perform
* actions based on the information entered into the menu system.
*
* @param $link
* Associative array defining a menu link as passed into menu_link_save().
*
* @see hook_menu_link_insert()
* @see hook_menu_link_update()
*/
function hook_menu_link_delete($link) {
// Delete the record from our table.
db_delete('menu_example')
->condition('mlid', $link['mlid'])
->execute();
}
/**
* Alter tabs and actions displayed on the page before they are rendered.
*
* This hook is invoked by menu_local_tasks(). The system-determined tabs and
* actions are passed in by reference. Additional tabs or actions may be added,
* or existing items altered.
*
* Each tab or action is an associative array containing:
* - #theme: The theme function to use to render.
* - #link: An associative array containing:
* - title: The localized title of the link.
* - href: The system path to link to.
* - localized_options: An array of options to pass to url().
* - #active: Whether the link should be marked as 'active'.
*
* @param $data
* An associative array containing:
* - actions: An associative array containing:
* - count: The amount of actions determined by the menu system, which can
* be ignored.
* - output: A list of of actions, each one being an associative array
* as described above.
* - tabs: An indexed array (list) of tab levels (up to 2 levels), each
* containing an associative array:
* - count: The amount of tabs determined by the menu system. This value
* does not need to be altered if there is more than one tab.
* - output: A list of of tabs, each one being an associative array as
* described above.
Dries Buytaert
committed
* @param $router_item
* The menu system router item of the page.
* @param $root_path
* The path to the root item for this set of tabs.
Angie Byron
committed
*/
function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) {
// Add an action linking to node/add to all pages.
$data['actions']['output'][] = array(