system.api.php 151 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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/**
 * 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;
}

95
96
97
/**
 * Perform periodic actions.
 *
98
99
100
101
102
 * 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.
103
 *
104
105
 * Short-running or non-resource-intensive tasks can be executed directly in
 * the hook_cron() implementation.
106
 *
107
108
109
 * 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
110
 * more queues via hook_queue_info(). Then, add items that need to be
111
 * processed to the defined queues.
112
113
 */
function hook_cron() {
114
115
  // Short-running operation example, not using a queue:
  // Delete all expired records since the last cron run.
116
  $expires = state()->get('mymodule.cron_last_run') ?: REQUEST_TIME;
117
118
119
  db_delete('mymodule_table')
    ->condition('expires', $expires, '>=')
    ->execute();
120
  state()->set('mymodule.cron_last_run', REQUEST_TIME);
121

122
123
  // Long-running operation example, leveraging a queue:
  // Fetch feeds from other sites.
124
  $result = db_query('SELECT * FROM {aggregator_feed} WHERE checked + refresh < :time AND refresh <> :never', array(
125
126
127
    ':time' => REQUEST_TIME,
    ':never' => AGGREGATOR_CLEAR_NEVER,
  ));
128
  $queue = queue('aggregator_feeds');
129
130
  foreach ($result as $feed) {
    $queue->createItem($feed);
131
132
133
  }
}

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/**
 * Defines available data types for the typed data API.
 *
 * The typed data API allows modules to support any kind of data based upon
 * pre-defined primitive types and interfaces for complex data and lists.
 *
 * Defined data types may map to one of the pre-defined primitive types in
 * \Drupal\Core\TypedData\Primitive or may be complex data types, containing one
 * or more data properties. Typed data objects for complex data types have to
 * implement the \Drupal\Core\TypedData\ComplexDataInterface. Further interfaces
 * that may be implemented are:
 *  - \Drupal\Core\TypedData\AccessibleInterface
 *  - \Drupal\Core\TypedData\TranslatableInterface
 *
 * Furthermore, lists of data items are represented by objects implementing
 * the \Drupal\Core\TypedData\ListInterface. A list contains items of the same
 * data type, is ordered and may contain duplicates. The classed used for a list
 * of items of a certain type may be specified using the 'list class' key.
 *
 * @return array
 *   An associative array where the key is the data type name and the value is
 *   again an associative array. Supported keys are:
 *   - label: The human readable label of the data type.
 *   - class: The associated typed data class. Must implement the
 *     \Drupal\Core\TypedData\TypedDataInterface.
 *   - list class: (optional) A typed data class used for wrapping multiple
 *     data items of the type. Must implement the
 *     \Drupal\Core\TypedData\ListInterface.
 *   - primitive type: (optional) Maps the data type to one of the pre-defined
 *     primitive types in \Drupal\Core\TypedData\Primitive. If set, it must be
 *     a constant defined by \Drupal\Core\TypedData\Primitive such as
165
 *     \Drupal\Core\TypedData\Primitive::STRING.
166
167
 *   - constraints: An array of validation constraints for this type. See
 *     \Drupal\Core\TypedData\TypedDataManager::getConstraints() for details.
168
169
170
171
172
173
174
175
176
177
 *
 * @see typed_data()
 * @see Drupal\Core\TypedData\TypedDataManager::create()
 * @see hook_data_type_info_alter()
 */
function hook_data_type_info() {
  return array(
    'email' => array(
      'label' => t('Email'),
      'class' => '\Drupal\email\Type\Email',
178
      'primitive type' => \Drupal\Core\TypedData\Primitive::STRING,
179
      'constraints' => array('Email' => array()),
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
    ),
  );
}

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

196
197
198
199
200
201
/**
 * 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
202
203
204
 * 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.
205
 *
206
207
208
209
 * 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.
 *
210
211
212
 * @return
 *   An associative array where the key is the queue name and the value is
 *   again an associative array. Possible keys are:
213
 *   - 'worker callback': The name of the function to call. It will be called
214
215
 *     with one argument, the item created via
 *     Drupal\Core\Queue\QueueInterface::createItem() in hook_cron().
216
217
218
219
220
 *   - '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.
221
222
 *
 * @see hook_cron()
223
 * @see hook_queue_info_alter()
224
 */
225
function hook_queue_info() {
226
  $queues['aggregator_feeds'] = array(
227
    'title' => t('Aggregator refresh'),
228
    'worker callback' => 'aggregator_refresh',
229
230
231
232
    // Only needed if this queue should be processed by cron.
    'cron' => array(
      'time' => 60,
    ),
233
234
235
236
  );
  return $queues;
}

237
238
239
/**
 * Alter cron queue information before cron runs.
 *
240
 * Called by drupal_cron_run() to allow modules to alter cron queue settings
241
242
243
244
245
 * before any jobs are processesed.
 *
 * @param array $queues
 *   An array of cron queue information.
 *
246
 * @see hook_queue_info()
247
 * @see drupal_cron_run()
248
 */
249
function hook_queue_info_alter(&$queues) {
250
251
  // This site has many feeds so let's spend 90 seconds on each cron run
  // updating feeds instead of the default 60.
252
  $queues['aggregator_feeds']['cron']['time'] = 90;
253
254
}

255
/**
256
 * Allows modules to declare their own Form API element types and specify their
257
258
259
260
261
262
263
264
265
266
267
268
 * 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.
 *
269
 * For more information about custom element types see the explanation at
270
271
272
273
274
275
276
277
 * 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).
278
279
 *  - "#process": array of callback functions taking $element, $form_state,
 *    and $complete_form.
280
281
282
283
284
285
286
 *  - "#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.
287
288
 *  - "#title_display": optional string indicating if and how #title should be
 *    displayed, see theme_form_element() and theme_form_element_label().
289
290
291
 *
 * @see hook_element_info_alter()
 * @see system_element_info()
292
 */
293
294
295
296
297
function hook_element_info() {
  $types['filter_format'] = array(
    '#input' => TRUE,
  );
  return $types;
298
299
}

300
301
302
303
304
305
/**
 * 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.
 *
306
 * @param $type
307
 *   All element type defaults as collected by hook_element_info().
308
 *
309
 * @see hook_element_info()
310
311
312
313
314
315
316
317
 */
function hook_element_info_alter(&$type) {
  // Decrease the default size of textfields.
  if (isset($type['textfield']['#size'])) {
    $type['textfield']['#size'] = 40;
  }
}

318
319
320
/**
 * Perform cleanup tasks.
 *
321
322
323
324
 * This hook is run at the end of each non-cached page request. It is often
 * used for page logging and specialized cleanup. This hook MUST NOT print
 * anything because by the time it runs the response is already sent to the
 * browser.
325
 *
326
 * This hook is not run on cached pages.
327
328
329
330
331
332
 *
 * @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) {
333
  watchdog('mymodule', 'Page was built for user %name.', array('%name' => user_format_name($GLOBALS['user'])), WATCHDOG_INFO);
334
335
336
337
338
339
340
341
}

/**
 * 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.
342
 *
343
344
345
346
347
348
 * @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.
349
  $javascript['core/misc/jquery.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js';
350
351
}

352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
/**
 * 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
372
373
374
 *   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.
375
376
377
378
379
380
381
382
 *
 * 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.
 *
383
 * @see system_library_info()
384
385
386
 * @see drupal_add_library()
 * @see drupal_get_library()
 */
387
function hook_library_info() {
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  // 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.
417
      array('system', 'jquery.ui.core'),
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
      // 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.
 *
441
 * @see hook_library_info()
442
 */
443
function hook_library_info_alter(&$libraries, $module) {
444
445
446
447
448
449
450
451
452
453
454
455
456
  // 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(),
      );
    }
  }
}

457
458
459
460
461
/**
 * 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.
462
 *
463
464
465
466
467
468
469
470
 * @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']);
}

471
/**
472
 * Alter the commands that are sent to the user through the Ajax framework.
473
474
475
 *
 * @param $commands
 *   An array of all commands that will be sent to the user.
476
 *
477
478
479
480
481
482
483
 * @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'));
}

484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
/**
 * 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) {
507
508
509
510
511
512
513
514
515
516
517
518
519
  $path = drupal_get_path('module', 'foo');
  // Add JavaScript/CSS assets to all pages.
  // @see drupal_process_attached()
  $page['#attached']['js'][$path . '/foo.css'] = array('every_page' => TRUE);
  $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.
520
521
522
523
524
525
526
527
  if (menu_get_object('node', 1)) {
    $page['content']['disclaimer'] = array(
      '#markup' => t('Acme, Inc. is not responsible for the contents of this sample code.'),
      '#weight' => 25,
    );
  }
}

528
529
530
531
532
/**
 * 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
533
 * access. The passed-in $router_item is statically cached for the current request, so this
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
 * 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...
554
  if ($path == current_path()) {
555
556
557
558
559
    // ...call a function that prepares something for this request.
    mymodule_prepare_something();
  }
}

560
561
562
563
564
/**
 * 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
565
 * can register a link to be placed in a menu (usually the Tools menu). A
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
 * 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',
 *     );
584
 *     return $items;
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
 *   }
 *
 *   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
605
606
607
608
609
 * 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:
610
611
612
613
614
615
 * @code
 *   function mymodule_menu() {
 *     $items['abc/def'] = array(
 *       'page callback' => 'mymodule_abc_view',
 *       'page arguments' => array(1, 'foo'),
 *     );
616
 *     return $items;
617
618
619
620
621
 *   }
 * @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.
 *
622
623
624
625
626
627
 * 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.
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
 *
 * 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
649
650
 * with 'foo' and passed to the callback function. Note that wildcards may not
 * be used as the first component.
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
 *
 * 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
675
676
 * 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()
677
678
679
680
681
 * 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.
682
683
684
685
686
687
 *
 * 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
688
 * 'tracker/%user_uid_optional'). This function returns the user ID of the
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
 * 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.
706
707
708
709
710
711
712
713
714
715
 *
 * 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
716
 * $items['admin/config/system/foo'] = array(
717
718
 *   'title' => 'Foo settings',
 *   'type' => MENU_NORMAL_ITEM,
719
 *   // Page callback, etc. need to be added here.
720
 * );
721
722
723
 * // Make "Tab 1" the main tab on the "Foo settings" page
 * $items['admin/config/system/foo/tab1'] = array(
 *   'title' => 'Tab 1',
724
 *   'type' => MENU_DEFAULT_LOCAL_TASK,
725
 *   // Access callback, page callback, and theme callback will be inherited
726
 *   // from 'admin/config/system/foo', if not specified here to override.
727
 * );
728
729
730
 * // Make an additional tab called "Tab 2" on "Foo settings"
 * $items['admin/config/system/foo/tab2'] = array(
 *   'title' => 'Tab 2',
731
 *   'type' => MENU_LOCAL_TASK,
732
 *   // Page callback and theme callback will be inherited from
733
 *   // 'admin/config/system/foo', if not specified here to override.
734
 *   // Need to add access callback or access arguments.
735
736
737
738
739
740
741
742
743
744
745
746
747
 * );
 * @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.
748
749
750
751
 *   - description callback: Function to generate the description; defaults to
 *     t(). If you require only the raw string to be output, set this to FALSE.
 *   - description arguments: Arguments to send to t() or your custom callback,
 *     with path component substitution as described above.
752
753
754
755
756
 *   - "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.
757
758
759
760
 *   - "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
761
762
763
764
 *     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).
765
 *   - "access arguments": An array of arguments to pass to the access callback
766
767
768
 *     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.
769
 *   - "theme callback": (optional) A function returning the machine-readable
770
771
772
773
774
775
776
777
778
779
780
781
 *     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.
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
 *   - "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
817
 *     item to be placed in the default Tools menu.
818
819
820
821
 *   - "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.
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
 *   - "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.
859
 *   - "options": An array of options to be passed to l() when generating a link
860
861
 *     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.
862
863
864
865
866
867
 *
 * 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() {
868
869
870
  $items['example'] = array(
    'title' => 'Example Page',
    'page callback' => 'example_page',
871
872
873
    'access arguments' => array('access content'),
    'type' => MENU_SUGGESTED_ITEM,
  );
874
875
876
  $items['example/feed'] = array(
    'title' => 'Example RSS feed',
    'page callback' => 'example_feed',
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
    '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 tabs and actions displayed on the page before they are rendered.
 *
 * This hook is invoked by menu_local_tasks(). The system-determined tabs and
904
 * actions are passed in by reference. Additional tabs or actions may be added.
905
906
907
908
909
910
 *
 * 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.
911
 *   - localized_options: An array of options to pass to l().
912
 * - #weight: The link's weight compared to other links.
913
914
 * - #active: Whether the link should be marked as 'active'.
 *
915
 * @param array $data
916
 *   An associative array containing:
917
918
919
920
921
 *   - 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.
 * @param array $router_item
922
 *   The menu system router item of the page.
923
 * @param string $root_path
924
 *   The path to the root item for this set of tabs.
925
 */
926
function hook_menu_local_tasks(&$data, $router_item, $root_path) {
927
  // Add an action linking to node/add to all pages.
928
929
  $data['actions']['node/add'] = array(
    '#theme' => 'menu_local_action',
930
931
932
933
934
935
936
937
938
939
940
941
    '#link' => array(
      'title' => t('Add new content'),
      'href' => 'node/add',
      'localized_options' => array(
        'attributes' => array(
          'title' => t('Add new content'),
        ),
      ),
    ),
  );

  // Add a tab linking to node/add to all pages.
942
  $data['tabs'][0]['node/add'] = array(
943
944
945
946
947
948
949
950
951
952
    '#theme' => 'menu_local_task',
    '#link' => array(
      'title' => t('Example tab'),
      'href' => 'node/add',
      'localized_options' => array(
        'attributes' => array(
          'title' => t('Add new content'),
        ),
      ),
    ),
953
    // Define whether this link is active. This can usually be omitted.
954
955
956
957
    '#active' => ($router_item['path'] == $root_path),
  );
}

958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
/**
 * 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.
 * @param array $router_item
 *   The menu system router item of the page.
 * @param string $root_path
 *   The path to the root item for this set of tabs.
 *
 * @see hook_menu_local_tasks()
 */
function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) {
}

977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
/**
 * Alter links in the active trail before it is rendered as the breadcrumb.
 *
 * This hook is invoked by menu_get_active_breadcrumb() and allows alteration
 * of the breadcrumb links for the current page, which may be preferred instead
 * of setting a custom breadcrumb via drupal_set_breadcrumb().
 *
 * Implementations should take into account that menu_get_active_breadcrumb()
 * subsequently performs the following adjustments to the active trail *after*
 * this hook has been invoked:
 * - The last link in $active_trail is removed, if its 'href' is identical to
 *   the 'href' of $item. This happens, because the breadcrumb normally does
 *   not contain a link to the current page.
 * - The (second to) last link in $active_trail is removed, if the current $item
 *   is a MENU_DEFAULT_LOCAL_TASK. This happens in order to do not show a link
 *   to the current page, when being on the path for the default local task;
 *   e.g. when being on the path node/%/view, the breadcrumb should not contain
 *   a link to node/%.
 *
 * Each link in the active trail must contain:
 * - title: The localized title of the link.
 * - href: The system path to link to.
 * - localized_options: An array of options to pass to url().
 *
 * @param $active_trail
 *   An array containing breadcrumb links for the current page.
 * @param $item
 *   The menu router item of the current page.
 *
 * @see drupal_set_breadcrumb()
 * @see menu_get_active_breadcrumb()
 * @see menu_get_active_trail()
 * @see menu_set_active_trail()
 */
function hook_menu_breadcrumb_alter(&$active_trail, $item) {
  // Always display a link to the current page by duplicating the last link in
  // the active trail. This means that menu_get_active_breadcrumb() will remove
  // the last link (for the current page), but since it is added once more here,
  // it will appear.
  if (!drupal_is_front_page()) {
    $end = end($active_trail);
    if ($item['href'] == $end['href']) {
      $active_trail[] = $end;
    }
  }
}

1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
/**
 * Alter contextual links before they are rendered.
 *
 * This hook is invoked by menu_contextual_links(). The system-determined
 * contextual links are passed in by reference. Additional links may be added
 * or existing links can be altered.
 *
 * Each contextual link must at least contain:
 * - title: The localized title of the link.
 * - href: The system path to link to.
 * - localized_options: An array of options to pass to url().
 *
 * @param $links
 *   An associative array containing contextual links for the given $root_path,
 *   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.
 * @param $router_item
 *   The menu router item belonging to the $root_path being requested.
 * @param $root_path
 *   The (parent) path that has been requested to build contextual links for.
 *   This is a normalized path, which means that an originally passed path of
 *   'node/123' became 'node/%'.
 *
1048
 * @see hook_contextual_links_view_alter()
1049
1050
 * @see menu_contextual_links()
 * @see hook_menu()
1051
 * @see contextual_preprocess()
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
 */
function hook_menu_contextual_links_alter(&$links, $router_item, $root_path) {
  // Add a link to all contextual links for nodes.
  if ($root_path == 'node/%') {
    $links['foo'] = array(
      'title' => t('Do fu'),
      'href' => 'foo/do',
      'localized_options' => array(
        'query' => array(
          'foo' => 'bar',
        ),
      ),
    );
  }
}

1068
1069
1070
/**
 * Perform alterations before a page is rendered.
 *
1071
1072
1073
1074
1075
 * 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
1076
1077
1078
1079
1080
 * 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
1081
 *   $page['page_top']
1082
 *   $page['header']
1083
 *   $page['sidebar_first']
1084
 *   $page['content']
1085
 *   $page['sidebar_second']
1086
 *   $page['page_bottom']
1087
1088
1089
1090
1091
1092
1093
 * @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'].
 *
1094
 * Pages built by Drupal's core Node module use a standard structure:
1095
1096
1097
 *
 * @code
 *   // Node body.
1098
 *   $page['content']['system_main']['nodes'][$nid]['body']
1099
 *   // Array of links attached to the node (add comments, read more).
1100
 *   $page['content']['system_main']['nodes'][$nid]['links']
1101
 *   // The node entity itself.
1102
 *   $page['content']['system_main']['nodes'][$nid]['#node']
1103
 *   // The results pager.
1104
 *   $page['content']['system_main']['pager']
1105
 * @endcode
1106
1107
1108
 *
 * Blocks may be referenced by their module/delta pair within a region:
 * @code
1109
 *   // The login block in the first sidebar region.
1110
 *   $page['sidebar_first']['user_login']['#block'];
1111
1112
1113
1114
1115
 * @endcode
 *
 * @param $page
 *   Nested array of renderable elements that make up the page.
 *
1116
 * @see hook_page_build()
1117
1118
 * @see drupal_render_page()
 */
1119
1120
1121
1122
1123
1124
function hook_page_alter(&$page) {
  // Add help text to the user login block.
  $page['sidebar_first']['user_login']['help'] = array(
    '#weight' => -10,
    '#markup' => t('To post comments or add new content, you first have to log in.'),
  );
1125
1126
}

1127
1128
1129
1130
/**
 * Perform alterations before a form is rendered.
 *
 * One popular use of this hook is to add form elements to the node form. When
1131
1132
 * altering a node form, the node entity can be retrieved by invoking
 * $form_state['controller']->getEntity($form_state).
1133
 *
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
 * 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.
1149
 *
1150
1151
1152
 * @param $form
 *   Nested array of form elements that comprise the form.
 * @param $form_state
1153
1154
1155
 *   A keyed array containing the current state of the form. The arguments
 *   that drupal_get_form() was originally called with are available in the
 *   array $form_state['build_info']['args'].
1156
1157
1158
 * @param $form_id
 *   String representing the name of the form itself. Typically this is the
 *   name of the function that generated the form.
1159
 *
1160
 * @see hook_form_BASE_FORM_ID_alter()
1161
 * @see hook_form_FORM_ID_alter()
1162
 * @see forms_api_reference.html
1163
 */
1164
function hook_form_alter(&$form, &$form_state, $form_id) {
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
  if (isset($form['type']) && $form['type']['#value'] . '_node_settings' == $form_id) {
    $form['workflow']['upload_' . $form['type']['#value']] = array(
      '#type' => 'radios',
      '#title' => t('Attachments'),
      '#default_value' => variable_get('upload_' . $form['type']['#value'], 1),
      '#options' => array(t('Disabled'), t('Enabled')),
    );
  }
}

/**
 * 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.
 *
1182
1183
1184
1185
 * 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.
 *
1186
1187
1188
 * @param $form
 *   Nested array of form elements that comprise the form.
 * @param $form_state
1189
1190
1191
 *   A keyed array containing the current state of the form. The arguments
 *   that drupal_get_form() was originally called with are available in the
 *   array $form_state['build_info']['args'].
1192
1193
1194
 * @param $form_id
 *   String representing the name of the form itself. Typically this is the
 *   name of the function that generated the form.
1195
 *
1196
 * @see hook_form_alter()
1197
 * @see hook_form_BASE_FORM_ID_alter()
1198
 * @see drupal_prepare_form()
1199
 * @see forms_api_reference.html
1200
 */
1201
function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
1202
  // Modification for the form with the given form ID goes here. For example, if
1203
  // FORM_ID is "user_register_form" this code would run only on the user
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
  // 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,
  );
}

1214
/**
1215
1216
1217
1218
1219
1220
 * Provide a form-specific alteration for shared ('base') forms.
 *
 * By default, when drupal_get_form() 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.
1221
1222
 *
 * Modules can implement hook_form_BASE_FORM_ID_alter() to modify a specific
1223
1224
1225
1226
1227
1228
 * 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'].
1229
 *
1230
1231
 * See hook_forms() for more information on how to implement base forms in
 * Drupal.
1232
 *
1233
1234
1235
 * 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.
1236
1237
1238
1239
1240
1241
1242
1243
1244
 *
 * @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.
 *
1245
 * @see hook_form_alter()
1246
1247
 * @see hook_form_FORM_ID_alter()
 * @see drupal_prepare_form()
1248
 * @see hook_forms()
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
 */
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,
  );
}

1263
/**
1264
 * Map form_ids to form builder functions.
1265
 *
1266
1267
 * By default, when drupal_get_form() is called, the system will look for a
 * function with the same name as the form ID, and use that function to build
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
 * the form. If no such function is found, Drupal calls this hook. Modules
 * implementing this hook can then provide their own instructions for mapping
 * form IDs to constructor functions. As a result, you can easily map multiple
 * form IDs to a single form constructor (referred to as a 'base' form).
 *
 * Using a base form can help to avoid code duplication, by allowing many
 * similar forms to use the same code base. Another benefit is that it becomes
 * much easier for other modules to apply a general change to the group of
 * forms; hook_form_BASE_FORM_ID_alter() can be used to easily alter multiple
 * forms at once by directly targeting the shared base form.
 *
 * Two example use cases where base forms may be useful are given below.
1280
 *
1281
1282
1283
1284
 * First, you can use this hook to tell the form system to use a different
 * function to build certain forms in your module; this is often used to define
 * a form "factory" function that is used to build several similar forms. In
 * this case, your hook implementation will likely ignore all of the input
1285
1286
 * arguments. See node_forms() for an example of this. Note, node_forms() is the
 * hook_forms() implementation; the base form itself is defined in node_form().
1287
 *
1288
1289
1290
1291
 * Second, you could use this hook to define how to build a form with a
 * dynamically-generated form ID. In this case, you would need to verify that
 * the $form_id input matched your module's format for dynamically-generated
 * form IDs, and if so, act appropriately.
1292
 *
1293
1294
1295
 * @param $form_id
 *   The unique string identifying the desired form.
 * @param $args
1296
1297
1298
 *   An array containing the original arguments provided to drupal_get_form()
 *   or drupal_form_submit(). These are always passed to the form builder and
 *   do not have to be specified manually in 'callback arguments'.
1299
 *
1300
 * @return
1301
1302
 *   An associative array whose keys define form_ids and whose values are an
 *   associative array defining the following keys:
1303
1304
1305
 *   - callback: The name of the form builder function to invoke. This will be
 *     used for the base form ID, for example, to target a base form using
 *     hook_form_BASE_FORM_ID_alter().
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
 *   - callback arguments: (optional) Additional arguments to pass to the
 *     function defined in 'callback', which are prepended to $args.
 *   - wrapper_callback: (optional) The name of a form builder function to
 *     invoke before the form builder defined in 'callback' is invoked. This
 *     wrapper callback may prepopulate the $form array with form elements,
 *     which will then be already contained in the $form that is passed on to
 *     the form builder defined in 'callback'. For example, a wrapper callback
 *     could setup wizard-alike form buttons that are the same for a variety of
 *     forms that belong to the wizard, which all share the same wrapper
 *     callback.
1316
 */
1317
function hook_forms($form_id, $args) {
1318
1319
  // Simply reroute the (non-existing) $form_id 'mymodule_first_form' to
  // 'mymodule_main_form'.
1320
  $forms['mymodule_first_form'] = array(
1321
    'callback' => 'mymodule_main_form',
1322
  );
1323
1324
1325

  // Reroute the $form_id and prepend an additional argument that gets passed to
  // the 'mymodule_main_form' form builder function.
1326
  $forms['mymodule_second_form'] = array(
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
    'callback' => 'mymodule_main_form',
    'callback arguments' => array('some parameter'),
  );

  // Reroute the $form_id, but invoke the form builder function
  // 'mymodule_main_form_wrapper' first, so we can prepopulate the $form array
  // that is passed to the actual form builder 'mymodule_main_form'.
  $forms['mymodule_wrapped_form'] = array(
    'callback' => 'mymodule_main_form',
    'wrapper_callback' => 'mymodule_main_form_wrapper',
1337
  );
1338

1339
1340
1341
1342
  return $forms;
}

/**
1343
 * Perform setup tasks for non-cached page requests.
1344
1345
 *
 * This hook is run at the beginning of the page request. It is typically
1346
 * used to set up global parameters that are needed later in the request.
1347
1348
 * When this hook is called, the theme and all modules are already loaded in
 * memory.
1349
 *
1350
1351
 * This hook is not run on cached pages.
 *
1352
1353
1354
1355
1356
 * @see hook_exit()
 *
 * Do not use this hook to add CSS/JS to pages, use hook_page_build() instead.
 *
 * @see hook_page_build()
1357
1358
1359
1360
1361
 */
function hook_init() {
}

/**
1362
1363
1364
 * Define image toolkits provided by this module.
 *
 * The file which includes each toolkit's functions must be declared as part of
1365
1366
 * the files array in the module .info.yml file so that the registry will find
 * and parse it.
1367
1368
1369
1370
1371
1372
1373
 *
 * The toolkit's functions must be named image_toolkitname_operation().
 * where the operation may be:
 *   - 'load': Required. See image_gd_load() for usage.
 *   - 'save': Required. See image_gd_save() for usage.
 *   - 'settings': Optional. See image_gd_settings() for usage.
 *   - 'resize': Optional. See image_gd_resize() for usage.
1374
 *   - 'rotate': Optional. See image_gd_rotate() for usage.
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
 *   - 'crop': Optional. See image_gd_crop() for usage.
 *   - 'desaturate': Optional. See image_gd_desaturate() for usage.
 *
 * @return
 *   An array with the toolkit name as keys and sub-arrays with these keys:
 *     - 'title': A string with the toolkit's title.
 *     - 'available': A Boolean value to indicate that the toolkit is operating
 *       properly, e.g. all required libraries exist.
 *
 * @see system_image_toolkits()
 */
1386
function hook_image_toolkits() {
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
  return array(
    'working' => array(
      'title' => t('A toolkit that works.'),
      'available' => TRUE,
    ),
    'broken' => array(
      'title' => t('A toolkit that is "broken" and will not be listed.'),
      'available' => FALSE,
    ),
  );
1397
1398
1399
}

/**
1400
1401
1402
1403
1404
1405
1406
1407
 * 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
1408
 * calling the drupal_mail_system()->mail() or PHP mail() function
1409
 * will not invoke this hook. All core modules use drupal_mail() for
1410
 * messaging, it is best practice but not mandatory in contributed modules.
1411
1412
 *
 * @param $message
1413
 *   An array containing the message data. Keys in this array include:
1414
 *  - 'id':
1415
 *     The drupal_mail() id of the message. Look at module source code or
1416
 *     drupal_mail() for possible id values.
1417
 *  - 'to':
1418
 *     The address or addresses the message will be sent to. The
1419
 *     formatting of this string must comply with RFC 2822.
1420
 *  - 'from':
1421
1422
 *     The address the message will be marked as being from, which is
 *     either a custom address or the site-wide default email address.
1423
1424
1425
1426
1427
 *  - '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
1428
 *     created by concatenating the individual array strings into a single text
1429
1430
 *     string using "\n\n" as a separator.
 *  - 'headers':
1431
 *     Associative array containing mail headers, such as From, Sender,
1432
 *     MIME-Version, Content-Type, etc.
1433
1434
1435
1436
1437
1438
 *  - '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.
1439
1440
 *  - 'send':
 *     Set to FALSE to abort sending this email message.
1441
1442
 *
 * @see drupal_mail()
1443
1444
 */
function hook_mail_alter(&$message) {
1445
  if ($message['id'] == 'modulename_messagekey') {
1446
1447
1448
1449
1450
1451
    if (!example_notifications_optin($message['to'], $message['id'])) {
      // If the recipient has opted to not receive such messages, cancel
      // sending.
      $message['send'] = FALSE;
      return;
    }
1452
    $message['body'][] = "--\nMail sent out from " . config('system.site')->get('name');
1453
1454
1455
  }
}

1456
1457
1458
1459
1460
1461
1462
/**
 * Alter the registry of modules implementing a hook.
 *
 * This hook is invoked during module_implements(). A module may implement this
 * hook in order to reorder the implementing modules, which are otherwise
 * ordered by the module's system weight.
 *
1463
1464
1465
1466
1467
1468
 * Note that hooks invoked using drupal_alter() can have multiple variations
 * (such as hook_form_alter() and hook_form_FORM_ID_alter()). drupal_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
1469
 * change the order of hook_form_alter() implementation in
1470
1471
 * hook_module_implements_alter().
 *
1472
 * @param $implementations
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
 *   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') {
    // Move my_module_rdf_mapping() to the end of the list. module_implements()
    // 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;
  }
}

1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
/**
 * Return additional themes provided by modules.
 *
 * Only use this hook for testing purposes. Use a hidden MYMODULE_test.module
 * to implement this hook. Testing themes should be hidden, too.
 *
 * This hook is invoked from _system_rebuild_theme_data() and allows modules to
 * register additional themes outside of the regular 'themes' directories of a
 * Drupal installation.
 *
 * @return
 *   An associative array. Each key is the system name of a theme and each value
1503
 *   is the corresponding path to the theme's .info.yml file.
1504
1505
 */
function hook_system_theme_info() {
1506
  $themes['mymodule_test_theme'] = drupal_get_path('module', 'mymodule') . '/mymodule_test_theme/mymodule_test_theme.info.yml';
1507
1508
1509
  return $themes;
}