Skip to content
system.api.php 166 KiB
Newer Older
<?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.
 */
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';
}

/**
 * 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;
}

 * 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.
 * 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
 * more queues via hook_queue_info(). Then, add items that need to be
 * processed to the defined queues.
  // 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);
  // Long-running operation example, leveraging a queue:
  // Fetch feeds from other sites.
  $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);
/**
 * 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.
 * 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.
 *
 * @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().
 *   - '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.
    'worker callback' => 'aggregator_refresh',
    // Only needed if this queue should be processed by cron.
    'cron' => array(
      'time' => 60,
    ),
/**
 * Alter cron queue information before cron runs.
 *
 * Called by drupal_cron_run() to allow modules to alter cron queue settings
 * before any jobs are processesed.
 *
 * @param array $queues
 *   An array of cron queue information.
 *
 * @see drupal_cron_run()
function hook_queue_info_alter(&$queues) {
  // This site has many feeds so let's spend 90 seconds on each cron run
  // updating feeds instead of the default 60.
  $queues['aggregator_feeds']['cron']['time'] = 90;
/**
 * 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
 * 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).
 *  - "#process": array of callback functions taking $element, $form_state,
 *    and $complete_form.
 *  - "#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.
 *  - "#title_display": optional string indicating if and how #title should be
 *    displayed, see theme_form_element() and theme_form_element_label().
 *
 * @see hook_element_info_alter()
 * @see system_element_info()
function hook_element_info() {
  $types['filter_format'] = array(
    '#input' => TRUE,
  );
  return $types;
/**
 * 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.
 *
 *   All element type defaults as collected by hook_element_info().
 */
function hook_element_info_alter(&$type) {
  // Decrease the default size of textfields.
  if (isset($type['textfield']['#size'])) {
    $type['textfield']['#size'] = 40;
  }
}

/**
 * Perform cleanup tasks.
 *
 * This hook is run at the end of each page request. It is often used for
 * page logging and specialized cleanup. This hook MUST NOT print anything.
 *
 * Only use this hook if your code must run even for cached page views.
 * 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
 * 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) {
  db_update('counter')
    ->expression('hits', 'hits + 1')
    ->condition('type', 1)
    ->execute();
}

/**
 * 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.
 * @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.
  $javascript['core/misc/jquery.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js';
/**
 * 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.
 *
 * 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 drupal_add_library()
 * @see drupal_get_library()
 */
function hook_library_info() {
  // 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.
      // 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.
 *
function hook_library_info_alter(&$libraries, $module) {
  // 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(),
      );
    }
  }
}

/**
 * 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.
 * @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.
 * @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'));
}

/**
 * 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,
    );
  }
}

/**
 * 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
 * access. The passed-in $router_item is statically cached for the current request, so this
 * 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();
  }
}

/**
 * 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',
 *     );
 *   }
 *
 *   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
 * 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:
 * @code
 *   function mymodule_menu() {
 *     $items['abc/def'] = array(
 *       'page callback' => 'mymodule_abc_view',
 *       'page arguments' => array(1, 'foo'),
 *     );
 *   }
 * @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.
 *
 * 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
 * with 'foo' and passed to the callback function. Note that wildcards may not
 * be used as the first component.
 *
 * 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
 * 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.
 *
 * 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.
 *
 * 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
 * $items['admin/config/system/foo'] = array(
 *   'title' => 'Foo settings',
 *   'type' => MENU_NORMAL_ITEM,
 *   // Page callback, etc. need to be added here.
 * // Make "Tab 1" the main tab on the "Foo settings" page
 * $items['admin/config/system/foo/tab1'] = array(
 *   'title' => 'Tab 1',
 *   // Access callback, page callback, and theme callback will be inherited
 *   // from 'admin/config/system/foo', if not specified here to override.
 * // Make an additional tab called "Tab 2" on "Foo settings"
 * $items['admin/config/system/foo/tab2'] = array(
 *   'title' => 'Tab 2',
 *   // Page callback and theme callback will be inherited from
 *   // 'admin/config/system/foo', if not specified here to override.
 *   // Need to add access callback or access arguments.
 * );
 * @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
 *     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:
 *     @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.
 *   - "options": An array of options to be passed to l() when generating a link
 *     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.
 *
 * 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',
    'access arguments' => array('access content'),
    'type' => MENU_SUGGESTED_ITEM,
  );
  $items['example/feed'] = array(
    'title' => 'Example RSS feed',
    'page callback' => 'example_feed',
    '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().
  // Make all new admin links hidden (a.k.a disabled).
  if (strpos($item['link_path'], 'admin') === 0 && empty($item['mlid'])) {
    $item['hidden'] = 1;
  }
  // Flag a link to be altered by hook_translated_menu_link_alter().
  if ($item['link_path'] == 'devel/cache/clear') {
    $item['options']['alter'] = TRUE;
  }
  // 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;
  }
 * 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
 *
 * @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).
 */
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.
  $menu_name = db_query("SELECT menu_name FROM {menu_example} WHERE mlid = :mlid", array(':mlid' => $link['mlid']))->fetchField();
  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.
 * @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.
 */
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(