| Commit | Line | Data |
|---|---|---|
| 66df6025 | 1 | <?php |
| 66df6025 AB |
2 | |
| 3 | /** | |
| 4 | * @file | |
| 5 | * Hooks provided by Drupal core and the System module. | |
| 6 | */ | |
| 7 | ||
| 8 | /** | |
| 9 | * @addtogroup hooks | |
| 10 | * @{ | |
| 11 | */ | |
| 12 | ||
| 13 | /** | |
| 13d3072f DB |
14 | * Defines one or more hooks that are exposed by a module. |
| 15 | * | |
| 16 | * Normally hooks do not need to be explicitly defined. However, by declaring a | |
| 17 | * hook explicitly, a module may define a "group" for it. Modules that implement | |
| 18 | * a hook may then place their implementation in either $module.module or in | |
| 19 | * $module.$group.inc. If the hook is located in $module.$group.inc, then that | |
| 20 | * file will be automatically loaded when needed. | |
| 21 | * In general, hooks that are rarely invoked and/or are very large should be | |
| 22 | * placed in a separate include file, while hooks that are very short or very | |
| 23 | * frequently called should be left in the main module file so that they are | |
| 24 | * always available. | |
| 25 | * | |
| 26 | * @return | |
| 27 | * An associative array whose keys are hook names and whose values are an | |
| 28 | * associative array containing: | |
| 29 | * - group: A string defining the group to which the hook belongs. The module | |
| 30 | * system will determine whether a file with the name $module.$group.inc | |
| 31 | * exists, and automatically load it when required. | |
| 32 | * | |
| 33 | * See system_hook_info() for all hook groups defined by Drupal core. | |
| 269da037 AB |
34 | * |
| 35 | * @see hook_hook_info_alter(). | |
| 13d3072f DB |
36 | */ |
| 37 | function hook_hook_info() { | |
| 38 | $hooks['token_info'] = array( | |
| 39 | 'group' => 'tokens', | |
| 40 | ); | |
| 41 | $hooks['tokens'] = array( | |
| 42 | 'group' => 'tokens', | |
| 43 | ); | |
| 44 | return $hooks; | |
| 45 | } | |
| 46 | ||
| 47 | /** | |
| 269da037 AB |
48 | * Alter information from hook_hook_info(). |
| 49 | * | |
| 50 | * @param $hooks | |
| 51 | * Information gathered by module_hook_info() from other modules' | |
| 52 | * implementations of hook_hook_info(). Alter this array directly. | |
| 53 | * See hook_hook_info() for information on what this may contain. | |
| 54 | */ | |
| 55 | function hook_hook_info_alter(&$hooks) { | |
| 56 | // Our module wants to completely override the core tokens, so make | |
| 57 | // sure the core token hooks are not found. | |
| 58 | $hooks['token_info']['group'] = 'mytokens'; | |
| 59 | $hooks['tokens']['group'] = 'mytokens'; | |
| 60 | } | |
| 61 | ||
| 62 | /** | |
| 3f36af04 DB |
63 | * Inform the base system and the Field API about one or more entity types. |
| 64 | * | |
| 65 | * Inform the system about one or more entity types (i.e., object types that | |
| 66 | * can be loaded via entity_load() and, optionally, to which fields can be | |
| 67 | * attached). | |
| 68 | * | |
| 3f36af04 DB |
69 | * @return |
| 70 | * An array whose keys are entity type names and whose values identify | |
| 53748ab5 | 71 | * properties of those types that the system needs to know about: |
| 539ba0dc | 72 | * - label: The human-readable name of the type. |
| 4c686375 | 73 | * - controller class: The name of the class that is used to load the objects. |
| 42f9d899 | 74 | * The class has to implement the DrupalEntityControllerInterface interface. |
| 539ba0dc DB |
75 | * Leave blank to use the DrupalDefaultEntityController implementation. |
| 76 | * - base table: (used by DrupalDefaultEntityController) The name of the | |
| 4c686375 | 77 | * entity type's base table. |
| 66f93d71 | 78 | * - revision table: The name of the entity type's revision table (if any). |
| 539ba0dc | 79 | * - static cache: (used by DrupalDefaultEntityController) FALSE to disable |
| 3f36af04 | 80 | * static caching of entities during a page request. Defaults to TRUE. |
| d864fc63 DB |
81 | * - field cache: (used by Field API loading and saving of field data) FALSE |
| 82 | * to disable Field API's persistent cache of field data. Only recommended | |
| 83 | * if a higher level persistent cache is available for the entity type. | |
| 84 | * Defaults to TRUE. | |
| 4c686375 DB |
85 | * - load hook: The name of the hook which should be invoked by |
| 86 | * DrupalDefaultEntityController:attachLoad(), for example 'node_load'. | |
| 52195a6b AB |
87 | * - uri callback: A function taking an entity as argument and returning the |
| 88 | * uri elements of the entity, e.g. 'path' and 'options'. The actual entity | |
| 89 | * uri can be constructed by passing these elements to url(). | |
| 267b9c43 | 90 | * - label callback: (optional) A function taking an entity and an entity type |
| 91 | * as arguments and returning the label of the entity. The entity label is | |
| 92 | * the main string associated with an entity; for example, the title of a | |
| 93 | * node or the subject of a comment. If there is an entity object property | |
| 94 | * that defines the label, use the 'label' element of the 'entity keys' | |
| 95 | * return value component to provide this information (see below). If more | |
| 96 | * complex logic is needed to determine the label of an entity, you can | |
| 97 | * instead specify a callback function here, which will be called to | |
| 98 | * determine the entity label. See also the entity_label() function, which | |
| 99 | * implements this logic. | |
| 66f93d71 | 100 | * - fieldable: Set to TRUE if you want your entity type to accept fields |
| 101 | * being attached to it. | |
| d073fa2a AB |
102 | * - translation: An associative array of modules registered as field |
| 103 | * translation handlers. Array keys are the module names, array values | |
| 104 | * can be any data structure the module uses to provide field translation. | |
| 105 | * Any empty value disallows the module to appear as a translation handler. | |
| 7d4b84b8 | 106 | * - entity keys: An array describing how the Field API can extract the |
| 4c686375 | 107 | * information it needs from the objects of the type. Elements: |
| 3f36af04 | 108 | * - id: The name of the property that contains the primary id of the |
| 6c049009 DB |
109 | * entity. Every entity object passed to the Field API must have this |
| 110 | * property and its value must be numeric. | |
| 3f36af04 | 111 | * - revision: The name of the property that contains the revision id of |
| 6c049009 DB |
112 | * the entity. The Field API assumes that all revision ids are unique |
| 113 | * across all entities of a type. This entry can be omitted if the | |
| 114 | * entities of this type are not versionable. | |
| 3f36af04 | 115 | * - bundle: The name of the property that contains the bundle name for the |
| 6c049009 DB |
116 | * entity. The bundle name defines which set of fields are attached to |
| 117 | * the entity (e.g. what nodes call "content type"). This entry can be | |
| 118 | * omitted if this entity type exposes a single bundle (all entities have | |
| ce08394b DB |
119 | * the same collection of fields). The name of this single bundle will be |
| 120 | * the same as the entity type. | |
| 6d13ffa4 | 121 | * - label: The name of the property that contains the entity label. For |
| b06d19e3 | 122 | * example, if the entity's label is located in $entity->subject, then |
| 6d13ffa4 AB |
123 | * 'subject' should be specified here. If complex logic is required to |
| 124 | * build the label, a 'label callback' should be defined instead (see | |
| 125 | * the 'label callback' section above for details). | |
| 3f36af04 | 126 | * - bundle keys: An array describing how the Field API can extract the |
| eeadb939 DB |
127 | * information it needs from the bundle objects for this type. This entry |
| 128 | * is required if the 'path' provided in the 'bundles'/'admin' section | |
| 129 | * identifies the bundle using a named menu placeholder whose loader | |
| 130 | * callback returns an object (e.g., $vocabulary for taxonomy terms, or | |
| 131 | * $node_type for nodes). If the path does not include the bundle, or the | |
| 132 | * bundle is just a string rather than an automatically loaded object, then | |
| 133 | * this can be omitted. Elements: | |
| 134 | * - bundle: The name of the property of the bundle object that contains | |
| 135 | * the name of the bundle object. | |
| 6c049009 DB |
136 | * - bundles: An array describing all bundles for this object type. Keys are |
| 137 | * bundles machine names, as found in the objects' 'bundle' property | |
| 138 | * (defined in the 'entity keys' entry above). Elements: | |
| 3f36af04 | 139 | * - label: The human-readable name of the bundle. |
| ba96cffd DB |
140 | * - uri callback: Same as the 'uri callback' key documented above for the |
| 141 | * entity type, but for the bundle only. When determining the URI of an | |
| 142 | * entity, if a 'uri callback' is defined for both the entity type and | |
| 143 | * the bundle, the one for the bundle is used. | |
| ea51c321 DB |
144 | * - admin: An array of information that allows Field UI pages to attach |
| 145 | * themselves to the existing administration pages for the bundle. | |
| e92e8ddb | 146 | * Elements: |
| 3f36af04 DB |
147 | * - path: the path of the bundle's main administration page, as defined |
| 148 | * in hook_menu(). If the path includes a placeholder for the bundle, | |
| eeadb939 DB |
149 | * the 'bundle argument' and 'real path' keys below are required. |
| 150 | * - bundle argument: The position of the bundle placeholder in 'path', if | |
| 151 | * any. | |
| 3f36af04 DB |
152 | * - real path: The actual path (no placeholder) of the bundle's main |
| 153 | * administration page. This will be used to generate links. | |
| 154 | * - access callback: As in hook_menu(). 'user_access' will be assumed if | |
| 155 | * no value is provided. | |
| 156 | * - access arguments: As in hook_menu(). | |
| 53748ab5 DB |
157 | * - view modes: An array describing the view modes for the entity type. View |
| 158 | * modes let entities be displayed differently depending on the context. | |
| 159 | * For instance, a node can be displayed differently on its own page | |
| 160 | * ('full' mode), on the home page or taxonomy listings ('teaser' mode), or | |
| 161 | * in an RSS feed ('rss' mode). Modules taking part in the display of the | |
| 162 | * entity (notably the Field API) can adjust their behavior depending on | |
| 5ff0c0d3 DB |
163 | * the requested view mode. An additional 'default' view mode is available |
| 164 | * for all entity types. This view mode is not intended for actual entity | |
| 165 | * display, but holds default display settings. For each available view | |
| 166 | * mode, administrators can configure whether it should use its own set of | |
| 167 | * field display settings, or just replicate the settings of the 'default' | |
| 168 | * view mode, thus reducing the amount of display configurations to keep | |
| 169 | * track of. Keys of the array are view mode names. Each view mode is | |
| 170 | * described by an array with the following key/value pairs: | |
| 53748ab5 | 171 | * - label: The human-readable name of the view mode |
| 5ff0c0d3 | 172 | * - custom settings: A boolean specifying whether the view mode should by |
| f9de90e1 DB |
173 | * default use its own custom field display settings. If FALSE, entities |
| 174 | * displayed in this view mode will reuse the 'default' display settings | |
| 175 | * by default (e.g. right after the module exposing the view mode is | |
| 176 | * enabled), but administrators can later use the Field UI to apply custom | |
| 177 | * display settings specific to the view mode. | |
| 87f1bf45 DB |
178 | * |
| 179 | * @see entity_load() | |
| 180 | * @see hook_entity_info_alter() | |
| 3f36af04 DB |
181 | */ |
| 182 | function hook_entity_info() { | |
| 183 | $return = array( | |
| 184 | 'node' => array( | |
| 539ba0dc | 185 | 'label' => t('Node'), |
| 3f36af04 DB |
186 | 'controller class' => 'NodeController', |
| 187 | 'base table' => 'node', | |
| 539ba0dc | 188 | 'revision table' => 'node_revision', |
| 5ff0c0d3 | 189 | 'uri callback' => 'node_uri', |
| 3f36af04 | 190 | 'fieldable' => TRUE, |
| d073fa2a AB |
191 | 'translation' => array( |
| 192 | 'locale' => TRUE, | |
| 193 | ), | |
| 7d4b84b8 | 194 | 'entity keys' => array( |
| 539ba0dc DB |
195 | 'id' => 'nid', |
| 196 | 'revision' => 'vid', | |
| 197 | 'bundle' => 'type', | |
| 198 | ), | |
| 199 | 'bundle keys' => array( | |
| 200 | 'bundle' => 'type', | |
| 201 | ), | |
| 539ba0dc DB |
202 | 'bundles' => array(), |
| 203 | 'view modes' => array( | |
| 204 | 'full' => array( | |
| 5ff0c0d3 DB |
205 | 'label' => t('Full content'), |
| 206 | 'custom settings' => FALSE, | |
| 539ba0dc DB |
207 | ), |
| 208 | 'teaser' => array( | |
| 209 | 'label' => t('Teaser'), | |
| 5ff0c0d3 | 210 | 'custom settings' => TRUE, |
| 539ba0dc DB |
211 | ), |
| 212 | 'rss' => array( | |
| 213 | 'label' => t('RSS'), | |
| 5ff0c0d3 | 214 | 'custom settings' => FALSE, |
| 539ba0dc DB |
215 | ), |
| 216 | ), | |
| 3f36af04 DB |
217 | ), |
| 218 | ); | |
| 539ba0dc DB |
219 | |
| 220 | // Search integration is provided by node.module, so search-related | |
| 221 | // view modes for nodes are defined here and not in search.module. | |
| 222 | if (module_exists('search')) { | |
| 223 | $return['node']['view modes'] += array( | |
| 224 | 'search_index' => array( | |
| 225 | 'label' => t('Search index'), | |
| 5ff0c0d3 | 226 | 'custom settings' => FALSE, |
| 539ba0dc DB |
227 | ), |
| 228 | 'search_result' => array( | |
| 229 | 'label' => t('Search result'), | |
| 5ff0c0d3 | 230 | 'custom settings' => FALSE, |
| 539ba0dc DB |
231 | ), |
| 232 | ); | |
| 233 | } | |
| 234 | ||
| 235 | // Bundles must provide a human readable name so we can create help and error | |
| 236 | // messages, and the path to attach Field admin pages to. | |
| 237 | foreach (node_type_get_names() as $type => $name) { | |
| 238 | $return['node']['bundles'][$type] = array( | |
| 239 | 'label' => $name, | |
| 240 | 'admin' => array( | |
| 241 | 'path' => 'admin/structure/types/manage/%node_type', | |
| 242 | 'real path' => 'admin/structure/types/manage/' . str_replace('_', '-', $type), | |
| 243 | 'bundle argument' => 4, | |
| 244 | 'access arguments' => array('administer content types'), | |
| 245 | ), | |
| 246 | ); | |
| 247 | } | |
| 248 | ||
| 3f36af04 DB |
249 | return $return; |
| 250 | } | |
| 251 | ||
| 252 | /** | |
| 253 | * Alter the entity info. | |
| 254 | * | |
| 255 | * Modules may implement this hook to alter the information that defines an | |
| 256 | * entity. All properties that are available in hook_entity_info() can be | |
| 257 | * altered here. | |
| 258 | * | |
| 3f36af04 DB |
259 | * @param $entity_info |
| 260 | * The entity info array, keyed by entity name. | |
| 87f1bf45 DB |
261 | * |
| 262 | * @see hook_entity_info() | |
| 3f36af04 DB |
263 | */ |
| 264 | function hook_entity_info_alter(&$entity_info) { | |
| 265 | // Set the controller class for nodes to an alternate implementation of the | |
| 266 | // DrupalEntityController interface. | |
| 267 | $entity_info['node']['controller class'] = 'MyCustomNodeController'; | |
| 268 | } | |
| 269 | ||
| 270 | /** | |
| 1c7bca0b AB |
271 | * Act on entities when loaded. |
| 272 | * | |
| 273 | * This is a generic load hook called for all entity types loaded via the | |
| 274 | * entity API. | |
| 275 | * | |
| 276 | * @param $entities | |
| 277 | * The entities keyed by entity ID. | |
| 278 | * @param $type | |
| 279 | * The type of entities being loaded (i.e. node, user, comment). | |
| 280 | */ | |
| 281 | function hook_entity_load($entities, $type) { | |
| 282 | foreach ($entities as $entity) { | |
| 5674b54f | 283 | $entity->foo = mymodule_add_something($entity, $type); |
| 1c7bca0b AB |
284 | } |
| 285 | } | |
| 286 | ||
| 287 | /** | |
| 71c4e3ec AB |
288 | * Act on an entity before it is about to be created or updated. |
| 289 | * | |
| 290 | * @param $entity | |
| 291 | * The entity object. | |
| 292 | * @param $type | |
| 293 | * The type of entity being saved (i.e. node, user, comment). | |
| 294 | */ | |
| 295 | function hook_entity_presave($entity, $type) { | |
| 296 | $entity->changed = REQUEST_TIME; | |
| 297 | } | |
| 298 | ||
| 299 | /** | |
| 02c1eeee AB |
300 | * Act on entities when inserted. |
| 301 | * | |
| 02c1eeee AB |
302 | * @param $entity |
| 303 | * The entity object. | |
| 304 | * @param $type | |
| 305 | * The type of entity being inserted (i.e. node, user, comment). | |
| 306 | */ | |
| 307 | function hook_entity_insert($entity, $type) { | |
| 91bc8bed AB |
308 | // Insert the new entity into a fictional table of all entities. |
| 309 | $info = entity_get_info($type); | |
| fee217fa | 310 | list($id) = entity_extract_ids($type, $entity); |
| 91bc8bed AB |
311 | db_insert('example_entity') |
| 312 | ->fields(array( | |
| 313 | 'type' => $type, | |
| 314 | 'id' => $id, | |
| 315 | 'created' => REQUEST_TIME, | |
| 316 | 'updated' => REQUEST_TIME, | |
| 317 | )) | |
| 318 | ->execute(); | |
| 02c1eeee AB |
319 | } |
| 320 | ||
| 321 | /** | |
| 322 | * Act on entities when updated. | |
| 323 | * | |
| 02c1eeee AB |
324 | * @param $entity |
| 325 | * The entity object. | |
| 326 | * @param $type | |
| 327 | * The type of entity being updated (i.e. node, user, comment). | |
| 328 | */ | |
| 329 | function hook_entity_update($entity, $type) { | |
| 91bc8bed AB |
330 | // Update the entity's entry in a fictional table of all entities. |
| 331 | $info = entity_get_info($type); | |
| fee217fa | 332 | list($id) = entity_extract_ids($type, $entity); |
| 91bc8bed AB |
333 | db_update('example_entity') |
| 334 | ->fields(array( | |
| 335 | 'updated' => REQUEST_TIME, | |
| 336 | )) | |
| 337 | ->condition('type', $type) | |
| 338 | ->condition('id', $id) | |
| 339 | ->execute(); | |
| 340 | } | |
| 341 | ||
| 342 | /** | |
| 343 | * Act on entities when deleted. | |
| 344 | * | |
| 345 | * @param $entity | |
| 346 | * The entity object. | |
| 347 | * @param $type | |
| 348 | * The type of entity being deleted (i.e. node, user, comment). | |
| 349 | */ | |
| 350 | function hook_entity_delete($entity, $type) { | |
| 351 | // Delete the entity's entry from a fictional table of all entities. | |
| 352 | $info = entity_get_info($type); | |
| fee217fa | 353 | list($id) = entity_extract_ids($type, $entity); |
| 91bc8bed AB |
354 | db_delete('example_entity') |
| 355 | ->condition('type', $type) | |
| 356 | ->condition('id', $id) | |
| 357 | ->execute(); | |
| 02c1eeee AB |
358 | } |
| 359 | ||
| 360 | /** | |
| 9cf21be9 DB |
361 | * Alter or execute an EntityFieldQuery. |
| 362 | * | |
| 363 | * @param EntityFieldQuery $query | |
| 364 | * An EntityFieldQuery. One of the most important properties to be changed is | |
| 365 | * EntityFieldQuery::executeCallback. If this is set to an existing function, | |
| 366 | * this function will get the query as its single argument and its result | |
| 367 | * will be the returned as the result of EntityFieldQuery::execute(). This can | |
| 368 | * be used to change the behavior of EntityFieldQuery entirely. For example, | |
| 369 | * the default implementation can only deal with one field storage engine, but | |
| 370 | * it is possible to write a module that can query across field storage | |
| 371 | * engines. Also, the default implementation presumes entities are stored in | |
| 372 | * SQL, but the execute callback could instead query any other entity storage, | |
| 373 | * local or remote. | |
| 0c33e863 AB |
374 | * |
| 375 | * Note the $query->altered attribute which is TRUE in case the query has | |
| 376 | * already been altered once. This happens with cloned queries. | |
| 377 | * If there is a pager, then such a cloned query will be executed to count | |
| 378 | * all elements. This query can be detected by checking for | |
| 379 | * ($query->pager && $query->count), allowing the driver to return 0 from | |
| 380 | * the count query and disable the pager. | |
| 9cf21be9 DB |
381 | */ |
| 382 | function hook_entity_query_alter($query) { | |
| 383 | $query->executeCallback = 'my_module_query_callback'; | |
| 384 | } | |
| 385 | ||
| 386 | /** | |
| 43558501 AB |
387 | * Act on entities being assembled before rendering. |
| 388 | * | |
| 389 | * @param $entity | |
| 390 | * The entity object. | |
| 391 | * @param $type | |
| 392 | * The type of entity being rendered (i.e. node, user, comment). | |
| 393 | * @param $view_mode | |
| 394 | * The view mode the entity is rendered in. | |
| 395 | * @param $langcode | |
| 396 | * The language code used for rendering. | |
| 397 | * | |
| 398 | * The module may add elements to $entity->content prior to rendering. The | |
| 399 | * structure of $entity->content is a renderable array as expected by | |
| 400 | * drupal_render(). | |
| 401 | * | |
| 402 | * @see hook_entity_view_alter() | |
| 403 | * @see hook_comment_view() | |
| 404 | * @see hook_node_view() | |
| 405 | * @see hook_user_view() | |
| 406 | */ | |
| 407 | function hook_entity_view($entity, $type, $view_mode, $langcode) { | |
| 408 | $entity->content['my_additional_field'] = array( | |
| 409 | '#markup' => $additional_field, | |
| 410 | '#weight' => 10, | |
| 411 | '#theme' => 'mymodule_my_additional_field', | |
| 412 | ); | |
| 413 | } | |
| 414 | ||
| 415 | /** | |
| 416 | * Alter the results of ENTITY_view(). | |
| 417 | * | |
| 418 | * This hook is called after the content has been assembled in a structured | |
| 419 | * array and may be used for doing processing which requires that the complete | |
| 420 | * entity content structure has been built. | |
| 421 | * | |
| 422 | * If a module wishes to act on the rendered HTML of the entity rather than the | |
| 423 | * structured content array, it may use this hook to add a #post_render | |
| 424 | * callback. Alternatively, it could also implement hook_preprocess_ENTITY(). | |
| 425 | * See drupal_render() and theme() for details. | |
| 426 | * | |
| 427 | * @param $build | |
| 428 | * A renderable array representing the entity content. | |
| 429 | * @param $type | |
| 430 | * The type of entity being rendered (i.e. node, user, comment). | |
| 431 | * | |
| 432 | * @see hook_entity_view() | |
| 433 | * @see hook_comment_view_alter() | |
| 434 | * @see hook_node_view_alter() | |
| 435 | * @see hook_taxonomy_term_view_alter() | |
| 436 | * @see hook_user_view_alter() | |
| 437 | */ | |
| 438 | function hook_entity_view_alter(&$build, $type) { | |
| 439 | if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) { | |
| 440 | // Change its weight. | |
| 441 | $build['an_additional_field']['#weight'] = -10; | |
| 442 | ||
| 443 | // Add a #post_render callback to act on the rendered HTML of the entity. | |
| 444 | $build['#post_render'][] = 'my_module_node_post_render'; | |
| 445 | } | |
| 446 | } | |
| 447 | ||
| 448 | /** | |
| c9120083 AB |
449 | * Define administrative paths. |
| 450 | * | |
| 451 | * Modules may specify whether or not the paths they define in hook_menu() are | |
| 452 | * to be considered administrative. Other modules may use this information to | |
| 453 | * display those pages differently (e.g. in a modal overlay, or in a different | |
| 454 | * theme). | |
| 455 | * | |
| 456 | * To change the administrative status of menu items defined in another module's | |
| 457 | * hook_menu(), modules should implement hook_admin_paths_alter(). | |
| 458 | * | |
| 459 | * @return | |
| 460 | * An associative array. For each item, the key is the path in question, in | |
| 461 | * a format acceptable to drupal_match_path(). The value for each item should | |
| 462 | * be TRUE (for paths considered administrative) or FALSE (for non- | |
| 463 | * administrative paths). | |
| 464 | * | |
| 465 | * @see hook_menu() | |
| 466 | * @see drupal_match_path() | |
| 467 | * @see hook_admin_paths_alter() | |
| 468 | */ | |
| 469 | function hook_admin_paths() { | |
| 470 | $paths = array( | |
| 471 | 'mymodule/*/add' => TRUE, | |
| 472 | 'mymodule/*/edit' => TRUE, | |
| 473 | ); | |
| 474 | return $paths; | |
| 475 | } | |
| 476 | ||
| 477 | /** | |
| 478 | * Redefine administrative paths defined by other modules. | |
| 479 | * | |
| 480 | * @param $paths | |
| 481 | * An associative array of administrative paths, as defined by implementations | |
| 482 | * of hook_admin_paths(). | |
| 483 | * | |
| 484 | * @see hook_admin_paths() | |
| 485 | */ | |
| 486 | function hook_admin_paths_alter(&$paths) { | |
| 487 | // Treat all user pages as administrative. | |
| 488 | $paths['user'] = TRUE; | |
| 489 | $paths['user/*'] = TRUE; | |
| 490 | // Treat the forum topic node form as a non-administrative page. | |
| 491 | $paths['node/add/forum'] = FALSE; | |
| 492 | } | |
| 493 | ||
| 494 | /** | |
| 3a0f6b33 AB |
495 | * Act on entities as they are being prepared for view. |
| 496 | * | |
| 497 | * Allows you to operate on multiple entities as they are being prepared for | |
| 498 | * view. Only use this if attaching the data during the entity_load() phase | |
| 499 | * is not appropriate, for example when attaching other 'entity' style objects. | |
| 500 | * | |
| 501 | * @param $entities | |
| 502 | * The entities keyed by entity ID. | |
| 503 | * @param $type | |
| 504 | * The type of entities being loaded (i.e. node, user, comment). | |
| 75a0deb2 | 505 | * @param $langcode |
| 506 | * The language to display the entity in. | |
| 3a0f6b33 | 507 | */ |
| 75a0deb2 | 508 | function hook_entity_prepare_view($entities, $type, $langcode) { |
| 3a0f6b33 AB |
509 | // Load a specific node into the user object for later theming. |
| 510 | if ($type == 'user') { | |
| 511 | $nodes = mymodule_get_user_nodes(array_keys($entities)); | |
| 512 | foreach ($entities as $uid => $entity) { | |
| 513 | $entity->user_node = $nodes[$uid]; | |
| 514 | } | |
| 515 | } | |
| 516 | } | |
| 517 | ||
| 518 | /** | |
| 66df6025 AB |
519 | * Perform periodic actions. |
| 520 | * | |
| f1b30b89 AB |
521 | * Modules that require some commands to be executed periodically can |
| 522 | * implement hook_cron(). The engine will then call the hook whenever a cron | |
| 523 | * run happens, as defined by the administrator. Typical tasks managed by | |
| 524 | * hook_cron() are database maintenance, backups, recalculation of settings | |
| 525 | * or parameters, automated mailing, and retrieving remote data. | |
| 66df6025 | 526 | * |
| f1b30b89 AB |
527 | * Short-running or non-resource-intensive tasks can be executed directly in |
| 528 | * the hook_cron() implementation. | |
| 9e638424 | 529 | * |
| f1b30b89 AB |
530 | * Long-running tasks and tasks that could time out, such as retrieving remote |
| 531 | * data, sending email, and intensive file tasks, should use the queue API | |
| 532 | * instead of executing the tasks directly. To do this, first define one or | |
| 533 | * more queues via hook_cron_queue_info(). Then, add items that need to be | |
| 534 | * processed to the defined queues. | |
| 66df6025 AB |
535 | */ |
| 536 | function hook_cron() { | |
| 9e638424 DB |
537 | // Short-running operation example, not using a queue: |
| 538 | // Delete all expired records since the last cron run. | |
| 539 | $expires = variable_get('mymodule_cron_last_run', REQUEST_TIME); | |
| 540 | db_delete('mymodule_table') | |
| 541 | ->condition('expires', $expires, '>=') | |
| 542 | ->execute(); | |
| 543 | variable_set('mymodule_cron_last_run', REQUEST_TIME); | |
| 66df6025 | 544 | |
| 9e638424 DB |
545 | // Long-running operation example, leveraging a queue: |
| 546 | // Fetch feeds from other sites. | |
| 5dedc4c4 | 547 | $result = db_query('SELECT * FROM {aggregator_feed} WHERE checked + refresh < :time AND refresh <> :never', array( |
| 9e638424 DB |
548 | ':time' => REQUEST_TIME, |
| 549 | ':never' => AGGREGATOR_CLEAR_NEVER, | |
| 550 | )); | |
| 551 | $queue = DrupalQueue::get('aggregator_feeds'); | |
| 552 | foreach ($result as $feed) { | |
| 553 | $queue->createItem($feed); | |
| 66df6025 AB |
554 | } |
| 555 | } | |
| 556 | ||
| 557 | /** | |
| 762be09f DB |
558 | * Declare queues holding items that need to be run periodically. |
| 559 | * | |
| 560 | * While there can be only one hook_cron() process running at the same time, | |
| 561 | * there can be any number of processes defined here running. Because of | |
| 562 | * this, long running tasks are much better suited for this API. Items queued | |
| 9e638424 DB |
563 | * in hook_cron() might be processed in the same cron run if there are not many |
| 564 | * items in the queue, otherwise it might take several requests, which can be | |
| 565 | * run in parallel. | |
| 762be09f DB |
566 | * |
| 567 | * @return | |
| 568 | * An associative array where the key is the queue name and the value is | |
| 569 | * again an associative array. Possible keys are: | |
| 9e638424 DB |
570 | * - 'worker callback': The name of the function to call. It will be called |
| 571 | * with one argument, the item created via DrupalQueue::createItem() in | |
| 572 | * hook_cron(). | |
| 573 | * - 'time': (optional) How much time Drupal should spend on calling this | |
| 574 | * worker in seconds. Defaults to 15. | |
| 575 | * | |
| 576 | * @see hook_cron() | |
| 3cd6a773 | 577 | * @see hook_cron_queue_info_alter() |
| 762be09f DB |
578 | */ |
| 579 | function hook_cron_queue_info() { | |
| 580 | $queues['aggregator_feeds'] = array( | |
| 581 | 'worker callback' => 'aggregator_refresh', | |
| 3cd6a773 | 582 | 'time' => 60, |
| 762be09f DB |
583 | ); |
| 584 | return $queues; | |
| 585 | } | |
| 586 | ||
| 587 | /** | |
| 3cd6a773 DB |
588 | * Alter cron queue information before cron runs. |
| 589 | * | |
| bdffe481 | 590 | * Called by drupal_cron_run() to allow modules to alter cron queue settings |
| 3cd6a773 DB |
591 | * before any jobs are processesed. |
| 592 | * | |
| 593 | * @param array $queues | |
| 594 | * An array of cron queue information. | |
| 595 | * | |
| ba6d89a4 DB |
596 | * @see hook_cron_queue_info() |
| 597 | * @see drupal_cron_run() | |
| 3cd6a773 DB |
598 | */ |
| 599 | function hook_cron_queue_info_alter(&$queues) { | |
| 600 | // This site has many feeds so let's spend 90 seconds on each cron run | |
| 601 | // updating feeds instead of the default 60. | |
| 602 | $queues['aggregator_feeds']['time'] = 90; | |
| 603 | } | |
| 604 | ||
| 605 | /** | |
| 66df6025 AB |
606 | * Allows modules to declare their own Forms API element types and specify their |
| 607 | * default values. | |
| 608 | * | |
| 609 | * This hook allows modules to declare their own form element types and to | |
| 610 | * specify their default values. The values returned by this hook will be | |
| 611 | * merged with the elements returned by hook_form() implementations and so | |
| 612 | * can return defaults for any Form APIs keys in addition to those explicitly | |
| 613 | * mentioned below. | |
| 614 | * | |
| 615 | * Each of the form element types defined by this hook is assumed to have | |
| 616 | * a matching theme function, e.g. theme_elementtype(), which should be | |
| 617 | * registered with hook_theme() as normal. | |
| 618 | * | |
| 6f1a855a | 619 | * For more information about custom element types see the explanation at |
| 66df6025 AB |
620 | * http://drupal.org/node/169815. |
| 621 | * | |
| 622 | * @return | |
| 623 | * An associative array describing the element types being defined. The array | |
| 624 | * contains a sub-array for each element type, with the machine-readable type | |
| 625 | * name as the key. Each sub-array has a number of possible attributes: | |
| 626 | * - "#input": boolean indicating whether or not this element carries a value | |
| 627 | * (even if it's hidden). | |
| 2ac0eb58 DB |
628 | * - "#process": array of callback functions taking $element, $form_state, |
| 629 | * and $complete_form. | |
| 66df6025 AB |
630 | * - "#after_build": array of callback functions taking $element and $form_state. |
| 631 | * - "#validate": array of callback functions taking $form and $form_state. | |
| 632 | * - "#element_validate": array of callback functions taking $element and | |
| 633 | * $form_state. | |
| 634 | * - "#pre_render": array of callback functions taking $element and $form_state. | |
| 635 | * - "#post_render": array of callback functions taking $element and $form_state. | |
| 636 | * - "#submit": array of callback functions taking $form and $form_state. | |
| 99833c62 DB |
637 | * - "#title_display": optional string indicating if and how #title should be |
| 638 | * displayed, see theme_form_element() and theme_form_element_label(). | |
| d481f1cd DB |
639 | * |
| 640 | * @see hook_element_info_alter() | |
| 641 | * @see system_element_info() | |
| 66df6025 | 642 | */ |
| d481f1cd DB |
643 | function hook_element_info() { |
| 644 | $types['filter_format'] = array( | |
| 645 | '#input' => TRUE, | |
| 646 | ); | |
| 647 | return $types; | |
| 66df6025 AB |
648 | } |
| 649 | ||
| 650 | /** | |
| dbb5457c AB |
651 | * Alter the element type information returned from modules. |
| 652 | * | |
| 653 | * A module may implement this hook in order to alter the element type defaults | |
| 654 | * defined by a module. | |
| 655 | * | |
| a22d7770 | 656 | * @param $type |
| d481f1cd | 657 | * All element type defaults as collected by hook_element_info(). |
| dbb5457c | 658 | * |
| d481f1cd | 659 | * @see hook_element_info() |
| dbb5457c AB |
660 | */ |
| 661 | function hook_element_info_alter(&$type) { | |
| 662 | // Decrease the default size of textfields. | |
| 663 | if (isset($type['textfield']['#size'])) { | |
| 664 | $type['textfield']['#size'] = 40; | |
| 665 | } | |
| 666 | } | |
| 667 | ||
| 668 | /** | |
| 66df6025 AB |
669 | * Perform cleanup tasks. |
| 670 | * | |
| 671 | * This hook is run at the end of each page request. It is often used for | |
| 24c259cd | 672 | * page logging and specialized cleanup. This hook MUST NOT print anything. |
| 66df6025 AB |
673 | * |
| 674 | * Only use this hook if your code must run even for cached page views. | |
| 7f0feebe DB |
675 | * If you have code which must run once on all non-cached pages, use |
| 676 | * hook_init() instead. That is the usual case. If you implement this hook | |
| 66df6025 AB |
677 | * and see an error like 'Call to undefined function', it is likely that |
| 678 | * you are depending on the presence of a module which has not been loaded yet. | |
| 679 | * It is not loaded because Drupal is still in bootstrap mode. | |
| 680 | * | |
| 681 | * @param $destination | |
| 682 | * If this hook is invoked as part of a drupal_goto() call, then this argument | |
| 683 | * will be a fully-qualified URL that is the destination of the redirect. | |
| 66df6025 AB |
684 | */ |
| 685 | function hook_exit($destination = NULL) { | |
| 196da1b8 DB |
686 | db_update('counter') |
| 687 | ->expression('hits', 'hits + 1') | |
| 688 | ->condition('type', 1) | |
| 689 | ->execute(); | |
| 66df6025 AB |
690 | } |
| 691 | ||
| 692 | /** | |
| 66df6025 AB |
693 | * Perform necessary alterations to the JavaScript before it is presented on |
| 694 | * the page. | |
| 695 | * | |
| 696 | * @param $javascript | |
| 697 | * An array of all JavaScript being presented on the page. | |
| d428fe37 | 698 | * |
| 66df6025 AB |
699 | * @see drupal_add_js() |
| 700 | * @see drupal_get_js() | |
| 701 | * @see drupal_js_defaults() | |
| 702 | */ | |
| 703 | function hook_js_alter(&$javascript) { | |
| 704 | // Swap out jQuery to use an updated version of the library. | |
| 705 | $javascript['misc/jquery.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js'; | |
| 706 | } | |
| 707 | ||
| 708 | /** | |
| 4a4a6570 AB |
709 | * Registers JavaScript/CSS libraries associated with a module. |
| 710 | * | |
| 711 | * Modules implementing this return an array of arrays. The key to each | |
| 712 | * sub-array is the machine readable name of the library. Each library may | |
| 713 | * contain the following items: | |
| 714 | * | |
| 715 | * - 'title': The human readable name of the library. | |
| 716 | * - 'website': The URL of the library's web site. | |
| 717 | * - 'version': A string specifying the version of the library; intentionally | |
| 718 | * not a float because a version like "1.2.3" is not a valid float. Use PHP's | |
| 719 | * version_compare() to compare different versions. | |
| 720 | * - 'js': An array of JavaScript elements; each element's key is used as $data | |
| 721 | * argument, each element's value is used as $options array for | |
| 722 | * drupal_add_js(). To add library-specific (not module-specific) JavaScript | |
| 723 | * settings, the key may be skipped, the value must specify | |
| 724 | * 'type' => 'setting', and the actual settings must be contained in a 'data' | |
| 725 | * element of the value. | |
| 726 | * - 'css': Like 'js', an array of CSS elements passed to drupal_add_css(). | |
| 727 | * - 'dependencies': An array of libraries that are required for a library. Each | |
| 648d8ab8 DB |
728 | * element is an array listing the module and name of another library. Note |
| 729 | * that all dependencies for each dependent library will also be added when | |
| 730 | * this library is added. | |
| 4a4a6570 AB |
731 | * |
| 732 | * Registered information for a library should contain re-usable data only. | |
| 733 | * Module- or implementation-specific data and integration logic should be added | |
| 734 | * separately. | |
| 735 | * | |
| 736 | * @return | |
| 737 | * An array defining libraries associated with a module. | |
| 738 | * | |
| 739 | * @see system_library() | |
| 740 | * @see drupal_add_library() | |
| 741 | * @see drupal_get_library() | |
| 742 | */ | |
| 743 | function hook_library() { | |
| 744 | // Library One. | |
| 745 | $libraries['library-1'] = array( | |
| 746 | 'title' => 'Library One', | |
| 747 | 'website' => 'http://example.com/library-1', | |
| 748 | 'version' => '1.2', | |
| 749 | 'js' => array( | |
| 750 | drupal_get_path('module', 'my_module') . '/library-1.js' => array(), | |
| 751 | ), | |
| 752 | 'css' => array( | |
| 753 | drupal_get_path('module', 'my_module') . '/library-2.css' => array( | |
| 754 | 'type' => 'file', | |
| 755 | 'media' => 'screen', | |
| 756 | ), | |
| 757 | ), | |
| 758 | ); | |
| 759 | // Library Two. | |
| 760 | $libraries['library-2'] = array( | |
| 761 | 'title' => 'Library Two', | |
| 762 | 'website' => 'http://example.com/library-2', | |
| 763 | 'version' => '3.1-beta1', | |
| 764 | 'js' => array( | |
| 765 | // JavaScript settings may use the 'data' key. | |
| 766 | array( | |
| 767 | 'type' => 'setting', | |
| 768 | 'data' => array('library2' => TRUE), | |
| 769 | ), | |
| 770 | ), | |
| 771 | 'dependencies' => array( | |
| 772 | // Require jQuery UI core by System module. | |
| 648d8ab8 | 773 | array('system', 'ui'), |
| 4a4a6570 AB |
774 | // Require our other library. |
| 775 | array('my_module', 'library-1'), | |
| 776 | // Require another library. | |
| 777 | array('other_module', 'library-3'), | |
| 778 | ), | |
| 779 | ); | |
| 780 | return $libraries; | |
| 781 | } | |
| 782 | ||
| 783 | /** | |
| 784 | * Alters the JavaScript/CSS library registry. | |
| 785 | * | |
| 786 | * Allows certain, contributed modules to update libraries to newer versions | |
| 787 | * while ensuring backwards compatibility. In general, such manipulations should | |
| 788 | * only be done by designated modules, since most modules that integrate with a | |
| 789 | * certain library also depend on the API of a certain library version. | |
| 790 | * | |
| 791 | * @param $libraries | |
| 792 | * The JavaScript/CSS libraries provided by $module. Keyed by internal library | |
| 793 | * name and passed by reference. | |
| 794 | * @param $module | |
| 795 | * The name of the module that registered the libraries. | |
| 796 | * | |
| 797 | * @see hook_library() | |
| 798 | */ | |
| 799 | function hook_library_alter(&$libraries, $module) { | |
| 800 | // Update Farbtastic to version 2.0. | |
| 801 | if ($module == 'system' && isset($libraries['farbtastic'])) { | |
| 802 | // Verify existing version is older than the one we are updating to. | |
| 803 | if (version_compare($libraries['farbtastic']['version'], '2.0', '<')) { | |
| 804 | // Update the existing Farbtastic to version 2.0. | |
| 805 | $libraries['farbtastic']['version'] = '2.0'; | |
| 806 | $libraries['farbtastic']['js'] = array( | |
| 807 | drupal_get_path('module', 'farbtastic_update') . '/farbtastic-2.0.js' => array(), | |
| 808 | ); | |
| 809 | } | |
| 810 | } | |
| 811 | } | |
| 812 | ||
| 813 | /** | |
| 1a5c71e2 DB |
814 | * Alter CSS files before they are output on the page. |
| 815 | * | |
| 816 | * @param $css | |
| 817 | * An array of all CSS items (files and inline CSS) being requested on the page. | |
| d428fe37 | 818 | * |
| 1a5c71e2 DB |
819 | * @see drupal_add_css() |
| 820 | * @see drupal_get_css() | |
| 821 | */ | |
| 822 | function hook_css_alter(&$css) { | |
| 823 | // Remove defaults.css file. | |
| 824 | unset($css[drupal_get_path('module', 'system') . '/defaults.css']); | |
| 825 | } | |
| 826 | ||
| 827 | /** | |
| fa39282e | 828 | * Alter the commands that are sent to the user through the Ajax framework. |
| 1fed2bf2 AB |
829 | * |
| 830 | * @param $commands | |
| 831 | * An array of all commands that will be sent to the user. | |
| d428fe37 | 832 | * |
| 1fed2bf2 AB |
833 | * @see ajax_render() |
| 834 | */ | |
| 835 | function hook_ajax_render_alter($commands) { | |
| 836 | // Inject any new status messages into the content area. | |
| 837 | $commands[] = ajax_command_prepend('#block-system-main .content', theme('status_messages')); | |
| 838 | } | |
| 839 | ||
| 840 | /** | |
| a244b45c AB |
841 | * Add elements to a page before it is rendered. |
| 842 | * | |
| 843 | * Use this hook when you want to add elements at the page level. For your | |
| 844 | * additions to be printed, they have to be placed below a top level array key | |
| 845 | * of the $page array that has the name of a region of the active theme. | |
| 846 | * | |
| 847 | * By default, valid region keys are 'page_top', 'header', 'sidebar_first', | |
| 848 | * 'content', 'sidebar_second' and 'page_bottom'. To get a list of all regions | |
| 849 | * of the active theme, use system_region_list($theme). Note that $theme is a | |
| 850 | * global variable. | |
| 851 | * | |
| 852 | * If you want to alter the elements added by other modules or if your module | |
| 853 | * depends on the elements of other modules, use hook_page_alter() instead which | |
| 854 | * runs after this hook. | |
| 855 | * | |
| 856 | * @param $page | |
| 857 | * Nested array of renderable elements that make up the page. | |
| 858 | * | |
| 859 | * @see hook_page_alter() | |
| 860 | * @see drupal_render_page() | |
| 861 | */ | |
| 862 | function hook_page_build(&$page) { | |
| 863 | if (menu_get_object('node', 1)) { | |
| 864 | // We are on a node detail page. Append a standard disclaimer to the | |
| 865 | // content region. | |
| 866 | $page['content']['disclaimer'] = array( | |
| 867 | '#markup' => t('Acme, Inc. is not responsible for the contents of this sample code.'), | |
| 868 | '#weight' => 25, | |
| 869 | ); | |
| 870 | } | |
| 871 | } | |
| 872 | ||
| 873 | /** | |
| 9b3c8c52 AB |
874 | * Alter a menu router item right after it has been retrieved from the database or cache. |
| 875 | * | |
| 876 | * This hook is invoked by menu_get_item() and allows for run-time alteration of router | |
| 877 | * information (page_callback, title, and so on) before it is translated and checked for | |
| 8cdf750e | 878 | * access. The passed-in $router_item is statically cached for the current request, so this |
| 9b3c8c52 AB |
879 | * hook is only invoked once for any router item that is retrieved via menu_get_item(). |
| 880 | * | |
| 881 | * Usually, modules will only want to inspect the router item and conditionally | |
| 882 | * perform other actions (such as preparing a state for the current request). | |
| 883 | * Note that this hook is invoked for any router item that is retrieved by | |
| 884 | * menu_get_item(), which may or may not be called on the path itself, so implementations | |
| 885 | * should check the $path parameter if the alteration should fire for the current request | |
| 886 | * only. | |
| 887 | * | |
| 888 | * @param $router_item | |
| 889 | * The menu router item for $path. | |
| 890 | * @param $path | |
| 891 | * The originally passed path, for which $router_item is responsible. | |
| 892 | * @param $original_map | |
| 893 | * The path argument map, as contained in $path. | |
| 894 | * | |
| 895 | * @see menu_get_item() | |
| 896 | */ | |
| 897 | function hook_menu_get_item_alter(&$router_item, $path, $original_map) { | |
| 898 | // When retrieving the router item for the current path... | |
| 899 | if ($path == $_GET['q']) { | |
| 900 | // ...call a function that prepares something for this request. | |
| 901 | mymodule_prepare_something(); | |
| 902 | } | |
| 903 | } | |
| 904 | ||
| 905 | /** | |
| 5c5bd803 AB |
906 | * Define menu items and page callbacks. |
| 907 | * | |
| 908 | * This hook enables modules to register paths in order to define how URL | |
| 909 | * requests are handled. Paths may be registered for URL handling only, or they | |
| 910 | * can register a link to be placed in a menu (usually the Navigation menu). A | |
| 911 | * path and its associated information is commonly called a "menu router item". | |
| 912 | * This hook is rarely called (for example, when modules are enabled), and | |
| 913 | * its results are cached in the database. | |
| 914 | * | |
| 915 | * hook_menu() implementations return an associative array whose keys define | |
| 916 | * paths and whose values are an associative array of properties for each | |
| 917 | * path. (The complete list of properties is in the return value section below.) | |
| 918 | * | |
| 919 | * The definition for each path may include a page callback function, which is | |
| 920 | * invoked when the registered path is requested. If there is no other | |
| 921 | * registered path that fits the requested path better, any further path | |
| 922 | * components are passed to the callback function. For example, your module | |
| 923 | * could register path 'abc/def': | |
| 924 | * @code | |
| 925 | * function mymodule_menu() { | |
| 926 | * $items['abc/def'] = array( | |
| 927 | * 'page callback' => 'mymodule_abc_view', | |
| 928 | * ); | |
| 20b62b29 | 929 | * return $items; |
| 5c5bd803 AB |
930 | * } |
| 931 | * | |
| 932 | * function mymodule_abc_view($ghi = 0, $jkl = '') { | |
| 933 | * // ... | |
| 934 | * } | |
| 935 | * @endcode | |
| 936 | * When path 'abc/def' is requested, no further path components are in the | |
| 937 | * request, and no additional arguments are passed to the callback function (so | |
| 938 | * $ghi and $jkl would take the default values as defined in the function | |
| 939 | * signature). When 'abc/def/123/foo' is requested, $ghi will be '123' and | |
| 940 | * $jkl will be 'foo'. Note that this automatic passing of optional path | |
| 941 | * arguments applies only to page and theme callback functions. | |
| 942 | * | |
| 943 | * In addition to optional path arguments, the page callback and other callback | |
| 944 | * functions may specify argument lists as arrays. These argument lists may | |
| 945 | * contain both fixed/hard-coded argument values and integers that correspond | |
| 946 | * to path components. When integers are used and the callback function is | |
| 947 | * called, the corresponding path components will be substituted for the | |
| 948 | * integers. That is, the integer 0 in an argument list will be replaced with | |
| 949 | * the first path component, integer 1 with the second, and so on (path | |
| e45c7803 | 950 | * components are numbered starting from zero). To pass an integer without it |
| 951 | * being replaced with its respective path component, use the string value of | |
| 952 | * the integer (e.g., '1') as the argument value. This substitution feature | |
| 953 | * allows you to re-use a callback function for several different paths. For | |
| 954 | * example: | |
| 5c5bd803 AB |
955 | * @code |
| 956 | * function mymodule_menu() { | |
| 957 | * $items['abc/def'] = array( | |
| 958 | * 'page callback' => 'mymodule_abc_view', | |
| 959 | * 'page arguments' => array(1, 'foo'), | |
| 960 | * ); | |
| 20b62b29 | 961 | * return $items; |
| 5c5bd803 AB |
962 | * } |
| 963 | * @endcode | |
| 964 | * When path 'abc/def' is requested, the page callback function will get 'def' | |
| 965 | * as the first argument and (always) 'foo' as the second argument. | |
| 966 | * | |
| 9de419ad | 967 | * If a page callback function uses an argument list array, and its path is |
| 968 | * requested with optional path arguments, then the list array's arguments are | |
| 969 | * passed to the callback function first, followed by the optional path | |
| 970 | * arguments. Using the above example, when path 'abc/def/bar/baz' is requested, | |
| 971 | * mymodule_abc_view() will be called with 'def', 'foo', 'bar' and 'baz' as | |
| 972 | * arguments, in that order. | |
| 5c5bd803 AB |
973 | * |
| 974 | * Special care should be taken for the page callback drupal_get_form(), because | |
| 975 | * your specific form callback function will always receive $form and | |
| 976 | * &$form_state as the first function arguments: | |
| 977 | * @code | |
| 978 | * function mymodule_abc_form($form, &$form_state) { | |
| 979 | * // ... | |
| 980 | * return $form; | |
| 981 | * } | |
| 982 | * @endcode | |
| 983 | * See @link form_api Form API documentation @endlink for details. | |
| 984 | * | |
| 985 | * Wildcards within paths also work with integer substitution. For example, | |
| 986 | * your module could register path 'my-module/%/edit': | |
| 987 | * @code | |
| 988 | * $items['my-module/%/edit'] = array( | |
| 989 | * 'page callback' => 'mymodule_abc_edit', | |
| 990 | * 'page arguments' => array(1), | |
| 991 | * ); | |
| 992 | * @endcode | |
| 993 | * When path 'my-module/foo/edit' is requested, integer 1 will be replaced | |
| ac274733 D |
994 | * with 'foo' and passed to the callback function. Note that wildcards may not |
| 995 | * be used as the first component. | |
| 5c5bd803 AB |
996 | * |
| 997 | * Registered paths may also contain special "auto-loader" wildcard components | |
| 998 | * in the form of '%mymodule_abc', where the '%' part means that this path | |
| 999 | * component is a wildcard, and the 'mymodule_abc' part defines the prefix for a | |
| 1000 | * load function, which here would be named mymodule_abc_load(). When a matching | |
| 1001 | * path is requested, your load function will receive as its first argument the | |
| 1002 | * path component in the position of the wildcard; load functions may also be | |
| 1003 | * passed additional arguments (see "load arguments" in the return value | |
| 1004 | * section below). For example, your module could register path | |
| 1005 | * 'my-module/%mymodule_abc/edit': | |
| 1006 | * @code | |
| 1007 | * $items['my-module/%mymodule_abc/edit'] = array( | |
| 1008 | * 'page callback' => 'mymodule_abc_edit', | |
| 1009 | * 'page arguments' => array(1), | |
| 1010 | * ); | |
| 1011 | * @endcode | |
| 1012 | * When path 'my-module/123/edit' is requested, your load function | |
| 1013 | * mymodule_abc_load() will be invoked with the argument '123', and should | |
| 1014 | * load and return an "abc" object with internal id 123: | |
| 1015 | * @code | |
| 1016 | * function mymodule_abc_load($abc_id) { | |
| 1017 | * return db_query("SELECT * FROM {mymodule_abc} WHERE abc_id = :abc_id", array(':abc_id' => $abc_id))->fetchObject(); | |
| 1018 | * } | |
| 1019 | * @endcode | |
| aeb6712b DB |
1020 | * This 'abc' object will then be passed into the callback functions defined |
| 1021 | * for the menu item, such as the page callback function mymodule_abc_edit() | |
| 2c51f2d6 | 1022 | * to replace the integer 1 in the argument array. Note that a load function |
| 1023 | * should return FALSE when it is unable to provide a loadable object. For | |
| 1024 | * example, the node_load() function for the 'node/%node/edit' menu item will | |
| 1025 | * return FALSE for the path 'node/999/edit' if a node with a node ID of 999 | |
| 1026 | * does not exist. The menu routing system will return a 404 error in this case. | |
| aeb6712b DB |
1027 | * |
| 1028 | * You can also define a %wildcard_to_arg() function (for the example menu | |
| 1029 | * entry above this would be 'mymodule_abc_to_arg()'). The _to_arg() function | |
| 1030 | * is invoked to retrieve a value that is used in the path in place of the | |
| 1031 | * wildcard. A good example is user.module, which defines | |
| 1032 | * user_uid_optional_to_arg() (corresponding to the menu entry | |
| 1033 | * 'user/%user_uid_optional'). This function returns the user ID of the | |
| 1034 | * current user. | |
| 1035 | * | |
| 1036 | * The _to_arg() function will get called with three arguments: | |
| 1037 | * - $arg: A string representing whatever argument may have been supplied by | |
| 1038 | * the caller (this is particularly useful if you want the _to_arg() | |
| 1039 | * function only supply a (default) value if no other value is specified, | |
| 1040 | * as in the case of user_uid_optional_to_arg(). | |
| 1041 | * - $map: An array of all path fragments (e.g. array('node','123','edit') for | |
| 1042 | * 'node/123/edit'). | |
| 1043 | * - $index: An integer indicating which element of $map corresponds to $arg. | |
| 1044 | * | |
| 1045 | * _load() and _to_arg() functions may seem similar at first glance, but they | |
| 1046 | * have different purposes and are called at different times. _load() | |
| 1047 | * functions are called when the menu system is collecting arguments to pass | |
| 1048 | * to the callback functions defined for the menu item. _to_arg() functions | |
| 1049 | * are called when the menu system is generating links to related paths, such | |
| 1050 | * as the tabs for a set of MENU_LOCAL_TASK items. | |
| 5c5bd803 AB |
1051 | * |
| 1052 | * You can also make groups of menu items to be rendered (by default) as tabs | |
| 1053 | * on a page. To do that, first create one menu item of type MENU_NORMAL_ITEM, | |
| 1054 | * with your chosen path, such as 'foo'. Then duplicate that menu item, using a | |
| 1055 | * subdirectory path, such as 'foo/tab1', and changing the type to | |
| 1056 | * MENU_DEFAULT_LOCAL_TASK to make it the default tab for the group. Then add | |
| 1057 | * the additional tab items, with paths such as "foo/tab2" etc., with type | |
| 1058 | * MENU_LOCAL_TASK. Example: | |
| 1059 | * @code | |
| 1060 | * // Make "Foo settings" appear on the admin Config page | |
| c8334a08 | 1061 | * $items['admin/config/system/foo'] = array( |
| 5c5bd803 AB |
1062 | * 'title' => 'Foo settings', |
| 1063 | * 'type' => MENU_NORMAL_ITEM, | |
| 24de8090 | 1064 | * // Page callback, etc. need to be added here. |
| 5c5bd803 | 1065 | * ); |
| c8334a08 DB |
1066 | * // Make "Tab 1" the main tab on the "Foo settings" page |
| 1067 | * $items['admin/config/system/foo/tab1'] = array( | |
| 1068 | * 'title' => 'Tab 1', | |
| 5c5bd803 | 1069 | * 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 24de8090 | 1070 | * // Access callback, page callback, and theme callback will be inherited |
| c8334a08 | 1071 | * // from 'admin/config/system/foo', if not specified here to override. |
| 5c5bd803 | 1072 | * ); |
| c8334a08 DB |
1073 | * // Make an additional tab called "Tab 2" on "Foo settings" |
| 1074 | * $items['admin/config/system/foo/tab2'] = array( | |
| 1075 | * 'title' => 'Tab 2', | |
| 5c5bd803 | 1076 | * 'type' => MENU_LOCAL_TASK, |
| 24de8090 | 1077 | * // Page callback and theme callback will be inherited from |
| c8334a08 | 1078 | * // 'admin/config/system/foo', if not specified here to override. |
| 24de8090 | 1079 | * // Need to add access callback or access arguments. |
| 5c5bd803 AB |
1080 | * ); |
| 1081 | * @endcode | |
| 1082 | * | |
| 1083 | * @return | |
| 1084 | * An array of menu items. Each menu item has a key corresponding to the | |
| 1085 | * Drupal path being registered. The corresponding array value is an | |
| 1086 | * associative array that may contain the following key-value pairs: | |
| 1087 | * - "title": Required. The untranslated title of the menu item. | |
| 1088 | * - "title callback": Function to generate the title; defaults to t(). | |
| 1089 | * If you require only the raw string to be output, set this to FALSE. | |
| 1090 | * - "title arguments": Arguments to send to t() or your custom callback, | |
| 1091 | * with path component substitution as described above. | |
| 1092 | * - "description": The untranslated description of the menu item. | |
| 1093 | * - "page callback": The function to call to display a web page when the user | |
| 1094 | * visits the path. If omitted, the parent menu item's callback will be used | |
| 1095 | * instead. | |
| 1096 | * - "page arguments": An array of arguments to pass to the page callback | |
| 1097 | * function, with path component substitution as described above. | |
| 1098 | * - "delivery callback": The function to call to package the result of the | |
| 1099 | * page callback function and send it to the browser. Defaults to | |
| 1100 | * drupal_deliver_html_page() unless a value is inherited from a parent menu | |
| 98745678 AB |
1101 | * item. Note that this function is called even if the access checks fail, |
| 1102 | * so any custom delivery callback function should take that into account. | |
| 1103 | * See drupal_deliver_html_page() for an example. | |
| a6cb5bbf DB |
1104 | * - "access callback": A function returning TRUE if the user has access |
| 1105 | * rights to this menu item, and FALSE if not. It can also be a boolean | |
| 1106 | * constant instead of a function, and you can also use numeric values | |
| 1107 | * (will be cast to boolean). Defaults to user_access() unless a value is | |
| 24de8090 AB |
1108 | * inherited from the parent menu item; only MENU_DEFAULT_LOCAL_TASK items |
| 1109 | * can inherit access callbacks. To use the user_access() default callback, | |
| 1110 | * you must specify the permission to check as 'access arguments' (see | |
| 1111 | * below). | |
| 5c5bd803 | 1112 | * - "access arguments": An array of arguments to pass to the access callback |
| 24de8090 AB |
1113 | * function, with path component substitution as described above. If the |
| 1114 | * access callback is inherited (see above), the access arguments will be | |
| 1115 | * inherited with it, unless overridden in the child menu item. | |
| a6cb5bbf | 1116 | * - "theme callback": (optional) A function returning the machine-readable |
| 84c72d06 DB |
1117 | * name of the theme that will be used to render the page. If not provided, |
| 1118 | * the value will be inherited from a parent menu item. If there is no | |
| 1119 | * theme callback, or if the function does not return the name of a current | |
| 1120 | * active theme on the site, the theme for this page will be determined by | |
| 1121 | * either hook_custom_theme() or the default theme instead. As a general | |
| 1122 | * rule, the use of theme callback functions should be limited to pages | |
| 1123 | * whose functionality is very closely tied to a particular theme, since | |
| 1124 | * they can only be overridden by modules which specifically target those | |
| 1125 | * pages in hook_menu_alter(). Modules implementing more generic theme | |
| 1126 | * switching functionality (for example, a module which allows the theme to | |
| 1127 | * be set dynamically based on the current user's role) should use | |
| 1128 | * hook_custom_theme() instead. | |
| 5c5bd803 AB |
1129 | * - "theme arguments": An array of arguments to pass to the theme callback |
| 1130 | * function, with path component substitution as described above. | |
| 1131 | * - "file": A file that will be included before the page callback is called; | |
| 1132 | * this allows page callback functions to be in separate files. The file | |
| 1133 | * should be relative to the implementing module's directory unless | |
| 1134 | * otherwise specified by the "file path" option. Does not apply to other | |
| 1135 | * callbacks (only page callback). | |
| 1136 | * - "file path": The path to the directory containing the file specified in | |
| 1137 | * "file". This defaults to the path to the module implementing the hook. | |
| 1138 | * - "load arguments": An array of arguments to be passed to each of the | |
| 1139 | * wildcard object loaders in the path, after the path argument itself. | |
| 1140 | * For example, if a module registers path node/%node/revisions/%/view | |
| 1141 | * with load arguments set to array(3), the '%node' in the path indicates | |
| 1142 | * that the loader function node_load() will be called with the second | |
| 1143 | * path component as the first argument. The 3 in the load arguments | |
| 1144 | * indicates that the fourth path component will also be passed to | |
| 1145 | * node_load() (numbering of path components starts at zero). So, if path | |
| 1146 | * node/12/revisions/29/view is requested, node_load(12, 29) will be called. | |
| 1147 | * There are also two "magic" values that can be used in load arguments. | |
| 1148 | * "%index" indicates the index of the wildcard path component. "%map" | |
| 1149 | * indicates the path components as an array. For example, if a module | |
| 1150 | * registers for several paths of the form 'user/%user_category/edit/*', all | |
| 1151 | * of them can use the same load function user_category_load(), by setting | |
| 1152 | * the load arguments to array('%map', '%index'). For instance, if the user | |
| 1153 | * is editing category 'foo' by requesting path 'user/32/edit/foo', the load | |
| 1154 | * function user_category_load() will be called with 32 as its first | |
| 1155 | * argument, the array ('user', 32, 'edit', 'foo') as the map argument, | |
| 1156 | * and 1 as the index argument (because %user_category is the second path | |
| 1157 | * component and numbering starts at zero). user_category_load() can then | |
| 1158 | * use these values to extract the information that 'foo' is the category | |
| 1159 | * being requested. | |
| 1160 | * - "weight": An integer that determines the relative position of items in | |
| 1161 | * the menu; higher-weighted items sink. Defaults to 0. Menu items with the | |
| 1162 | * same weight are ordered alphabetically. | |
| 1163 | * - "menu_name": Optional. Set this to a custom menu if you don't want your | |
| 1164 | * item to be placed in Navigation. | |
| 1165 | * - "context": (optional) Defines the context a tab may appear in. By | |
| 1166 | * default, all tabs are only displayed as local tasks when being rendered | |
| 1167 | * in a page context. All tabs that should be accessible as contextual links | |
| 1168 | * in page region containers outside of the parent menu item's primary page | |
| 1169 | * context should be registered using one of the following contexts: | |
| 1170 | * - MENU_CONTEXT_PAGE: (default) The tab is displayed as local task for the | |
| 1171 | * page context only. | |
| 1172 | * - MENU_CONTEXT_INLINE: The tab is displayed as contextual link outside of | |
| 1173 | * the primary page context only. | |
| 1174 | * Contexts can be combined. For example, to display a tab both on a page | |
| 1175 | * and inline, a menu router item may specify: | |
| 1176 | * @code | |
| 1177 | * 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE, | |
| 1178 | * @endcode | |
| 1179 | * - "tab_parent": For local task menu items, the path of the task's parent | |
| 1180 | * item; defaults to the same path without the last component (e.g., the | |
| 1181 | * default parent for 'admin/people/create' is 'admin/people'). | |
| 1182 | * - "tab_root": For local task menu items, the path of the closest non-tab | |
| 1183 | * item; same default as "tab_parent". | |
| 5c5bd803 AB |
1184 | * - "position": Position of the block ('left' or 'right') on the system |
| 1185 | * administration page for this item. | |
| 1186 | * - "type": A bitmask of flags describing properties of the menu item. | |
| 1187 | * Many shortcut bitmasks are provided as constants in menu.inc: | |
| 1188 | * - MENU_NORMAL_ITEM: Normal menu items show up in the menu tree and can be | |
| 1189 | * moved/hidden by the administrator. | |
| 1190 | * - MENU_CALLBACK: Callbacks simply register a path so that the correct | |
| 1191 | * information is generated when the path is accessed. | |
| 1192 | * - MENU_SUGGESTED_ITEM: Modules may "suggest" menu items that the | |
| 1193 | * administrator may enable. | |
| 1194 | * - MENU_LOCAL_ACTION: Local actions are menu items that describe actions | |
| 1195 | * on the parent item such as adding a new user or block, and are | |
| 1196 | * rendered in the action-links list in your theme. | |
| 1197 | * - MENU_LOCAL_TASK: Local tasks are menu items that describe different | |
| 1198 | * displays of data, and are generally rendered as tabs. | |
| 1199 | * - MENU_DEFAULT_LOCAL_TASK: Every set of local tasks should provide one | |
| 1200 | * "default" task, which should display the same page as the parent item. | |
| 1201 | * If the "type" element is omitted, MENU_NORMAL_ITEM is assumed. | |
| 5eb6a99c | 1202 | * - "options": An array of options to be passed to l() when generating a link |
| a5f9c985 D |
1203 | * from this menu item. Note that the "options" parameter has no effect on |
| 1204 | * MENU_LOCAL_TASK, MENU_DEFAULT_LOCAL_TASK, and MENU_LOCAL_ACTION items. | |
| 5c5bd803 AB |
1205 | * |
| 1206 | * For a detailed usage example, see page_example.module. | |
| 1207 | * For comprehensive documentation on the menu system, see | |
| 1208 | * http://drupal.org/node/102338. | |
| 1209 | */ | |
| 1210 | function hook_menu() { | |
| 1211 | $items['blog'] = array( | |
| 1212 | 'title' => 'blogs', | |
| 1213 | 'page callback' => 'blog_page', | |
| 1214 | 'access arguments' => array('access content'), | |
| 1215 | 'type' => MENU_SUGGESTED_ITEM, | |
| 1216 | ); | |
| 1217 | $items['blog/feed'] = array( | |
| 1218 | 'title' => 'RSS feed', | |
| 1219 | 'page callback' => 'blog_feed', | |
| 1220 | 'access arguments' => array('access content'), | |
| 1221 | 'type' => MENU_CALLBACK, | |
| 1222 | ); | |
| 1223 | ||
| 1224 | return $items; | |
| 1225 | } | |
| 1226 | ||
| 1227 | /** | |
| 1228 | * Alter the data being saved to the {menu_router} table after hook_menu is invoked. | |
| 1229 | * | |
| 1230 | * This hook is invoked by menu_router_build(). The menu definitions are passed | |
| 1231 | * in by reference. Each element of the $items array is one item returned | |
| 1232 | * by a module from hook_menu. Additional items may be added, or existing items | |
| 1233 | * altered. | |
| 1234 | * | |
| 1235 | * @param $items | |
| 1236 | * Associative array of menu router definitions returned from hook_menu(). | |
| 1237 | */ | |
| 1238 | function hook_menu_alter(&$items) { | |
| 1239 | // Example - disable the page at node/add | |
| 1240 | $items['node/add']['access callback'] = FALSE; | |
| 1241 | } | |
| 1242 | ||
| 1243 | /** | |
| 1244 | * Alter the data being saved to the {menu_links} table by menu_link_save(). | |
| 1245 | * | |
| 1246 | * @param $item | |
| 1247 | * Associative array defining a menu link as passed into menu_link_save(). | |
| f3ab0a0f DB |
1248 | * |
| 1249 | * @see hook_translated_menu_link_alter() | |
| 5c5bd803 AB |
1250 | */ |
| 1251 | function hook_menu_link_alter(&$item) { | |
| f3ab0a0f | 1252 | // Make all new admin links hidden (a.k.a disabled). |
| 5c5bd803 AB |
1253 | if (strpos($item['link_path'], 'admin') === 0 && empty($item['mlid'])) { |
| 1254 | $item['hidden'] = 1; | |
| 1255 | } | |
| f3ab0a0f | 1256 | // Flag a link to be altered by hook_translated_menu_link_alter(). |
| 5c5bd803 AB |
1257 | if ($item['link_path'] == 'devel/cache/clear') { |
| 1258 | $item['options']['alter'] = TRUE; | |
| 1259 | } | |
| f3ab0a0f DB |
1260 | // Flag a link to be altered by hook_translated_menu_link_alter(), but only |
| 1261 | // if it is derived from a menu router item; i.e., do not alter a custom | |
| 1262 | // menu link pointing to the same path that has been created by a user. | |
| 1263 | if ($item['link_path'] == 'user' && $item['module'] == 'system') { | |
| 1264 | $item['options']['alter'] = TRUE; | |
| 1265 | } | |
| 5c5bd803 AB |
1266 | } |
| 1267 | ||
| 1268 | /** | |
| f3ab0a0f DB |
1269 | * Alter a menu link after it has been translated and before it is rendered. |
| 1270 | * | |
| 1271 | * This hook is invoked from _menu_link_translate() after a menu link has been | |
| 1272 | * translated; i.e., after dynamic path argument placeholders (%) have been | |
| 1273 | * replaced with actual values, the user access to the link's target page has | |
| 1274 | * been checked, and the link has been localized. It is only invoked if | |
| 1275 | * $item['options']['alter'] has been set to a non-empty value (e.g., TRUE). | |
| 1276 | * This flag should be set using hook_menu_link_alter(). | |
| 1277 | * | |
| 1278 | * Implementations of this hook are able to alter any property of the menu link. | |
| 1279 | * For example, this hook may be used to add a page-specific query string to all | |
| 1280 | * menu links, or hide a certain link by setting: | |
| 1281 | * @code | |
| 1282 | * 'hidden' => 1, | |
| 1283 | * @endcode | |
| 5c5bd803 AB |
1284 | * |
| 1285 | * @param $item | |
| 1286 | * Associative array defining a menu link after _menu_link_translate() | |
| 1287 | * @param $map | |
| 1288 | * Associative array containing the menu $map (path parts and/or objects). | |
| f3ab0a0f DB |
1289 | * |
| 1290 | * @see hook_menu_link_alter() | |
| 5c5bd803 AB |
1291 | */ |
| 1292 | function hook_translated_menu_link_alter(&$item, $map) { | |
| 1293 | if ($item['href'] == 'devel/cache/clear') { | |
| 1294 | $item['localized_options']['query'] = drupal_get_destination(); | |
| 1295 | } | |
| 1296 | } | |
| 1297 | ||
| 1298 | /** | |
| 1299 | * Inform modules that a menu link has been created. | |
| 1300 | * | |
| 1301 | * This hook is used to notify modules that menu items have been | |
| 1302 | * created. Contributed modules may use the information to perform | |
| 1303 | * actions based on the information entered into the menu system. | |
| 1304 | * | |
| 1305 | * @param $link | |
| 1306 | * Associative array defining a menu link as passed into menu_link_save(). | |
| 1307 | * | |
| 1308 | * @see hook_menu_link_update() | |
| 1309 | * @see hook_menu_link_delete() | |
| 1310 | */ | |
| 1311 | function hook_menu_link_insert($link) { | |
| 1312 | // In our sample case, we track menu items as editing sections | |
| 1313 | // of the site. These are stored in our table as 'disabled' items. | |
| 1314 | $record['mlid'] = $link['mlid']; | |
| 1315 | $record['menu_name'] = $link['menu_name']; | |
| 1316 | $record['status'] = 0; | |
| 1317 | drupal_write_record('menu_example', $record); | |
| 1318 | } | |
| 1319 | ||
| 1320 | /** | |
| 1321 | * Inform modules that a menu link has been updated. | |
| 1322 | * | |
| 1323 | * This hook is used to notify modules that menu items have been | |
| 1324 | * updated. Contributed modules may use the information to perform | |
| 1325 | * actions based on the information entered into the menu system. | |
| 1326 | * | |
| 1327 | * @param $link | |
| 1328 | * Associative array defining a menu link as passed into menu_link_save(). | |
| 1329 | * | |
| 1330 | * @see hook_menu_link_insert() | |
| 1331 | * @see hook_menu_link_delete() | |
| 1332 | */ | |
| 1333 | function hook_menu_link_update($link) { | |
| 1334 | // If the parent menu has changed, update our record. | |
| 4538ad0e | 1335 | $menu_name = db_query("SELECT menu_name FROM {menu_example} WHERE mlid = :mlid", array(':mlid' => $link['mlid']))->fetchField(); |
| 5c5bd803 AB |
1336 | if ($menu_name != $link['menu_name']) { |
| 1337 | db_update('menu_example') | |
| 1338 | ->fields(array('menu_name' => $link['menu_name'])) | |
| 1339 | ->condition('mlid', $link['mlid']) | |
| 1340 | ->execute(); | |
| 1341 | } | |
| 1342 | } | |
| 1343 | ||
| 1344 | /** | |
| 1345 | * Inform modules that a menu link has been deleted. | |
| 1346 | * | |
| 1347 | * This hook is used to notify modules that menu items have been | |
| 1348 | * deleted. Contributed modules may use the information to perform | |
| 1349 | * actions based on the information entered into the menu system. | |
| 1350 | * | |
| 1351 | * @param $link | |
| 1352 | * Associative array defining a menu link as passed into menu_link_save(). | |
| 1353 | * | |
| 1354 | * @see hook_menu_link_insert() | |
| 1355 | * @see hook_menu_link_update() | |
| 1356 | */ | |
| 1357 | function hook_menu_link_delete($link) { | |
| 1358 | // Delete the record from our table. | |
| 1359 | db_delete('menu_example') | |
| 1360 | ->condition('mlid', $link['mlid']) | |
| 1361 | ->execute(); | |
| 1362 | } | |
| 1363 | ||
| 1364 | /** | |
| 1365 | * Alter tabs and actions displayed on the page before they are rendered. | |
| 1366 | * | |
| 1367 | * This hook is invoked by menu_local_tasks(). The system-determined tabs and | |
| 1368 | * actions are passed in by reference. Additional tabs or actions may be added, | |
| 1369 | * or existing items altered. | |
| 1370 | * | |
| 1371 | * Each tab or action is an associative array containing: | |
| 1372 | * - #theme: The theme function to use to render. | |
| 1373 | * - #link: An associative array containing: | |
| 1374 | * - title: The localized title of the link. | |
| 1375 | * - href: The system path to link to. | |
| 1376 | * - localized_options: An array of options to pass to url(). | |
| 1377 | * - #active: Whether the link should be marked as 'active'. | |
| 1378 | * | |
| 1379 | * @param $data | |
| 1380 | * An associative array containing: | |
| 1381 | * - actions: An associative array containing: | |
| 1382 | * - count: The amount of actions determined by the menu system, which can | |
| 1383 | * be ignored. | |
| 1384 | * - output: A list of of actions, each one being an associative array | |
| 1385 | * as described above. | |
| 1386 | * - tabs: An indexed array (list) of tab levels (up to 2 levels), each | |
| 1387 | * containing an associative array: | |
| 1388 | * - count: The amount of tabs determined by the menu system. This value | |
| 1389 | * does not need to be altered if there is more than one tab. | |
| 1390 | * - output: A list of of tabs, each one being an associative array as | |
| 1391 | * described above. | |
| 50787d83 DB |
1392 | * @param $router_item |
| 1393 | * The menu system router item of the page. | |
| 1394 | * @param $root_path | |
| 1395 | * The path to the root item for this set of tabs. | |
| 5c5bd803 AB |
1396 | */ |
| 1397 | function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) { | |
| 1398 | // Add an action linking to node/add to all pages. | |
| 1399 | $data['actions']['output'][] = array( | |
| 1400 | '#theme' => 'menu_local_task', | |
| 1401 | '#link' => array( | |
| 1402 | 'title' => t('Add new content'), | |
| 1403 | 'href' => 'node/add', | |
| 1404 | 'localized_options' => array( | |
| 1405 | 'attributes' => array( | |
| 1406 | 'title' => t('Add new content'), | |
| 1407 | ), | |
| 1408 | ), | |
| 1409 | ), | |
| 1410 | ); | |
| 1411 | ||
| 1412 | // Add a tab linking to node/add to all pages. | |
| 1413 | $data['tabs'][0]['output'][] = array( | |
| 1414 | '#theme' => 'menu_local_task', | |
| 1415 | '#link' => array( | |
| 1416 | 'title' => t('Example tab'), | |
| 1417 | 'href' => 'node/add', | |
| 1418 | 'localized_options' => array( | |
| 1419 | 'attributes' => array( | |
| 1420 | 'title' => t('Add new content'), | |
| 1421 | ), | |
| 1422 | ), | |
| 1423 | ), | |
| 1424 | // Define whether this link is active. This can be omitted for | |
| 1425 | // implementations that add links to pages outside of the current page | |
| 1426 | // context. | |
| 1427 | '#active' => ($router_item['path'] == $root_path), | |
| 1428 | ); | |
| 1429 | } | |
| 1430 | ||
| 1431 | /** | |
| c9de4646 DB |
1432 | * Alter links in the active trail before it is rendered as the breadcrumb. |
| 1433 | * | |
| 1434 | * This hook is invoked by menu_get_active_breadcrumb() and allows alteration | |
| 1435 | * of the breadcrumb links for the current page, which may be preferred instead | |
| 1436 | * of setting a custom breadcrumb via drupal_set_breadcrumb(). | |
| 1437 | * | |
| 1438 | * Implementations should take into account that menu_get_active_breadcrumb() | |
| 1439 | * subsequently performs the following adjustments to the active trail *after* | |
| 1440 | * this hook has been invoked: | |
| 1441 | * - The last link in $active_trail is removed, if its 'href' is identical to | |
| 1442 | * the 'href' of $item. This happens, because the breadcrumb normally does | |
| 1443 | * not contain a link to the current page. | |
| 1444 | * - The (second to) last link in $active_trail is removed, if the current $item | |
| 1445 | * is a MENU_DEFAULT_LOCAL_TASK. This happens in order to do not show a link | |
| 1446 | * to the current page, when being on the path for the default local task; | |
| 1447 | * e.g. when being on the path node/%/view, the breadcrumb should not contain | |
| 1448 | * a link to node/%. | |
| 1449 | * | |
| 1450 | * Each link in the active trail must contain: | |
| 1451 | * - title: The localized title of the link. | |
| 1452 | * - href: The system path to link to. | |
| 1453 | * - localized_options: An array of options to pass to url(). | |
| 1454 | * | |
| 1455 | * @param $active_trail | |
| 1456 | * An array containing breadcrumb links for the current page. | |
| 1457 | * @param $item | |
| 1458 | * The menu router item of the current page. | |
| 1459 | * | |
| 1460 | * @see drupal_set_breadcrumb() | |
| 1461 | * @see menu_get_active_breadcrumb() | |
| 1462 | * @see menu_get_active_trail() | |
| 1463 | * @see menu_set_active_trail() | |
| 1464 | */ | |
| 1465 | function hook_menu_breadcrumb_alter(&$active_trail, $item) { | |
| 1466 | // Always display a link to the current page by duplicating the last link in | |
| 1467 | // the active trail. This means that menu_get_active_breadcrumb() will remove | |
| 1468 | // the last link (for the current page), but since it is added once more here, | |
| 1469 | // it will appear. | |
| 1470 | if (!drupal_is_front_page()) { | |
| 1471 | $end = end($active_trail); | |
| 1472 | if ($item['href'] == $end['href']) { | |
| 1473 | $active_trail[] = $end; | |
| 1474 | } | |
| 1475 | } | |
| 1476 | } | |
| 1477 | ||
| 1478 | /** | |
| 5c5bd803 AB |
1479 | * Alter contextual links before they are rendered. |
| 1480 | * | |
| 1481 | * This hook is invoked by menu_contextual_links(). The system-determined | |
| 1482 | * contextual links are passed in by reference. Additional links may be added | |
| 1483 | * or existing links can be altered. | |
| 1484 | * | |
| 1485 | * Each contextual link must at least contain: | |
| 1486 | * - title: The localized title of the link. | |
| 1487 | * - href: The system path to link to. | |
| 1488 | * - localized_options: An array of options to pass to url(). | |
| 1489 | * | |
| 1490 | * @param $links | |
| 1491 | * An associative array containing contextual links for the given $root_path, | |
| 1492 | * as described above. The array keys are used to build CSS class names for | |
| 1493 | * contextual links and must therefore be unique for each set of contextual | |
| 1494 | * links. | |
| 1495 | * @param $router_item | |
| 1496 | * The menu router item belonging to the $root_path being requested. | |
| 1497 | * @param $root_path | |
| 1498 | * The (parent) path that has been requested to build contextual links for. | |
| 1499 | * This is a normalized path, which means that an originally passed path of | |
| 1500 | * 'node/123' became 'node/%'. | |
| 1501 | * | |
| 84e5d10b | 1502 | * @see hook_contextual_links_view_alter() |
| 5c5bd803 AB |
1503 | * @see menu_contextual_links() |
| 1504 | * @see hook_menu() | |
| 84e5d10b | 1505 | * @see contextual_preprocess() |
| 5c5bd803 AB |
1506 | */ |
| 1507 | function hook_menu_contextual_links_alter(&$links, $router_item, $root_path) { | |
| 1508 | // Add a link to all contextual links for nodes. | |
| 1509 | if ($root_path == 'node/%') { | |
| 1510 | $links['foo'] = array( | |
| 1511 | 'title' => t('Do fu'), | |
| 1512 | 'href' => 'foo/do', | |
| 1513 | 'localized_options' => array( | |
| 1514 | 'query' => array( | |
| 1515 | 'foo' => 'bar', | |
| 1516 | ), | |
| 1517 | ), | |
| 1518 | ); | |
| 1519 | } | |
| 1520 | } | |
| 1521 | ||
| 1522 | /** | |
| 2e8ca690 DB |
1523 | * Perform alterations before a page is rendered. |
| 1524 | * | |
| a244b45c AB |
1525 | * Use this hook when you want to remove or alter elements at the page |
| 1526 | * level, or add elements at the page level that depend on an other module's | |
| 1527 | * elements (this hook runs after hook_page_build(). | |
| 1528 | * | |
| 1529 | * If you are making changes to entities such as forms, menus, or user | |
| 2e8ca690 DB |
1530 | * profiles, use those objects' native alter hooks instead (hook_form_alter(), |
| 1531 | * for example). | |
| 1532 | * | |
| 1533 | * The $page array contains top level elements for each block region: | |
| 1534 | * @code | |
| a244b45c | 1535 | * $page['page_top'] |
| 2e8ca690 | 1536 | * $page['header'] |
| 62e0ddc7 | 1537 | * $page['sidebar_first'] |
| 2e8ca690 | 1538 | * $page['content'] |
| 62e0ddc7 | 1539 | * $page['sidebar_second'] |
| a244b45c | 1540 | * $page['page_bottom'] |
| 2e8ca690 DB |
1541 | * @endcode |
| 1542 | * | |
| 1543 | * The 'content' element contains the main content of the current page, and its | |
| 1544 | * structure will vary depending on what module is responsible for building the | |
| 1545 | * page. Some legacy modules may not return structured content at all: their | |
| 1546 | * pre-rendered markup will be located in $page['content']['main']['#markup']. | |
| 1547 | * | |
| 1548 | * Pages built by Drupal's core Node and Blog modules use a standard structure: | |
| 1549 | * | |
| 1550 | * @code | |
| 1551 | * // Node body. | |
| b922148c | 1552 | * $page['content']['system_main']['nodes'][$nid]['body'] |
| 2e8ca690 | 1553 | * // Array of links attached to the node (add comments, read more). |
| b922148c | 1554 | * $page['content']['system_main']['nodes'][$nid]['links'] |
| 2e8ca690 | 1555 | * // The node object itself. |
| b922148c | 1556 | * $page['content']['system_main']['nodes'][$nid]['#node'] |
| 2e8ca690 | 1557 | * // The results pager. |
| b922148c | 1558 | * $page['content']['system_main']['pager'] |
| 1dafc60c | 1559 | * @endcode |
| 2e8ca690 DB |
1560 | * |
| 1561 | * Blocks may be referenced by their module/delta pair within a region: | |
| 1562 | * @code | |
| 62e0ddc7 | 1563 | * // The login block in the first sidebar region. |
| a244b45c | 1564 | * $page['sidebar_first']['user_login']['#block']; |
| 2e8ca690 DB |
1565 | * @endcode |
| 1566 | * | |
| 1567 | * @param $page | |
| 1568 | * Nested array of renderable elements that make up the page. | |
| 1569 | * | |
| a244b45c | 1570 | * @see hook_page_build() |
| 2e8ca690 DB |
1571 | * @see drupal_render_page() |
| 1572 | */ | |
| a244b45c AB |
1573 | function hook_page_alter(&$page) { |
| 1574 | // Add help text to the user login block. | |
| 1575 | $page['sidebar_first']['user_login']['help'] = array( | |
| 1576 | '#weight' => -10, | |
| 1577 | '#markup' => t('To post comments or add new content, you first have to log in.'), | |
| 1578 | ); | |
| 2e8ca690 DB |
1579 | } |
| 1580 | ||
| 1581 | /** | |
| 66df6025 AB |
1582 | * Perform alterations before a form is rendered. |
| 1583 | * | |
| 1584 | * One popular use of this hook is to add form elements to the node form. When | |
| 4ce4c4eb | 1585 | * altering a node form, the node object can be accessed at $form['#node']. |
| 66df6025 | 1586 | * |
| 184c145d D |
1587 | * In addition to hook_form_alter(), which is called for all forms, there are |
| 1588 | * two more specific form hooks available. The first, | |
| 1589 | * hook_form_BASE_FORM_ID_alter(), allows targeting of a form/forms via a base | |
| 1590 | * form (if one exists). The second, hook_form_FORM_ID_alter(), can be used to | |
| 1591 | * target a specific form directly. | |
| 1592 | * | |
| 1593 | * The call order is as follows: all existing form alter functions are called | |
| 1594 | * for module A, then all for module B, etc., followed by all for any base | |
| 1595 | * theme(s), and finally for the theme itself. The module order is determined | |
| 1596 | * by system weight, then by module name. | |
| 1597 | * | |
| 1598 | * Within each module, form alter hooks are called in the following order: | |
| 1599 | * first, hook_form_alter(); second, hook_form_BASE_FORM_ID_alter(); third, | |
| 1600 | * hook_form_FORM_ID_alter(). So, for each module, the more general hooks are | |
| 1601 | * called first followed by the more specific. | |
| ad84a926 | 1602 | * |
| 66df6025 AB |
1603 | * @param $form |
| 1604 | * Nested array of form elements that comprise the form. | |
| 1605 | * @param $form_state | |
| d3c83c02 DB |
1606 | * A keyed array containing the current state of the form. The arguments |
| 1607 | * that drupal_get_form() was originally called with are available in the | |
| 1608 | * array $form_state['build_info']['args']. | |
| 66df6025 AB |
1609 | * @param $form_id |
| 1610 | * String representing the name of the form itself. Typically this is the | |
| 1611 | * name of the function that generated the form. | |
| 19a45ce5 | 1612 | * |
| 184c145d | 1613 | * @see hook_form_BASE_FORM_ID_alter() |
| 19a45ce5 | 1614 | * @see hook_form_FORM_ID_alter() |
| 66df6025 | 1615 | */ |
| 7dd203c4 | 1616 | function hook_form_alter(&$form, &$form_state, $form_id) { |
| 66df6025 AB |
1617 | if (isset($form['type']) && $form['type']['#value'] . '_node_settings' == $form_id) { |
| 1618 | $form['workflow']['upload_' . $form['type']['#value']] = array( | |
| 1619 | '#type' => 'radios', | |
| 1620 | '#title' => t('Attachments'), | |
| 1621 | '#default_value' => variable_get('upload_' . $form['type']['#value'], 1), | |
| 1622 | '#options' => array(t('Disabled'), t('Enabled')), | |
| 1623 | ); | |
| 1624 | } | |
| 1625 | } | |
| 1626 | ||
| 1627 | /** | |
| 1628 | * Provide a form-specific alteration instead of the global hook_form_alter(). | |
| 1629 | * | |
| 1630 | * Modules can implement hook_form_FORM_ID_alter() to modify a specific form, | |
| 1631 | * rather than implementing hook_form_alter() and checking the form ID, or | |
| 1632 | * using long switch statements to alter multiple forms. | |
| 1633 | * | |
| 184c145d D |
1634 | * Form alter hooks are called in the following order: hook_form_alter(), |
| 1635 | * hook_form_BASE_FORM_ID_alter(), hook_form_FORM_ID_alter(). See | |
| 1636 | * hook_form_alter() for more details. | |
| 1637 | * | |
| 66df6025 AB |
1638 | * @param $form |
| 1639 | * Nested array of form elements that comprise the form. | |
| 1640 | * @param $form_state | |
| d3c83c02 DB |
1641 | * A keyed array containing the current state of the form. The arguments |
| 1642 | * that drupal_get_form() was originally called with are available in the | |
| 1643 | * array $form_state['build_info']['args']. | |
| eaee909a DB |
1644 | * @param $form_id |
| 1645 | * String representing the name of the form itself. Typically this is the | |
| 1646 | * name of the function that generated the form. | |
| 66df6025 | 1647 | * |
| 19a45ce5 | 1648 | * @see hook_form_alter() |
| 184c145d | 1649 | * @see hook_form_BASE_FORM_ID_alter() |
| d428fe37 | 1650 | * @see drupal_prepare_form() |
| 66df6025 | 1651 | */ |
| eaee909a | 1652 | function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) { |
| 66df6025 | 1653 | // Modification for the form with the given form ID goes here. For example, if |
| d16bead1 | 1654 | // FORM_ID is "user_register_form" this code would run only on the user |
| 66df6025 AB |
1655 | // registration form. |
| 1656 | ||
| 1657 | // Add a checkbox to registration form about agreeing to terms of use. | |
| 1658 | $form['terms_of_use'] = array( | |
| 1659 | '#type' => 'checkbox', | |
| 1660 | '#title' => t("I agree with the website's terms and conditions."), | |
| 1661 | '#required' => TRUE, | |
| 1662 | ); | |
| 1663 | } | |
| 1664 | ||
| 1665 | /** | |
| 184c145d D |
1666 | * Provide a form-specific alteration for shared ('base') forms. |
| 1667 | * | |
| 1668 | * By default, when drupal_get_form() is called, Drupal looks for a function | |
| 1669 | * with the same name as the form ID, and uses that function to build the form. | |
| 1670 | * In contrast, base forms allow multiple form IDs to be mapped to a single base | |
| 1671 | * (also called 'factory') form function. | |
| eaee909a DB |
1672 | * |
| 1673 | * Modules can implement hook_form_BASE_FORM_ID_alter() to modify a specific | |
| 184c145d D |
1674 | * base form, rather than implementing hook_form_alter() and checking for |
| 1675 | * conditions that would identify the shared form constructor. | |
| 1676 | * | |
| 1677 | * To identify the base form ID for a particular form (or to determine whether | |
| 1678 | * one exists) check the $form_state. The base form ID is stored under | |
| 1679 | * $form_state['build_info']['base_form_id']. | |
| eaee909a | 1680 | * |
| 184c145d D |
1681 | * See hook_forms() for more information on how to implement base forms in |
| 1682 | * Drupal. | |
| eaee909a | 1683 | * |
| 184c145d D |
1684 | * Form alter hooks are called in the following order: hook_form_alter(), |
| 1685 | * hook_form_BASE_FORM_ID_alter(), hook_form_FORM_ID_alter(). See | |
| 1686 | * hook_form_alter() for more details. | |
| eaee909a DB |
1687 | * |
| 1688 | * @param $form | |
| 1689 | * Nested array of form elements that comprise the form. | |
| 1690 | * @param $form_state | |
| 1691 | * A keyed array containing the current state of the form. | |
| 1692 | * @param $form_id | |
| 1693 | * String representing the name of the form itself. Typically this is the | |
| 1694 | * name of the function that generated the form. | |
| 1695 | * | |
| 184c145d | 1696 | * @see hook_form_alter() |
| eaee909a DB |
1697 | * @see hook_form_FORM_ID_alter() |
| 1698 | * @see drupal_prepare_form() | |
| 184c145d | 1699 | * @see hook_forms() |
| eaee909a DB |
1700 | */ |
| 1701 | function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) { | |
| 1702 | // Modification for the form with the given BASE_FORM_ID goes here. For | |
| 1703 | // example, if BASE_FORM_ID is "node_form", this code would run on every | |
| 1704 | // node form, regardless of node type. | |
| 1705 | ||
| 1706 | // Add a checkbox to the node form about agreeing to terms of use. | |
| 1707 | $form['terms_of_use'] = array( | |
| 1708 | '#type' => 'checkbox', | |
| 1709 | '#title' => t("I agree with the website's terms and conditions."), | |
| 1710 | '#required' => TRUE, | |
| 1711 | ); | |
| 1712 | } | |
| 1713 | ||
| 1714 | /** | |
| 7511394e | 1715 | * Map form_ids to form builder functions. |
| 66df6025 | 1716 | * |
| 7511394e DB |
1717 | * By default, when drupal_get_form() is called, the system will look for a |
| 1718 | * function with the same name as the form ID, and use that function to build | |
| 184c145d D |
1719 | * the form. If no such function is found, Drupal calls this hook. Modules |
| 1720 | * implementing this hook can then provide their own instructions for mapping | |
| 1721 | * form IDs to constructor functions. As a result, you can easily map multiple | |
| 1722 | * form IDs to a single form constructor (referred to as a 'base' form). | |
| 1723 | * | |
| 1724 | * Using a base form can help to avoid code duplication, by allowing many | |
| 1725 | * similar forms to use the same code base. Another benefit is that it becomes | |
| 1726 | * much easier for other modules to apply a general change to the group of | |
| 1727 | * forms; hook_form_BASE_FORM_ID_alter() can be used to easily alter multiple | |
| 1728 | * forms at once by directly targeting the shared base form. | |
| 1729 | * | |
| 1730 | * Two example use cases where base forms may be useful are given below. | |
| 66df6025 | 1731 | * |
| 7511394e DB |
1732 | * First, you can use this hook to tell the form system to use a different |
| 1733 | * function to build certain forms in your module; this is often used to define | |
| 1734 | * a form "factory" function that is used to build several similar forms. In | |
| 1735 | * this case, your hook implementation will likely ignore all of the input | |
| 184c145d D |
1736 | * arguments. See node_forms() for an example of this. Note, node_forms() is the |
| 1737 | * hook_forms() implementation; the base form itself is defined in node_form(). | |
| 66df6025 | 1738 | * |
| 7511394e DB |
1739 | * Second, you could use this hook to define how to build a form with a |
| 1740 | * dynamically-generated form ID. In this case, you would need to verify that | |
| 1741 | * the $form_id input matched your module's format for dynamically-generated | |
| 1742 | * form IDs, and if so, act appropriately. | |
| 66df6025 | 1743 | * |
| a4dc8467 DB |
1744 | * @param $form_id |
| 1745 | * The unique string identifying the desired form. | |
| 1746 | * @param $args | |
| 7511394e DB |
1747 | * An array containing the original arguments provided to drupal_get_form() |
| 1748 | * or drupal_form_submit(). These are always passed to the form builder and | |
| 1749 | * do not have to be specified manually in 'callback arguments'. | |
| b006ec6c | 1750 | * |
| 66df6025 | 1751 | * @return |
| b006ec6c AB |
1752 | * An associative array whose keys define form_ids and whose values are an |
| 1753 | * associative array defining the following keys: | |
| 184c145d D |
1754 | * - callback: The name of the form builder function to invoke. This will be |
| 1755 | * used for the base form ID, for example, to target a base form using | |
| 1756 | * hook_form_BASE_FORM_ID_alter(). | |
| b006ec6c AB |
1757 | * - callback arguments: (optional) Additional arguments to pass to the |
| 1758 | * function defined in 'callback', which are prepended to $args. | |
| 1759 | * - wrapper_callback: (optional) The name of a form builder function to | |
| 1760 | * invoke before the form builder defined in 'callback' is invoked. This | |
| 1761 | * wrapper callback may prepopulate the $form array with form elements, | |
| 1762 | * which will then be already contained in the $form that is passed on to | |
| 1763 | * the form builder defined in 'callback'. For example, a wrapper callback | |
| 1764 | * could setup wizard-alike form buttons that are the same for a variety of | |
| 1765 | * forms that belong to the wizard, which all share the same wrapper | |
| 1766 | * callback. | |
| 66df6025 | 1767 | */ |
| a4dc8467 | 1768 | function hook_forms($form_id, $args) { |
| b006ec6c AB |
1769 | // Simply reroute the (non-existing) $form_id 'mymodule_first_form' to |
| 1770 | // 'mymodule_main_form'. | |
| 66df6025 | 1771 | $forms['mymodule_first_form'] = array( |
| b006ec6c | 1772 | 'callback' => 'mymodule_main_form', |
| 66df6025 | 1773 | ); |
| b006ec6c AB |
1774 | |
| 1775 | // Reroute the $form_id and prepend an additional argument that gets passed to | |
| 1776 | // the 'mymodule_main_form' form builder function. | |
| 66df6025 | 1777 | $forms['mymodule_second_form'] = array( |
| b006ec6c AB |
1778 | 'callback' => 'mymodule_main_form', |
| 1779 | 'callback arguments' => array('some parameter'), | |
| 1780 | ); | |
| 1781 | ||
| 1782 | // Reroute the $form_id, but invoke the form builder function | |
| 1783 | // 'mymodule_main_form_wrapper' first, so we can prepopulate the $form array | |
| 1784 | // that is passed to the actual form builder 'mymodule_main_form'. | |
| 1785 | $forms['mymodule_wrapped_form'] = array( | |
| 1786 | 'callback' => 'mymodule_main_form', | |
| 1787 | 'wrapper_callback' => 'mymodule_main_form_wrapper', | |
| 66df6025 | 1788 | ); |
| a4dc8467 | 1789 | |
| 66df6025 AB |
1790 | return $forms; |
| 1791 | } | |
| 1792 | ||
| 1793 | /** | |
| 7f0feebe | 1794 | * Perform setup tasks for all page requests. |
| 66df6025 AB |
1795 | * |
| 1796 | * This hook is run at the beginning of the page request. It is typically | |
| 7f0feebe | 1797 | * used to set up global parameters that are needed later in the request. |
| 66df6025 | 1798 | * |
| 7f0feebe DB |
1799 | * Only use this hook if your code must run even for cached page views. This |
| 1800 | * hook is called before modules or most include files are loaded into memory. | |
| 66df6025 | 1801 | * It happens while Drupal is still in bootstrap mode. |
| 7f0feebe DB |
1802 | * |
| 1803 | * @see hook_init() | |
| 66df6025 AB |
1804 | */ |
| 1805 | function hook_boot() { | |
| 7f0feebe | 1806 | // We need user_access() in the shutdown function. Make sure it gets loaded. |
| 66df6025 | 1807 | drupal_load('module', 'user'); |
| 8d01aeb4 | 1808 | drupal_register_shutdown_function('devel_shutdown'); |
| 66df6025 AB |
1809 | } |
| 1810 | ||
| 1811 | /** | |
| 7f0feebe | 1812 | * Perform setup tasks for non-cached page requests. |
| 66df6025 AB |
1813 | * |
| 1814 | * This hook is run at the beginning of the page request. It is typically | |
| 7f0feebe DB |
1815 | * used to set up global parameters that are needed later in the request. |
| 1816 | * When this hook is called, all modules are already loaded in memory. | |
| 66df6025 | 1817 | * |
| fb9c1df0 DB |
1818 | * This hook is not run on cached pages. |
| 1819 | * | |
| 1820 | * To add CSS or JS that should be present on all pages, modules should not | |
| 1821 | * implement this hook, but declare these files in their .info file. | |
| 7f0feebe DB |
1822 | * |
| 1823 | * @see hook_boot() | |
| 66df6025 AB |
1824 | */ |
| 1825 | function hook_init() { | |
| 5834cd45 AB |
1826 | // Since this file should only be loaded on the front page, it cannot be |
| 1827 | // declared in the info file. | |
| 1828 | if (drupal_is_front_page()) { | |
| 1829 | drupal_add_css(drupal_get_path('module', 'foo') . '/foo.css'); | |
| 1830 | } | |
| 66df6025 AB |
1831 | } |
| 1832 | ||
| 1833 | /** | |
| 0ea65350 DB |
1834 | * Define image toolkits provided by this module. |
| 1835 | * | |
| 1836 | * The file which includes each toolkit's functions must be declared as part of | |
| 1837 | * the files array in the module .info file so that the registry will find and | |
| 1838 | * parse it. | |
| 1839 | * | |
| 1840 | * The toolkit's functions must be named image_toolkitname_operation(). | |
| 1841 | * where the operation may be: | |
| 1842 | * - 'load': Required. See image_gd_load() for usage. | |
| 1843 | * - 'save': Required. See image_gd_save() for usage. | |
| 1844 | * - 'settings': Optional. See image_gd_settings() for usage. | |
| 1845 | * - 'resize': Optional. See image_gd_resize() for usage. | |
| a4ee7092 | 1846 | * - 'rotate': Optional. See image_gd_rotate() for usage. |
| 0ea65350 DB |
1847 | * - 'crop': Optional. See image_gd_crop() for usage. |
| 1848 | * - 'desaturate': Optional. See image_gd_desaturate() for usage. | |
| 1849 | * | |
| 1850 | * @return | |
| 1851 | * An array with the toolkit name as keys and sub-arrays with these keys: | |
| 1852 | * - 'title': A string with the toolkit's title. | |
| 1853 | * - 'available': A Boolean value to indicate that the toolkit is operating | |
| 1854 | * properly, e.g. all required libraries exist. | |
| 1855 | * | |
| 1856 | * @see system_image_toolkits() | |
| 1857 | */ | |
| 66df6025 | 1858 | function hook_image_toolkits() { |
| 0ea65350 DB |
1859 | return array( |
| 1860 | 'working' => array( | |
| 1861 | 'title' => t('A toolkit that works.'), | |
| 1862 | 'available' => TRUE, | |
| 1863 | ), | |
| 1864 | 'broken' => array( | |
| 1865 | 'title' => t('A toolkit that is "broken" and will not be listed.'), | |
| 1866 | 'available' => FALSE, | |
| 1867 | ), | |
| 1868 | ); | |
| 66df6025 AB |
1869 | } |
| 1870 | ||
| 1871 | /** | |
| 45da7480 DB |
1872 | * Alter an email message created with the drupal_mail() function. |
| 1873 | * | |
| 1874 | * hook_mail_alter() allows modification of email messages created and sent | |
| 1875 | * with drupal_mail(). Usage examples include adding and/or changing message | |
| 1876 | * text, message fields, and message headers. | |
| 1877 | * | |
| 1878 | * Email messages sent using functions other than drupal_mail() will not | |
| 1879 | * invoke hook_mail_alter(). For example, a contributed module directly | |
| 13d3072f | 1880 | * calling the drupal_mail_system()->mail() or PHP mail() function |
| c4a548f6 | 1881 | * will not invoke this hook. All core modules use drupal_mail() for |
| af3f94b3 | 1882 | * messaging, it is best practice but not mandatory in contributed modules. |
| 66df6025 AB |
1883 | * |
| 1884 | * @param $message | |
| 45da7480 | 1885 | * An array containing the message data. Keys in this array include: |
| 9850918a | 1886 | * - 'id': |
| 45da7480 | 1887 | * The drupal_mail() id of the message. Look at module source code or |
| cef10893 | 1888 | * drupal_mail() for possible id values. |
| 45da7480 | 1889 | * - 'to': |
| 9850918a | 1890 | * The address or addresses the message will be sent to. The |
| 66df6025 | 1891 | * formatting of this string must comply with RFC 2822. |
| 45da7480 | 1892 | * - 'from': |
| 9850918a DB |
1893 | * The address the message will be marked as being from, which is |
| 1894 | * either a custom address or the site-wide default email address. | |
| 45da7480 DB |
1895 | * - 'subject': |
| 1896 | * Subject of the email to be sent. This must not contain any newline | |
| 1897 | * characters, or the email may not be sent properly. | |
| 1898 | * - 'body': | |
| 1899 | * An array of strings containing the message text. The message body is | |
| cef10893 | 1900 | * created by concatenating the individual array strings into a single text |
| 45da7480 DB |
1901 | * string using "\n\n" as a separator. |
| 1902 | * - 'headers': | |
| 9850918a | 1903 | * Associative array containing mail headers, such as From, Sender, |
| 5fbaa4b8 | 1904 | * MIME-Version, Content-Type, etc. |
| 45da7480 DB |
1905 | * - 'params': |
| 1906 | * An array of optional parameters supplied by the caller of drupal_mail() | |
| 1907 | * that is used to build the message before hook_mail_alter() is invoked. | |
| 1908 | * - 'language': | |
| 1909 | * The language object used to build the message before hook_mail_alter() | |
| 1910 | * is invoked. | |
| 13874568 | 1911 | * - 'send': |
| 1912 | * Set to FALSE to abort sending this email message. | |
| 45da7480 DB |
1913 | * |
| 1914 | * @see drupal_mail() | |
| 66df6025 AB |
1915 | */ |
| 1916 | function hook_mail_alter(&$message) { | |
| 22273a43 | 1917 | if ($message['id'] == 'modulename_messagekey') { |
| 13874568 | 1918 | if (!example_notifications_optin($message['to'], $message['id'])) { |
| 1919 | // If the recipient has opted to not receive such messages, cancel | |
| 1920 | // sending. | |
| 1921 | $message['send'] = FALSE; | |
| 1922 | return; | |
| 1923 | } | |
| 9ae311ba | 1924 | $message['body'][] = "--\nMail sent out from " . variable_get('site_name', t('Drupal')); |
| 66df6025 AB |
1925 | } |
| 1926 | } | |
| 1927 | ||
| 1928 | /** | |
| 453032c1 AB |
1929 | * Alter the registry of modules implementing a hook. |
| 1930 | * | |
| 1931 | * This hook is invoked during module_implements(). A module may implement this | |
| 1932 | * hook in order to reorder the implementing modules, which are otherwise | |
| 1933 | * ordered by the module's system weight. | |
| 1934 | * | |
| b96a83b4 D |
1935 | * Note that hooks invoked using drupal_alter() can have multiple variations |
| 1936 | * (such as hook_form_alter() and hook_form_FORM_ID_alter()). drupal_alter() | |
| 1937 | * will call all such variants defined by a single module in turn. For the | |
| 1938 | * purposes of hook_module_implements_alter(), these variants are treated as | |
| 1939 | * a single hook. Thus, to ensure that your implementation of | |
| 1940 | * hook_form_FORM_ID_alter() is called at the right time, you will have to | |
| 1941 | * have to change the order of hook_form_alter() implementation in | |
| 1942 | * hook_module_implements_alter(). | |
| 1943 | * | |
| a22d7770 | 1944 | * @param $implementations |
| 453032c1 AB |
1945 | * An array keyed by the module's name. The value of each item corresponds |
| 1946 | * to a $group, which is usually FALSE, unless the implementation is in a | |
| 1947 | * file named $module.$group.inc. | |
| 1948 | * @param $hook | |
| 1949 | * The name of the module hook being implemented. | |
| 1950 | */ | |
| 1951 | function hook_module_implements_alter(&$implementations, $hook) { | |
| 1952 | if ($hook == 'rdf_mapping') { | |
| 1953 | // Move my_module_rdf_mapping() to the end of the list. module_implements() | |
| 1954 | // iterates through $implementations with a foreach loop which PHP iterates | |
| 1955 | // in the order that the items were added, so to move an item to the end of | |
| 1956 | // the array, we remove it and then add it. | |
| 1957 | $group = $implementations['my_module']; | |
| 1958 | unset($implementations['my_module']); | |
| 1959 | $implementations['my_module'] = $group; | |
| 1960 | } | |
| 1961 | } | |
| 1962 | ||
| 1963 | /** | |
| 11d884be | 1964 | * Return additional themes provided by modules. |
| 1965 | * | |
| 1966 | * Only use this hook for testing purposes. Use a hidden MYMODULE_test.module | |
| 1967 | * to implement this hook. Testing themes should be hidden, too. | |
| 1968 | * | |
| 1969 | * This hook is invoked from _system_rebuild_theme_data() and allows modules to | |
| 1970 | * register additional themes outside of the regular 'themes' directories of a | |
| 1971 | * Drupal installation. | |
| 1972 | * | |
| 1973 | * @return | |
| 1974 | * An associative array. Each key is the system name of a theme and each value | |
| 1975 | * is the corresponding path to the theme's .info file. | |
| 1976 | */ | |
| 1977 | function hook_system_theme_info() { | |
| 1978 | $themes['mymodule_test_theme'] = drupal_get_path('module', 'mymodule') . '/mymodule_test_theme/mymodule_test_theme.info'; | |
| 1979 | return $themes; | |
| 1980 | } | |
| 1981 | ||
| 1982 | /** | |
| 66df6025 AB |
1983 | * Alter the information parsed from module and theme .info files |
| 1984 | * | |
| 89d04ea7 AB |
1985 | * This hook is invoked in _system_rebuild_module_data() and in |
| 1986 | * _system_rebuild_theme_data(). A module may implement this hook in order to | |
| 1987 | * add to or alter the data generated by reading the .info file with | |
| 1988 | * drupal_parse_info_file(). | |
| 66df6025 | 1989 | * |
| a22d7770 | 1990 | * @param $info |
| 66df6025 AB |
1991 | * The .info file contents, passed by reference so that it can be altered. |
| 1992 | * @param $file | |
| 1993 | * Full information about the module or theme, including $file->name, and | |
| 1994 | * $file->filename | |
| 9e638424 DB |
1995 | * @param $type |
| 1996 | * Either 'module' or 'theme', depending on the type of .info file that was | |
| 1997 | * passed. | |
| 66df6025 | 1998 | */ |
| 9e638424 | 1999 | function hook_system_info_alter(&$info, $file, $type) { |
| 66df6025 AB |
2000 | // Only fill this in if the .info file does not define a 'datestamp'. |
| 2001 | if (empty($info['datestamp'])) { | |
| 2002 | $info['datestamp'] = filemtime($file->filename); | |
| 2003 | } | |
| 2004 | } | |
| 2005 | ||
| 2006 | /** | |
| 2007 | * Define user permissions. | |
| 2008 | * | |
| 2009 | * This hook can supply permissions that the module defines, so that they | |
| da794083 | 2010 | * can be selected on the user permissions page and used to grant or restrict |
| 66df6025 AB |
2011 | * access to actions the module performs. |
| 2012 | * | |
| 66df6025 AB |
2013 | * Permissions are checked using user_access(). |
| 2014 | * | |
| 2015 | * For a detailed usage example, see page_example.module. | |
| 6586b764 | 2016 | * |
| 1a2d10ec | 2017 | * @return |
| 25feb96f DB |
2018 | * An array whose keys are permission names and whose corresponding values |
| 2019 | * are arrays containing the following key-value pairs: | |
| 2020 | * - title: The human-readable name of the permission, to be shown on the | |
| 2021 | * permission administration page. This should be wrapped in the t() | |
| 2022 | * function so it can be translated. | |
| 2023 | * - description: (optional) A description of what the permission does. This | |
| 2024 | * should be wrapped in the t() function so it can be translated. | |
| 2025 | * - restrict access: (optional) A boolean which can be set to TRUE to | |
| 2026 | * indicate that site administrators should restrict access to this | |
| 2027 | * permission to trusted users. This should be used for permissions that | |
| 2028 | * have inherent security risks across a variety of potential use cases | |
| 2029 | * (for example, the "administer filters" and "bypass node access" | |
| 2030 | * permissions provided by Drupal core). When set to TRUE, a standard | |
| 170208b2 | 2031 | * warning message defined in user_admin_permissions() and output via |
| 2032 | * theme_user_permission_description() will be associated with the | |
| 2033 | * permission and displayed with it on the permission administration page. | |
| 2034 | * Defaults to FALSE. | |
| 2035 | * - warning: (optional) A translated warning message to display for this | |
| 2036 | * permission on the permission administration page. This warning overrides | |
| 2037 | * the automatic warning generated by 'restrict access' being set to TRUE. | |
| 2038 | * This should rarely be used, since it is important for all permissions to | |
| 2039 | * have a clear, consistent security warning that is the same across the | |
| 2040 | * site. Use the 'description' key instead to provide any information that | |
| 2041 | * is specific to the permission you are defining. | |
| 2042 | * | |
| 2043 | * @see theme_user_permission_description() | |
| 66df6025 | 2044 | */ |
| e4a4b7cc | 2045 | function hook_permission() { |
| 66df6025 | 2046 | return array( |
| da794083 DB |
2047 | 'administer my module' => array( |
| 2048 | 'title' => t('Administer my module'), | |
| 2049 | 'description' => t('Perform administration tasks for my module.'), | |
| 2050 | ), | |
| 66df6025 AB |
2051 | ); |
| 2052 | } | |
| 2053 | ||
| 2054 | /** | |
| 2055 | * Register a module (or theme's) theme implementations. | |
| 2056 | * | |
| 9ebcbc70 | 2057 | * The implementations declared by this hook have two purposes: either they |
| 2058 | * specify how a particular render array is to be rendered as HTML (this is | |
| 2059 | * usually the case if the theme function is assigned to the render array's | |
| 2060 | * #theme property), or they return the HTML that should be returned by an | |
| 2061 | * invocation of theme(). | |
| 2062 | * | |
| 66df6025 AB |
2063 | * The following parameters are all optional. |
| 2064 | * | |
| 06585e6b | 2065 | * @param array $existing |
| 66df6025 AB |
2066 | * An array of existing implementations that may be used for override |
| 2067 | * purposes. This is primarily useful for themes that may wish to examine | |
| 2068 | * existing implementations to extract data (such as arguments) so that | |
| 2069 | * it may properly register its own, higher priority implementations. | |
| 2070 | * @param $type | |
| 06585e6b AB |
2071 | * Whether a theme, module, etc. is being processed. This is primarily useful |
| 2072 | * so that themes tell if they are the actual theme being called or a parent | |
| 2073 | * theme. May be one of: | |
| 2074 | * - 'module': A module is being checked for theme implementations. | |
| 2075 | * - 'base_theme_engine': A theme engine is being checked for a theme that is | |
| 2076 | * a parent of the actual theme being used. | |
| 2077 | * - 'theme_engine': A theme engine is being checked for the actual theme | |
| 2078 | * being used. | |
| 2079 | * - 'base_theme': A base theme is being checked for theme implementations. | |
| 2080 | * - 'theme': The actual theme in use is being checked. | |
| 66df6025 | 2081 | * @param $theme |
| 06585e6b | 2082 | * The actual name of theme, module, etc. that is being being processed. |
| 66df6025 AB |
2083 | * @param $path |
| 2084 | * The directory path of the theme or module, so that it doesn't need to be | |
| 2085 | * looked up. | |
| 2086 | * | |
| 06585e6b AB |
2087 | * @return array |
| 2088 | * An associative array of theme hook information. The keys on the outer | |
| 2089 | * array are the internal names of the hooks, and the values are arrays | |
| 9ebcbc70 | 2090 | * containing information about the hook. Each information array must contain |
| 2091 | * either a 'variables' element or a 'render element' element, but not both. | |
| 2092 | * Use 'render element' if you are theming a single element or element tree | |
| 2093 | * composed of elements, such as a form array, a page array, or a single | |
| 2094 | * checkbox element. Use 'variables' if your theme implementation is | |
| 2095 | * intended to be called directly through theme() and has multiple arguments | |
| 2096 | * for the data and style; in this case, the variables not supplied by the | |
| 2097 | * calling function will be given default values and passed to the template | |
| 2098 | * or theme function. The returned theme information array can contain the | |
| 2099 | * following key/value pairs: | |
| 2100 | * - variables: (see above) Each array key is the name of the variable, and | |
| 2101 | * the value given is used as the default value if the function calling | |
| 2102 | * theme() does not supply it. Template implementations receive each array | |
| 2103 | * key as a variable in the template file (so they must be legal PHP | |
| 2104 | * variable names). Function implementations are passed the variables in a | |
| 2105 | * single $variables function argument. | |
| 2106 | * - render element: (see above) The name of the renderable element or element | |
| 2107 | * tree to pass to the theme function. This name is used as the name of the | |
| 2108 | * variable that holds the renderable element or tree in preprocess and | |
| 2109 | * process functions. | |
| 06585e6b AB |
2110 | * - file: The file the implementation resides in. This file will be included |
| 2111 | * prior to the theme being rendered, to make sure that the function or | |
| 2112 | * preprocess function (as needed) is actually loaded; this makes it | |
| 2113 | * possible to split theme functions out into separate files quite easily. | |
| 2114 | * - path: Override the path of the file to be used. Ordinarily the module or | |
| d48016fc | 2115 | * theme path will be used, but if the file will not be in the default |
| 2116 | * path, include it here. This path should be relative to the Drupal root | |
| 06585e6b | 2117 | * directory. |
| d48016fc | 2118 | * - template: If specified, this theme implementation is a template, and |
| 2119 | * this is the template file without an extension. Do not put .tpl.php on | |
| 2120 | * this file; that extension will be added automatically by the default | |
| 2121 | * rendering engine (which is PHPTemplate). If 'path', above, is specified, | |
| 2122 | * the template should also be in this path. | |
| 2123 | * - function: If specified, this will be the function name to invoke for | |
| 2124 | * this implementation. If neither 'template' nor 'function' is specified, | |
| 2125 | * a default function name will be assumed. For example, if a module | |
| 2126 | * registers the 'node' theme hook, 'theme_node' will be assigned to its | |
| 2127 | * function. If the chameleon theme registers the node hook, it will be | |
| 2128 | * assigned 'chameleon_node' as its function. | |
| 06585e6b AB |
2129 | * - pattern: A regular expression pattern to be used to allow this theme |
| 2130 | * implementation to have a dynamic name. The convention is to use __ to | |
| 2131 | * differentiate the dynamic portion of the theme. For example, to allow | |
| 2132 | * forums to be themed individually, the pattern might be: 'forum__'. Then, | |
| 2133 | * when the forum is themed, call: | |
| 2134 | * @code | |
| 2135 | * theme(array('forum__' . $tid, 'forum'), $forum) | |
| 2136 | * @endcode | |
| 2137 | * - preprocess functions: A list of functions used to preprocess this data. | |
| 2138 | * Ordinarily this won't be used; it's automatically filled in. By default, | |
| 2139 | * for a module this will be filled in as template_preprocess_HOOK. For | |
| 2140 | * a theme this will be filled in as phptemplate_preprocess and | |
| 2141 | * phptemplate_preprocess_HOOK as well as themename_preprocess and | |
| 2142 | * themename_preprocess_HOOK. | |
| d48016fc | 2143 | * - override preprocess functions: Set to TRUE when a theme does NOT want |
| 2144 | * the standard preprocess functions to run. This can be used to give a | |
| 2145 | * theme FULL control over how variables are set. For example, if a theme | |
| 2146 | * wants total control over how certain variables in the page.tpl.php are | |
| 2147 | * set, this can be set to true. Please keep in mind that when this is used | |
| 06585e6b AB |
2148 | * by a theme, that theme becomes responsible for making sure necessary |
| 2149 | * variables are set. | |
| 2150 | * - type: (automatically derived) Where the theme hook is defined: | |
| 2151 | * 'module', 'theme_engine', or 'theme'. | |
| 2152 | * - theme path: (automatically derived) The directory path of the theme or | |
| 2153 | * module, so that it doesn't need to be looked up. | |
| 66df6025 AB |
2154 | */ |
| 2155 | function hook_theme($existing, $type, $theme, $path) { | |
| 2156 | return array( | |
| 2157 | 'forum_display' => array( | |
| a7149821 | 2158 | 'variables' => array('forums' => NULL, 'topics' => NULL, 'parents' => NULL, 'tid' => NULL, 'sortby' => NULL, 'forum_per_page' => NULL), |
| 66df6025 AB |
2159 | ), |
| 2160 | 'forum_list' => array( | |
| a7149821 | 2161 | 'variables' => array('forums' => NULL, 'parents' => NULL, 'tid' => NULL), |
| 66df6025 AB |
2162 | ), |
| 2163 | 'forum_topic_list' => array( | |
| a7149821 | 2164 | 'variables' => array('tid' => NULL, 'topics' => NULL, 'sortby' => NULL, 'forum_per_page' => NULL), |
| 66df6025 AB |
2165 | ), |
| 2166 | 'forum_icon' => array( | |
| a7149821 AB |
2167 | 'variables' => array('new_posts' => NULL, 'num_posts' => 0, 'comment_mode' => 0, 'sticky' => 0), |
| 2168 | ), | |
| 2169 | 'status_report' => array( | |
| 2170 | 'render element' => 'requirements', | |
| 2171 | 'file' => 'system.admin.inc', | |
| 2172 | ), | |
| 2173 | 'system_date_time_settings' => array( | |
| 2174 | 'render element' => 'form', | |
| 2175 | 'file' => 'system.admin.inc', | |
| 66df6025 | 2176 | ), |
| 66df6025 AB |
2177 | ); |
| 2178 | } | |
| 2179 | ||
| 2180 | /** | |
| 2181 | * Alter the theme registry information returned from hook_theme(). | |
| 2182 | * | |
| 2183 | * The theme registry stores information about all available theme hooks, | |
| 2184 | * including which callback functions those hooks will call when triggered, | |
| 2185 | * what template files are exposed by these hooks, and so on. | |
| 2186 | * | |
| 2187 | * Note that this hook is only executed as the theme cache is re-built. | |
| 2188 | * Changes here will not be visible until the next cache clear. | |
| 2189 | * | |
| 2190 | * The $theme_registry array is keyed by theme hook name, and contains the | |
| 2191 | * information returned from hook_theme(), as well as additional properties | |
| 2192 | * added by _theme_process_registry(). | |
| 2193 | * | |
| 2194 | * For example: | |
| 2195 | * @code | |
| 03d4cbdb DB |
2196 | * $theme_registry['user_profile'] = array( |
| 2197 | * 'variables' => array( | |
| 2198 | * 'account' => NULL, | |
| 2199 | * ), | |
| 2200 | * 'template' => 'modules/user/user-profile', | |
| 2201 | * 'file' => 'modules/user/user.pages.inc', | |
| 2202 | * 'type' => 'module', | |
| 2203 | * 'theme path' => 'modules/user', | |
| 2204 | * 'preprocess functions' => array( | |
| 2205 | * 0 => 'template_preprocess', | |
| 2206 | * 1 => 'template_preprocess_user_profile', | |
| 2207 | * ), | |
| 66df6025 AB |
2208 | * ); |
| 2209 | * @endcode | |
| 2210 | * | |
| 2211 | * @param $theme_registry | |
| 2212 | * The entire cache of theme registry information, post-processing. | |
| 87f1bf45 | 2213 | * |
| 66df6025 AB |
2214 | * @see hook_theme() |
| 2215 | * @see _theme_process_registry() | |
| 2216 | */ | |
| 2217 | function hook_theme_registry_alter(&$theme_registry) { | |
| 2218 | // Kill the next/previous forum topic navigation links. | |
| 2219 | foreach ($theme_registry['forum_topic_navigation']['preprocess functions'] as $key => $value) { | |
| b53e9583 | 2220 | if ($value == 'template_preprocess_forum_topic_navigation') { |
| 66df6025 AB |
2221 | unset($theme_registry['forum_topic_navigation']['preprocess functions'][$key]); |
| 2222 | } | |
| 2223 | } | |
| 2224 | } | |
| 2225 | ||
| 2226 | /** | |
| 196aaa7d AB |
2227 | * Return the machine-readable name of the theme to use for the current page. |
| 2228 | * | |
| 2229 | * This hook can be used to dynamically set the theme for the current page | |
| 84c72d06 DB |
2230 | * request. It should be used by modules which need to override the theme |
| 2231 | * based on dynamic conditions (for example, a module which allows the theme to | |
| 2232 | * be set based on the current user's role). The return value of this hook will | |
| 2233 | * be used on all pages except those which have a valid per-page or per-section | |
| 2234 | * theme set via a theme callback function in hook_menu(); the themes on those | |
| 2235 | * pages can only be overridden using hook_menu_alter(). | |
| 196aaa7d AB |
2236 | * |
| 2237 | * Since only one theme can be used at a time, the last (i.e., highest | |
| 2238 | * weighted) module which returns a valid theme name from this hook will | |
| 2239 | * prevail. | |
| 2240 | * | |
| 2241 | * @return | |
| 2242 | * The machine-readable name of the theme that should be used for the current | |
| 2243 | * page request. The value returned from this function will only have an | |
| 2244 | * effect if it corresponds to a currently-active theme on the site. | |
| 2245 | */ | |
| 2246 | function hook_custom_theme() { | |
| 2247 | // Allow the user to request a particular theme via a query parameter. | |
| 2248 | if (isset($_GET['theme'])) { | |
| 2249 | return $_GET['theme']; | |
| 2250 | } | |
| 2251 | } | |
| 2252 | ||
| 2253 | /** | |
| 66df6025 AB |
2254 | * Register XML-RPC callbacks. |
| 2255 | * | |
| 2256 | * This hook lets a module register callback functions to be called when | |
| 2257 | * particular XML-RPC methods are invoked by a client. | |
| 2258 | * | |
| 2259 | * @return | |
| 2260 | * An array which maps XML-RPC methods to Drupal functions. Each array | |
| 2261 | * element is either a pair of method => function or an array with four | |
| 2262 | * entries: | |
| 2263 | * - The XML-RPC method name (for example, module.function). | |
| 2264 | * - The Drupal callback function (for example, module_function). | |
| 2265 | * - The method signature is an array of XML-RPC types. The first element | |
| 2266 | * of this array is the type of return value and then you should write a | |
| 2267 | * list of the types of the parameters. XML-RPC types are the following | |
| 2268 | * (See the types at http://www.xmlrpc.com/spec): | |
| 2269 | * - "boolean": 0 (false) or 1 (true). | |
| 2270 | * - "double": a floating point number (for example, -12.214). | |
| 2271 | * - "int": a integer number (for example, -12). | |
| 2272 | * - "array": an array without keys (for example, array(1, 2, 3)). | |
| 2273 | * - "struct": an associative array or an object (for example, | |
| 2274 | * array('one' => 1, 'two' => 2)). | |
| 2275 | * - "date": when you return a date, then you may either return a | |
| 2276 | * timestamp (time(), mktime() etc.) or an ISO8601 timestamp. When | |
| 2277 | * date is specified as an input parameter, then you get an object, | |
| 2278 | * which is described in the function xmlrpc_date | |
| 2279 | * - "base64": a string containing binary data, automatically | |
| 2280 | * encoded/decoded automatically. | |
| 2281 | * - "string": anything else, typically a string. | |
| 2282 | * - A descriptive help string, enclosed in a t() function for translation | |
| 2283 | * purposes. | |
| 2284 | * Both forms are shown in the example. | |
| 2285 | */ | |
| 2286 | function hook_xmlrpc() { | |
| 2287 | return array( | |
| 2288 | 'drupal.login' => 'drupal_login', | |
| 2289 | array( | |
| 2290 | 'drupal.site.ping', | |
| 2291 | 'drupal_directory_ping', | |
| 2292 | array('boolean', 'string', 'string', 'string', 'string', 'string'), | |
| 2293 | t('Handling ping request')) | |
| 2294 | ); | |
| 2295 | } | |
| 2296 | ||
| 2297 | /** | |
| 579310a4 | 2298 | * Alters the definition of XML-RPC methods before they are called. |
| a1e08d93 | 2299 | * |
| 579310a4 DB |
2300 | * This hook allows modules to modify the callback definition of declared |
| 2301 | * XML-RPC methods, right before they are invoked by a client. Methods may be | |
| 2302 | * added, or existing methods may be altered. | |
| a1e08d93 | 2303 | * |
| 579310a4 DB |
2304 | * Note that hook_xmlrpc() supports two distinct and incompatible formats to |
| 2305 | * define a callback, so care must be taken when altering other methods. | |
| a1e08d93 | 2306 | * |
| a1e08d93 | 2307 | * @param $methods |
| 579310a4 DB |
2308 | * An asssociative array of method callback definitions, as returned from |
| 2309 | * hook_xmlrpc() implementations. | |
| 87f1bf45 DB |
2310 | * |
| 2311 | * @see hook_xmlrpc() | |
| 579310a4 | 2312 | * @see xmlrpc_server() |
| a1e08d93 DB |
2313 | */ |
| 2314 | function hook_xmlrpc_alter(&$methods) { | |
| 579310a4 | 2315 | // Directly change a simple method. |
| a1e08d93 DB |
2316 | $methods['drupal.login'] = 'mymodule_login'; |
| 2317 | ||
| 579310a4 | 2318 | // Alter complex definitions. |
| a1e08d93 | 2319 | foreach ($methods as $key => &$method) { |
| 579310a4 | 2320 | // Skip simple method definitions. |
| a1e08d93 DB |
2321 | if (!is_int($key)) { |
| 2322 | continue; | |
| 2323 | } | |
| 579310a4 | 2324 | // Perform the wanted manipulation. |
| a1e08d93 DB |
2325 | if ($method[0] == 'drupal.site.ping') { |
| 2326 | $method[1] = 'mymodule_directory_ping'; | |
| 2327 | } | |
| 2328 | } | |
| 2329 | } | |
| 2330 | ||
| 2331 | /** | |
| 66df6025 AB |
2332 | * Log an event message |
| 2333 | * | |
| 2334 | * This hook allows modules to route log events to custom destinations, such as | |
| 2335 | * SMS, Email, pager, syslog, ...etc. | |
| 2336 | * | |
| 2337 | * @param $log_entry | |
| 5bbad8a4 | 2338 | * An associative array containing the following keys: |
| 66df6025 AB |
2339 | * - type: The type of message for this entry. For contributed modules, this is |
| 2340 | * normally the module name. Do not use 'debug', use severity WATCHDOG_DEBUG instead. | |
| 2341 | * - user: The user object for the user who was logged in when the event happened. | |
| 2342 | * - request_uri: The Request URI for the page the event happened in. | |
| 2343 | * - referer: The page that referred the use to the page where the event occurred. | |
| 2344 | * - ip: The IP address where the request for the page came from. | |
| af3f94b3 | 2345 | * - timestamp: The UNIX timestamp of the date/time the event occurred |
| 66df6025 | 2346 | * - severity: One of the following values as defined in RFC 3164 http://www.faqs.org/rfcs/rfc3164.html |
| 052a1da5 | 2347 | * WATCHDOG_EMERGENCY Emergency: system is unusable |
| 66df6025 AB |
2348 | * WATCHDOG_ALERT Alert: action must be taken immediately |
| 2349 | * WATCHDOG_CRITICAL Critical: critical conditions | |
| 2350 | * WATCHDOG_ERROR Error: error conditions | |
| 2351 | * WATCHDOG_WARNING Warning: warning conditions | |
| 2352 | * WATCHDOG_NOTICE Notice: normal but significant condition | |
| 2353 | * WATCHDOG_INFO Informational: informational messages | |
| 2354 | * WATCHDOG_DEBUG Debug: debug-level messages | |
| 2355 | * - link: an optional link provided by the module that called the watchdog() function. | |
| 2356 | * - message: The text of the message to be logged. | |
| 66df6025 | 2357 | */ |
| 5bbad8a4 DB |
2358 | function hook_watchdog(array $log_entry) { |
| 2359 | global $base_url, $language; | |
| 66df6025 AB |
2360 | |
| 2361 | $severity_list = array( | |
| 052a1da5 DB |
2362 | WATCHDOG_EMERGENCY => t('Emergency'), |
| 2363 | WATCHDOG_ALERT => t('Alert'), | |
| 2364 | WATCHDOG_CRITICAL => t('Critical'), | |
| 2365 | WATCHDOG_ERROR => t('Error'), | |
| 2366 | WATCHDOG_WARNING => t('Warning'), | |
| 2367 | WATCHDOG_NOTICE => t('Notice'), | |
| 2368 | WATCHDOG_INFO => t('Info'), | |
| 2369 | WATCHDOG_DEBUG => t('Debug'), | |
| 66df6025 AB |
2370 | ); |
| 2371 | ||
| 5bbad8a4 DB |
2372 | $to = 'someone@example.com'; |
| 2373 | $params = array(); | |
| 2374 | $params['subject'] = t('[@site_name] @severity_desc: Alert from your web site', array( | |
| 2375 | '@site_name' => variable_get('site_name', 'Drupal'), | |
| 2376 | '@severity_desc' => $severity_list[$log_entry['severity']], | |
| 2377 | )); | |
| 2378 | ||
| 2379 | $params['message'] = "\nSite: @base_url"; | |
| 2380 | $params['message'] .= "\nSeverity: (@severity) @severity_desc"; | |
| 2381 | $params['message'] .= "\nTimestamp: @timestamp"; | |
| 2382 | $params['message'] .= "\nType: @type"; | |
| 2383 | $params['message'] .= "\nIP Address: @ip"; | |
| 2384 | $params['message'] .= "\nRequest URI: @request_uri"; | |
| 2385 | $params['message'] .= "\nReferrer URI: @referer_uri"; | |
| 2386 | $params['message'] .= "\nUser: (@uid) @name"; | |
| 2387 | $params['message'] .= "\nLink: @link"; | |
| 2388 | $params['message'] .= "\nMessage: \n\n@message"; | |
| 2389 | ||
| 2390 | $params['message'] = t($params['message'], array( | |
| 66df6025 | 2391 | '@base_url' => $base_url, |
| 5bbad8a4 DB |
2392 | '@severity' => $log_entry['severity'], |
| 2393 | '@severity_desc' => $severity_list[$log_entry['severity']], | |
| 2394 | '@timestamp' => format_date($log_entry['timestamp']), | |
| 2395 | '@type' => $log_entry['type'], | |
| 2396 | '@ip' => $log_entry['ip'], | |
| 2397 | '@request_uri' => $log_entry['request_uri'], | |
| 2398 | '@referer_uri' => $log_entry['referer'], | |
| 2399 | '@uid' => $log_entry['user']->uid, | |
| 2400 | '@name' => $log_entry['user']->name, | |
| 2401 | '@link' => strip_tags($log_entry['link']), | |
| 2402 | '@message' => strip_tags($log_entry['message']), | |
| 66df6025 AB |
2403 | )); |
| 2404 | ||
| 5bbad8a4 | 2405 | drupal_mail('emaillog', 'entry', $to, $language, $params); |
| 66df6025 AB |
2406 | } |
| 2407 | ||
| 2408 | /** | |
| 9850918a | 2409 | * Prepare a message based on parameters; called from drupal_mail(). |
| 66df6025 | 2410 | * |
| b077fb56 DB |
2411 | * Note that hook_mail(), unlike hook_mail_alter(), is only called on the |
| 2412 | * $module argument to drupal_mail(), not all modules. | |
| 2413 | * | |
| 66df6025 AB |
2414 | * @param $key |
| 2415 | * An identifier of the mail. | |
| 2416 | * @param $message | |
| b077fb56 DB |
2417 | * An array to be filled in. Elements in this array include: |
| 2418 | * - id: An ID to identify the mail sent. Look at module source code | |
| 9850918a | 2419 | * or drupal_mail() for possible id values. |
| b077fb56 | 2420 | * - to: The address or addresses the message will be sent to. The |
| 66df6025 | 2421 | * formatting of this string must comply with RFC 2822. |
| b077fb56 DB |
2422 | * - subject: Subject of the e-mail to be sent. This must not contain any |
| 2423 | * newline characters, or the mail may not be sent properly. drupal_mail() | |
| 2424 | * sets this to an empty string when the hook is invoked. | |
| 2425 | * - body: An array of lines containing the message to be sent. Drupal will | |
| 2426 | * format the correct line endings for you. drupal_mail() sets this to an | |
| 2427 | * empty array when the hook is invoked. | |
| 2428 | * - from: The address the message will be marked as being from, which is | |
| 5fbaa4b8 | 2429 | * set by drupal_mail() to either a custom address or the site-wide |
| 9850918a | 2430 | * default email address when the hook is invoked. |
| b077fb56 DB |
2431 | * - headers: Associative array containing mail headers, such as From, |
| 2432 | * Sender, MIME-Version, Content-Type, etc. drupal_mail() pre-fills | |
| 9850918a | 2433 | * several headers in this array. |
| 66df6025 | 2434 | * @param $params |
| 9850918a | 2435 | * An array of parameters supplied by the caller of drupal_mail(). |
| 66df6025 AB |
2436 | */ |
| 2437 | function hook_mail($key, &$message, $params) { | |
| 2438 | $account = $params['account']; | |
| 2439 | $context = $params['context']; | |
| 2440 | $variables = array( | |
| 2441 | '%site_name' => variable_get('site_name', 'Drupal'), | |
| ca8eee75 | 2442 | '%username' => format_username($account), |
| 66df6025 AB |
2443 | ); |
| 2444 | if ($context['hook'] == 'taxonomy') { | |
| 7d4b84b8 | 2445 | $entity = $params['entity']; |
| 7562a8ef | 2446 | $vocabulary = taxonomy_vocabulary_load($entity->vid); |
| 66df6025 | 2447 | $variables += array( |
| 7562a8ef AB |
2448 | '%term_name' => $entity->name, |
| 2449 | '%term_description' => $entity->description, | |
| 2450 | '%term_id' => $entity->tid, | |
| 66df6025 AB |
2451 | '%vocabulary_name' => $vocabulary->name, |
| 2452 | '%vocabulary_description' => $vocabulary->description, | |
| 2453 | '%vocabulary_id' => $vocabulary->vid, | |
| 2454 | ); | |
| 2455 | } | |
| 2456 | ||
| 2457 | // Node-based variable translation is only available if we have a node. | |
| 2458 | if (isset($params['node'])) { | |
| 2459 | $node = $params['node']; | |
| 2460 | $variables += array( | |
| 2461 | '%uid' => $node->uid, | |
| 2462 | '%node_url' => url('node/' . $node->nid, array('absolute' => TRUE)), | |
| cab88a70 | 2463 | '%node_type' => node_type_get_name($node), |
| 147bb138 | 2464 | '%title' => $node->title, |
| 66df6025 AB |
2465 | '%teaser' => $node->teaser, |
| 2466 | '%body' => $node->body, | |
| 2467 | ); | |
| 2468 | } | |
| 2469 | $subject = strtr($context['subject'], $variables); | |
| 2470 | $body = strtr($context['message'], $variables); | |
| 2471 | $message['subject'] .= str_replace(array("\r", "\n"), '', $subject); | |
| 2472 | $message['body'][] = drupal_html_to_text($body); | |
| 2473 | } | |
| 2474 | ||
| 2475 | /** | |
| 2476 | * Add a list of cache tables to be cleared. | |
| 2477 | * | |
| 2478 | * This hook allows your module to add cache table names to the list of cache | |
| 2479 | * tables that will be cleared by the Clear button on the Performance page or | |
| 2480 | * whenever drupal_flush_all_caches is invoked. | |
| 2481 | * | |
| 66df6025 AB |
2482 | * @return |
| 2483 | * An array of cache table names. | |
| 87f1bf45 DB |
2484 | * |
| 2485 | * @see drupal_flush_all_caches() | |
| 66df6025 AB |
2486 | */ |
| 2487 | function hook_flush_caches() { | |
| 2488 | return array('cache_example'); | |
| 2489 | } | |
| 2490 | ||
| 2491 | /** | |
| 2492 | * Perform necessary actions after modules are installed. | |
| 2493 | * | |
| 77f6e36f DB |
2494 | * This function differs from hook_install() in that it gives all other modules |
| 2495 | * a chance to perform actions when a module is installed, whereas | |
| 2496 | * hook_install() is only called on the module actually being installed. See | |
| 2497 | * module_enable() for a detailed description of the order in which install and | |
| 2498 | * enable hooks are invoked. | |
| 66df6025 AB |
2499 | * |
| 2500 | * @param $modules | |
| 69c8ff26 | 2501 | * An array of the modules that were installed. |
| 77f6e36f DB |
2502 | * |
| 2503 | * @see module_enable() | |
| 2504 | * @see hook_modules_enabled() | |
| 2505 | * @see hook_install() | |
| 66df6025 AB |
2506 | */ |
| 2507 | function hook_modules_installed($modules) { | |
| 2508 | if (in_array('lousy_module', $modules)) { | |
| 2509 | variable_set('lousy_module_conflicting_variable', FALSE); | |
| 2510 | } | |
| 2511 | } | |
| 2512 | ||
| 2513 | /** | |
| 2514 | * Perform necessary actions after modules are enabled. | |
| 2515 | * | |
| 77f6e36f DB |
2516 | * This function differs from hook_enable() in that it gives all other modules a |
| 2517 | * chance to perform actions when modules are enabled, whereas hook_enable() is | |
| 2518 | * only called on the module actually being enabled. See module_enable() for a | |
| 2519 | * detailed description of the order in which install and enable hooks are | |
| 2520 | * invoked. | |
| 66df6025 AB |
2521 | * |
| 2522 | * @param $modules | |
| 69c8ff26 | 2523 | * An array of the modules that were enabled. |
| 77f6e36f DB |
2524 | * |
| 2525 | * @see hook_enable() | |
| 2526 | * @see hook_modules_installed() | |
| 2527 | * @see module_enable() | |
| 66df6025 AB |
2528 | */ |
| 2529 | function hook_modules_enabled($modules) { | |
| 2530 | if (in_array('lousy_module', $modules)) { | |
| 2531 | drupal_set_message(t('mymodule is not compatible with lousy_module'), 'error'); | |
| 2532 | mymodule_disable_functionality(); | |
| 2533 | } | |
| 2534 | } | |
| 2535 | ||
| 2536 | /** | |
| 2537 | * Perform necessary actions after modules are disabled. | |
| 2538 | * | |
| 77f6e36f DB |
2539 | * This function differs from hook_disable() in that it gives all other modules |
| 2540 | * a chance to perform actions when modules are disabled, whereas hook_disable() | |
| 2541 | * is only called on the module actually being disabled. | |
| 66df6025 AB |
2542 | * |
| 2543 | * @param $modules | |
| 69c8ff26 | 2544 | * An array of the modules that were disabled. |
| 77f6e36f DB |
2545 | * |
| 2546 | * @see hook_disable() | |
| 2547 | * @see hook_modules_uninstalled() | |
| 66df6025 AB |
2548 | */ |
| 2549 | function hook_modules_disabled($modules) { | |
| 2550 | if (in_array('lousy_module', $modules)) { | |
| 2551 | mymodule_enable_functionality(); | |
| 2552 | } | |
| 2553 | } | |
| 2554 | ||
| 2555 | /** | |
| 2556 | * Perform necessary actions after modules are uninstalled. | |
| 2557 | * | |
| 77f6e36f DB |
2558 | * This function differs from hook_uninstall() in that it gives all other |
| 2559 | * modules a chance to perform actions when a module is uninstalled, whereas | |
| 2560 | * hook_uninstall() is only called on the module actually being uninstalled. | |
| 66df6025 | 2561 | * |
| f1cc8651 DB |
2562 | * It is recommended that you implement this hook if your module stores |
| 2563 | * data that may have been set by other modules. | |
| 66df6025 | 2564 | * |
| 66df6025 | 2565 | * @param $modules |
| 69c8ff26 | 2566 | * An array of the modules that were uninstalled. |
| 77f6e36f DB |
2567 | * |
| 2568 | * @see hook_uninstall() | |
| 2569 | * @see hook_modules_disabled() | |
| 66df6025 AB |
2570 | */ |
| 2571 | function hook_modules_uninstalled($modules) { | |
| 2572 | foreach ($modules as $module) { | |
| 2573 | db_delete('mymodule_table') | |
| 2574 | ->condition('module', $module) | |
| 2575 | ->execute(); | |
| 2576 | } | |
| 2577 | mymodule_cache_rebuild(); | |
| 2578 | } | |
| 2579 | ||
| 2580 | /** | |
| 5468b47b DB |
2581 | * Registers PHP stream wrapper implementations associated with a module. |
| 2582 | * | |
| 2583 | * Provide a facility for managing and querying user-defined stream wrappers | |
| 2584 | * in PHP. PHP's internal stream_get_wrappers() doesn't return the class | |
| 2585 | * registered to handle a stream, which we need to be able to find the handler | |
| 2586 | * for class instantiation. | |
| 2587 | * | |
| 2588 | * If a module registers a scheme that is already registered with PHP, it will | |
| 2589 | * be unregistered and replaced with the specified class. | |
| 2590 | * | |
| 2591 | * @return | |
| 2592 | * A nested array, keyed first by scheme name ("public" for "public://"), | |
| 2593 | * then keyed by the following values: | |
| 2594 | * - 'name' A short string to name the wrapper. | |
| 2595 | * - 'class' A string specifying the PHP class that implements the | |
| 2596 | * DrupalStreamWrapperInterface interface. | |
| 2597 | * - 'description' A string with a short description of what the wrapper does. | |
| 2a0e3264 DB |
2598 | * - 'type' (Optional) A bitmask of flags indicating what type of streams this |
| 2599 | * wrapper will access - local or remote, readable and/or writeable, etc. | |
| 2600 | * Many shortcut constants are defined in stream_wrappers.inc. Defaults to | |
| 2601 | * STREAM_WRAPPERS_NORMAL which includes all of these bit flags: | |
| 2602 | * - STREAM_WRAPPERS_READ | |
| 2603 | * - STREAM_WRAPPERS_WRITE | |
| 2604 | * - STREAM_WRAPPERS_VISIBLE | |
| 5468b47b DB |
2605 | * |
| 2606 | * @see file_get_stream_wrappers() | |
| 2607 | * @see hook_stream_wrappers_alter() | |
| 2608 | * @see system_stream_wrappers() | |
| 2609 | */ | |
| 2610 | function hook_stream_wrappers() { | |
| 2611 | return array( | |
| 2612 | 'public' => array( | |
| 2613 | 'name' => t('Public files'), | |
| 2614 | 'class' => 'DrupalPublicStreamWrapper', | |
| 2615 | 'description' => t('Public local files served by the webserver.'), | |
| 2a0e3264 | 2616 | 'type' => STREAM_WRAPPERS_LOCAL_NORMAL, |
| 5468b47b DB |
2617 | ), |
| 2618 | 'private' => array( | |
| 2619 | 'name' => t('Private files'), | |
| 2620 | 'class' => 'DrupalPrivateStreamWrapper', | |
| 2621 | 'description' => t('Private local files served by Drupal.'), | |
| 2a0e3264 | 2622 | 'type' => STREAM_WRAPPERS_LOCAL_NORMAL, |
| 5468b47b DB |
2623 | ), |
| 2624 | 'temp' => array( | |
| 2625 | 'name' => t('Temporary files'), | |
| 2626 | 'class' => 'DrupalTempStreamWrapper', | |
| 2627 | 'description' => t('Temporary local files for upload and previews.'), | |
| 2a0e3264 DB |
2628 | 'type' => STREAM_WRAPPERS_LOCAL_HIDDEN, |
| 2629 | ), | |
| 2630 | 'cdn' => array( | |
| 2631 | 'name' => t('Content delivery network files'), | |
| 2632 | 'class' => 'MyModuleCDNStreamWrapper', | |
| 2633 | 'description' => t('Files served by a content delivery network.'), | |
| 2634 | // 'type' can be omitted to use the default of STREAM_WRAPPERS_NORMAL | |
| 2635 | ), | |
| 2636 | 'youtube' => array( | |
| 2637 | 'name' => t('YouTube video'), | |
| 2638 | 'class' => 'MyModuleYouTubeStreamWrapper', | |
| 2639 | 'description' => t('Video streamed from YouTube.'), | |
| 2640 | // A module implementing YouTube integration may decide to support using | |
| 2641 | // the YouTube API for uploading video, but here, we assume that this | |
| 2642 | // particular module only supports playing YouTube video. | |
| 2643 | 'type' => STREAM_WRAPPERS_READ_VISIBLE, | |
| 2644 | ), | |
| 5468b47b DB |
2645 | ); |
| 2646 | } | |
| 2647 | ||
| 2648 | /** | |
| 2649 | * Alters the list of PHP stream wrapper implementations. | |
| 2650 | * | |
| 2651 | * @see file_get_stream_wrappers() | |
| 2652 | * @see hook_stream_wrappers() | |
| 2653 | */ | |
| 2654 | function hook_stream_wrappers_alter(&$wrappers) { | |
| 2655 | // Change the name of private files to reflect the performance. | |
| 2656 | $wrappers['private']['name'] = t('Slow files'); | |
| 2657 | } | |
| 2658 | ||
| 2659 | /** | |
| d813e367 | 2660 | * Load additional information into file objects. |
| 66df6025 | 2661 | * |
| d813e367 DB |
2662 | * file_load_multiple() calls this hook to allow modules to load |
| 2663 | * additional information into each file. | |
| 66df6025 | 2664 | * |
| d813e367 DB |
2665 | * @param $files |
| 2666 | * An array of file objects, indexed by fid. | |
| 66df6025 | 2667 | * |
| d813e367 | 2668 | * @see file_load_multiple() |
| 15e66edf | 2669 | * @see file_load() |
| 66df6025 | 2670 | */ |
| d813e367 | 2671 | function hook_file_load($files) { |
| 66df6025 | 2672 | // Add the upload specific data into the file object. |
| d813e367 DB |
2673 | $result = db_query('SELECT * FROM {upload} u WHERE u.fid IN (:fids)', array(':fids' => array_keys($files)))->fetchAll(PDO::FETCH_ASSOC); |
| 2674 | foreach ($result as $record) { | |
| 2675 | foreach ($record as $key => $value) { | |
| 2676 | $files[$record['fid']]->$key = $value; | |
| 2677 | } | |
| 66df6025 AB |
2678 | } |
| 2679 | } | |
| 2680 | ||
| 2681 | /** | |
| 2682 | * Check that files meet a given criteria. | |
| 2683 | * | |
| 2684 | * This hook lets modules perform additional validation on files. They're able | |
| 2685 | * to report a failure by returning one or more error messages. | |
| 2686 | * | |
| 2687 | * @param $file | |
| 2688 | * The file object being validated. | |
| 2689 | * @return | |
| 2690 | * An array of error messages. If there are no problems with the file return | |
| 2691 | * an empty array. | |
| 2692 | * | |
| 2693 | * @see file_validate() | |
| 2694 | */ | |
| 80aacdb0 | 2695 | function hook_file_validate($file) { |
| 66df6025 AB |
2696 | $errors = array(); |
| 2697 | ||
| 2698 | if (empty($file->filename)) { | |
| 2699 | $errors[] = t("The file's name is empty. Please give a name to the file."); | |
| 2700 | } | |
| 2701 | if (strlen($file->filename) > 255) { | |
| 2702 | $errors[] = t("The file's name exceeds the 255 characters limit. Please rename the file and try again."); | |
| 2703 | } | |
| 2704 | ||
| 2705 | return $errors; | |
| 2706 | } | |
| 2707 | ||
| 2708 | /** | |
| 71c4e3ec | 2709 | * Act on a file being inserted or updated. |
| 66df6025 AB |
2710 | * |
| 2711 | * This hook is called when a file has been added to the database. The hook | |
| 2712 | * doesn't distinguish between files created as a result of a copy or those | |
| 2713 | * created by an upload. | |
| 2714 | * | |
| 2715 | * @param $file | |
| 2716 | * The file that has just been created. | |
| 66df6025 AB |
2717 | * |
| 2718 | * @see file_save() | |
| 2719 | */ | |
| 71c4e3ec AB |
2720 | function hook_file_presave($file) { |
| 2721 | // Change the file timestamp to an hour prior. | |
| 2722 | $file->timestamp -= 3600; | |
| 2723 | } | |
| 2724 | ||
| 2725 | /** | |
| 2726 | * Respond to a file being added. | |
| 2727 | * | |
| b30fae02 | 2728 | * This hook is called after a file has been added to the database. The hook |
| 71c4e3ec AB |
2729 | * doesn't distinguish between files created as a result of a copy or those |
| 2730 | * created by an upload. | |
| 2731 | * | |
| 2732 | * @param $file | |
| b30fae02 | 2733 | * The file that has been added. |
| 71c4e3ec AB |
2734 | * |
| 2735 | * @see file_save() | |
| 2736 | */ | |
| b0ab9f28 | 2737 | function hook_file_insert($file) { |
| b30fae02 DB |
2738 | // Add a message to the log, if the file is a jpg |
| 2739 | $validate = file_validate_extensions($file, 'jpg'); | |
| 2740 | if (empty($validate)) { | |
| 2741 | watchdog('file', 'A jpg has been added.'); | |
| 2742 | } | |
| 66df6025 AB |
2743 | } |
| 2744 | ||
| 2745 | /** | |
| 2746 | * Respond to a file being updated. | |
| 2747 | * | |
| 2748 | * This hook is called when file_save() is called on an existing file. | |
| 2749 | * | |
| 2750 | * @param $file | |
| 2751 | * The file that has just been updated. | |
| 66df6025 AB |
2752 | * |
| 2753 | * @see file_save() | |
| 2754 | */ | |
| b0ab9f28 | 2755 | function hook_file_update($file) { |
| 66df6025 AB |
2756 | |
| 2757 | } | |
| 2758 | ||
| 2759 | /** | |
| 2760 | * Respond to a file that has been copied. | |
| 2761 | * | |
| 2762 | * @param $file | |
| 2763 | * The newly copied file object. | |
| 2764 | * @param $source | |
| 2765 | * The original file before the copy. | |
| 66df6025 AB |
2766 | * |
| 2767 | * @see file_copy() | |
| 2768 | */ | |
| 2769 | function hook_file_copy($file, $source) { | |
| 2770 | ||
| 2771 | } | |
| 2772 | ||
| 2773 | /** | |
| 2774 | * Respond to a file that has been moved. | |
| 2775 | * | |
| 2776 | * @param $file | |
| 2777 | * The updated file object after the move. | |
| 2778 | * @param $source | |
| 2779 | * The original file object before the move. | |
| 66df6025 AB |
2780 | * |
| 2781 | * @see file_move() | |
| 2782 | */ | |
| 2783 | function hook_file_move($file, $source) { | |
| 2784 | ||
| 2785 | } | |
| 2786 | ||
| 2787 | /** | |
| 66df6025 AB |
2788 | * Respond to a file being deleted. |
| 2789 | * | |
| 2790 | * @param $file | |
| 2791 | * The file that has just been deleted. | |
| 66df6025 AB |
2792 | * |
| 2793 | * @see file_delete() | |
| 66df6025 AB |
2794 | */ |
| 2795 | function hook_file_delete($file) { | |
| 2796 | // Delete all information associated with the file. | |
| 2797 | db_delete('upload')->condition('fid', $file->fid)->execute(); | |
| 2798 | } | |
| 2799 | ||
| 2800 | /** | |
| 66df6025 AB |
2801 | * Control access to private file downloads and specify HTTP headers. |
| 2802 | * | |
| 2803 | * This hook allows modules enforce permissions on file downloads when the | |
| 2804 | * private file download method is selected. Modules can also provide headers | |
| 2805 | * to specify information like the file's name or MIME type. | |
| 2806 | * | |
| 0d2b7fe8 DB |
2807 | * @param $uri |
| 2808 | * The URI of the file. | |
| 66df6025 AB |
2809 | * @return |
| 2810 | * If the user does not have permission to access the file, return -1. If the | |
| 2811 | * user has permission, return an array with the appropriate headers. If the | |
| 2812 | * file is not controlled by the current module, the return value should be | |
| 2813 | * NULL. | |
| 2814 | * | |
| 2815 | * @see file_download() | |
| 66df6025 | 2816 | */ |
| 0d2b7fe8 | 2817 | function hook_file_download($uri) { |
| 66df6025 | 2818 | // Check if the file is controlled by the current module. |
| 0d2b7fe8 DB |
2819 | if (!file_prepare_directory($uri)) { |
| 2820 | $uri = FALSE; | |
| b4132364 | 2821 | } |
| c448440c | 2822 | if (strpos(file_uri_target($uri), variable_get('user_picture_path', 'pictures') . '/picture-') === 0) { |
| 2823 | if (!user_access('access user profiles')) { | |
| 2824 | // Access to the file is denied. | |
| 66df6025 AB |
2825 | return -1; |
| 2826 | } | |
| c448440c | 2827 | else { |
| 2828 | $info = image_get_info($uri); | |
| 2829 | return array('Content-Type' => $info['mime_type']); | |
| 2830 | } | |
| 66df6025 AB |
2831 | } |
| 2832 | } | |
| 2833 | ||
| 2834 | /** | |
| feb48454 DB |
2835 | * Alter the URL to a file. |
| 2836 | * | |
| 2837 | * This hook is called from file_create_url(), and is called fairly | |
| 2838 | * frequently (10+ times per page), depending on how many files there are in a | |
| 2839 | * given page. | |
| 2840 | * If CSS and JS aggregation are disabled, this can become very frequently | |
| 2841 | * (50+ times per page) so performance is critical. | |
| 2842 | * | |
| 2843 | * This function should alter the URI, if it wants to rewrite the file URL. | |
| feb48454 DB |
2844 | * |
| 2845 | * @param $uri | |
| 2846 | * The URI to a file for which we need an external URL, or the path to a | |
| 2847 | * shipped file. | |
| 2848 | */ | |
| 2849 | function hook_file_url_alter(&$uri) { | |
| 2850 | global $user; | |
| 2851 | ||
| 2852 | // User 1 will always see the local file in this example. | |
| 2853 | if ($user->uid == 1) { | |
| 2854 | return; | |
| 2855 | } | |
| 2856 | ||
| 2857 | $cdn1 = 'http://cdn1.example.com'; | |
| 2858 | $cdn2 = 'http://cdn2.example.com'; | |
| 2859 | $cdn_extensions = array('css', 'js', 'gif', 'jpg', 'jpeg', 'png'); | |
| 2860 | ||
| 2861 | // Most CDNs don't support private file transfers without a lot of hassle, | |
| 2862 | // so don't support this in the common case. | |
| 2863 | $schemes = array('public'); | |
| 2864 | ||
| 2865 | $scheme = file_uri_scheme($uri); | |
| 2866 | ||
| 2867 | // Only serve shipped files and public created files from the CDN. | |
| 2868 | if (!$scheme || in_array($scheme, $schemes)) { | |
| 2869 | // Shipped files. | |
| 2870 | if (!$scheme) { | |
| 2871 | $path = $uri; | |
| 2872 | } | |
| 2873 | // Public created files. | |
| 2874 | else { | |
| 2875 | $wrapper = file_stream_wrapper_get_instance_by_scheme($scheme); | |
| 2876 | $path = $wrapper->getDirectoryPath() . '/' . file_uri_target($uri); | |
| 2877 | } | |
| 2878 | ||
| 2879 | // Clean up Windows paths. | |
| 2880 | $path = str_replace('\\', '/', $path); | |
| 2881 | ||
| 2882 | // Serve files with one of the CDN extensions from CDN 1, all others from | |
| 2883 | // CDN 2. | |
| 2884 | $pathinfo = pathinfo($path); | |
| 1d0f6479 | 2885 | if (isset($pathinfo['extension']) && in_array($pathinfo['extension'], $cdn_extensions)) { |
| feb48454 DB |
2886 | $uri = $cdn1 . '/' . $path; |
| 2887 | } | |
| 2888 | else { | |
| 2889 | $uri = $cdn2 . '/' . $path; | |
| 2890 | } | |
| 2891 | } | |
| 2892 | } | |
| 729a23e1 DB |
2893 | |
| 2894 | /** | |
| 66df6025 AB |
2895 | * Check installation requirements and do status reporting. |
| 2896 | * | |
| 585a2b96 DB |
2897 | * This hook has three closely related uses, determined by the $phase argument: |
| 2898 | * - Checking installation requirements ($phase == 'install'). | |
| 2899 | * - Checking update requirements ($phase == 'update'). | |
| 2900 | * - Status reporting ($phase == 'runtime'). | |
| 66df6025 AB |
2901 | * |
| 2902 | * Note that this hook, like all others dealing with installation and updates, | |
| 2903 | * must reside in a module_name.install file, or it will not properly abort | |
| 2904 | * the installation of the module if a critical requirement is missing. | |
| 2905 | * | |
| 2906 | * During the 'install' phase, modules can for example assert that | |
| 2907 | * library or server versions are available or sufficient. | |
| 2908 | * Note that the installation of a module can happen during installation of | |
| 2909 | * Drupal itself (by install.php) with an installation profile or later by hand. | |
| 2910 | * As a consequence, install-time requirements must be checked without access | |
| 2911 | * to the full Drupal API, because it is not available during install.php. | |
| 92a8adea DB |
2912 | * For localization you should for example use $t = get_t() to |
| 2913 | * retrieve the appropriate localization function name (t() or st()). | |
| 66df6025 AB |
2914 | * If a requirement has a severity of REQUIREMENT_ERROR, install.php will abort |
| 2915 | * or at least the module will not install. | |
| 2916 | * Other severity levels have no effect on the installation. | |
| 2917 | * Module dependencies do not belong to these installation requirements, | |
| 2918 | * but should be defined in the module's .info file. | |
| 2919 | * | |
| 2920 | * The 'runtime' phase is not limited to pure installation requirements | |
| 2921 | * but can also be used for more general status information like maintenance | |
| 2922 | * tasks and security issues. | |
| 2923 | * The returned 'requirements' will be listed on the status report in the | |
| 2924 | * administration section, with indication of the severity level. | |
| 2925 | * Moreover, any requirement with a severity of REQUIREMENT_ERROR severity will | |
| 2926 | * result in a notice on the the administration overview page. | |
| 2927 | * | |
| 2928 | * @param $phase | |
| 729a23e1 DB |
2929 | * The phase in which requirements are checked: |
| 2930 | * - install: The module is being installed. | |
| 2931 | * - update: The module is enabled and update.php is run. | |
| 2932 | * - runtime: The runtime requirements are being checked and shown on the | |
| 2933 | * status report page. | |
| 66df6025 AB |
2934 | * |
| 2935 | * @return | |
| 2936 | * A keyed array of requirements. Each requirement is itself an array with | |
| 2937 | * the following items: | |
| 729a23e1 DB |
2938 | * - title: The name of the requirement. |
| 2939 | * - value: The current value (e.g., version, time, level, etc). During | |
| 2940 | * install phase, this should only be used for version numbers, do not set | |
| 2941 | * it if not applicable. | |
| 2942 | * - description: The description of the requirement/status. | |
| 2943 | * - severity: The requirement's result/severity level, one of: | |
| 2944 | * - REQUIREMENT_INFO: For info only. | |
| 2945 | * - REQUIREMENT_OK: The requirement is satisfied. | |
| 2946 | * - REQUIREMENT_WARNING: The requirement failed with a warning. | |
| 2947 | * - REQUIREMENT_ERROR: The requirement failed with an error. | |
| 66df6025 AB |
2948 | */ |
| 2949 | function hook_requirements($phase) { | |
| 2950 | $requirements = array(); | |
| 2951 | // Ensure translations don't break at install time | |
| 2952 | $t = get_t(); | |
| 2953 | ||
| 2954 | // Report Drupal version | |
| 2955 | if ($phase == 'runtime') { | |
| 2956 | $requirements['drupal'] = array( | |
| 2957 | 'title' => $t('Drupal'), | |
| 2958 | 'value' => VERSION, | |
| 2959 | 'severity' => REQUIREMENT_INFO | |
| 2960 | ); | |
| 2961 | } | |
| 2962 | ||
| 2963 | // Test PHP version | |
| 2964 | $requirements['php'] = array( | |
| 2965 | 'title' => $t('PHP'), | |
| b26aa370 | 2966 | 'value' => ($phase == 'runtime') ? l(phpversion(), 'admin/reports/status/php') : phpversion(), |
| 66df6025 AB |
2967 | ); |
| 2968 | if (version_compare(phpversion(), DRUPAL_MINIMUM_PHP) < 0) { | |
| 2969 | $requirements['php']['description'] = $t('Your PHP installation is too old. Drupal requires at least PHP %version.', array('%version' => DRUPAL_MINIMUM_PHP)); | |
| 2970 | $requirements['php']['severity'] = REQUIREMENT_ERROR; | |
| 2971 | } | |
| 2972 | ||
| 2973 | // Report cron status | |
| 2974 | if ($phase == 'runtime') { | |
| 2c381622 | 2975 | $cron_last = variable_get('cron_last'); |
| 66df6025 AB |
2976 | |
| 2977 | if (is_numeric($cron_last)) { | |
| 2978 | $requirements['cron']['value'] = $t('Last run !time ago', array('!time' => format_interval(REQUEST_TIME - $cron_last))); | |
| 2979 | } | |
| 2980 | else { | |
| 2981 | $requirements['cron'] = array( | |
| 71ee49de | 2982 | 'description' => $t('Cron has not run. It appears cron jobs have not been setup on your system. Check the help pages for <a href="@url">configuring cron jobs</a>.', array('@url' => 'http://drupal.org/cron')), |
| 66df6025 AB |
2983 | 'severity' => REQUIREMENT_ERROR, |
| 2984 | 'value' => $t('Never run'), | |
| 2985 | ); | |
| 2986 | } | |
| 2987 | ||
| b26aa370 | 2988 | $requirements['cron']['description'] .= ' ' . $t('You can <a href="@cron">run cron manually</a>.', array('@cron' => url('admin/reports/status/run-cron'))); |
| 66df6025 AB |
2989 | |
| 2990 | $requirements['cron']['title'] = $t('Cron maintenance tasks'); | |
| 2991 | } | |
| 2992 | ||
| 2993 | return $requirements; | |
| 2994 | } | |
| 2995 | ||
| 2996 | /** | |
| 2997 | * Define the current version of the database schema. | |
| 2998 | * | |
| 2999 | * A Drupal schema definition is an array structure representing one or | |
| 3000 | * more tables and their related keys and indexes. A schema is defined by | |
| 3001 | * hook_schema() which must live in your module's .install file. | |
| 3002 | * | |
| 5d735a07 | 3003 | * This hook is called at both install and uninstall time, and in the latter |
| 3004 | * case, it cannot rely on the .module file being loaded or hooks being known. | |
| 3005 | * If the .module file is needed, it may be loaded with drupal_load(). | |
| 3006 | * | |
| c545f6ee | 3007 | * The tables declared by this hook will be automatically created when |
| 3008 | * the module is first enabled, and removed when the module is uninstalled. | |
| 3009 | * This happens before hook_install() is invoked, and after hook_uninstall() | |
| 3010 | * is invoked, respectively. | |
| 3011 | * | |
| 3012 | * By declaring the tables used by your module via an implementation of | |
| 3013 | * hook_schema(), these tables will be available on all supported database | |
| 3014 | * engines. You don't have to deal with the different SQL dialects for table | |
| 8ad62e2d | 3015 | * creation and alteration of the supported database engines. |
| 3016 | * | |
| 66df6025 AB |
3017 | * See the Schema API Handbook at http://drupal.org/node/146843 for |
| 3018 | * details on schema definition structures. | |
| 3019 | * | |
| 3020 | * @return | |
| f833423b DB |
3021 | * A schema definition structure array. For each element of the |
| 3022 | * array, the key is a table name and the value is a table structure | |
| 3023 | * definition. | |
| 3024 | * | |
| 3025 | * @ingroup schemaapi | |
| 66df6025 AB |
3026 | */ |
| 3027 | function hook_schema() { | |
| 3028 | $schema['node'] = array( | |
| 3029 | // example (partial) specification for table "node" | |
| 9c79816c | 3030 | 'description' => 'The base table for nodes.', |
| 66df6025 AB |
3031 | 'fields' => array( |
| 3032 | 'nid' => array( | |
| 9c79816c | 3033 | 'description' => 'The primary identifier for a node.', |
| 66df6025 AB |
3034 | 'type' => 'serial', |
| 3035 | 'unsigned' => TRUE, | |
| 3036 | 'not null' => TRUE), | |
| 3037 | 'vid' => array( | |
| 9c79816c | 3038 | 'description' => 'The current {node_revision}.vid version identifier.', |
| 66df6025 AB |
3039 | 'type' => 'int', |
| 3040 | 'unsigned' => TRUE, | |
| 3041 | 'not null' => TRUE, | |
| 3042 | 'default' => 0), | |
| 3043 | 'type' => array( | |
| 9c79816c | 3044 | 'description' => 'The {node_type} of this node.', |
| 66df6025 AB |
3045 | 'type' => 'varchar', |
| 3046 | 'length' => 32, | |
| 3047 | 'not null' => TRUE, | |
| 3048 | 'default' => ''), | |
| 3049 | 'title' => array( | |
| 401d1bb8 | 3050 | 'description' => 'The title of this node, always treated as non-markup plain text.', |
| 66df6025 AB |
3051 | 'type' => 'varchar', |
| 3052 | 'length' => 255, | |
| 3053 | 'not null' => TRUE, | |
| 3054 | 'default' => ''), | |
| 3055 | ), | |
| 3056 | 'indexes' => array( | |
| 3057 | 'node_changed' => array('changed'), | |
| 3058 | 'node_created' => array('created'), | |
| 3059 | ), | |
| 3060 | 'unique keys' => array( | |
| 3061 | 'nid_vid' => array('nid', 'vid'), | |
| 3062 | 'vid' => array('vid') | |
| 3063 | ), | |
| db536802 DB |
3064 | 'foreign keys' => array( |
| 3065 | 'node_revision' => array( | |
| 3066 | 'table' => 'node_revision', | |
| 3067 | 'columns' => array('vid' => 'vid'), | |
| 3068 | ), | |
| 3069 | 'node_author' => array( | |
| 3070 | 'table' => 'users', | |
| 3071 | 'columns' => array('uid' => 'uid') | |
| 3072 | ), | |
| 3073 | ), | |
| 66df6025 AB |
3074 | 'primary key' => array('nid'), |
| 3075 | ); | |
| 3076 | return $schema; | |
| 3077 | } | |
| 3078 | ||
| 3079 | /** | |
| 3080 | * Perform alterations to existing database schemas. | |
| 3081 | * | |
| 3082 | * When a module modifies the database structure of another module (by | |
| 3083 | * changing, adding or removing fields, keys or indexes), it should | |
| 0ed10779 DB |
3084 | * implement hook_schema_alter() to update the default $schema to take its |
| 3085 | * changes into account. | |
| 66df6025 AB |
3086 | * |
| 3087 | * See hook_schema() for details on the schema definition structure. | |
| 3088 | * | |
| 3089 | * @param $schema | |
| 3090 | * Nested array describing the schemas for all modules. | |
| 66df6025 AB |
3091 | */ |
| 3092 | function hook_schema_alter(&$schema) { | |
| 3093 | // Add field to existing schema. | |
| 665c9fdc | 3094 | $schema['users']['fields']['timezone_id'] = array( |
| 66df6025 AB |
3095 | 'type' => 'int', |
| 3096 | 'not null' => TRUE, | |
| 3097 | 'default' => 0, | |
| 9c79816c | 3098 | 'description' => 'Per-user timezone configuration.', |
| 66df6025 AB |
3099 | ); |
| 3100 | } | |
| 3101 | ||
| 3102 | /** | |
| 63437929 DB |
3103 | * Perform alterations to a structured query. |
| 3104 | * | |
| 3105 | * Structured (aka dynamic) queries that have tags associated may be altered by any module | |
| 3106 | * before the query is executed. | |
| 3107 | * | |
| 87f1bf45 DB |
3108 | * @param $query |
| 3109 | * A Query object describing the composite parts of a SQL query. | |
| 3110 | * | |
| 63437929 DB |
3111 | * @see hook_query_TAG_alter() |
| 3112 | * @see node_query_node_access_alter() | |
| 01a33182 DB |
3113 | * @see QueryAlterableInterface |
| 3114 | * @see SelectQueryInterface | |
| 63437929 DB |
3115 | */ |
| 3116 | function hook_query_alter(QueryAlterableInterface $query) { | |
| 01a33182 DB |
3117 | if ($query->hasTag('micro_limit')) { |
| 3118 | $query->range(0, 2); | |
| 3119 | } | |
| 63437929 DB |
3120 | } |
| 3121 | ||
| 3122 | /** | |
| 3123 | * Perform alterations to a structured query for a given tag. | |
| 3124 | * | |
| 87f1bf45 DB |
3125 | * @param $query |
| 3126 | * An Query object describing the composite parts of a SQL query. | |
| 3127 | * | |
| 63437929 DB |
3128 | * @see hook_query_alter() |
| 3129 | * @see node_query_node_access_alter() | |
| 01a33182 DB |
3130 | * @see QueryAlterableInterface |
| 3131 | * @see SelectQueryInterface | |
| 63437929 DB |
3132 | */ |
| 3133 | function hook_query_TAG_alter(QueryAlterableInterface $query) { | |
| 3134 | // Skip the extra expensive alterations if site has no node access control modules. | |
| 3135 | if (!node_access_view_all_nodes()) { | |
| 3136 | // Prevent duplicates records. | |
| 3137 | $query->distinct(); | |
| 3138 | // The recognized operations are 'view', 'update', 'delete'. | |
| 3139 | if (!$op = $query->getMetaData('op')) { | |
| 3140 | $op = 'view'; | |
| 3141 | } | |
| 3142 | // Skip the extra joins and conditions for node admins. | |
| 3143 | if (!user_access('bypass node access')) { | |
| 3144 | // The node_access table has the access grants for any given node. | |
| 7b77b90c | 3145 | $access_alias = $query->join('node_access', 'na', '%alias.nid = n.nid'); |
| 63437929 DB |
3146 | $or = db_or(); |
| 3147 | // If any grant exists for the specified user, then user has access to the node for the specified operation. | |
| 3148 | foreach (node_access_grants($op, $query->getMetaData('account')) as $realm => $gids) { | |
| 3149 | foreach ($gids as $gid) { | |
| 3150 | $or->condition(db_and() | |
| 7b77b90c DB |
3151 | ->condition($access_alias . '.gid', $gid) |
| 3152 | ->condition($access_alias . '.realm', $realm) | |
| 63437929 DB |
3153 | ); |
| 3154 | } | |
| 3155 | } | |
| 3156 | ||
| 3157 | if (count($or->conditions())) { | |
| 3158 | $query->condition($or); | |
| 3159 | } | |
| 6d3d75fe | 3160 | |
| 7b77b90c | 3161 | $query->condition($access_alias . 'grant_' . $op, 1, '>='); |
| 63437929 DB |
3162 | } |
| 3163 | } | |
| 3164 | } | |
| 3165 | ||
| 3166 | /** | |
| 029c48c6 DB |
3167 | * Perform setup tasks when the module is installed. |
| 3168 | * | |
| 3169 | * If the module implements hook_schema(), the database tables will | |
| 3170 | * be created before this hook is fired. | |
| 66df6025 | 3171 | * |
| 18b96d0c | 3172 | * Implementations of this hook are by convention declared in the module's |
| 5d735a07 | 3173 | * .install file. The implementation can rely on the .module file being loaded. |
| 3174 | * The hook will only be called the first time a module is enabled or after it | |
| 3175 | * is re-enabled after being uninstalled. The module's schema version will be | |
| 3176 | * set to the module's greatest numbered update hook. Because of this, any time | |
| 3177 | * a hook_update_N() is added to the module, this function needs to be updated | |
| 3178 | * to reflect the current version of the database schema. | |
| 66df6025 | 3179 | * |
| d2feb622 AB |
3180 | * See the Schema API documentation at |