PageRenderTime 55ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/apis/6/core.php

https://github.com/fiasco/Drupal-Module-Builder
PHP | 2452 lines | 790 code | 114 blank | 1548 comment | 111 complexity | a744f8ff9ecb90db26d8697040aaf1bc MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // $Id: core.php,v 1.168.2.64 2009/06/29 20:25:15 jhodgdon Exp $
  3. /**
  4. * @file
  5. * These are the hooks that are invoked by the Drupal core.
  6. *
  7. * Core hooks are typically called in all modules at once using
  8. * module_invoke_all().
  9. */
  10. /**
  11. * @addtogroup hooks
  12. * @{
  13. */
  14. /**
  15. * Declare information about one or more Drupal actions.
  16. *
  17. * Any module can define any number of Drupal actions. The trigger module is an
  18. * example of a module that uses actions. An action consists of two or three
  19. * parts: (1) an action definition (returned by this hook), (2) a function which
  20. * does the action (which by convention is named module + '_' + description of
  21. * what the function does + '_action'), and an optional form definition
  22. * function that defines a configuration form (which has the name of the action
  23. * with '_form' appended to it.)
  24. *
  25. * @return
  26. * - An array of action descriptions. Each action description is an associative
  27. * array, where the key of the item is the action's function, and the
  28. * following key-value pairs:
  29. * - 'type': (required) the type is determined by what object the action
  30. * acts on. Possible choices are node, user, comment, and system. Or
  31. * whatever your own custom type is. So, for the nodequeue module, the
  32. * type might be set to 'nodequeue' if the action would be performed on a
  33. * nodequeue.
  34. * - 'description': (required) The human-readable name of the action.
  35. * - 'configurable': (required) If FALSE, then the action doesn't require
  36. * any extra configuration. If TRUE, then you should define a form
  37. * function with the same name as the key, but with '_form' appended to
  38. * it (i.e., the form for 'node_assign_owner_action' is
  39. * 'node_assign_owner_action_form'.)
  40. * This function will take the $context as the only parameter, and is
  41. * paired with the usual _submit function, and possibly a _validate
  42. * function.
  43. * - 'hooks': (required) An array of all of the operations this action is
  44. * appropriate for, keyed by hook name. The trigger module uses this to
  45. * filter out inappropriate actions when presenting the interface for
  46. * assigning actions to events. If you are writing actions in your own
  47. * modules and you simply want to declare support for all possible hooks,
  48. * you can set 'hooks' => array('any' => TRUE). Common hooks are 'user',
  49. * 'nodeapi', 'comment', or 'taxonomy'. Any hook that has been described
  50. * to Drupal in hook_hook_info() will work is a possiblity.
  51. * - 'behavior': (optional) Human-readable array of behavior descriptions.
  52. * The only one we have now is 'changes node property'. You will almost
  53. * certainly never have to return this in your own implementations of this
  54. * hook.
  55. *
  56. * The function that is called when the action is triggered is passed two
  57. * parameters - an object of the same type as the 'type' value of the
  58. * hook_action_info array, and a context variable that contains the context
  59. * under which the action is currently running, sent as an array. For example,
  60. * the actions module sets the 'hook' and 'op' keys of the context array (so,
  61. * 'hook' may be 'nodeapi' and 'op' may be 'insert').
  62. */
  63. function hook_action_info() {
  64. return array(
  65. 'comment_unpublish_action' => array(
  66. 'description' => t('Unpublish comment'),
  67. 'type' => 'comment',
  68. 'configurable' => FALSE,
  69. 'hooks' => array(
  70. 'comment' => array('insert', 'update'),
  71. )
  72. ),
  73. 'comment_unpublish_by_keyword_action' => array(
  74. 'description' => t('Unpublish comment containing keyword(s)'),
  75. 'type' => 'comment',
  76. 'configurable' => TRUE,
  77. 'hooks' => array(
  78. 'comment' => array('insert', 'update'),
  79. )
  80. )
  81. );
  82. }
  83. /**
  84. * Execute code after an action is deleted.
  85. *
  86. * @param $aid
  87. * The action ID.
  88. */
  89. function hook_actions_delete($aid) {
  90. db_query("DELETE FROM {actions_assignments} WHERE aid = '%s'", $aid);
  91. }
  92. /**
  93. * Alter the actions declared by another module.
  94. *
  95. * Called by actions_list() to allow modules to alter the return
  96. * values from implementations of hook_action_info().
  97. *
  98. * @see trigger_example_action_info_alter().
  99. */
  100. function hook_action_info_alter(&$actions) {
  101. $actions['node_unpublish_action']['description'] = t('Unpublish and remove from public view.');
  102. }
  103. /**
  104. * Declare a block or set of blocks.
  105. *
  106. * Any module can export a block (or blocks) to be displayed by defining
  107. * the _block hook. This hook is called by theme.inc to display a block,
  108. * and also by block.module to procure the list of available blocks.
  109. *
  110. * @param $op
  111. * What kind of information to retrieve about the block or blocks.
  112. * Possible values:
  113. * - 'list': A list of all blocks defined by the module.
  114. * - 'configure': Configuration form for the block.
  115. * - 'save': Save the configuration options.
  116. * - 'view': Process the block when enabled in a region in order to view its contents.
  117. * @param $delta
  118. * Which block to return (not applicable if $op is 'list'). Although it is
  119. * most commonly an integer starting at 0, this is not mandatory. For
  120. * instance, aggregator.module uses string values for $delta
  121. * @param $edit
  122. * If $op is 'save', the submitted form data from the configuration form.
  123. * @return
  124. * - If $op is 'list': An array of block descriptions. Each block description
  125. * is an associative array, with the following key-value pairs:
  126. * - 'info': (required) The human-readable name of the block.
  127. * - 'cache': A bitmask of flags describing how the block should behave with
  128. * respect to block caching. The following shortcut bitmasks are provided
  129. * as constants in block.module:
  130. * - BLOCK_CACHE_PER_ROLE (default): The block can change depending on the
  131. * roles the user viewing the page belongs to.
  132. * - BLOCK_CACHE_PER_USER: The block can change depending on the user
  133. * viewing the page. This setting can be resource-consuming for sites
  134. * with large number of users, and should only be used when
  135. * BLOCK_CACHE_PER_ROLE is not sufficient.
  136. * - BLOCK_CACHE_PER_PAGE: The block can change depending on the page
  137. * being viewed.
  138. * - BLOCK_CACHE_GLOBAL: The block is the same for every user on every
  139. * page where it is visible.
  140. * - BLOCK_NO_CACHE: The block should not get cached.
  141. * - 'weight', 'status', 'region', 'visibility', 'pages':
  142. * You can give your blocks an explicit weight, enable them, limit them to
  143. * given pages, etc. These settings will be registered when the block is first
  144. * loaded at admin/block, and from there can be changed manually via block
  145. * administration.
  146. * Note that if you set a region that isn't available in a given theme, the
  147. * block will be registered instead to that theme's default region (the first
  148. * item in the _regions array).
  149. * - If $op is 'configure': optionally return the configuration form.
  150. * - If $op is 'save': return nothing.
  151. * - If $op is 'view': return an array which must define a 'subject' element
  152. * and a 'content' element defining the block indexed by $delta.
  153. *
  154. * The functions mymodule_display_block_1 and 2, as used in the example,
  155. * should of course be defined somewhere in your module and return the
  156. * content you want to display to your users. If the "content" element
  157. * is empty, no block will be displayed even if "subject" is present.
  158. *
  159. * After completing your blocks, do not forget to enable them in the
  160. * block admin menu.
  161. *
  162. * For a detailed usage example, see block_example.module.
  163. */
  164. function hook_block($op = 'list', $delta = 0, $edit = array()) {
  165. if ($op == 'list') {
  166. $blocks[0] = array('info' => t('Mymodule block #1 shows ...'),
  167. 'weight' => 0, 'status' => 1, 'region' => 'left');
  168. // BLOCK_CACHE_PER_ROLE will be assumed for block 0.
  169. $blocks[1] = array('info' => t('Mymodule block #2 describes ...'),
  170. 'cache' => BLOCK_CACHE_PER_ROLE | BLOCK_CACHE_PER_PAGE);
  171. return $blocks;
  172. }
  173. else if ($op == 'configure' && $delta == 0) {
  174. $form['items'] = array(
  175. '#type' => 'select',
  176. '#title' => t('Number of items'),
  177. '#default_value' => variable_get('mymodule_block_items', 0),
  178. '#options' => array('1', '2', '3'),
  179. );
  180. return $form;
  181. }
  182. else if ($op == 'save' && $delta == 0) {
  183. variable_set('mymodule_block_items', $edit['items']);
  184. }
  185. else if ($op == 'view') {
  186. switch($delta) {
  187. case 0:
  188. $block = array('subject' => t('Title of block #1'),
  189. 'content' => mymodule_display_block_1());
  190. break;
  191. case 1:
  192. $block = array('subject' => t('Title of block #2'),
  193. 'content' => mymodule_display_block_2());
  194. break;
  195. }
  196. return $block;
  197. }
  198. }
  199. /**
  200. * Act on comments.
  201. *
  202. * This hook allows modules to extend the comments system.
  203. *
  204. * @param $a1
  205. * Dependent on the action being performed.
  206. * - For "validate","update","insert", passes in an array of form values submitted by the user.
  207. * - For all other operations, passes in the comment the action is being performed on.
  208. * @param $op
  209. * What kind of action is being performed. Possible values:
  210. * - "insert": The comment is being inserted.
  211. * - "update": The comment is being updated.
  212. * - "view": The comment is being viewed. This hook can be used to add additional data to the comment before theming.
  213. * - "validate": The user has just finished editing the comment and is
  214. * trying to preview or submit it. This hook can be used to check or
  215. * even modify the node. Errors should be set with form_set_error().
  216. * - "publish": The comment is being published by the moderator.
  217. * - "unpublish": The comment is being unpublished by the moderator.
  218. * - "delete": The comment is being deleted by the moderator.
  219. * @return
  220. * Dependent on the action being performed.
  221. * - For all other operations, nothing.
  222. */
  223. function hook_comment(&$a1, $op) {
  224. if ($op == 'insert' || $op == 'update') {
  225. $nid = $a1['nid'];
  226. }
  227. cache_clear_all_like(drupal_url(array('id' => $nid)));
  228. }
  229. /**
  230. * Perform periodic actions.
  231. *
  232. * Modules that require to schedule some commands to be executed at regular
  233. * intervals can implement hook_cron(). The engine will then call the hook
  234. * at the appropriate intervals defined by the administrator. This interface
  235. * is particularly handy to implement timers or to automate certain tasks.
  236. * Database maintenance, recalculation of settings or parameters, and
  237. * automatic mailings are good candidates for cron tasks.
  238. *
  239. * @return
  240. * None.
  241. *
  242. * This hook will only be called if cron.php is run (e.g. by crontab).
  243. */
  244. function hook_cron() {
  245. $result = db_query('SELECT * FROM {site} WHERE checked = 0 OR checked
  246. + refresh < %d', time());
  247. while ($site = db_fetch_array($result)) {
  248. cloud_update($site);
  249. }
  250. }
  251. /**
  252. * Expose a list of triggers (events) that your module is allowing users to
  253. * assign actions to.
  254. *
  255. * This hook is used by the Triggers API to present information about triggers
  256. * (or events) that your module allows users to assign actions to.
  257. *
  258. * See also hook_action_info().
  259. *
  260. * @return
  261. * - A nested array. The outermost key defines the module that the triggers
  262. * are from. The menu system will use the key to look at the .info file of
  263. * the module and make a local task (a tab) in the trigger UI.
  264. * - The next key defines the hook being described.
  265. * - Inside of that array are a list of arrays keyed by hook operation.
  266. * - Each of those arrays have a key of 'runs when' and a value which is
  267. * an English description of the hook.
  268. *
  269. * For example, the node_hook_info implementation has 'node' as the outermost
  270. * key, as that's the module it's in. Next it has 'nodeapi' as the next key,
  271. * as hook_nodeapi() is what applies to changes in nodes. Finally the keys
  272. * after that are the various operations for hook_nodeapi() that the node module
  273. * is exposing as triggers.
  274. */
  275. function hook_hook_info() {
  276. return array(
  277. 'node' => array(
  278. 'nodeapi' => array(
  279. 'presave' => array(
  280. 'runs when' => t('When either saving a new post or updating an existing post'),
  281. ),
  282. 'insert' => array(
  283. 'runs when' => t('After saving a new post'),
  284. ),
  285. 'update' => array(
  286. 'runs when' => t('After saving an updated post'),
  287. ),
  288. 'delete' => array(
  289. 'runs when' => t('After deleting a post')
  290. ),
  291. 'view' => array(
  292. 'runs when' => t('When content is viewed by an authenticated user')
  293. ),
  294. ),
  295. ),
  296. );
  297. }
  298. /**
  299. * Alter the data being saved to the {menu_router} table after hook_menu is invoked.
  300. *
  301. * This hook is invoked by menu_router_build(). The menu definitions are passed
  302. * in by reference. Each element of the $items array is one item returned
  303. * by a module from hook_menu. Additional items may be added, or existing items
  304. * altered.
  305. *
  306. * @param $items
  307. * Associative array of menu router definitions returned from hook_menu().
  308. * @return
  309. * None.
  310. */
  311. function hook_menu_alter(&$items) {
  312. // Example - disable the page at node/add
  313. $items['node/add']['access callback'] = FALSE;
  314. }
  315. /**
  316. * Alter the data being saved to the {menu_links} table by menu_link_save().
  317. *
  318. * @param $item
  319. * Associative array defining a menu link as passed into menu_link_save().
  320. * @param $menu
  321. * Associative array containg the menu router returned from menu_router_build().
  322. * @return
  323. * None.
  324. */
  325. function hook_menu_link_alter(&$item, $menu) {
  326. // Example 1 - make all new admin links hidden (a.k.a disabled).
  327. if (strpos($item['link_path'], 'admin') === 0 && empty($item['mlid'])) {
  328. $item['hidden'] = 1;
  329. }
  330. // Example 2 - flag a link to be altered by hook_translated_menu_link_alter()
  331. if ($item['link_path'] == 'devel/cache/clear') {
  332. $item['options']['alter'] = TRUE;
  333. }
  334. }
  335. /**
  336. * Alter a menu link after it's translated, but before it's rendered.
  337. *
  338. * This hook may be used, for example, to add a page-specific query string.
  339. * For performance reasons, only links that have $item['options']['alter'] == TRUE
  340. * will be passed into this hook. The $item['options']['alter'] flag should
  341. * generally be set using hook_menu_link_alter().
  342. *
  343. * @param $item
  344. * Associative array defining a menu link after _menu_link_translate()
  345. * @param $map
  346. * Associative array containing the menu $map (path parts and/or objects).
  347. * @return
  348. * None.
  349. */
  350. function hook_translated_menu_link_alter(&$item, $map) {
  351. if ($item['href'] == 'devel/cache/clear') {
  352. $item['localized_options']['query'] = drupal_get_destination();
  353. }
  354. }
  355. /**
  356. * Rewrite database queries, usually for access control.
  357. *
  358. * Add JOIN and WHERE statements to queries and decide whether the primary_field
  359. * shall be made DISTINCT. For node objects, primary field is always called nid.
  360. * For taxonomy terms, it is tid and for vocabularies it is vid. For comments,
  361. * it is cid. Primary table is the table where the primary object (node, file,
  362. * term_node etc.) is.
  363. *
  364. * You shall return an associative array. Possible keys are 'join', 'where' and
  365. * 'distinct'. The value of 'distinct' shall be 1 if you want that the
  366. * primary_field made DISTINCT.
  367. *
  368. * @param $query
  369. * Query to be rewritten.
  370. * @param $primary_table
  371. * Name or alias of the table which has the primary key field for this query.
  372. * Typical table names would be: {blocks}, {comments}, {forum}, {node},
  373. * {menu}, {term_data} or {vocabulary}. However, it is more common for
  374. * $primary_table to contain the usual table alias: b, c, f, n, m, t or v.
  375. * @param $primary_field
  376. * Name of the primary field.
  377. * @param $args
  378. * Array of additional arguments.
  379. * @return
  380. * An array of join statements, where statements, distinct decision.
  381. */
  382. function hook_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
  383. switch ($primary_field) {
  384. case 'nid':
  385. // this query deals with node objects
  386. $return = array();
  387. if ($primary_table != 'n') {
  388. $return['join'] = "LEFT JOIN {node} n ON $primary_table.nid = n.nid";
  389. }
  390. $return['where'] = 'created >' . mktime(0, 0, 0, 1, 1, 2005);
  391. return $return;
  392. break;
  393. case 'tid':
  394. // this query deals with taxonomy objects
  395. break;
  396. case 'vid':
  397. // this query deals with vocabulary objects
  398. break;
  399. }
  400. }
  401. /**
  402. * Allows modules to declare their own Forms API element types and specify their
  403. * default values.
  404. *
  405. * This hook allows modules to declare their own form element types and to
  406. * specify their default values. The values returned by this hook will be
  407. * merged with the elements returned by hook_form() implementations and so
  408. * can return defaults for any Form APIs keys in addition to those explicitly
  409. * mentioned below.
  410. *
  411. * Each of the form element types defined by this hook is assumed to have
  412. * a matching theme function, e.g. theme_elementtype(), which should be
  413. * registered with hook_theme() as normal.
  414. *
  415. * Form more information about custom element types see the explanation at
  416. * @link http://drupal.org/node/169815 http://drupal.org/node/169815 @endlink .
  417. *
  418. * @return
  419. * An associative array describing the element types being defined. The array
  420. * contains a sub-array for each element type, with the machine-readable type
  421. * name as the key. Each sub-array has a number of possible attributes:
  422. * - "#input": boolean indicating whether or not this element carries a value
  423. * (even if it's hidden).
  424. * - "#process": array of callback functions taking $element and $form_state.
  425. * - "#after_build": array of callback functions taking $element and $form_state.
  426. * - "#validate": array of callback functions taking $form and $form_state.
  427. * - "#element_validate": array of callback functions taking $element and
  428. * $form_state.
  429. * - "#pre_render": array of callback functions taking $element and $form_state.
  430. * - "#post_render": array of callback functions taking $element and $form_state.
  431. * - "#submit": array of callback functions taking $form and $form_state.
  432. */
  433. function hook_elements() {
  434. $type['filter_format'] = array('#input' => TRUE);
  435. return $type;
  436. }
  437. /**
  438. * Perform cleanup tasks.
  439. *
  440. * This hook is run at the end of each page request. It is often used for
  441. * page logging and printing out debugging information.
  442. *
  443. * Only use this hook if your code must run even for cached page views.
  444. * If you have code which must run once on all non cached pages, use
  445. * hook_init instead. Thats the usual case. If you implement this hook
  446. * and see an error like 'Call to undefined function', it is likely that
  447. * you are depending on the presence of a module which has not been loaded yet.
  448. * It is not loaded because Drupal is still in bootstrap mode.
  449. *
  450. * @param $destination
  451. * If this hook is invoked as part of a drupal_goto() call, then this argument
  452. * will be a fully-qualified URL that is the destination of the redirect.
  453. * Modules may use this to react appropriately; for example, nothing should
  454. * be output in this case, because PHP will then throw a "headers cannot be
  455. * modified" error when attempting the redirection.
  456. * @return
  457. * None.
  458. */
  459. function hook_exit($destination = NULL) {
  460. db_query('UPDATE {counter} SET hits = hits + 1 WHERE type = 1');
  461. }
  462. /**
  463. * Control access to private file downloads and specify HTTP headers.
  464. *
  465. * This hook allows modules enforce permisisons on file downloads when the
  466. * private file download method is selected. Modules can also provide headers
  467. * to specify information like the file's name or MIME type.
  468. *
  469. * @param $filepath
  470. * String of the file's path.
  471. * @return
  472. * If the user does not have permission to access the file, return -1. If the
  473. * user has permission, return an array with the appropriate headers. If the file
  474. * is not controlled by the current module, the return value should be NULL.
  475. */
  476. function hook_file_download($filepath) {
  477. // Check if the file is controlled by the current module.
  478. if ($filemime = db_result(db_query("SELECT filemime FROM {fileupload} WHERE filepath = '%s'", file_create_path($filepath)))) {
  479. if (user_access('access content')) {
  480. return array('Content-type:' . $filemime);
  481. }
  482. else {
  483. return -1;
  484. }
  485. }
  486. }
  487. /**
  488. * Define content filters.
  489. *
  490. * Content in Drupal is passed through all enabled filters before it is
  491. * output. This lets a module modify content to the site administrator's
  492. * liking.
  493. *
  494. * This hook contains all that is needed for having a module provide filtering
  495. * functionality.
  496. *
  497. * Depending on $op, different tasks are performed.
  498. *
  499. * A module can contain as many filters as it wants. The 'list' operation tells
  500. * the filter system which filters are available. Every filter has a numerical
  501. * 'delta' which is used to refer to it in every operation.
  502. *
  503. * Filtering is a two-step process. First, the content is 'prepared' by calling
  504. * the 'prepare' operation for every filter. The purpose of 'prepare' is to
  505. * escape HTML-like structures. For example, imagine a filter which allows the
  506. * user to paste entire chunks of programming code without requiring manual
  507. * escaping of special HTML characters like @< or @&. If the programming code
  508. * were left untouched, then other filters could think it was HTML and change
  509. * it. For most filters however, the prepare-step is not necessary, and they can
  510. * just return the input without changes.
  511. *
  512. * Filters should not use the 'prepare' step for anything other than escaping,
  513. * because that would short-circuits the control the user has over the order
  514. * in which filters are applied.
  515. *
  516. * The second step is the actual processing step. The result from the
  517. * prepare-step gets passed to all the filters again, this time with the
  518. * 'process' operation. It's here that filters should perform actual changing of
  519. * the content: transforming URLs into hyperlinks, converting smileys into
  520. * images, etc.
  521. *
  522. * An important aspect of the filtering system are 'input formats'. Every input
  523. * format is an entire filter setup: which filters to enable, in what order
  524. * and with what settings. Filters that provide settings should usually store
  525. * these settings per format.
  526. *
  527. * If the filter's behaviour depends on an extensive list and/or external data
  528. * (e.g. a list of smileys, a list of glossary terms) then filters are allowed
  529. * to provide a separate, global configuration page rather than provide settings
  530. * per format. In that case, there should be a link from the format-specific
  531. * settings to the separate settings page.
  532. *
  533. * For performance reasons content is only filtered once; the result is stored
  534. * in the cache table and retrieved the next time the piece of content is
  535. * displayed. If a filter's output is dynamic it can override the cache
  536. * mechanism, but obviously this feature should be used with caution: having one
  537. * 'no cache' filter in a particular input format disables caching for the
  538. * entire format, not just for one filter.
  539. *
  540. * Beware of the filter cache when developing your module: it is advised to set
  541. * your filter to 'no cache' while developing, but be sure to remove it again
  542. * if it's not needed. You can clear the cache by running the SQL query 'DELETE
  543. * FROM cache_filter';
  544. *
  545. * @param $op
  546. * Which filtering operation to perform. Possible values:
  547. * - list: provide a list of available filters.
  548. * Returns an associative array of filter names with numerical keys.
  549. * These keys are used for subsequent operations and passed back through
  550. * the $delta parameter.
  551. * - no cache: Return true if caching should be disabled for this filter.
  552. * - description: Return a short description of what this filter does.
  553. * - prepare: Return the prepared version of the content in $text.
  554. * - process: Return the processed version of the content in $text.
  555. * - settings: Return HTML form controls for the filter's settings. These
  556. * settings are stored with variable_set() when the form is submitted.
  557. * Remember to use the $format identifier in the variable and control names
  558. * to store settings per input format (e.g. "mymodule_setting_$format").
  559. * @param $delta
  560. * Which of the module's filters to use (applies to every operation except
  561. * 'list'). Modules that only contain one filter can ignore this parameter.
  562. * @param $format
  563. * Which input format the filter is being used in (applies to 'prepare',
  564. * 'process' and 'settings').
  565. * @param $text
  566. * The content to filter (applies to 'prepare' and 'process').
  567. * @param $cache_id
  568. * The cache id of the content.
  569. * @return
  570. * The return value depends on $op. The filter hook is designed so that a
  571. * module can return $text for operations it does not use/need.
  572. *
  573. * For a detailed usage example, see filter_example.module. For an example of
  574. * using multiple filters in one module, see filter_filter() and
  575. * filter_filter_tips().
  576. */
  577. function hook_filter($op, $delta = 0, $format = -1, $text = '', $cache_id = 0) {
  578. switch ($op) {
  579. case 'list':
  580. return array(0 => t('Code filter'));
  581. case 'description':
  582. return t('Allows users to post code verbatim using &lt;code&gt; and &lt;?php ?&gt; tags.');
  583. case 'prepare':
  584. // Note: we use the bytes 0xFE and 0xFF to replace < > during the
  585. // filtering process. These bytes are not valid in UTF-8 data and thus
  586. // least likely to cause problems.
  587. $text = preg_replace('@<code>(.+?)</code>@se', "'\xFEcode\xFF'. codefilter_escape('\\1') .'\xFE/code\xFF'", $text);
  588. $text = preg_replace('@<(\?(php)?|%)(.+?)(\?|%)>@se', "'\xFEphp\xFF'. codefilter_escape('\\3') .'\xFE/php\xFF'", $text);
  589. return $text;
  590. case "process":
  591. $text = preg_replace('@\xFEcode\xFF(.+?)\xFE/code\xFF@se', "codefilter_process_code('$1')", $text);
  592. $text = preg_replace('@\xFEphp\xFF(.+?)\xFE/php\xFF@se', "codefilter_process_php('$1')", $text);
  593. return $text;
  594. default:
  595. return $text;
  596. }
  597. }
  598. /**
  599. * Provide tips for using filters.
  600. *
  601. * A module's tips should be informative and to the point. Short tips are
  602. * preferably one-liners.
  603. *
  604. * @param $delta
  605. * Which of this module's filters to use. Modules which only implement one
  606. * filter can ignore this parameter.
  607. * @param $format
  608. * Which format we are providing tips for.
  609. * @param $long
  610. * If set to true, long tips are requested, otherwise short tips are needed.
  611. * @return
  612. * The text of the filter tip.
  613. *
  614. *
  615. */
  616. function hook_filter_tips($delta, $format, $long = false) {
  617. if ($long) {
  618. return t('To post pieces of code, surround them with &lt;code&gt;...&lt;/code&gt; tags. For PHP code, you can use &lt;?php ... ?&gt;, which will also colour it based on syntax.');
  619. }
  620. else {
  621. return t('You may post code using &lt;code&gt;...&lt;/code&gt; (generic) or &lt;?php ... ?&gt; (highlighted PHP) tags.');
  622. }
  623. }
  624. /**
  625. * Insert closing HTML.
  626. *
  627. * This hook enables modules to insert HTML just before the \</body\> closing
  628. * tag of web pages. This is useful for adding JavaScript code to the footer
  629. * and for outputting debug information. It is not possible to add JavaScript
  630. * to the header at this point, and developers wishing to do so should use
  631. * hook_init() instead.
  632. *
  633. * @param $main
  634. * Whether the current page is the front page of the site.
  635. * @return
  636. * The HTML to be inserted.
  637. */
  638. function hook_footer($main = 0) {
  639. if (variable_get('dev_query', 0)) {
  640. return '<div style="clear:both;">'. devel_query_table() .'</div>';
  641. }
  642. }
  643. /**
  644. * Perform alterations to existing database schemas.
  645. *
  646. * When a module modifies the database structure of another module (by
  647. * changing, adding or removing fields, keys or indexes), it should
  648. * implement hook_schema_alter() to update the default $schema to take
  649. * it's changes into account.
  650. *
  651. * See hook_schema() for details on the schema definition structure.
  652. *
  653. * @param $schema
  654. * Nested array describing the schemas for all modules.
  655. * @return
  656. * None.
  657. */
  658. function hook_schema_alter(&$schema) {
  659. // Add field to existing schema.
  660. $schema['users']['fields']['timezone_id'] = array(
  661. 'type' => 'int',
  662. 'not null' => TRUE,
  663. 'default' => 0,
  664. 'description' => 'Per-user timezone configuration.',
  665. );
  666. }
  667. /**
  668. * Perform alterations before a form is rendered.
  669. *
  670. * One popular use of this hook is to add form elements to the node form. When
  671. * altering a node form, the node object retrieved at from $form['#node'].
  672. *
  673. * Note that instead of hook_form_alter(), which is called for all forms, you
  674. * can also use hook_form_FORM_ID_alter() to alter a specific form.
  675. *
  676. * @param $form
  677. * Nested array of form elements that comprise the form.
  678. * @param $form_state
  679. * A keyed array containing the current state of the form.
  680. * @param $form_id
  681. * String representing the name of the form itself. Typically this is the
  682. * name of the function that generated the form.
  683. */
  684. function hook_form_alter(&$form, $form_state, $form_id) {
  685. if ('node_type_form' == $form_id) {
  686. $form['workflow']['upload'] = array(
  687. '#type' => 'radios',
  688. '#title' => t('Attachments'),
  689. '#default_value' => variable_get('upload_'. $form['#node_type']->type, 1),
  690. '#options' => array(t('Disabled'), t('Enabled')),
  691. );
  692. }
  693. }
  694. /**
  695. * Provide a form-specific alteration instead of the global hook_form_alter().
  696. *
  697. * Modules can implement hook_form_FORM_ID_alter() to modify a specific form,
  698. * rather than implementing hook_form_alter() and checking the form ID, or
  699. * using long switch statements to alter multiple forms.
  700. *
  701. * Note that this hook fires before hook_form_alter(). Therefore all
  702. * implementations of hook_form_FORM_ID_alter() will run before all
  703. * implementations of hook_form_alter(), regardless of the module order.
  704. *
  705. * @param $form
  706. * Nested array of form elements that comprise the form.
  707. * @param $form_state
  708. * A keyed array containing the current state of the form.
  709. * @return
  710. * None.
  711. *
  712. * @see drupal_prepare_form().
  713. */
  714. function hook_form_FORM_ID_alter(&$form, &$form_state) {
  715. // Modification for the form with the given form ID goes here. For example, if
  716. // FORM_ID is "user_register" this code would run only on the user
  717. // registration form.
  718. // Add a checkbox to registration form about agreeing to terms of use.
  719. $form['terms_of_use'] = array(
  720. '#type' => 'checkbox',
  721. '#title' => t("I agree with the website's terms and conditions."),
  722. '#required' => TRUE,
  723. );
  724. }
  725. /**
  726. * Map form_ids to builder functions.
  727. *
  728. * This hook allows modules to build multiple forms from a single form "factory"
  729. * function but each form will have a different form id for submission,
  730. * validation, theming or alteration by other modules.
  731. *
  732. * The callback arguments will be passed as parameters to the function. Callers
  733. * of drupal_get_form() are also able to pass in parameters. These will be
  734. * appended after those specified by hook_forms().
  735. *
  736. * See node_forms() for an actual example of how multiple forms share a common
  737. * building function.
  738. *
  739. * @return
  740. * An array keyed by form id with callbacks and optional, callback arguments.
  741. */
  742. function hook_forms() {
  743. $forms['mymodule_first_form'] = array(
  744. 'callback' => 'mymodule_form_builder',
  745. 'callback arguments' => array('some parameter'),
  746. );
  747. $forms['mymodule_second_form'] = array(
  748. 'callback' => 'mymodule_form_builder',
  749. );
  750. return $forms;
  751. }
  752. /**
  753. * Provide online user help.
  754. *
  755. * By implementing hook_help(), a module can make documentation
  756. * available to the engine or to other modules. All user help should be
  757. * returned using this hook; developer help should be provided with
  758. * Doxygen/api.module comments.
  759. *
  760. * @param $path
  761. * A Drupal menu router path the help is being requested for, e.g.
  762. * admin/node or user/edit. If the router path includes a % wildcard,
  763. * then this will appear in the path - for example all node pages will
  764. * have the path node/% or node/%/view.
  765. * Also recognizes special descriptors after a "#" sign. Some examples:
  766. * - admin/help#modulename
  767. * The module's help text, displayed on the admin/help page and through
  768. * the module's individual help link.
  769. * - user/help#modulename
  770. * The help for a distributed authorization module (if applicable).
  771. * @param $arg
  772. * An array that corresponds to the return of the arg() function - if a module
  773. * needs to provide help for a page with additional parameters after the
  774. * Drupal path or help for a specific value for a wildcard in the path, then
  775. * the values in this array can be referenced. For example you could provide
  776. * help for user/1 by looking for the path user/% and $arg[1] == '1'. This
  777. * array should always be used rather than directly invoking arg(). Note that
  778. * depending on which module is invoking hook_help, $arg may contain only,
  779. * empty strings. Regardless, $arg[0] to $arg[11] will always be set.
  780. * @return
  781. * A localized string containing the help text. Every web link, l(), or
  782. * url() must be replaced with %something and put into the final t()
  783. * call:
  784. * $output .= 'A role defines a group of users that have certain
  785. * privileges as defined in %permission.';
  786. * $output = t($output, array('%permission' => l(t('user permissions'),
  787. * 'admin/user/permission')));
  788. *
  789. * For a detailed usage example, see page_example.module.
  790. */
  791. function hook_help($path, $arg) {
  792. switch ($path) {
  793. case 'admin/help#block':
  794. return '<p>'. t('Blocks are boxes of content that may be rendered into certain regions of your web pages, for example, into sidebars. Blocks are usually generated automatically by modules (e.g., Recent Forum Topics), but administrators can also define custom blocks.') .'</p>';
  795. case 'admin/build/block':
  796. return t('<p>Blocks are boxes of content that may be rendered into certain regions of your web pages, for example, into sidebars. They are usually generated automatically by modules, but administrators can create blocks manually.</p>
  797. <p>If you want certain blocks to disable themselves temporarily during high server loads, check the "Throttle" box. You can configure the auto-throttle on the <a href="@throttle">throttle configuration page</a> after having enabled the throttle module.</p>
  798. <p>You can configure the behaviour of each block (for example, specifying on which pages and for what users it will appear) by clicking the "configure" link for each block.</p>', array('@throttle' => url('admin/settings/throttle')));
  799. }
  800. }
  801. /**
  802. * Perform setup tasks. See also, hook_init.
  803. *
  804. * This hook is run at the beginning of the page request. It is typically
  805. * used to set up global parameters which are needed later in the request.
  806. *
  807. * Only use this hook if your code must run even for cached page views.This hook
  808. * is called before modules or most include files are loaded into memory.
  809. * It happens while Drupal is still in bootstrap mode.
  810. *
  811. * @return
  812. * None.
  813. */
  814. function hook_boot() {
  815. // we need user_access() in the shutdown function. make sure it gets loaded
  816. drupal_load('module', 'user');
  817. register_shutdown_function('devel_shutdown');
  818. }
  819. /**
  820. * Perform setup tasks. See also, hook_boot.
  821. *
  822. * This hook is run at the beginning of the page request. It is typically
  823. * used to set up global parameters which are needed later in the request.
  824. * when this hook is called, all modules are already loaded in memory.
  825. *
  826. * For example, this hook is a typical place for modules to add CSS or JS
  827. * that should be present on every page. This hook is not run on cached
  828. * pages - though CSS or JS added this way will be present on a cached page.
  829. *
  830. * @return
  831. * None.
  832. */
  833. function hook_init() {
  834. drupal_add_css(drupal_get_path('module', 'book') .'/book.css');
  835. }
  836. /**
  837. * Define internal Drupal links.
  838. *
  839. * This hook enables modules to add links to many parts of Drupal. Links
  840. * may be added in nodes or in the navigation block, for example.
  841. *
  842. * The returned array should be a keyed array of link entries. Each link can
  843. * be in one of two formats.
  844. *
  845. * The first format will use the l() function to render the link:
  846. * - attributes: Optional. See l() for usage.
  847. * - fragment: Optional. See l() for usage.
  848. * - href: Required. The URL of the link.
  849. * - html: Optional. See l() for usage.
  850. * - query: Optional. See l() for usage.
  851. * - title: Required. The name of the link.
  852. *
  853. * The second format can be used for non-links. Leaving out the href index will
  854. * select this format:
  855. * - title: Required. The text or HTML code to display.
  856. * - attributes: Optional. An associative array of HTML attributes to apply to the span tag.
  857. * - html: Optional. If not set to true, check_plain() will be run on the title before it is displayed.
  858. *
  859. * @param $type
  860. * An identifier declaring what kind of link is being requested.
  861. * Possible values:
  862. * - comment: Links to be placed below a comment being viewed.
  863. * - node: Links to be placed below a node being viewed.
  864. * @param $object
  865. * A node object or a comment object according to the $type.
  866. * @param $teaser
  867. * In case of node link: a 0/1 flag depending on whether the node is
  868. * displayed with its teaser or its full form.
  869. * @return
  870. * An array of the requested links.
  871. *
  872. */
  873. function hook_link($type, $object, $teaser = FALSE) {
  874. $links = array();
  875. if ($type == 'node' && isset($object->parent)) {
  876. if (!$teaser) {
  877. if (book_access('create', $object)) {
  878. $links['book_add_child'] = array(
  879. 'title' => t('add child page'),
  880. 'href' => "node/add/book/parent/$object->nid",
  881. );
  882. }
  883. if (user_access('see printer-friendly version')) {
  884. $links['book_printer'] = array(
  885. 'title' => t('printer-friendly version'),
  886. 'href' => 'book/export/html/'. $object->nid,
  887. 'attributes' => array('title' => t('Show a printer-friendly version of this book page and its sub-pages.'))
  888. );
  889. }
  890. }
  891. }
  892. $links['sample_link'] = array(
  893. 'title' => t('go somewhere'),
  894. 'href' => 'node/add',
  895. 'query' => 'foo=bar',
  896. 'fragment' => 'anchorname',
  897. 'attributes' => array('title' => t('go to another page')),
  898. );
  899. // Example of a link that's not an anchor
  900. if ($type == 'video') {
  901. if (variable_get('video_playcounter', 1) && user_access('view play counter')) {
  902. $links['play_counter'] = array(
  903. 'title' => format_plural($object->play_counter, '1 play', '@count plays'),
  904. );
  905. }
  906. }
  907. return $links;
  908. }
  909. /**
  910. * Perform alterations before links on a node are rendered. One popular use of
  911. * this hook is to modify/remove links from other modules. If you want to add a link
  912. * to the links section of a node, use hook_link instead.
  913. *
  914. * @param $links
  915. * Nested array of links for the node keyed by providing module.
  916. * @param $node
  917. * A node object that contains the links.
  918. * @return
  919. * None.
  920. */
  921. function hook_link_alter(&$links, $node) {
  922. foreach ($links as $module => $link) {
  923. if (strstr($module, 'taxonomy_term')) {
  924. // Link back to the forum and not the taxonomy term page
  925. $links[$module]['href'] = str_replace('taxonomy/term', 'forum', $link['href']);
  926. }
  927. }
  928. }
  929. /**
  930. * Perform alterations profile items before they are rendered. You may omit/add/re-sort/re-categorize, etc.
  931. *
  932. * @param $account
  933. * A user object whose profile is being rendered. Profile items
  934. * are stored in $account->content.
  935. * @return
  936. * None.
  937. */
  938. function hook_profile_alter(&$account) {
  939. foreach ($account->content AS $key => $field) {
  940. // do something
  941. }
  942. }
  943. /**
  944. * Alter any aspect of email sent by Drupal. You can use this hook to add a
  945. * common site footer to all outgoing email, add extra header fields, and/or
  946. * modify the email in any way. HTML-izing the outgoing email is one possibility.
  947. * See also drupal_mail().
  948. *
  949. * @param $message
  950. * A structured array containing the message to be altered. Keys in this
  951. * array include:
  952. * - 'id'
  953. * An id to identify the mail sent. Look at module source code or
  954. * drupal_mail() for possible id values.
  955. * - 'to'
  956. * The mail address or addresses the message will be sent to. The
  957. * formatting of this string must comply with RFC 2822.
  958. * - 'subject'
  959. * Subject of the e-mail to be sent. This must not contain any newline
  960. * characters, or the mail may not be sent properly.
  961. * - 'body'
  962. * An array of lines containing the message to be sent. Drupal will format
  963. * the correct line endings for you.
  964. * - 'from'
  965. * The address the message will be marked as being from, which is either a
  966. * custom address or the site-wide default email address.
  967. * - 'headers'
  968. * Associative array containing mail headers, such as From, Sender,
  969. * MIME-Version, Content-Type, etc.
  970. */
  971. function hook_mail_alter(&$message) {
  972. if ($message['id'] == 'my_message') {
  973. $message['body'] .= "\n\n--\nMail sent out from " . variable_get('sitename', t('Drupal'));
  974. }
  975. }
  976. /**
  977. * Define menu items and page callbacks.
  978. *
  979. * This hook enables modules to register paths, which determines whose
  980. * requests are to be handled. Depending on the type of registration
  981. * requested by each path, a link is placed in the the navigation block and/or
  982. * an item appears in the menu administration page (q=admin/menu).
  983. *
  984. * This hook is called rarely - for example when modules are enabled.
  985. *
  986. * @return
  987. * An array of menu items. Each menu item has a key corresponding to the
  988. * Drupal path being registered. The item is an associative array that may
  989. * contain the following key-value pairs:
  990. *
  991. * - "title": Required. The untranslated title of the menu item.
  992. * - "title callback": Function to generate the title, defaults to t().
  993. * If you require only the raw string to be output, set this to FALSE.
  994. * - "title arguments": Arguments to send to t() or your custom callback.
  995. * - "description": The untranslated description of the menu item.
  996. * - "page callback": The function to call to display a web page when the user
  997. * visits the path. If omitted, the parent menu item's callback will be used
  998. * instead.
  999. * - "page arguments": An array of arguments to pass to the page callback
  1000. * function. Integer values pass the corresponding URL component (see arg()).
  1001. * - "access callback": A function returning a boolean value that determines
  1002. * whether the user has access rights to this menu item. Defaults to
  1003. * user_access() unless a value is inherited from a parent menu item..
  1004. * - "access arguments": An array of arguments to pass to the access callback
  1005. * function. Integer values pass the corresponding URL component.
  1006. * - "file": A file that will be included before the callbacks are accessed;
  1007. * this allows callback functions to be in separate files. The file should
  1008. * be relative to the implementing module's directory unless otherwise
  1009. * specified by the "file path" option.
  1010. * - "file path": The path to the folder containing the file specified in
  1011. * "file". This defaults to the path to the module implementing the hook.
  1012. * - "weight": An integer that determines relative position of items in the
  1013. * menu; higher-weighted items sink. Defaults to 0. When in doubt, leave
  1014. * this alone; the default alphabetical order is usually best.
  1015. * - "menu_name": Optional. Set this to a custom menu if you don't want your
  1016. * item to be placed in Navigation.
  1017. * - "type": A bitmask of flags describing properties of the menu item.
  1018. * Many shortcut bitmasks are provided as constants in menu.inc:
  1019. * - MENU_NORMAL_ITEM: Normal menu items show up in the menu tree and can be
  1020. * moved/hidden by the administrator.
  1021. * - MENU_CALLBACK: Callbacks simply register a path so that the correct
  1022. * function is fired when the URL is accessed.
  1023. * - MENU_SUGGESTED_ITEM: Modules may "suggest" menu items that the
  1024. * administrator may enable.
  1025. * - MENU_LOCAL_TASK: Local tasks are rendered as tabs by default.
  1026. * - MENU_DEFAULT_LOCAL_TASK: Every set of local tasks should provide one
  1027. * "default" task, that links to the same path as its parent when clicked.
  1028. * If the "type" key is omitted, MENU_NORMAL_ITEM is assumed.
  1029. *
  1030. * For a detailed usage example, see page_example.module.
  1031. *
  1032. * For comprehensive documentation on the menu system, see
  1033. * @link http://drupal.org/node/102338 http://drupal.org/node/102338 @endlink .
  1034. *
  1035. */
  1036. function hook_menu() {
  1037. $items = array();
  1038. $items['blog'] = array(
  1039. 'title' => 'blogs',
  1040. 'description' => 'Listing of blogs.',
  1041. 'page callback' => 'blog_page',
  1042. 'access arguments' => array('access content'),
  1043. 'type' => MENU_SUGGESTED_ITEM,
  1044. );
  1045. $items['blog/feed'] = array(
  1046. 'title' => 'RSS feed',
  1047. 'page callback' => 'blog_feed',
  1048. 'access arguments' => array('access content'),
  1049. 'type' => MENU_CALLBACK,
  1050. );
  1051. return $items;
  1052. }
  1053. /**
  1054. * Alter the information parsed from module and theme .info files
  1055. *
  1056. * This hook is invoked in module_rebuild_cache() and in system_theme_data().
  1057. * A module may implement this hook in order to add to or alter the data
  1058. * generated by reading the .info file with drupal_parse_info_file().
  1059. *
  1060. * @param &$info
  1061. * The .info file contents, passed by reference so that it can be altered.
  1062. * @param $file
  1063. * Full information about the module or theme, including $file->name, and
  1064. * $file->filename
  1065. */
  1066. function hook_system_info_alter(&$info, $file) {
  1067. // Only fill this in if the .info file does not define a 'datestamp'.
  1068. if (empty($info['datestamp'])) {
  1069. $info['datestamp'] = filemtime($file->filename);
  1070. }
  1071. }
  1072. /**
  1073. * Alter the information about available updates for projects.
  1074. *
  1075. * @param $projects
  1076. * Reference to an array of information about available updates to each
  1077. * project installed on the system.
  1078. *
  1079. * @see update_calculate_project_data()
  1080. */
  1081. function hook_update_status_alter(&$projects) {
  1082. $settings = variable_get('update_advanced_project_settings', array());
  1083. foreach ($projects as $project => $project_info) {
  1084. if (isset($settings[$project]) && isset($settings[$project]['check']) &&
  1085. ($settings[$project]['check'] == 'never' ||
  1086. (isset($project_info['recommended']) &&
  1087. $settings[$project]['check'] === $project_info['recommended']))) {
  1088. $projects[$project]['status'] = UPDATE_NOT_CHECKED;
  1089. $projects[$project]['reason'] = t('Ignored from settings');
  1090. if (!empty($settings[$project]['notes'])) {
  1091. $projects[$project]['extra'][] = array(
  1092. 'class' => 'admin-note',
  1093. 'label' => t('Administrator note'),
  1094. 'data' => $settings[$project]['notes'],
  1095. );
  1096. }
  1097. }
  1098. }
  1099. }
  1100. /**
  1101. * Alter the list of projects before fetching data and comparing versions.
  1102. *
  1103. * Most modules will never need to implement this hook. It is for advanced
  1104. * interaction with the update status module: mere mortals need not apply.
  1105. * The primary use-case for this hook is to add projects to the list, for
  1106. * example, to provide update status data on disabled modules and themes. A
  1107. * contributed module might want to hide projects from the list, for example,
  1108. * if there is a site-specific module that doesn't have any official releases,
  1109. * that module could remove itself from this list to avoid "No available
  1110. * releases found" warnings on the available updates report. In rare cases, a
  1111. * module might want to alter the data associated with a project already in
  1112. * the list.
  1113. *
  1114. * @param $projects
  1115. * Reference to an array of the projects installed on the system. This
  1116. * includes all the metadata documented in the comments below for each
  1117. * project (either module or theme) that is currently enabled. The array is
  1118. * initially populated inside update_get_projects() with the help of
  1119. * _update_process_info_list(), so look there for examples of how to
  1120. * populate the array with real values.
  1121. *
  1122. * @see update_get_projects()
  1123. * @see _update_process_info_list()
  1124. */
  1125. function hook_update_projects_alter(&$projects) {
  1126. // Hide a site-specific module from the list.
  1127. unset($projects['site_specific_module']);
  1128. // Add a disabled module to the list.
  1129. // The key for the array should be the machine-readable project "short name".
  1130. $projects['disabled_project_name'] = array(
  1131. // Machine-readable project short name (same as the array key above).
  1132. 'name' => 'disabled_project_name',
  1133. // Array of values from the main .info file for this project.
  1134. 'info' => array(
  1135. 'name' => 'Some disabled module',
  1136. 'description' => 'A module not enabled on the site that you want to see in the available updates report.',
  1137. 'version' => '6.x-1.0',
  1138. 'core' => '6.x',
  1139. // The maximum file change time (the "ctime" returned by the filectime()
  1140. // PHP method) for all of the .info files included in this project.
  1141. '_info_file_ctime' => 1243888165,
  1142. ),
  1143. // The date stamp when the project was released, if known. If the disabled
  1144. // project was an officially packaged release from drupal.org, this will
  1145. // be included in the .info file as the 'datestamp' field. This only
  1146. // really matters for development snapshot releases that are regenerated,
  1147. // so it can be left undefined or set to 0 in most cases.
  1148. 'datestamp' => 1243888185,
  1149. // Any modules (or themes) included in this project. Keyed by machine-
  1150. // readable "short name", value is the human-readable project name printed
  1151. // in the UI.
  1152. 'includes' => array(
  1153. 'disabled_project' => 'Disabled module',
  1154. 'disabled_project_helper' => 'Disabled module helper module',
  1155. 'disabled_project_foo' => 'Disabled module foo add-on module',
  1156. ),
  1157. // Does this project contain a 'module', 'theme', 'disabled-module', or
  1158. // 'disabled-theme'?
  1159. 'project_type' => 'disabled-module',
  1160. );
  1161. }
  1162. /**
  1163. * Inform the node acces…

Large files files are truncated, but you can click here to view the full file