system.api.php 120 KB
Newer Older
1 2 3 4 5 6 7
<?php

/**
 * @file
 * Hooks provided by Drupal core and the System module.
 */

8 9
use Drupal\Core\Utility\UpdateException;

10 11 12 13 14
/**
 * @addtogroup hooks
 * @{
 */

15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/**
 * 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.
36 37
 *
 * @see hook_hook_info_alter().
38 39 40 41 42 43 44 45 46 47 48
 */
function hook_hook_info() {
  $hooks['token_info'] = array(
    'group' => 'tokens',
  );
  $hooks['tokens'] = array(
    'group' => 'tokens',
  );
  return $hooks;
}

49 50 51
/**
 * Perform periodic actions.
 *
52 53 54 55 56
 * 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.
57
 *
58 59
 * Short-running or non-resource-intensive tasks can be executed directly in
 * the hook_cron() implementation.
60
 *
61 62 63
 * 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
64
 * more queues via hook_queue_info(). Then, add items that need to be
65
 * processed to the defined queues.
66 67
 */
function hook_cron() {
68 69
  // Short-running operation example, not using a queue:
  // Delete all expired records since the last cron run.
70
  $expires = \Drupal::state()->get('mymodule.cron_last_run', REQUEST_TIME);
71 72 73
  db_delete('mymodule_table')
    ->condition('expires', $expires, '>=')
    ->execute();
74
  \Drupal::state()->set('mymodule.cron_last_run', REQUEST_TIME);
75

76 77
  // Long-running operation example, leveraging a queue:
  // Fetch feeds from other sites.
78
  $result = db_query('SELECT * FROM {aggregator_feed} WHERE checked + refresh < :time AND refresh <> :never', array(
79 80 81
    ':time' => REQUEST_TIME,
    ':never' => AGGREGATOR_CLEAR_NEVER,
  ));
82
  $queue = \Drupal::queue('aggregator_feeds');
83 84
  foreach ($result as $feed) {
    $queue->createItem($feed);
85 86 87
  }
}

88 89 90 91 92 93 94 95 96 97 98 99
/**
 * Alter available data types for typed data wrappers.
 *
 * @param array $data_types
 *   An array of data type information.
 *
 * @see hook_data_type_info()
 */
function hook_data_type_info_alter(&$data_types) {
  $data_types['email']['class'] = '\Drupal\mymodule\Type\Email';
}

100 101 102 103 104 105
/**
 * 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
106 107 108
 * 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.
109
 *
110 111 112 113
 * 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.
 *
114 115 116
 * @return
 *   An associative array where the key is the queue name and the value is
 *   again an associative array. Possible keys are:
117 118
 *   - 'worker callback': A PHP callable to call that is an implementation of
 *     callback_queue_worker().
119 120 121 122 123
 *   - '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.
124 125
 *
 * @see hook_cron()
126
 * @see hook_queue_info_alter()
127
 */
128
function hook_queue_info() {
129
  $queues['aggregator_feeds'] = array(
130
    'title' => t('Aggregator refresh'),
131
    'worker callback' => array('Drupal\my_module\MyClass', 'aggregatorRefresh'),
132 133 134 135
    // Only needed if this queue should be processed by cron.
    'cron' => array(
      'time' => 60,
    ),
136 137 138 139
  );
  return $queues;
}

140 141 142
/**
 * Alter cron queue information before cron runs.
 *
143
 * Called by \Drupal\Core\Cron to allow modules to alter cron queue settings
144 145 146 147 148
 * before any jobs are processesed.
 *
 * @param array $queues
 *   An array of cron queue information.
 *
149
 * @see hook_queue_info()
150
 * @see \Drupal\Core\Cron
151
 */
152
function hook_queue_info_alter(&$queues) {
153 154
  // This site has many feeds so let's spend 90 seconds on each cron run
  // updating feeds instead of the default 60.
155
  $queues['aggregator_feeds']['cron']['time'] = 90;
156 157
}

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
/**
 * Work on a single queue item.
 *
 * Callback for hook_queue_info().
 *
 * @param $queue_item_data
 *   The data that was passed to \Drupal\Core\Queue\QueueInterface::createItem()
 *   when the item was queued.
 *
 * @throws \Exception
 *   The worker callback may throw an exception to indicate there was a problem.
 *   The cron process will log the exception, and leave the item in the queue to
 *   be processed again later.
 *
 * @see \Drupal\Core\Cron::run()
 */
function callback_queue_worker($queue_item_data) {
  $node = node_load($queue_item_data);
  $node->title = 'Updated title';
  $node->save();
}

180
/**
181
 * Allows modules to declare their own Form API element types and specify their
182 183 184 185
 * 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
186
 * merged with the elements returned by form constructor implementations and so
187 188 189 190 191 192 193
 * 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.
 *
194
 * For more information about custom element types see the explanation at
195 196 197 198 199 200 201 202
 * 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).
203 204
 *  - "#process": array of callback functions taking $element, $form_state,
 *    and $complete_form.
205
 *  - "#after_build": array of callables taking $element and $form_state.
206 207 208
 *  - "#validate": array of callback functions taking $form and $form_state.
 *  - "#element_validate": array of callback functions taking $element and
 *    $form_state.
209 210
 *  - "#pre_render": array of callables taking $element.
 *  - "#post_render": array of callables taking $children and $element.
211
 *  - "#submit": array of callback functions taking $form and $form_state.
212
 *  - "#title_display": optional string indicating if and how #title should be
213
 *    displayed, see the form-element template and theme_form_element_label().
214 215 216
 *
 * @see hook_element_info_alter()
 * @see system_element_info()
217
 */
218 219 220 221 222
function hook_element_info() {
  $types['filter_format'] = array(
    '#input' => TRUE,
  );
  return $types;
223 224
}

225 226 227 228 229 230
/**
 * 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.
 *
231
 * @param $type
232
 *   All element type defaults as collected by hook_element_info().
233
 *
234
 * @see hook_element_info()
235 236 237 238 239 240 241 242
 */
function hook_element_info_alter(&$type) {
  // Decrease the default size of textfields.
  if (isset($type['textfield']['#size'])) {
    $type['textfield']['#size'] = 40;
  }
}

243 244 245 246 247 248
/**
 * 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.
249
 *
250
 * @see _drupal_add_js()
251 252 253 254 255
 * @see drupal_get_js()
 * @see drupal_js_defaults()
 */
function hook_js_alter(&$javascript) {
  // Swap out jQuery to use an updated version of the library.
256
  $javascript['core/assets/vendor/jquery/jquery.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js';
257 258
}

259 260 261 262 263 264 265 266 267 268 269 270 271 272
/**
 * 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.
 */
273
function hook_library_info_alter(&$libraries, $module) {
274
  // Update Farbtastic to version 2.0.
275
  if ($module == 'core' && isset($libraries['jquery.farbtastic'])) {
276
    // Verify existing version is older than the one we are updating to.
277
    if (version_compare($libraries['jquery.farbtastic']['version'], '2.0', '<')) {
278
      // Update the existing Farbtastic to version 2.0.
279 280 281 282 283 284 285 286 287 288 289
      $libraries['jquery.farbtastic']['version'] = '2.0';
      // To accurately replace library files, the order of files and the options
      // of each file have to be retained; e.g., like this:
      $old_path = 'assets/vendor/farbtastic';
      // Since the replaced library files are no longer located in a directory
      // relative to the original extension, specify an absolute path (relative
      // to DRUPAL_ROOT / base_path()) to the new location.
      $new_path = '/' . drupal_get_path('module', 'farbtastic_update') . '/js';
      $new_js = array();
      $replacements = array(
        $old_path . '/farbtastic.js' => $new_path . '/farbtastic-2.0.js',
290
      );
291 292 293 294 295 296 297 298 299
      foreach ($libraries['jquery.farbtastic']['js'] as $source => $options) {
        if (isset($replacements[$source])) {
          $new_js[$replacements[$source]] = $options;
        }
        else {
          $new_js[$source] = $options;
        }
      }
      $libraries['jquery.farbtastic']['js'] = $new_js;
300 301 302 303
    }
  }
}

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
/**
 * Alters a JavaScript/CSS library before it is attached.
 *
 * Allows modules and themes to dynamically attach further assets to a library
 * when it is added to the page; e.g., to add JavaScript settings.
 *
 * This hook is only invoked once per library and page.
 *
 * @param array $library
 *   The JavaScript/CSS library that is being added.
 * @param string $extension
 *   The name of the extension that registered the library.
 * @param string $name
 *   The name of the library.
 *
319
 * @see _drupal_add_library()
320
 */
321 322
function hook_library_alter(array &$library, $name) {
  if ($name == 'core/jquery.ui.datepicker') {
323 324 325
    // Note: If the added assets do not depend on additional request-specific
    // data supplied here, consider to statically register it directly via
    // hook_library_info_alter() already.
326
    $library['dependencies'][] = 'locale/drupal.locale.datepicker';
327

328
    $language_interface = \Drupal::languageManager()->getCurrentLanguage();
329 330 331 332 333 334 335 336 337 338 339
    $settings['jquery']['ui']['datepicker'] = array(
      'isRTL' => $language_interface->direction == Language::DIRECTION_RTL,
      'firstDay' => \Drupal::config('system.date')->get('first_day'),
    );
    $library['js'][] = array(
      'type' => 'setting',
      'data' => $settings,
    );
  }
}

340 341 342 343 344
/**
 * 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.
345
 *
346
 * @see _drupal_add_css()
347 348 349 350 351 352 353
 * @see drupal_get_css()
 */
function hook_css_alter(&$css) {
  // Remove defaults.css file.
  unset($css[drupal_get_path('module', 'system') . '/defaults.css']);
}

354
/**
355
 * Alter the Ajax command data that is sent to the client.
356
 *
357 358
 * @param \Drupal\Core\Ajax\CommandInterface[] $data
 *   An array of all the rendered commands that will be sent to the client.
359
 *
360
 * @see \Drupal\Core\Ajax\AjaxResponse::ajaxRender()
361
 */
362
function hook_ajax_render_alter(array &$data) {
363
  // Inject any new status messages into the content area.
364
  $status_messages = array('#theme' => 'status_messages');
365 366
  $command = new \Drupal\Core\Ajax\PrependCommand('#block-system-main .content', drupal_render($status_messages));
  $data[] = $command->render();
367 368
}

369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
/**
 * 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) {
392 393 394
  $path = drupal_get_path('module', 'foo');
  // Add JavaScript/CSS assets to all pages.
  // @see drupal_process_attached()
395
  $page['#attached']['js'][$path . '/foo.js'] = array('every_page' => TRUE);
396 397 398 399 400 401 402 403 404
  $page['#attached']['css'][$path . '/foo.base.css'] = array('every_page' => TRUE);
  $page['#attached']['css'][$path . '/foo.theme.css'] = array('every_page' => TRUE);

  // Add a special CSS file to a certain page only.
  if (drupal_is_front_page()) {
    $page['#attached']['css'][] = $path . '/foo.front.css';
  }

  // Append a standard disclaimer to the content region on a node detail page.
405
  if (\Drupal::request()->attributes->get('node')) {
406 407 408 409 410 411 412
    $page['content']['disclaimer'] = array(
      '#markup' => t('Acme, Inc. is not responsible for the contents of this sample code.'),
      '#weight' => 25,
    );
  }
}

413
/**
414 415 416 417
 * Alter links for menus.
 *
 * @param array $links
 *   The link definitions to be altered.
418 419 420
 *
 * @return array
 *   An array of default menu links. Each link has a key that is the machine
421 422 423 424 425 426 427 428 429 430 431 432 433
 *   name, which must be unique. By default, use the route name as the
 *   machine name. In cases where multiple links use the same route name, such
 *   as two links to the same page in different menus, or two links using the
 *   same route name but different route parameters, the suggested machine name
 *   patten is the route name followed by a dot and a unique suffix. For
 *   example, an additional logout link might have a machine name of
 *   user.logout.navigation, and default links provided to edit the article and
 *   page content types could use machine names node.type_edit.article and
 *   node.type_edit.page. Since the machine name may be arbitrary, you should
 *   never write code that assumes it is identical to the route name.
 *
 *   The value corresponding to each machine name key is an associative array
 *   that may contain the following key-value pairs:
434
 *   - title: (required) The untranslated title of the menu link.
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
 *   - description: The untranslated description of the link.
 *   - route_name: (optional) The route name to be used to build the path.
 *     Either a route_name or a link_path must be provided.
 *   - route_parameters: (optional) The route parameters to build the path.
 *   - link_path: (optional) If you have an external link use link_path instead
 *     of providing a route_name.
 *   - parent: (optional) The machine name of the link that is this link's menu
 *     parent.
 *   - weight: (optional) 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) The machine name of a menu to put the link in, if
 *     not the default Tools menu.
 *   - expanded: (optional) If set to TRUE, and if a menu link is provided for
 *     this menu item (as a result of other properties), then the menu link is
 *     always expanded, equivalent to its 'always expanded' checkbox being set
 *     in the UI.
 *   - options: (optional) An array of options to be passed to l() when
 *     generating a link from this menu item.
 */
function hook_menu_link_defaults_alter(&$links) {
  // Change the weight and title of the user.logout link.
  $links['user.logout']['weight'] = -10;
458
  $links['user.logout']['title'] = 'Logout';
459 460
}

461 462 463 464
/**
 * 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
465
 * actions are passed in by reference. Additional tabs or actions may be added.
466 467 468 469 470 471
 *
 * 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.
472
 *   - localized_options: An array of options to pass to l().
473
 * - #weight: The link's weight compared to other links.
474 475
 * - #active: Whether the link should be marked as 'active'.
 *
476
 * @param array $data
477
 *   An associative array containing:
478 479 480 481
 *   - actions: A list of of actions keyed by their href, each one being an
 *     associative array as described above.
 *   - tabs: A list of (up to 2) tab levels that contain a list of of tabs keyed
 *     by their href, each one being an associative array as described above.
482 483
 * @param string $route_name
 *   The route name of the page.
484
 */
485
function hook_menu_local_tasks(&$data, $route_name) {
486
  // Add an action linking to node/add to all pages.
487 488
  $data['actions']['node/add'] = array(
    '#theme' => 'menu_local_action',
489
    '#link' => array(
490
      'title' => t('Add content'),
491 492 493
      'href' => 'node/add',
      'localized_options' => array(
        'attributes' => array(
494
          'title' => t('Add content'),
495 496 497 498 499 500
        ),
      ),
    ),
  );

  // Add a tab linking to node/add to all pages.
501
  $data['tabs'][0]['node/add'] = array(
502 503 504 505 506 507
    '#theme' => 'menu_local_task',
    '#link' => array(
      'title' => t('Example tab'),
      'href' => 'node/add',
      'localized_options' => array(
        'attributes' => array(
508
          'title' => t('Add content'),
509 510 511 512 513 514
        ),
      ),
    ),
  );
}

515 516 517 518 519 520 521 522 523
/**
 * 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. Existing tabs or actions may be altered.
 *
 * @param array $data
 *   An associative array containing tabs and actions. See
 *   hook_menu_local_tasks() for details.
524 525
 * @param string $route_name
 *   The route name of the page.
526 527 528
 *
 * @see hook_menu_local_tasks()
 */
529
function hook_menu_local_tasks_alter(&$data, $route_name) {
530 531
}

532 533 534 535 536 537 538 539 540 541 542 543
/**
 * Alter local actions plugins.
 *
 * @param array $local_actions
 *   The array of local action plugin definitions, keyed by plugin ID.
 *
 * @see \Drupal\Core\Menu\LocalActionInterface
 * @see \Drupal\Core\Menu\LocalActionManager
 */
function hook_menu_local_actions_alter(&$local_actions) {
}

544 545 546 547 548 549 550 551 552
/**
 * Alter local tasks plugins.
 *
 * @param array $local_tasks
 *   The array of local tasks plugin definitions, keyed by plugin ID.
 *
 * @see \Drupal\Core\Menu\LocalTaskInterface
 * @see \Drupal\Core\Menu\LocalTaskManager
 */
553
function hook_local_tasks_alter(&$local_tasks) {
554 555 556 557
  // Remove a specified local task plugin.
  unset($local_tasks['example_plugin_id']);
}

558 559 560
/**
 * Alter contextual links before they are rendered.
 *
561 562 563 564
 * This hook is invoked by
 * \Drupal\Core\Menu\ContextualLinkManager::getContextualLinkPluginsByGroup().
 * The system-determined contextual links are passed in by reference. Additional
 * links may be added and existing links can be altered.
565
 *
566
 * Each contextual link contains the following entries:
567
 * - title: The localized title of the link.
568 569
 * - route_name: The route name of the link.
 * - route_parameters: The route parameters of the link.
570
 * - localized_options: An array of options to pass to url().
571
 * - (optional) weight: The weight of the link, which is used to sort the links.
572
 *
573 574 575
 *
 * @param array $links
 *   An associative array containing contextual links for the given $group,
576 577 578
 *   as described above. The array keys are used to build CSS class names for
 *   contextual links and must therefore be unique for each set of contextual
 *   links.
579 580 581 582 583 584 585 586 587 588
 * @param string $group
 *   The group of contextual links being rendered.
 * @param array $route_parameters.
 *   The route parameters passed to each route_name of the contextual links.
 *   For example:
 *   @code
 *   array('node' => $node->id())
 *   @endcode
 *
 * @see \Drupal\Core\Menu\ContextualLinkManager
589
 */
590 591 592 593
function hook_contextual_links_alter(array &$links, $group, array $route_parameters) {
  if ($group == 'menu') {
    // Dynamically use the menu name for the title of the menu_edit contextual
    // link.
594
    $menu = \Drupal::entityManager()->getStorage('menu')->load($route_parameters['menu']);
595
    $links['menu_edit']['title'] = t('Edit menu: !label', array('!label' => $menu->label()));
596 597 598
  }
}

599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
/**
 * Alter the plugin definition of contextual links.
 *
 * @param array $contextual_links
 *   An array of contextual_links plugin definitions, keyed by contextual link
 *   ID. Each entry contains the following keys:
 *     - title: The displayed title of the link
 *     - route_name: The route_name of the contextual link to be displayed
 *     - group: The group under which the contextual links should be added to.
 *       Possible values are e.g. 'node' or 'menu'.
 *
 * @see \Drupal\Core\Menu\ContextualLinkManager
 */
function hook_contextual_links_plugins_alter(array &$contextual_links) {
  $contextual_links['menu_edit']['title'] = 'Edit the menu';
}

616 617 618
/**
 * Perform alterations before a page is rendered.
 *
619 620 621 622 623
 * Use this hook when you want to remove or alter elements at the page
 * level, or add elements at the page level that depend on an other module's
 * elements (this hook runs after hook_page_build().
 *
 * If you are making changes to entities such as forms, menus, or user
624 625 626 627 628
 * profiles, use those objects' native alter hooks instead (hook_form_alter(),
 * for example).
 *
 * The $page array contains top level elements for each block region:
 * @code
629
 *   $page['page_top']
630
 *   $page['header']
631
 *   $page['sidebar_first']
632
 *   $page['content']
633
 *   $page['sidebar_second']
634
 *   $page['page_bottom']
635 636 637 638 639 640 641
 * @endcode
 *
 * The 'content' element contains the main content of the current page, and its
 * structure will vary depending on what module is responsible for building the
 * page. Some legacy modules may not return structured content at all: their
 * pre-rendered markup will be located in $page['content']['main']['#markup'].
 *
642
 * Pages built by Drupal's core Node module use a standard structure:
643 644 645
 *
 * @code
 *   // Node body.
646
 *   $page['content']['system_main']['nodes'][$nid]['body']
647
 *   // Array of links attached to the node (add comments, read more).
648
 *   $page['content']['system_main']['nodes'][$nid]['links']
649
 *   // The node entity itself.
650
 *   $page['content']['system_main']['nodes'][$nid]['#node']
651
 *   // The results pager.
652
 *   $page['content']['system_main']['pager']
653
 * @endcode
654 655 656
 *
 * Blocks may be referenced by their module/delta pair within a region:
 * @code
657
 *   // The login block in the first sidebar region.
658
 *   $page['sidebar_first']['user_login']['#block'];
659 660 661 662 663
 * @endcode
 *
 * @param $page
 *   Nested array of renderable elements that make up the page.
 *
664
 * @see hook_page_build()
665 666
 * @see drupal_render_page()
 */
667 668 669 670
function hook_page_alter(&$page) {
  // Add help text to the user login block.
  $page['sidebar_first']['user_login']['help'] = array(
    '#weight' => -10,
671
    '#markup' => t('To post comments or add content, you first have to log in.'),
672
  );
673 674
}

675 676 677 678
/**
 * Perform alterations before a form is rendered.
 *
 * One popular use of this hook is to add form elements to the node form. When
679
 * altering a node form, the node entity can be retrieved by invoking
680
 * $form_state['controller']->getEntity().
681
 *
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
 * In addition to hook_form_alter(), which is called for all forms, there are
 * two more specific form hooks available. The first,
 * hook_form_BASE_FORM_ID_alter(), allows targeting of a form/forms via a base
 * form (if one exists). The second, hook_form_FORM_ID_alter(), can be used to
 * target a specific form directly.
 *
 * The call order is as follows: all existing form alter functions are called
 * for module A, then all for module B, etc., followed by all for any base
 * theme(s), and finally for the theme itself. The module order is determined
 * by system weight, then by module name.
 *
 * Within each module, form alter hooks are called in the following order:
 * first, hook_form_alter(); second, hook_form_BASE_FORM_ID_alter(); third,
 * hook_form_FORM_ID_alter(). So, for each module, the more general hooks are
 * called first followed by the more specific.
697
 *
698 699 700
 * @param $form
 *   Nested array of form elements that comprise the form.
 * @param $form_state
701
 *   A keyed array containing the current state of the form. The arguments
702 703
 *   that \Drupal::formBuilder()->getForm() was originally called with are
 *   available in the array $form_state['build_info']['args'].
704 705 706
 * @param $form_id
 *   String representing the name of the form itself. Typically this is the
 *   name of the function that generated the form.
707
 *
708
 * @see hook_form_BASE_FORM_ID_alter()
709
 * @see hook_form_FORM_ID_alter()
710
 * @see forms_api_reference.html
711
 */
712
function hook_form_alter(&$form, &$form_state, $form_id) {
713
  if (isset($form['type']) && $form['type']['#value'] . '_node_settings' == $form_id) {
714
    $upload_enabled_types = \Drupal::config('mymodule.settings')->get('upload_enabled_types');
715 716 717
    $form['workflow']['upload_' . $form['type']['#value']] = array(
      '#type' => 'radios',
      '#title' => t('Attachments'),
718
      '#default_value' => in_array($form['type']['#value'], $upload_enabled_types) ? 1 : 0,
719 720
      '#options' => array(t('Disabled'), t('Enabled')),
    );
721 722
    // Add a custom submit handler to save the array of types back to the config file.
    $form['actions']['submit']['#submit'][] = 'mymodule_upload_enabled_types_submit';
723 724 725 726 727 728 729 730 731 732
  }
}

/**
 * Provide a form-specific alteration instead of the global hook_form_alter().
 *
 * Modules can implement hook_form_FORM_ID_alter() to modify a specific form,
 * rather than implementing hook_form_alter() and checking the form ID, or
 * using long switch statements to alter multiple forms.
 *
733 734 735 736
 * Form alter hooks are called in the following order: hook_form_alter(),
 * hook_form_BASE_FORM_ID_alter(), hook_form_FORM_ID_alter(). See
 * hook_form_alter() for more details.
 *
737 738 739
 * @param $form
 *   Nested array of form elements that comprise the form.
 * @param $form_state
740
 *   A keyed array containing the current state of the form. The arguments
741 742
 *   that \Drupal::formBuilder()->getForm() was originally called with are
 *   available in the array $form_state['build_info']['args'].
743 744 745
 * @param $form_id
 *   String representing the name of the form itself. Typically this is the
 *   name of the function that generated the form.
746
 *
747
 * @see hook_form_alter()
748
 * @see hook_form_BASE_FORM_ID_alter()
749
 * @see drupal_prepare_form()
750
 * @see forms_api_reference.html
751
 */
752
function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
753
  // Modification for the form with the given form ID goes here. For example, if
754
  // FORM_ID is "user_register_form" this code would run only on the user
755 756 757 758 759 760 761 762 763 764
  // registration form.

  // Add a checkbox to registration form about agreeing to terms of use.
  $form['terms_of_use'] = array(
    '#type' => 'checkbox',
    '#title' => t("I agree with the website's terms and conditions."),
    '#required' => TRUE,
  );
}

765
/**
766 767
 * Provide a form-specific alteration for shared ('base') forms.
 *
768 769 770 771
 * By default, when \Drupal::formBuilder()->getForm() is called, Drupal looks
 * for a function with the same name as the form ID, and uses that function to
 * build the form. In contrast, base forms allow multiple form IDs to be mapped
 * to a single base (also called 'factory') form function.
772 773
 *
 * Modules can implement hook_form_BASE_FORM_ID_alter() to modify a specific
774 775 776 777 778 779
 * base form, rather than implementing hook_form_alter() and checking for
 * conditions that would identify the shared form constructor.
 *
 * To identify the base form ID for a particular form (or to determine whether
 * one exists) check the $form_state. The base form ID is stored under
 * $form_state['build_info']['base_form_id'].
780
 *
781 782 783
 * Form alter hooks are called in the following order: hook_form_alter(),
 * hook_form_BASE_FORM_ID_alter(), hook_form_FORM_ID_alter(). See
 * hook_form_alter() for more details.
784 785 786 787 788 789 790 791 792
 *
 * @param $form
 *   Nested array of form elements that comprise the form.
 * @param $form_state
 *   A keyed array containing the current state of the form.
 * @param $form_id
 *   String representing the name of the form itself. Typically this is the
 *   name of the function that generated the form.
 *
793
 * @see hook_form_alter()
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
 * @see hook_form_FORM_ID_alter()
 * @see drupal_prepare_form()
 */
function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
  // Modification for the form with the given BASE_FORM_ID goes here. For
  // example, if BASE_FORM_ID is "node_form", this code would run on every
  // node form, regardless of node type.

  // Add a checkbox to the node form about agreeing to terms of use.
  $form['terms_of_use'] = array(
    '#type' => 'checkbox',
    '#title' => t("I agree with the website's terms and conditions."),
    '#required' => TRUE,
  );
}

810
/**
811 812 813 814 815 816 817 818
 * Alter an email message created with the drupal_mail() function.
 *
 * hook_mail_alter() allows modification of email messages created and sent
 * with drupal_mail(). Usage examples include adding and/or changing message
 * text, message fields, and message headers.
 *
 * Email messages sent using functions other than drupal_mail() will not
 * invoke hook_mail_alter(). For example, a contributed module directly
819
 * calling the drupal_mail_system()->mail() or PHP mail() function
820
 * will not invoke this hook. All core modules use drupal_mail() for
821
 * messaging, it is best practice but not mandatory in contributed modules.
822 823
 *
 * @param $message
824
 *   An array containing the message data. Keys in this array include:
825
 *  - 'id':
826
 *     The drupal_mail() id of the message. Look at module source code or
827
 *     drupal_mail() for possible id values.
828
 *  - 'to':
829
 *     The address or addresses the message will be sent to. The
830
 *     formatting of this string must comply with RFC 2822.
831
 *  - 'from':
832 833
 *     The address the message will be marked as being from, which is
 *     either a custom address or the site-wide default email address.
834 835 836 837 838
 *  - 'subject':
 *     Subject of the email to be sent. This must not contain any newline
 *     characters, or the email may not be sent properly.
 *  - 'body':
 *     An array of strings containing the message text. The message body is
839
 *     created by concatenating the individual array strings into a single text
840 841
 *     string using "\n\n" as a separator.
 *  - 'headers':
842
 *     Associative array containing mail headers, such as From, Sender,
843
 *     MIME-Version, Content-Type, etc.
844 845 846 847 848 849
 *  - 'params':
 *     An array of optional parameters supplied by the caller of drupal_mail()
 *     that is used to build the message before hook_mail_alter() is invoked.
 *  - 'language':
 *     The language object used to build the message before hook_mail_alter()
 *     is invoked.
850 851
 *  - 'send':
 *     Set to FALSE to abort sending this email message.
852 853
 *
 * @see drupal_mail()
854 855
 */
function hook_mail_alter(&$message) {
856
  if ($message['id'] == 'modulename_messagekey') {
857 858 859 860 861 862
    if (!example_notifications_optin($message['to'], $message['id'])) {
      // If the recipient has opted to not receive such messages, cancel
      // sending.
      $message['send'] = FALSE;
      return;
    }
863
    $message['body'][] = "--\nMail sent out from " . \Drupal::config('system.site')->get('name');
864 865 866
  }
}

867 868 869
/**
 * Alter the registry of modules implementing a hook.
 *
870
 * This hook is invoked during \Drupal::moduleHandler()->getImplementations().
871 872
 * A module may implement this hook in order to reorder the implementing
 * modules, which are otherwise ordered by the module's system weight.
873
 *
874 875 876 877 878 879 880
 * Note that hooks invoked using \Drupal::moduleHandler->alter() can have
 * multiple variations(such as hook_form_alter() and hook_form_FORM_ID_alter()).
 * \Drupal::moduleHandler->alter() will call all such variants defined by a
 * single module in turn. For the purposes of hook_module_implements_alter(),
 * these variants are treated as a single hook. Thus, to ensure that your
 * implementation of hook_form_FORM_ID_alter() is called at the right time,
 * you will have to change the order of hook_form_alter() implementation in
881 882
 * hook_module_implements_alter().
 *
883
 * @param $implementations
884 885 886 887 888 889 890 891
 *   An array keyed by the module's name. The value of each item corresponds
 *   to a $group, which is usually FALSE, unless the implementation is in a
 *   file named $module.$group.inc.
 * @param $hook
 *   The name of the module hook being implemented.
 */
function hook_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'rdf_mapping') {
892
    // Move my_module_rdf_mapping() to the end of the list.
893
    // \Drupal::moduleHandler()->getImplementations()
894 895 896 897 898 899 900 901 902
    // iterates through $implementations with a foreach loop which PHP iterates
    // in the order that the items were added, so to move an item to the end of
    // the array, we remove it and then add it.
    $group = $implementations['my_module'];
    unset($implementations['my_module']);
    $implementations['my_module'] = $group;
  }
}

903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
/**
 * Perform alterations to the breadcrumb built by the BreadcrumbManager.
 *
 * @param array $breadcrumb
 *   An array of breadcrumb link a tags, returned by the breadcrumb manager
 *   build method, for example
 *   @code
 *     array('<a href="/">Home</a>');
 *   @endcode
 * @param array $attributes
 *   Attributes representing the current page, coming from
 *   \Drupal::request()->attributes.
 * @param array $context
 *   May include the following key:
 *   - builder: the instance of
 *     \Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface that constructed this
 *     breadcrumb, or NULL if no builder acted based on the current attributes.
 */
function hook_system_breadcrumb_alter(array &$breadcrumb, array $attributes, array $context) {
  // Add an item to the end of the breadcrumb.
  $breadcrumb[] = Drupal::l(t('Text'), 'example_route_name');
}

926
/**
927
 * Alter the information parsed from module and theme .info.yml files
928
 *
929 930
 * This hook is invoked in _system_rebuild_module_data() and in
 * _system_rebuild_theme_data(). A module may implement this hook in order to
931
 * add to or alter the data generated by reading the .info.yml file with
932
 * \Drupal\Core\Extension\InfoParser.
933
 *
934
 * @param array $info
935
 *   The .info.yml file contents, passed by reference so that it can be altered.
936 937 938
 * @param \Drupal\Core\Extension\Extension $file
 *   Full information about the module or theme.
 * @param string $type
939 940
 *   Either 'module' or 'theme', depending on the type of .info.yml file that
 *   was passed.
941
 */
942
function hook_system_info_alter(array &$info, \Drupal\Core\Extension\Extension $file, $type) {
943
  // Only fill this in if the .info.yml file does not define a 'datestamp'.
944
  if (empty($info['datestamp'])) {
945
    $info['datestamp'] = $file->getMTime();
946 947 948 949 950 951 952
  }
}

/**
 * Define user permissions.
 *
 * This hook can supply permissions that the module defines, so that they
953
 * can be selected on the user permissions page and used to grant or restrict
954 955 956 957 958
 * access to actions the module performs.
 *
 * Permissions are checked using user_access().
 *
 * For a detailed usage example, see page_example.module.
959
 *
960
 * @return
961 962 963 964 965 966 967 968 969 970 971 972 973
 *   An array whose keys are permission names and whose corresponding values
 *   are arrays containing the following key-value pairs:
 *   - title: The human-readable name of the permission, to be shown on the
 *     permission administration page. This should be wrapped in the t()
 *     function so it can be translated.
 *   - description: (optional) A description of what the permission does. This
 *     should be wrapped in the t() function so it can be translated.
 *   - restrict access: (optional) A boolean which can be set to TRUE to
 *     indicate that site administrators should restrict access to this
 *     permission to trusted users. This should be used for permissions that
 *     have inherent security risks across a variety of potential use cases
 *     (for example, the "administer filters" and "bypass node access"
 *     permissions provided by Drupal core). When set to TRUE, a standard
974 975 976 977 978 979 980 981 982 983 984 985 986
 *     warning message defined in user_admin_permissions() and output via
 *     theme_user_permission_description() will be associated with the
 *     permission and displayed with it on the permission administration page.
 *     Defaults to FALSE.
 *   - warning: (optional) A translated warning message to display for this
 *     permission on the permission administration page. This warning overrides
 *     the automatic warning generated by 'restrict access' being set to TRUE.
 *     This should rarely be used, since it is important for all permissions to
 *     have a clear, consistent security warning that is the same across the
 *     site. Use the 'description' key instead to provide any information that
 *     is specific to the permission you are defining.
 *
 * @see theme_user_permission_description()
987
 */
988
function hook_permission() {
989
  return array(
990 991 992 993
    'administer my module' =>  array(
      'title' => t('Administer my module'),
      'description' => t('Perform administration tasks for my module.'),
    ),
994 995 996 997
  );
}

/**
998
 * Register a module or theme's theme implementations.
999
 *
1000 1001 1002 1003
 * The implementations declared by this hook have several purposes:
 * - They can specify how a particular render array is to be rendered as HTML.
 *   This is usually the case if the theme function is assigned to the render
 *   array's #theme property.
1004 1005
 * - They can return HTML for default calls to _theme().
 * - They can return HTML for calls to _theme() for a theme suggestion.
1006
 *
1007
 * @param array $existing
1008 1009 1010 1011 1012
 *   An array of existing implementations that may be used for override
 *   purposes. This is primarily useful for themes that may wish to examine
 *   existing implementations to extract data (such as arguments) so that
 *   it may properly register its own, higher priority implementations.
 * @param $type
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
 *   Whether a theme, module, etc. is being processed. This is primarily useful
 *   so that themes tell if they are the actual theme being called or a parent
 *   theme. May be one of:
 *   - 'module': A module is being checked for theme implementations.
 *   - 'base_theme_engine': A theme engine is being checked for a theme that is
 *     a parent of the actual theme being used.
 *   - 'theme_engine': A theme engine is being checked for the actual theme
 *     being used.
 *   - 'base_theme': A base theme is being checked for theme implementations.
 *   - 'theme': The actual theme in use is being checked.
1023
 * @param $theme
1024
 *   The actual name of theme, module, etc. that is being being processed.
1025 1026 1027 1028
 * @param $path
 *   The directory path of the theme or module, so that it doesn't need to be
 *   looked up.
 *
1029
 * @return array
1030 1031
 *   An associative array of information about theme implementations. The keys
 *   on the outer array are known as "theme hooks". For simple theme
1032
 *   implementations for regular calls to _theme(), the theme hook is the first
1033 1034 1035 1036 1037
 *   argument. For theme suggestions, instead of the array key being the base
 *   theme hook, the key is a theme suggestion name with the format
 *   'base_hook_name__sub_hook_name'. For render elements, the key is the
 *   machine name of the render element. The array values are themselves arrays
 *   containing information about the theme hook and its implementation. Each
1038
 *   information array must contain either a 'variables' element (for _theme()
1039 1040
 *   calls) or a 'render element' element (for render elements), but not both.
 *   The following elements may be part of each information array:
1041
 *   - variables: Used for _theme() call items only: an array of variables,
1042
 *     where the array keys are the names of the variables, and the array
1043
 *     values are the default values if they are not passed into _theme().
1044 1045 1046 1047 1048 1049 1050 1051
 *     Template implementations receive each array key as a variable in the
 *     template file (so they must be legal PHP/Twig variable names). Function
 *     implementations are passed the variables in a single $variables function
 *     argument.
 *   - render element: Used for render element items only: the name of the
 *     renderable element or element tree to pass to the theme function. This
 *     name is used as the name of the variable that holds the renderable
 *     element or tree in preprocess and process functions.
1052 1053 1054 1055 1056
 *   - file: The file the implementation resides in. This file will be included
 *     prior to the theme being rendered, to make sure that the function or
 *     preprocess function (as needed) is actually loaded; this makes it
 *     possible to split theme functions out into separate files quite easily.
 *   - path: Override the path of the file to be used. Ordinarily the module or
1057 1058
 *     theme path will be used, but if the file will not be in the default
 *     path, include it here. This path should be relative to the Drupal root
1059
 *     directory.
1060
 *   - template: If specified, this theme implementation is a template, and
1061
 *     this is the template file without an extension. Do not put .html.twig on
1062
 *     this file; that extension will be added automatically by the default
1063 1064
 *     rendering engine (which is Twig). If 'path' above is specified, the
 *     template should also be in this path.
1065 1066 1067 1068 1069 1070
 *   - function: If specified, this will be the function name to invoke for
 *     this implementation. If neither 'template' nor 'function' is specified,
 *     a default function name will be assumed. For example, if a module
 *     registers the 'node' theme hook, 'theme_node' will be assigned to its
 *     function. If the chameleon theme registers the node hook, it will be
 *     assigned 'chameleon_node' as its function.
1071
 *   - base hook: Used for _theme() suggestions only: the base theme hook name.
1072 1073 1074 1075 1076 1077 1078 1079 1080
 *     Instead of this suggestion's implementation being used directly, the base
 *     hook will be invoked with this implementation as its first suggestion.
 *     The base hook's files will be included and the base hook's preprocess
 *     functions will be called in place of any suggestion's preprocess
 *     functions. If an implementation of hook_theme_suggestions_HOOK() (where
 *     HOOK is the base hook) changes the suggestion order, a different
 *     suggestion may be used in place of this suggestion. If after
 *     hook_theme_suggestions_HOOK() this suggestion remains the first
 *     suggestion, then this suggestion's function or template will be used to
1081
 *     generate the output for _theme().
1082 1083 1084 1085 1086 1087
 *   - pattern: A regular expression pattern to be used to allow this theme
 *     implementation to have a dynamic name. The convention is to use __ to
 *     differentiate the dynamic portion of the theme. For example, to allow
 *     forums to be themed individually, the pattern might be: 'forum__'. Then,
 *     when the forum is themed, call:
 *     @code
1088
 *     _theme(array('forum__' . $tid, 'forum'), $forum)
1089 1090 1091 1092
 *     @endcode
 *   - preprocess functions: A list of functions used to preprocess this data.
 *     Ordinarily this won't be used; it's automatically filled in. By default,
 *     for a module this will be filled in as template_preprocess_HOOK. For
1093 1094
 *     a theme this will be filled in as twig_preprocess and
 *     twig_preprocess_HOOK as well as themename_preprocess and
1095
 *     themename_preprocess_HOOK.
1096 1097 1098
 *   - override preprocess functions: Set to TRUE when a theme does NOT want
 *     the standard preprocess functions to run. This can be used to give a
 *     theme FULL control over how variables are set. For example, if a theme
1099
 *     wants total control over how certain variables in the page.html.twig are
1100
 *     set, this can be set to true. Please keep in mind that when this is used
1101 1102 1103 1104 1105 1106
 *     by a theme, that theme becomes responsible for making sure necessary
 *     variables are set.
 *   - type: (automatically derived) Where the theme hook is defined:
 *     'module', 'theme_engine', or 'theme'.
 *   - theme path: (automatically derived) The directory path of the theme or
 *     module, so that it doesn't need to be looked up.
1107 1108
 *
 * @see hook_theme_registry_alter()
1109 1110 1111 1112
 */
function hook_theme($existing, $type, $theme, $path) {
  return array(
    'forum_display' => array(
1113
      'variables' => array('forums' => NULL, 'topics' => NULL, 'parents' => NULL, 'tid' => NULL, 'sortby' => NULL, 'forum_per_page' => NULL),
1114 1115
    ),
    'forum_list' => array(
1116
      'variables' => array('forums' => NULL, 'parents' => NULL, 'tid' => NULL),
1117 1118
    ),
    'forum_icon' => array(
1119 1120 1121 1122 1123 1124
      'variables' => array('new_posts' => NULL, 'num_posts' => 0, 'comment_mode' => 0, 'sticky' => 0),
    ),
    'status_report' => array(
      'render element' => 'requirements',
      'file' => 'system.admin.inc',
    ),
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
  );
}

/**
 * Alter the theme registry information returned from hook_theme().
 *
 * The theme registry stores information about all available theme hooks,
 * including which callback functions those hooks will call when triggered,
 * what template files are exposed by these hooks, and so on.
 *
 * Note that this hook is only executed as the theme cache is re-built.
 * Changes here will not be visible until the next cache clear.
 *
 * The $theme_registry array is keyed by theme hook name, and contains the
 * information returned from hook_theme(), as well as additional properties