1. 8.2.x vendor/twig/twig/lib/Twig/Extension/Core.php
  2. 8.0.x vendor/twig/twig/lib/Twig/Extension/Core.php
  3. 8.1.x vendor/twig/twig/lib/Twig/Extension/Core.php
  4. 8.3.x vendor/twig/twig/lib/Twig/Extension/Core.php
  5. 4.6.x developer/hooks/core.php
  6. 4.7.x developer/hooks/core.php
  7. 5.x developer/hooks/core.php
  8. 6.x developer/hooks/core.php

These are the hooks that are invoked by the Drupal core.

Core hooks are typically called in all modules at once using module_invoke_all().

File

developer/hooks/core.php
View source
  1. <?php
  2. /**
  3. * @file
  4. * These are the hooks that are invoked by the Drupal core.
  5. *
  6. * Core hooks are typically called in all modules at once using
  7. * module_invoke_all().
  8. */
  9. /**
  10. * @addtogroup hooks
  11. * @{
  12. */
  13. /**
  14. * Declare a block or set of blocks.
  15. *
  16. * Any module can export a block (or blocks) to be displayed by defining
  17. * the _block hook. This hook is called by theme.inc to display a block,
  18. * and also by block.module to procure the list of available blocks.
  19. *
  20. * Since 4.7, all block properties (except theme) can be set in hook_block's
  21. * 'view' operation. You can give your blocks an explicit weight, enable them,
  22. * limit them to given pages, etc. These settings will be registered when the
  23. * block is first loaded at admin/block, and from there can be changed manually
  24. * via block administration.
  25. *
  26. * Note that if you set a region that isn't available in a given theme, the
  27. * block will be registered instead to that theme's default region (the first
  28. * item in the _regions array).
  29. *
  30. * @param $op
  31. * What kind of information to retrieve about the block or blocks.
  32. * Possible values:
  33. * - 'list': A list of all blocks defined by the module.
  34. * - 'configure': A configuration form.
  35. * - 'save': Save the configuration options.
  36. * - 'view': Information about a particular block and default settings.
  37. * @param $delta
  38. * Which block to return (not applicable if $op is 'list'). Although it is
  39. * most commonly an integer starting at 0, this is not mandatory. For
  40. * instance, aggregator.module uses string values for $delta
  41. * @param $edit
  42. * - If $op is 'save', the submitted form data from the configuration form.
  43. * - In other cases, it is ignored
  44. * @return
  45. * - If $op is 'list', return an array of arrays, each of which must define
  46. * an 'info' element describing the block.
  47. * - If $op is 'configure', optionally return a array containing the
  48. * configuration form.
  49. * - If $op is 'save', return nothing,
  50. * - If $op is 'view', return an array which must define a 'subject'
  51. * element and a 'content' element defining the block indexed by
  52. * $delta.
  53. *
  54. * The functions mymodule_display_block_1 and 2, as used in the example,
  55. * should of course be defined somewhere in your module and return the
  56. * content you want to display to your users. If the "content" element
  57. * is empty, no block will be displayed even if "subject" is present.
  58. *
  59. * After completing your blocks, do not forget to enable them in the
  60. * block admin menu.
  61. *
  62. * For a detailed usage example, see block_example.module.
  63. */
  64. function hook_block($op = 'list', $delta = 0, $edit = array()) {
  65. if ($op == 'list') {
  66. $blocks[0] = array('info' => t('Mymodule block #1 shows ...'),
  67. 'weight' => 0, 'status' => 1, 'region' => 'left');
  68. $blocks[1] = array('info' => t('Mymodule block #2 describes ...'),
  69. 'weight' => 0, 'status' => 0, 'region' => 'right');
  70. return $blocks;
  71. }
  72. elseif ($op == 'configure' && $delta == 0) {
  73. $form['items'] = array(
  74. '#type' => 'select',
  75. '#title' => t('Number of items'),
  76. '#default_value' => variable_get('mymodule_block_items', 0),
  77. '#options' => array('1', '2', '3'),
  78. );
  79. return $form;
  80. }
  81. else if ($op == 'save' && $delta == 0) {
  82. variable_set('mymodule_block_items', $edit['items']);
  83. }
  84. else if ($op == 'view') {
  85. switch($delta) {
  86. case 0:
  87. $block = array('subject' => t('Title of block #1'),
  88. 'content' => mymodule_display_block_1());
  89. break;
  90. case 1:
  91. $block = array('subject' => t('Title of block #2'),
  92. 'content' => mymodule_display_block_2());
  93. break;
  94. }
  95. return $block;
  96. }
  97. }
  98. /**
  99. * Act on comments.
  100. *
  101. * This hook allows modules to extend the comments system.
  102. *
  103. * @param $a1
  104. * Dependent on the action being performed.
  105. * - For "form", passes in the comment form.
  106. * - For "validate","update","insert", passes in an array of form values submitted by the user.
  107. * - For all other operations, passes in the comment the action is being performed on.
  108. * @param $op
  109. * What kind of action is being performed. Possible values:
  110. * - "insert": The comment is being inserted.
  111. * - "update": The comment is being updated.
  112. * - "view": The comment is being viewed. This hook can be used to add additional data to the comment before theming.
  113. * - "form": The comment form is about to be shown. Modules may add fields to the form at this point.
  114. * - "validate": The user has just finished editing the comment and is
  115. * trying to preview or submit it. This hook can be used to check or
  116. * even modify the node. Errors should be set with form_set_error().
  117. * - "publish": The comment is being published by the moderator.
  118. * - "unpublish": The comment is being unpublished by the moderator.
  119. * - "delete": The comment is being deleted by the moderator.
  120. * @return
  121. * Dependent on the action being performed.
  122. * - For "form", an array of form elements to add to the comment form.
  123. * - For all other operations, nothing.
  124. */
  125. function hook_comment(&$a1, $op) {
  126. if ($op == 'insert' || $op == 'update') {
  127. $nid = $a1['nid'];
  128. }
  129. cache_clear_all_like(drupal_url(array('id' => $nid)));
  130. }
  131. /**
  132. * Perform periodic actions.
  133. *
  134. * Modules that require to schedule some commands to be executed at regular
  135. * intervals can implement hook_cron(). The engine will then call the hook
  136. * at the appropriate intervals defined by the administrator. This interface
  137. * is particularly handy to implement timers or to automate certain tasks.
  138. * Database maintenance, recalculation of settings or parameters, and
  139. * automatic mailings are good candidates for cron tasks.
  140. *
  141. * @return
  142. * None.
  143. *
  144. * This hook will only be called if cron.php is run (e.g. by crontab).
  145. */
  146. function hook_cron() {
  147. $result = db_query('SELECT * FROM {site} WHERE checked = 0 OR checked
  148. + refresh < %d', time());
  149. while ($site = db_fetch_array($result)) {
  150. cloud_update($site);
  151. }
  152. }
  153. /**
  154. * Add JOIN and WHERE statements to queries and decide whether the primary_field
  155. * shall be made DISTINCT. For node objects, primary field is always called nid.
  156. * For taxonomy terms, it is tid and for vocabularies it is vid. For comments,
  157. * it is cid. Primary table is the table where the primary object (node, file,
  158. * term_node etc.) is.
  159. *
  160. * You shall return an associative array. Possible keys are 'join', 'where' and
  161. * 'distinct'. The value of 'distinct' shall be 1 if you want that the
  162. * primary_field made DISTINCT.
  163. *
  164. * @param $query
  165. * Query to be rewritten.
  166. * @param $primary_table
  167. * Name or alias of the table which has the primary key field for this query.
  168. * Typical table names would be: {blocks}, {comments}, {forum}, {node},
  169. * {menu}, {term_data} or {vocabulary}. However, it is more common for
  170. * $primary_table to contain the usual table alias: b, c, f, n, m, t or v.
  171. * @param $primary_field
  172. * Name of the primary field.
  173. * @param $args
  174. * Array of additional arguments.
  175. * @return
  176. * An array of join statements, where statements, distinct decision.
  177. */
  178. function hook_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
  179. switch ($primary_field) {
  180. case 'nid':
  181. // this query deals with node objects
  182. $return = array();
  183. if ($primary_table != 'n') {
  184. $return['join'] = "LEFT JOIN {node} n ON $primary_table.nid = n.nid";
  185. }
  186. $return['where'] = 'created >' . mktime(0, 0, 0, 1, 1, 2005);
  187. return $return;
  188. break;
  189. case 'tid':
  190. // this query deals with taxonomy objects
  191. break;
  192. case 'vid':
  193. // this query deals with vocabulary objects
  194. break;
  195. }
  196. }
  197. /**
  198. * Allows modules to declare their own form element types and specify their
  199. * default values.
  200. *
  201. * @return
  202. * An array of element types
  203. */
  204. function hook_elements() {
  205. $type['filter_format'] = array('#input' => TRUE);
  206. return $type;
  207. }
  208. /**
  209. * Perform cleanup tasks.
  210. *
  211. * This hook is run at the end of each page request. It is often used for
  212. * page logging and printing out debugging information.
  213. *
  214. * Only use this hook if your code must run even for cached page views.
  215. * If you have code which must run once on all non cached pages, use
  216. * hook_menu(!$may_cache) instead. Thats the usual case. If you implement this
  217. * hook and see an error like 'Call to undefined function', it is likely that
  218. * you are depending on the presence of a module which has not been loaded yet.
  219. * It is not loaded because Drupal is still in bootstrap mode. The usual fix is
  220. * to move your code to hook_menu(!$may_cache).
  221. *
  222. * @param $destination
  223. * If this hook is invoked as part of a drupal_goto() call, then this argument
  224. * will be a fully-qualified URL that is the destination of the redirect.
  225. * Modules may use this to react appropriately; for example, nothing should
  226. * be output in this case, because PHP will then throw a "headers cannot be
  227. * modified" error when attempting the redirection.
  228. * @return
  229. * None.
  230. */
  231. function hook_exit($destination = NULL) {
  232. db_query('UPDATE {counter} SET hits = hits + 1 WHERE type = 1');
  233. }
  234. /**
  235. * Allow file downloads.
  236. *
  237. * @param $file
  238. * String of the file's path.
  239. * @return
  240. * If the user does not have permission to access the file, return -1. If the
  241. * user has permission, return an array with the appropriate headers.
  242. */
  243. function hook_file_download($file) {
  244. if (user_access('access content')) {
  245. if ($filemime = db_result(db_query("SELECT filemime FROM {fileupload} WHERE filepath = '%s'", file_create_path($file)))) {
  246. return array('Content-type:' . $filemime);
  247. }
  248. }
  249. else {
  250. return -1;
  251. }
  252. }
  253. /**
  254. * Define content filters.
  255. *
  256. * Content in Drupal is passed through all enabled filters before it is
  257. * output. This lets a module modify content to the site administrator's
  258. * liking.
  259. *
  260. * This hook contains all that is needed for having a module provide filtering
  261. * functionality.
  262. *
  263. * Depending on $op, different tasks are performed.
  264. *
  265. * A module can contain as many filters as it wants. The 'list' operation tells
  266. * the filter system which filters are available. Every filter has a numerical
  267. * 'delta' which is used to refer to it in every operation.
  268. *
  269. * Filtering is a two-step process. First, the content is 'prepared' by calling
  270. * the 'prepare' operation for every filter. The purpose of 'prepare' is to
  271. * escape HTML-like structures. For example, imagine a filter which allows the
  272. * user to paste entire chunks of programming code without requiring manual
  273. * escaping of special HTML characters like @< or @&. If the programming code
  274. * were left untouched, then other filters could think it was HTML and change
  275. * it. For most filters however, the prepare-step is not necessary, and they can
  276. * just return the input without changes.
  277. *
  278. * Filters should not use the 'prepare' step for anything other than escaping,
  279. * because that would short-circuits the control the user has over the order
  280. * in which filters are applied.
  281. *
  282. * The second step is the actual processing step. The result from the
  283. * prepare-step gets passed to all the filters again, this time with the
  284. * 'process' operation. It's here that filters should perform actual changing of
  285. * the content: transforming URLs into hyperlinks, converting smileys into
  286. * images, etc.
  287. *
  288. * An important aspect of the filtering system are 'input formats'. Every input
  289. * format is an entire filter setup: which filters to enable, in what order
  290. * and with what settings. Filters that provide settings should usually store
  291. * these settings per format.
  292. *
  293. * If the filter's behaviour depends on an extensive list and/or external data
  294. * (e.g. a list of smileys, a list of glossary terms) then filters are allowed
  295. * to provide a separate, global configuration page rather than provide settings
  296. * per format. In that case, there should be a link from the format-specific
  297. * settings to the separate settings page.
  298. *
  299. * For performance reasons content is only filtered once; the result is stored
  300. * in the cache table and retrieved the next time the piece of content is
  301. * displayed. If a filter's output is dynamic it can override the cache
  302. * mechanism, but obviously this feature should be used with caution: having one
  303. * 'no cache' filter in a particular input format disables caching for the
  304. * entire format, not just for one filter.
  305. *
  306. * Beware of the filter cache when developing your module: it is advised to set
  307. * your filter to 'no cache' while developing, but be sure to remove it again
  308. * if it's not needed. You can clear the cache by running the SQL query 'DELETE
  309. * FROM cache';
  310. *
  311. * @param $op
  312. * Which filtering operation to perform. Possible values:
  313. * - list: provide a list of available filters.
  314. * Returns an associative array of filter names with numerical keys.
  315. * These keys are used for subsequent operations and passed back through
  316. * the $delta parameter.
  317. * - no cache: Return true if caching should be disabled for this filter.
  318. * - description: Return a short description of what this filter does.
  319. * - prepare: Return the prepared version of the content in $text.
  320. * - process: Return the processed version of the content in $text.
  321. * - settings: Return HTML form controls for the filter's settings. These
  322. * settings are stored with variable_set() when the form is submitted.
  323. * Remember to use the $format identifier in the variable and control names
  324. * to store settings per input format (e.g. "mymodule_setting_$format").
  325. * @param $delta
  326. * Which of the module's filters to use (applies to every operation except
  327. * 'list'). Modules that only contain one filter can ignore this parameter.
  328. * @param $format
  329. * Which input format the filter is being used in (applies to 'prepare',
  330. * 'process' and 'settings').
  331. * @param $text
  332. * The content to filter (applies to 'prepare' and 'process').
  333. * @return
  334. * The return value depends on $op. The filter hook is designed so that a
  335. * module can return $text for operations it does not use/need.
  336. *
  337. * For a detailed usage example, see filter_example.module. For an example of
  338. * using multiple filters in one module, see filter_filter() and
  339. * filter_filter_tips().
  340. */
  341. function hook_filter($op, $delta = 0, $format = -1, $text = '') {
  342. switch ($op) {
  343. case 'list':
  344. return array(0 => t('Code filter'));
  345. case 'description':
  346. return t('Allows users to post code verbatim using &lt;code&gt; and &lt;?php ?&gt; tags.');
  347. case 'prepare':
  348. // Note: we use the bytes 0xFE and 0xFF to replace < > during the
  349. // filtering process. These bytes are not valid in UTF-8 data and thus
  350. // least likely to cause problems.
  351. $text = preg_replace('@<code>(.+?)</code>@se', "'\xFEcode\xFF'. codefilter_escape('\\1') .'\xFE/code\xFF'", $text);
  352. $text = preg_replace('@<(\?(php)?|%)(.+?)(\?|%)>@se', "'\xFEphp\xFF'. codefilter_escape('\\3') .'\xFE/php\xFF'", $text);
  353. return $text;
  354. case "process":
  355. $text = preg_replace('@\xFEcode\xFF(.+?)\xFE/code\xFF@se', "codefilter_process_code('$1')", $text);
  356. $text = preg_replace('@\xFEphp\xFF(.+?)\xFE/php\xFF@se', "codefilter_process_php('$1')", $text);
  357. return $text;
  358. default:
  359. return $text;
  360. }
  361. }
  362. /**
  363. * Provide tips for using filters.
  364. *
  365. * A module's tips should be informative and to the point. Short tips are
  366. * preferably one-liners.
  367. *
  368. * @param $delta
  369. * Which of this module's filters to use. Modules which only implement one
  370. * filter can ignore this parameter.
  371. * @param $format
  372. * Which format we are providing tips for.
  373. * @param $long
  374. * If set to true, long tips are requested, otherwise short tips are needed.
  375. * @return
  376. * The text of the filter tip.
  377. *
  378. *
  379. */
  380. function hook_filter_tips($delta, $format, $long = false) {
  381. if ($long) {
  382. 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.');
  383. }
  384. else {
  385. return t('You may post code using &lt;code&gt;...&lt;/code&gt; (generic) or &lt;?php ... ?&gt; (highlighted PHP) tags.');
  386. }
  387. }
  388. /**
  389. * Insert closing HTML.
  390. *
  391. * This hook enables modules to insert HTML just before the \</body\> closing
  392. * tag of web pages. This is useful for including javascript code and for
  393. * outputting debug information.
  394. *
  395. * @param $main
  396. * Whether the current page is the front page of the site.
  397. * @return
  398. * The HTML to be inserted.
  399. */
  400. function hook_footer($main = 0) {
  401. if (variable_get('dev_query', 0)) {
  402. return '<div style="clear:both;">'. devel_query_table() .'</div>';
  403. }
  404. }
  405. /**
  406. * Perform alterations before a form is rendered.
  407. *
  408. * One popular use of this hook is to add form elements to the node form. When
  409. * altering a node form, the node object retrieved at from $form['#node'].
  410. *
  411. * @param $form_id
  412. * String representing the name of the form itself. Typically this is the
  413. * name of the function that generated the form.
  414. * @param $form
  415. * Nested array of form elements that comprise the form.
  416. * @return
  417. * None.
  418. */
  419. function hook_form_alter($form_id, &$form) {
  420. if (isset($form['type']) && $form['type']['#value'] .'_node_settings' == $form_id) {
  421. $form['workflow']['upload_'. $form['type']['#value']] = array(
  422. '#type' => 'radios',
  423. '#title' => t('Attachments'),
  424. '#default_value' => variable_get('upload_'. $form['type']['#value'], 1),
  425. '#options' => array(t('Disabled'), t('Enabled')),
  426. );
  427. }
  428. }
  429. /**
  430. * Map form_ids to builder functions.
  431. *
  432. * This hook allows modules to build multiple forms from a single form "factory"
  433. * function but each form will have a different form id for submission,
  434. * validation, theming or alteration by other modules.
  435. *
  436. * The callback arguments will be passed as parameters to the function. Callers
  437. * of drupal_get_form() are also able to pass in parameters. These will be
  438. * appended after those specified by hook_forms().
  439. *
  440. * See node_forms() for an actual example of how multiple forms share a common
  441. * building function.
  442. *
  443. * @return
  444. * An array keyed by form id with callbacks and optional, callback arguments.
  445. */
  446. function hook_forms() {
  447. $forms['mymodule_first_form'] = array(
  448. 'callback' => 'mymodule_form_builder',
  449. 'callback arguments' => array('some parameter'),
  450. );
  451. $forms['mymodule_second_form'] = array(
  452. 'callback' => 'mymodule_form_builder',
  453. );
  454. return $forms;
  455. }
  456. /**
  457. * Provide online user help.
  458. *
  459. * By implementing hook_help(), a module can make documentation
  460. * available to the engine or to other modules. All user help should be
  461. * returned using this hook; developer help should be provided with
  462. * Doxygen/api.module comments.
  463. *
  464. * @param $section
  465. * Drupal URL path (or: menu item) the help is being requested for, e.g.
  466. * admin/node or user/edit. Recognizes special descriptors after a "#"
  467. * sign. Some examples:
  468. * - admin/modules#name
  469. * The name of a module (unused, but there)
  470. * - admin/help#modulename
  471. * The module's help text, displayed on the admin/help page and through
  472. * the module's individual help link.
  473. * - user/help#modulename
  474. * The help for a distributed authorization module (if applicable).
  475. * - node/add#nodetype
  476. * The description of a node type (if applicable).
  477. * @return
  478. * A localized string containing the help text. Every web link, l(), or
  479. * url() must be replaced with %something and put into the final t()
  480. * call:
  481. * $output .= 'A role defines a group of users that have certain
  482. * privileges as defined in !permission.';
  483. * $output = t($output, array('!permission' => l(t('user permissions'),
  484. * 'admin/user/permission')));
  485. *
  486. * For a detailed usage example, see page_example.module.
  487. */
  488. function hook_help($section) {
  489. switch ($section) {
  490. case 'admin/help#block':
  491. 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>';
  492. case 'admin/build/block':
  493. 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>
  494. <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>
  495. <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')));
  496. }
  497. }
  498. /**
  499. * Perform setup tasks.
  500. *
  501. * This hook is run at the beginning of the page request. It is typically
  502. * used to set up global parameters which are needed later in the request.
  503. *
  504. * Only use this hook if your code must run even for cached page views. If you
  505. * have code which must run once on all non cached pages, use
  506. * hook_menu(!$may_cache) instead. Thats the usual case. If you implement this
  507. * hook and see an error like 'Call to undefined function', it is likely that
  508. * you are depending on the presence of a module which has not been loaded yet.
  509. * It is not loaded because Drupal is still in bootstrap mode. The usual fix is
  510. * to move your code to hook_menu(!$may_cache).
  511. *
  512. * @return
  513. * None.
  514. */
  515. function hook_init() {
  516. global $recent_activity;
  517. if ((variable_get('statistics_enable_auto_throttle', 0)) &&
  518. (!rand(0, variable_get('statistics_probability_limiter', 9)))) {
  519. $throttle = throttle_status();
  520. // if we're at throttle level 5, we don't do anything
  521. if ($throttle < 5) {
  522. $multiplier = variable_get('statistics_throttle_multiplier', 60);
  523. // count all hits in past sixty seconds
  524. $result = db_query('SELECT COUNT(timestamp) AS hits FROM
  525. {accesslog} WHERE timestamp >= %d', (time() - 60));
  526. $recent_activity = db_fetch_array($result);
  527. throttle_update($recent_activity['hits']);
  528. }
  529. }
  530. }
  531. /**
  532. * Define internal Drupal links.
  533. *
  534. * This hook enables modules to add links to many parts of Drupal. Links
  535. * may be added in nodes or in the navigation block, for example.
  536. *
  537. * The returned array should be a keyed array of link entries. Each link can
  538. * be in one of two formats.
  539. *
  540. * The first format will use the l() function to render the link:
  541. * - href: Required. The URL of the link.
  542. * - title: Required. The name of the link.
  543. * - attributes: Optional. See l() for usage.
  544. * - html: Optional. See l() for usage.
  545. * - query: Optional. See l() for usage.
  546. * - fragment: Optional. See l() for usage.
  547. *
  548. * The second format can be used for non-links. Leaving out the href index will
  549. * select this format:
  550. * - title: Required. The text or HTML code to display.
  551. * - attributes: Optional. An associative array of HTML attributes to apply to the span tag.
  552. * - html: Optional. If not set to true, check_plain() will be run on the title before it is displayed.
  553. *
  554. * @param $type
  555. * An identifier declaring what kind of link is being requested.
  556. * Possible values:
  557. * - node: Links to be placed below a node being viewed.
  558. * - comment: Links to be placed below a comment being viewed.
  559. * @param $node
  560. * A node object passed in case of node links.
  561. * @param $teaser
  562. * In case of node link: a 0/1 flag depending on whether the node is
  563. * displayed with its teaser or its full form (on a node/nid page)
  564. * @return
  565. * An array of the requested links.
  566. *
  567. */
  568. function hook_link($type, $node = NULL, $teaser = FALSE) {
  569. $links = array();
  570. if ($type == 'node' && isset($node->parent)) {
  571. if (!$teaser) {
  572. if (book_access('create', $node)) {
  573. $links['book_add_child'] = array(
  574. 'title' => t('add child page'),
  575. 'href' => "node/add/book/parent/$node->nid",
  576. );
  577. }
  578. if (user_access('see printer-friendly version')) {
  579. $links['book_printer'] = array(
  580. 'title' => t('printer-friendly version'),
  581. 'href' => 'book/export/html/'. $node->nid,
  582. 'attributes' => array('title' => t('Show a printer-friendly version of this book page and its sub-pages.'))
  583. );
  584. }
  585. }
  586. }
  587. $links['sample_link'] = array(
  588. 'title' => t('go somewhere'),
  589. 'href' => 'node/add',
  590. 'query' => 'foo=bar',
  591. 'fragment' => 'anchorname',
  592. 'attributes' => array('title' => t('go to another page')),
  593. );
  594. // Example of a link that's not an anchor
  595. if ($type == 'video') {
  596. if (variable_get('video_playcounter', 1) && user_access('view play counter')) {
  597. $links['play_counter'] = array(
  598. 'title' => format_plural($node->play_counter, '1 play', '@count plays'),
  599. );
  600. }
  601. }
  602. return $links;
  603. }
  604. /**
  605. * Perform alterations before links on a node are rendered. One popular use of
  606. * this hook is to modify/remove links from other modules. If you want to add a link
  607. * to the links section of a node, use hook_link instead.
  608. *
  609. * @param $node
  610. * A node object for editing links on
  611. * @param $links
  612. * Nested array of links for the node
  613. * @return
  614. * None.
  615. */
  616. function hook_link_alter(&$node, &$links) {
  617. foreach ($links as $module => $link) {
  618. if (strstr($module, 'taxonomy_term')) {
  619. // Link back to the forum and not the taxonomy term page
  620. $links[$module]['href'] = str_replace('taxonomy/term', 'forum', $link['href']);
  621. }
  622. }
  623. }
  624. /**
  625. * Perform alterations profile items before they are rendered. You may omit/add/re-sort/re-categorize, etc.
  626. *
  627. * @param $account
  628. * A user object specifying whose profile is being rendered
  629. * @param $fields
  630. * An array of $field objects, with unique module specified keys. Use this $key to find the item you care about.
  631. * @return
  632. * None.
  633. */
  634. function hook_profile_alter(&$account, &$fields) {
  635. foreach ($fields AS $key => $field) {
  636. // do something
  637. }
  638. }
  639. /**
  640. * Alter any aspect of the emails sent by Drupal. You can use this hook
  641. * to add a common site footer to all outgoing emails; add extra header
  642. * fields and/or modify the mails sent out in any way. HTML-izing the
  643. * outgoing mails is one possibility. See also drupal_mail().
  644. *
  645. * @param $mailkey
  646. * A key to indetify the mail sent. Look into the module source codes
  647. * for possible mailkey values.
  648. * @param $to
  649. * The mail address or addresses where the message will be send to. The
  650. * formatting of this string must comply with RFC 2822.
  651. * @param $subject
  652. * Subject of the e-mail to be sent. This must not contain any newline
  653. * characters, or the mail may not be sent properly.
  654. * @param $body
  655. * Message to be sent. Drupal will format the correct line endings for you.
  656. * @param $from
  657. * The From, Reply-To, Return-Path and Error-To headers in $headers
  658. * are already set to this value (if given).
  659. * @param $headers
  660. * Associative array containing the headers to add. This is typically
  661. * used to add extra headers (From, Cc, and Bcc).
  662. * @return
  663. * The return value is discarded. Modify the parameters directly.
  664. */
  665. function hook_mail_alter(&$mailkey, &$to, &$subject, &$body, &$from, &$headers) {
  666. $body .= "\n\n--\nMail sent out from " . variable_get('sitename', t('Drupal'));
  667. }
  668. /**
  669. * Define menu items and page callbacks.
  670. *
  671. * This hook enables modules to register paths, which determines whose
  672. * requests are to be handled. Depending on the type of registration
  673. * requested by each path, a link is placed in the the navigation block and/or
  674. * an item appears in the menu administration page (q=admin/menu).
  675. *
  676. * Drupal will call this hook twice: once with $may_cache set to TRUE, and once
  677. * with it set to FALSE. Therefore, each menu item should be registered when
  678. * $may_cache is either TRUE or FALSE, not both times. Setting a menu item
  679. * twice will result in unspecified behavior.
  680. *
  681. * This hook is also a good place to put code which should run exactly once
  682. * per page view. Put it in an if (!may_cache) block.
  683. *
  684. * @param $may_cache
  685. * A boolean indicating whether cacheable menu items should be returned. The
  686. * menu cache is per-user, so items can be cached so long as they are not
  687. * dependent on the user's current location. See the local task definitions
  688. * in node_menu() for an example of uncacheable menu items.
  689. * @return
  690. * An array of menu items. Each menu item is an associative array that may
  691. * contain the following key-value pairs:
  692. * - "path": Required. The path to link to when the user selects the item.
  693. * - "title": Required. The translated title of the menu item.
  694. * - "callback": The function to call to display a web page when the user
  695. * visits the path. If omitted, the parent menu item's callback will be used
  696. * instead.
  697. * - "callback arguments": An array of arguments to pass to the callback
  698. * function.
  699. * - "access": A boolean value that determines whether the user has access
  700. * rights to this menu item. Usually determined by a call to user_access().
  701. * If omitted and "callback" is also absent, the access rights of the parent
  702. * menu item will be used instead.
  703. * - "weight": An integer that determines relative position of items in the
  704. * menu; higher-weighted items sink. Defaults to 0. When in doubt, leave
  705. * this alone; the default alphabetical order is usually best.
  706. * - "type": A bitmask of flags describing properties of the menu item.
  707. * Many shortcut bitmasks are provided as constants in menu.inc:
  708. * - MENU_NORMAL_ITEM: Normal menu items show up in the menu tree and can be
  709. * moved/hidden by the administrator.
  710. * - MENU_ITEM_GROUPING: Item groupings are used for pages like "node/add"
  711. * that simply list subpages to visit.
  712. * - MENU_CALLBACK: Callbacks simply register a path so that the correct
  713. * function is fired when the URL is accessed.
  714. * - MENU_DYNAMIC_ITEM: Dynamic menu items change frequently, and so should
  715. * not be stored in the database for administrative customization.
  716. * - MENU_SUGGESTED_ITEM: Modules may "suggest" menu items that the
  717. * administrator may enable.
  718. * - MENU_LOCAL_TASK: Local tasks are rendered as tabs by default.
  719. * - MENU_DEFAULT_LOCAL_TASK: Every set of local tasks should provide one
  720. * "default" task, that links to the same path as its parent when clicked.
  721. * If the "type" key is omitted, MENU_NORMAL_ITEM is assumed.
  722. *
  723. * For a detailed usage example, see page_example.module.
  724. *
  725. */
  726. function hook_menu($may_cache) {
  727. global $user;
  728. $items = array();
  729. if ($may_cache) {
  730. $items[] = array('path' => 'node/add/blog', 'title' => t('blog entry'),
  731. 'access' => user_access('maintain personal blog'));
  732. $items[] = array('path' => 'blog', 'title' => t('blogs'),
  733. 'callback' => 'blog_page',
  734. 'access' => user_access('access content'),
  735. 'type' => MENU_SUGGESTED_ITEM);
  736. $items[] = array('path' => 'blog/'. $user->uid, 'title' => t('my blog'),
  737. 'access' => user_access('maintain personal blog'),
  738. 'type' => MENU_DYNAMIC_ITEM);
  739. $items[] = array('path' => 'blog/feed', 'title' => t('RSS feed'),
  740. 'callback' => 'blog_feed',
  741. 'access' => user_access('access content'),
  742. 'type' => MENU_CALLBACK);
  743. }
  744. return $items;
  745. }
  746. /**
  747. * Inform the node access system what permissions the user has.
  748. *
  749. * This hook is for implementation by node access modules. In addition to
  750. * managing access rights for nodes, the node access module must tell
  751. * the node access system what 'grant IDs' the current user has. In many
  752. * cases, the grant IDs will simply be role IDs, but grant IDs can be
  753. * arbitrary based upon the module.
  754. *
  755. * For example, modules can maintain their own lists of users, where each
  756. * list has an ID. In that case, the module could return a list of all
  757. * IDs of all lists that the current user is a member of.
  758. *
  759. * A node access module may implement as many realms as necessary to
  760. * properly define the access privileges for the nodes.
  761. *
  762. * @param $user
  763. * The user object whose grants are requested.
  764. * @param $op
  765. * The node operation to be performed, such as "view", "update", or "delete".
  766. * @return
  767. * An array whose keys are "realms" of grants such as "user" or "role", and
  768. * whose values are linear lists of grant IDs.
  769. *
  770. * For a detailed example, see node_access_example.module.
  771. *
  772. * @ingroup node_access
  773. */
  774. function hook_node_grants($account, $op) {
  775. if (user_access('access private content', $account)) {
  776. $grants['example'] = array(1);
  777. }
  778. $grants['example_owner'] = array($user->uid);
  779. return $grants;
  780. }
  781. /**
  782. * Set permissions for a node to be written to the database.
  783. *
  784. * When a node is saved, a module implementing node access will be asked
  785. * if it is interested in the access permissions to a node. If it is
  786. * interested, it must respond with an array of array of permissions for that
  787. * node.
  788. *
  789. * Each item in the array should contain:
  790. *
  791. * 'realm'
  792. * This should only be realms for which the module has returned
  793. * grant IDs in hook_node_grants.
  794. * 'gid'
  795. * This is a 'grant ID', which can have an arbitrary meaning per realm.
  796. * 'grant_view'
  797. * If set to TRUE a user with the gid in the realm can view this node.
  798. * 'grant_edit'
  799. * If set to TRUE a user with the gid in the realm can edit this node.
  800. * 'grant_delete'
  801. * If set to TRUE a user with the gid in the realm can delete this node.
  802. * 'priority'
  803. * If multiple modules seek to set permissions on a node, the realms
  804. * that have the highest priority will win out, and realms with a lower
  805. * priority will not be written. If there is any doubt, it is best to
  806. * leave this 0.
  807. *
  808. * @ingroup node_access
  809. */
  810. function hook_node_access_records($node) {
  811. if (node_access_example_disabling()) {
  812. return;
  813. }
  814. // We only care about the node if it's been marked private. If not, it is
  815. // treated just like any other node and we completely ignore it.
  816. if ($node->private) {
  817. $grants = array();
  818. $grants[] = array(
  819. 'realm' => 'example',
  820. 'gid' => TRUE,
  821. 'grant_view' => TRUE,
  822. 'grant_update' => FALSE,
  823. 'grant_delete' => FALSE,
  824. 'priority' => 0,
  825. );
  826. // For the example_author array, the GID is equivalent to a UID, which
  827. // means there are many many groups of just 1 user.
  828. $grants[] = array(
  829. 'realm' => 'example_author',
  830. 'gid' => $node->uid,
  831. 'grant_view' => TRUE,
  832. 'grant_update' => TRUE,
  833. 'grant_delete' => TRUE,
  834. 'priority' => 0,
  835. );
  836. return $grants;
  837. }
  838. }
  839. /**
  840. * Add mass node operations.
  841. *
  842. * This hook enables modules to inject custom operations into the mass operations
  843. * dropdown found at admin/content/node, by associating a callback function with
  844. * the operation, which is called when the form is submitted. The callback function
  845. * receives one initial argument, which is an array of the checked nodes.
  846. *
  847. * @return
  848. * An array of operations. Each operation is an associative array that may
  849. * contain the following key-value pairs:
  850. * - "label": Required. The label for the operation, displayed in the dropdown menu.
  851. * - "callback": Required. The function to call for the operation.
  852. * - "callback arguments": Optional. An array of additional arguments to pass to
  853. * the callback function.
  854. *
  855. */
  856. function hook_node_operations() {
  857. $operations = array(
  858. 'approve' => array(
  859. 'label' => t('Approve the selected posts'),
  860. 'callback' => 'node_operations_approve',
  861. ),
  862. 'promote' => array(
  863. 'label' => t('Promote the selected posts'),
  864. 'callback' => 'node_operations_promote',
  865. ),
  866. 'sticky' => array(
  867. 'label' => t('Make the selected posts sticky'),
  868. 'callback' => 'node_operations_sticky',
  869. ),
  870. 'demote' => array(
  871. 'label' => t('Demote the selected posts'),
  872. 'callback' => 'node_operations_demote',
  873. ),
  874. 'unpublish' => array(
  875. 'label' => t('Unpublish the selected posts'),
  876. 'callback' => 'node_operations_unpublish',
  877. ),
  878. 'delete' => array(
  879. 'label' => t('Delete the selected posts'),
  880. ),
  881. );
  882. return $operations;
  883. }
  884. /**
  885. * Act on nodes defined by other modules.
  886. *
  887. * Despite what its name might make you think, hook_nodeapi() is not
  888. * reserved for node modules. On the contrary, it allows modules to react
  889. * to actions affecting all kinds of nodes, regardless of whether that
  890. * module defined the node.
  891. *
  892. * @param &$node
  893. * The node the action is being performed on.
  894. * @param $op
  895. * What kind of action is being performed. Possible values:
  896. * - "delete": The node is being deleted.
  897. * - "delete revision": The revision of the node is deleted. You can delete data
  898. * associated with that revision.
  899. * - "insert": The node is being created (inserted in the database).
  900. * - "load": The node is about to be loaded from the database. This hook
  901. * can be used to load additional data at this time.
  902. * - "prepare": The node is about to be shown on the add/edit form.
  903. * - "search result": The node is displayed as a search result. If you
  904. * want to display extra information with the result, return it.
  905. * - "print": Prepare a node view for printing. Used for printer-friendly
  906. * view in book_module
  907. * - "update": The node is being updated.
  908. * - "submit": The node passed validation and will soon be saved. Modules may
  909. * use this to make changes to the node before it is saved to the database.
  910. * - "update index": The node is being indexed. If you want additional
  911. * information to be indexed which is not already visible through
  912. * nodeapi "view", then you should return it here.
  913. * - "validate": The user has just finished editing the node and is
  914. * trying to preview or submit it. This hook can be used to check
  915. * the node data. Errors should be set with form_set_error().
  916. * - "view": The node content is being assembled before rendering. The module
  917. * may add elements $node->content prior to rendering. This hook will be
  918. * called after hook_view(). The format of $node->content is the same as
  919. * used by Forms API.
  920. * - "alter": the $node->content array has been rendered, so the node body or
  921. * teaser is filtered and now contains HTML. This op should only be used when
  922. * text substitution, filtering, or other raw text operations are necessary.
  923. * - "rss item": An RSS feed is generated. The module can return properties
  924. * to be added to the RSS item generated for this node. See comment_nodeapi()
  925. * and upload_nodeapi() for examples. The $node passed can also be modified
  926. * to add or remove contents to the feed item.
  927. * @param $a3
  928. * - For "view", passes in the $teaser parameter from node_view().
  929. * - For "validate", passes in the $form parameter from node_validate().
  930. * @param $a4
  931. * - For "view", passes in the $page parameter from node_view().
  932. * @return
  933. * This varies depending on the operation.
  934. * - The "submit", "insert", "update", "delete", "print' and "view"
  935. * operations have no return value.
  936. * - The "load" operation should return an array containing pairs
  937. * of fields => values to be merged into the node object.
  938. *
  939. * If you are writing a node module, do not use this hook to perform
  940. * actions on your type of node alone. Instead, use the hooks set aside
  941. * for node modules, such as hook_insert() and hook_form().
  942. */
  943. function hook_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  944. switch ($op) {
  945. case 'submit':
  946. if ($node->nid && $node->moderate) {
  947. // Reset votes when node is updated:
  948. $node->score = 0;
  949. $node->users = '';
  950. $node->votes = 0;
  951. }
  952. break;
  953. case 'insert':
  954. case 'update':
  955. if ($node->moderate && user_access('access submission queue')) {
  956. drupal_set_message(t('The post is queued for approval'));
  957. }
  958. elseif ($node->moderate) {
  959. drupal_set_message(t('The post is queued for approval. The editors will decide whether it should be published.'));
  960. }
  961. break;
  962. case 'view':
  963. $node->content['my_additional_field'] = array(
  964. '#value' => theme('mymodule_my_additional_field', $additional_field),
  965. '#weight' => 10,
  966. );
  967. break;
  968. }
  969. }
  970. /**
  971. * Define user permissions.
  972. *
  973. * This hook can supply permissions that the module defines, so that they
  974. * can be selected on the user permissions page and used to restrict
  975. * access to actions the module performs.
  976. *
  977. * @return
  978. * An array of permissions strings.
  979. *
  980. * The permissions in the array do not need to be wrapped with the function t(),
  981. * since the string extractor takes care of extracting permission names defined in the perm hook for translation.
  982. *
  983. * Permissions are checked using user_access().
  984. *
  985. * For a detailed usage example, see page_example.module.
  986. */
  987. function hook_perm() {
  988. return array('administer my module');
  989. }
  990. /**
  991. * Ping another server.
  992. *
  993. * This hook allows a module to notify other sites of updates on your
  994. * Drupal site.
  995. *
  996. * @param $name
  997. * The name of your Drupal site.
  998. * @param $url
  999. * The URL of your Drupal site.
  1000. * @return
  1001. * None.
  1002. */
  1003. function hook_ping($name = '', $url = '') {
  1004. $feed = url('node/feed');
  1005. $client = new xmlrpc_client('/RPC2', 'rpc.weblogs.com', 80);
  1006. $message = new xmlrpcmsg('weblogUpdates.ping',
  1007. array(new xmlrpcval($name), new xmlrpcval($url)));
  1008. $result = $client->send($message);
  1009. if (!$result || $result->faultCode()) {
  1010. watchdog('error', 'failed to notify "weblogs.com" (site)');
  1011. }
  1012. unset($client);
  1013. }
  1014. /**
  1015. * Define a custom search routine.
  1016. *
  1017. * This hook allows a module to perform searches on content it defines
  1018. * (custom node types, users, or comments, for example) when a site search
  1019. * is performed.
  1020. *
  1021. * Note that you can use form API to extend the search. You will need to use
  1022. * hook_form_alter() to add any additional required form elements. You can
  1023. * process their values on submission using a custom validation function.
  1024. * You will need to merge any custom search values into the search keys
  1025. * using a key:value syntax. This allows all search queries to have a clean
  1026. * and permanent URL. See node_form_alter() for an example.
  1027. *
  1028. * The example given here is for node.module, which uses the indexed search
  1029. * capabilities. To do this, node module also implements hook_update_index()
  1030. * which is used to create and maintain the index.
  1031. *
  1032. * We call do_search() with the keys, the module name, and extra SQL fragments
  1033. * to use when searching. See hook_update_index() for more information.
  1034. *
  1035. * @param $op
  1036. * A string defining which operation to perform:
  1037. * - 'admin': The hook should return a form array, containing any fieldsets
  1038. * the module wants to add to the Search settings page at
  1039. * admin/settings/search.
  1040. * - 'name': The hook should return a translated name defining the type of
  1041. * items that are searched for with this module ('content', 'users', ...).
  1042. * - 'reset': The search index is going to be rebuilt. Modules which use
  1043. * hook_update_index() should update their indexing bookkeeping so that it
  1044. * starts from scratch the next time hook_update_index() is called.
  1045. * - 'search': The hook should perform a search using the keywords in $keys.
  1046. * - 'status': If the module implements hook_update_index(), it should return
  1047. * an array containing the following keys:
  1048. * - remaining: The amount of items that still need to be indexed.
  1049. * - total: The total amount of items (both indexed and unindexed).
  1050. * @param $keys
  1051. * The search keywords as entered by the user.
  1052. * @return
  1053. * This varies depending on the operation.
  1054. * - 'admin': The form array for the Search settings page at
  1055. * admin/settings/search.
  1056. * - 'name': The translated string of 'Content'.
  1057. * - 'reset': None.
  1058. * - 'search': An array of search results. To use the default search result
  1059. * display, each item should have the following keys':
  1060. * - 'link': Required. The URL of the found item.
  1061. * - 'type': The type of item.
  1062. * - 'title': Required. The name of the item.
  1063. * - 'user': The author of the item.
  1064. * - 'date': A timestamp when the item was last modified.
  1065. * - 'extra': An array of optional extra information items.
  1066. * - 'snippet': An excerpt or preview to show with the result (can be
  1067. * generated with search_excerpt()).
  1068. * - 'status': An associative array with the key-value pairs:
  1069. * - 'remaining': The number of items left to index.
  1070. * - 'total': The total number of items to index.
  1071. *
  1072. * @ingroup search
  1073. */
  1074. function hook_search($op = 'search', $keys = null) {
  1075. switch ($op) {
  1076. case 'name':
  1077. return t('Content');
  1078. case 'reset':
  1079. variable_del('node_cron_last');
  1080. variable_del('node_cron_last_nid');
  1081. return;
  1082. case 'status':
  1083. $last = variable_get('node_cron_last', 0);
  1084. $last_nid = variable_get('node_cron_last_nid', 0);
  1085. $total = db_result(db_query('SELECT COUNT(*) FROM {node} WHERE status = 1'));
  1086. $remaining = db_result(db_query('SELECT COUNT(*) FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE n.status = 1 AND ((GREATEST(n.created, n.changed, c.last_comment_timestamp) = %d AND n.nid > %d ) OR (n.created > %d OR n.changed > %d OR c.last_comment_timestamp > %d))', $last, $last_nid, $last, $last, $last));
  1087. return array('remaining' => $remaining, 'total' => $total);
  1088. case 'admin':
  1089. $form = array();
  1090. // Output form for defining rank factor weights.
  1091. $form['content_ranking'] = array('#type' => 'fieldset', '#title' => t('Content ranking'));
  1092. $form['content_ranking']['#theme'] = 'node_search_admin';
  1093. $form['content_ranking']['info'] = array('#value' => '<em>'. t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') .'</em>');
  1094. $ranking = array('node_rank_relevance' => t('Keyword relevance'),
  1095. 'node_rank_recent' => t('Recently posted'));
  1096. if (module_exists('comment')) {
  1097. $ranking['node_rank_comments'] = t('Number of comments');
  1098. }
  1099. if (module_exists('statistics') && variable_get('statistics_count_content_views', 0)) {
  1100. $ranking['node_rank_views'] = t('Number of views');
  1101. }
  1102. // Note: reversed to reflect that higher number = higher ranking.
  1103. $options = drupal_map_assoc(range(0, 10));
  1104. foreach ($ranking as $var => $title) {
  1105. $form['content_ranking']['factors'][$var] = array('#title' => $title, '#type' => 'select', '#options' => $options, '#default_value' => variable_get($var, 5));
  1106. }
  1107. return $form;
  1108. case 'search':
  1109. // Build matching conditions
  1110. list($join1, $where1) = _db_rewrite_sql();
  1111. $arguments1 = array();
  1112. $conditions1 = 'n.status = 1';
  1113. if ($type = search_query_extract($keys, 'type')) {
  1114. $types = array();
  1115. foreach (explode(',', $type) as $t) {
  1116. $types[] = "n.type = '%s'";
  1117. $arguments1[] = $t;
  1118. }
  1119. $conditions1 .= ' AND ('. implode(' OR ', $types) .')';
  1120. $keys = search_query_insert($keys, 'type');
  1121. }
  1122. if ($category = search_query_extract($keys, 'category')) {
  1123. $categories = array();
  1124. foreach (explode(',', $category) as $c) {
  1125. $categories[] = "tn.tid = %d";
  1126. $arguments1[] = $c;
  1127. }
  1128. $conditions1 .= ' AND ('. implode(' OR ', $categories) .')';
  1129. $join1 .= ' INNER JOIN {term_node} tn ON n.nid = tn.nid';
  1130. $keys = search_query_insert($keys, 'category');
  1131. }
  1132. // Build ranking expression (we try to map each parameter to a
  1133. // uniform distribution in the range 0..1).
  1134. $ranking = array();
  1135. $arguments2 = array();
  1136. $join2 = '';
  1137. // Used to avoid joining on node_comment_statistics twice
  1138. $stats_join = FALSE;
  1139. $total = 0;
  1140. if ($weight = (int)variable_get('node_rank_relevance', 5)) {
  1141. // Average relevance values hover around 0.15
  1142. $ranking[] = '%d * i.relevance';
  1143. $arguments2[] = $weight;
  1144. $total += $weight;
  1145. }
  1146. if ($weight = (int)variable_get('node_rank_recent', 5)) {
  1147. // Exponential decay with half-life of 6 months, starting at last indexed node
  1148. $ranking[] = '%d * POW(2, (GREATEST(n.created, n.changed, c.last_comment_timestamp) - %d) * 6.43e-8)';
  1149. $arguments2[] = $weight;
  1150. $arguments2[] = (int)variable_get('node_cron_last', 0);
  1151. $join2 .= ' INNER JOIN {node} n ON n.nid = i.sid LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
  1152. $stats_join = TRUE;
  1153. $total += $weight;
  1154. }
  1155. if (module_exists('comment') && $weight = (int)variable_get('node_rank_comments', 5)) {
  1156. // Inverse law that maps the highest reply count on the site to 1 and 0 to 0.
  1157. $scale = variable_get('node_cron_comments_scale', 0.0);
  1158. $ranking[] = '%d * (2.0 - 2.0 / (1.0 + c.comment_count * %f))';
  1159. $arguments2[] = $weight;
  1160. $arguments2[] = $scale;
  1161. if (!$stats_join) {
  1162. $join2 .= ' LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
  1163. }
  1164. $total += $weight;
  1165. }
  1166. if (module_exists('statistics') && variable_get('statistics_count_content_views', 0) &&
  1167. $weight = (int)variable_get('node_rank_views', 5)) {
  1168. // Inverse law that maps the highest view count on the site to 1 and 0 to 0.
  1169. $scale = variable_get('node_cron_views_scale', 0.0);
  1170. $ranking[] = '%d * (2.0 - 2.0 / (1.0 + nc.totalcount * %f))';
  1171. $arguments2[] = $weight;
  1172. $arguments2[] = $scale;
  1173. $join2 .= ' LEFT JOIN {node_counter} nc ON nc.nid = i.sid';
  1174. $total += $weight;
  1175. }
  1176. // When all search factors are disabled (ie they have a weight of zero),
  1177. // the default score is based only on keyword relevance and there is no need to
  1178. // adjust the score of each item.
  1179. if ($total == 0) {
  1180. $select2 = 'i.relevance AS score';
  1181. $total = 1;
  1182. }
  1183. else {
  1184. $select2 = implode(' + ', $ranking) . ' AS score';
  1185. }
  1186. // Do search.
  1187. $find = do_search($keys, 'node', 'INNER JOIN {node} n ON n.nid = i.sid '. $join1 .' INNER JOIN {users} u ON n.uid = u.uid', $conditions1 . (empty($where1) ? '' : ' AND '. $where1), $arguments1, $select2, $join2, $arguments2);
  1188. // Load results.
  1189. $results = array();
  1190. foreach ($find as $item) {
  1191. // Build the node body.
  1192. $node = node_load($item->sid);
  1193. $node = node_build_content($node, FALSE, FALSE);
  1194. $node->body = drupal_render($node->content);
  1195. // Fetch comments for snippet.
  1196. $node->body .= module_invoke('comment', 'nodeapi', $node, 'update index');
  1197. // Fetch terms for snippet.
  1198. $node->body .= module_invoke('taxonomy', 'nodeapi', $node, 'update index');
  1199. $extra = node_invoke_nodeapi($node, 'search result');
  1200. $results[] = array('link' => url('node/'. $item->sid, NULL, NULL, TRUE),
  1201. 'type' => node_get_types('name', $node),
  1202. 'title' => $node->title,
  1203. 'user' => theme('username', $node),
  1204. 'date' => $node->changed,
  1205. 'node' => $node,
  1206. 'extra' => $extra,
  1207. 'score' => $item->score / $total,
  1208. 'snippet' => search_excerpt($keys, $node->body));
  1209. }
  1210. return $results;
  1211. }
  1212. }
  1213. /**
  1214. * Preprocess text for the search index.
  1215. *
  1216. * This hook is called both for text added to the search index, as well as
  1217. * the keywords users have submitted for searching.
  1218. *
  1219. * This is required for example to allow Japanese or Chinese text to be
  1220. * searched. As these languages do not use spaces, it needs to be split into
  1221. * separate words before it can be indexed. There are various external
  1222. * libraries for this.
  1223. *
  1224. * @param $text
  1225. * The text to split. This is a single piece of plain-text that was
  1226. * extracted from between two HTML tags. Will not contain any HTML entities.
  1227. * @return
  1228. * The text after processing.
  1229. */
  1230. function hook_search_preprocess($text) {
  1231. // Do processing on $text
  1232. return $text;
  1233. }
  1234. /**
  1235. * Act on taxonomy changes.
  1236. *
  1237. * This hook allows modules to take action when the terms and vocabularies
  1238. * in the taxonomy are modified.
  1239. *
  1240. * @param $op
  1241. * What is being done to $object. Possible values:
  1242. * - "delete"
  1243. * - "insert"
  1244. * - "update"
  1245. * @param $type
  1246. * What manner of item $object is. Possible values:
  1247. * - "term"
  1248. * - "vocabulary"
  1249. * @param $array
  1250. * The item on which $op is being performed. Possible values:
  1251. * - for vocabularies, 'insert' and 'update' ops:
  1252. * $form_values from taxonomy_form_vocabulary_submit()
  1253. * - for vocabularies, 'delete' op:
  1254. * $vocabulary from taxonomy_get_vocabulary() cast to an array
  1255. * - for terms, 'insert' and 'update' ops:
  1256. * $form_values from taxonomy_form_term_submit()
  1257. * - for terms, 'delete' op:
  1258. * $term from taxonomy_get_term() cast to an array
  1259. * @return
  1260. * None.
  1261. */
  1262. function hook_taxonomy($op, $type, $array = NULL) {
  1263. if ($type == 'vocabulary' && ($op == 'insert' || $op == 'update')) {
  1264. if (variable_get('forum_nav_vocabulary', '') == ''
  1265. && in_array('forum', $array['nodes'])) {
  1266. // since none is already set, silently set this vocabulary as the
  1267. // navigation vocabulary
  1268. variable_set('forum_nav_vocabulary', $array['vid']);
  1269. }
  1270. }
  1271. }
  1272. /**
  1273. * Update Drupal's full-text index for this module.
  1274. *
  1275. * Modules can implement this hook if they want to use the full-text indexing
  1276. * mechanism in Drupal.
  1277. *
  1278. * This hook is called every cron run if search.module is enabled. A module
  1279. * should check which of its items were modified or added since the last
  1280. * run. It is advised that you implement a throttling mechanism which indexes
  1281. * at most 'search_cron_limit' items per run (see example below).
  1282. *
  1283. * You should also be aware that indexing may take too long and be aborted if
  1284. * there is a PHP time limit. That's why you should update your internal
  1285. * bookkeeping multiple times per run, preferably after every item that
  1286. * is indexed.
  1287. *
  1288. * Per item that needs to be indexed, you should call search_index() with
  1289. * its content as a single HTML string. The search indexer will analyse the
  1290. * HTML and use it to assign higher weights to important words (such as
  1291. * titles). It will also check for links that point to nodes, and use them to
  1292. * boost the ranking of the target nodes.
  1293. *
  1294. * @ingroup search
  1295. */
  1296. function hook_update_index() {
  1297. $last = variable_get('node_cron_last', 0);
  1298. $limit = (int)variable_get('search_cron_limit', 100);
  1299. $result = db_query_range('SELECT n.nid, c.last_comment_timestamp FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE n.status = 1 AND n.moderate = 0 AND (n.created > %d OR n.changed > %d OR c.last_comment_timestamp > %d) ORDER BY GREATEST(n.created, n.changed, c.last_comment_timestamp) ASC', $last, $last, $last, 0, $limit);
  1300. while ($node = db_fetch_object($result)) {
  1301. $last_comment = $node->last_comment_timestamp;
  1302. $node = node_load(array('nid' => $node->nid));
  1303. // We update this variable per node in case cron times out, or if the node
  1304. // cannot be indexed (PHP nodes which call drupal_goto, for example).
  1305. // In rare cases this can mean a node is only partially indexed, but the
  1306. // chances of this happening are very small.
  1307. variable_set('node_cron_last', max($last_comment, $node->changed, $node->created));
  1308. // Get node output (filtered and with module-specific fields).
  1309. if (node_hook($node, 'view')) {
  1310. node_invoke($node, 'view', false, false);
  1311. }
  1312. else {
  1313. $node = node_prepare($node, false);
  1314. }
  1315. // Allow modules to change $node->body before viewing.
  1316. node_invoke_nodeapi($node, 'view', false, false);
  1317. $text = '<h1>'. drupal_specialchars($node->title) .'</h1>'. $node->body;
  1318. // Fetch extra data normally not visible
  1319. $extra = node_invoke_nodeapi($node, 'update index');
  1320. foreach ($extra as $t) {
  1321. $text .= $t;
  1322. }
  1323. // Update index
  1324. search_index($node->nid, 'node', $text);
  1325. }
  1326. }
  1327. /**
  1328. * Act on user account actions.
  1329. *
  1330. * This hook allows modules to react when operations are performed on user
  1331. * accounts.
  1332. *
  1333. * @param $op
  1334. * What kind of action is being performed. Possible values:
  1335. * - "after_update": The user object has been updated and changed. Use this if
  1336. * (probably along with 'insert') if you want to reuse some information from
  1337. * the user object.
  1338. * - "categories": A set of user information categories is requested.
  1339. * - "delete": The user account is being deleted. The module should remove its
  1340. * custom additions to the user object from the database.
  1341. * - "form": The user account edit form is about to be displayed. The module
  1342. * should present the form elements it wishes to inject into the form.
  1343. * - "submit": Modify the account before it gets saved.
  1344. * - "insert": The user account is being added. The module should save its
  1345. * custom additions to the user object into the database and set the saved
  1346. * fields to NULL in $edit.
  1347. * - "login": The user just logged in.
  1348. * - "logout": The user just logged out.
  1349. * - "load": The user account is being loaded. The module may respond to this
  1350. * and insert additional information into the user object.
  1351. * - "register": The user account registration form is about to be displayed.
  1352. * The module should present the form elements it wishes to inject into the
  1353. * form.
  1354. * - "update": The user account is being changed. The module should save its
  1355. * custom additions to the user object into the database and set the saved
  1356. * fields to NULL in $edit.
  1357. * - "validate": The user account is about to be modified. The module should
  1358. * validate its custom additions to the user object, registering errors as
  1359. * necessary.
  1360. * - "view": The user's account information is being displayed. The module
  1361. * should format its custom additions for display.
  1362. * @param &$edit
  1363. * The array of form values submitted by the user.
  1364. * @param &$account
  1365. * The user object on which the operation is being performed.
  1366. * @param $category
  1367. * The active category of user information being edited.
  1368. * @return
  1369. * This varies depending on the operation.
  1370. * - "categories": A linear array of associative arrays. These arrays have
  1371. * keys:
  1372. * - "name": The internal name of the category.
  1373. * - "title": The human-readable, localized name of the category.
  1374. * - "weight": An integer specifying the category's sort ordering.
  1375. * - "submit": None:
  1376. * - "insert": None.
  1377. * - "update": None.
  1378. * - "delete": None.
  1379. * - "login": None.
  1380. * - "logout": None.
  1381. * - "load": None.
  1382. * - "form", "register": A $form array containing the form elements to display.
  1383. * - "validate": None.
  1384. * - "view": An associative array of associative arrays. The outer array should be keyed by category
  1385. * name. The interior array(s) should have a unique textual key and have 'title', 'value' and 'class' elements.
  1386. * See theme_user_profile() and an example at user_user()
  1387. */
  1388. function hook_user($op, &$edit, &$account, $category = NULL) {
  1389. if ($op == 'form' && $category == 'account') {
  1390. $form['comment_settings'] = array(
  1391. '#type' => 'fieldset',
  1392. '#title' => t('Comment settings'),
  1393. '#collapsible' => TRUE,
  1394. '#weight' => 4);
  1395. $form['comment_settings']['signature'] = array(
  1396. '#type' => 'textarea',
  1397. '#title' => t('Signature'),
  1398. '#default_value' => $edit['signature'],
  1399. '#description' => t('Your signature will be publicly displayed at the end of your comments.'));
  1400. return $form;
  1401. }
  1402. }
  1403. /**
  1404. * Add mass user operations.
  1405. *
  1406. * This hook enables modules to inject custom operations into the mass operations
  1407. * dropdown found at admin/user/user, by associating a callback function with
  1408. * the operation, which is called when the form is submitted. The callback function
  1409. * receives one initial argument, which is an array of the checked users.
  1410. *
  1411. * @return
  1412. * An array of operations. Each operation is an associative array that may
  1413. * contain the following key-value pairs:
  1414. * - "label": Required. The label for the operation, displayed in the dropdown menu.
  1415. * - "callback": Required. The function to call for the operation.
  1416. * - "callback arguments": Optional. An array of additional arguments to pass to
  1417. * the callback function.
  1418. *
  1419. */
  1420. function hook_user_operations() {
  1421. $operations = array(
  1422. 'unblock' => array(
  1423. 'label' => t('Unblock the selected users'),
  1424. 'callback' => 'user_user_operations_unblock',
  1425. ),
  1426. 'block' => array(
  1427. 'label' => t('Block the selected users'),
  1428. 'callback' => 'user_user_operations_block',
  1429. ),
  1430. 'delete' => array(
  1431. 'label' => t('Delete the selected users'),
  1432. ),
  1433. );
  1434. return $operations;
  1435. }
  1436. /**
  1437. * Register XML-RPC callbacks.
  1438. *
  1439. * This hook lets a module register callback functions to be called when
  1440. * particular XML-RPC methods are invoked by a client.
  1441. *
  1442. * @return
  1443. * An array which maps XML-RPC methods to Drupal functions. Each array
  1444. * element is either a pair of method => function or an array with four
  1445. * entries:
  1446. * - The XML-RPC method name (for example, module.function).
  1447. * - The Drupal callback function (for example, module_function).
  1448. * - The method signature is an array of XML-RPC types. The first element
  1449. * of this array is the type of return value and then you should write a
  1450. * list of the types of the parameters. XML-RPC types are the following
  1451. * (See the types at http://www.xmlrpc.com/spec):
  1452. * - "boolean": 0 (false) or 1 (true).
  1453. * - "double": a floating point number (for example, -12.214).
  1454. * - "int": a integer number (for example, -12).
  1455. * - "array": an array without keys (for example, array(1, 2, 3)).
  1456. * - "struct": an associative array or an object (for example,
  1457. * array('one' => 1, 'two' => 2)).
  1458. * - "date": when you return a date, then you may either return a
  1459. * timestamp (time(), mktime() etc.) or an ISO8601 timestamp. When
  1460. * date is specified as an input parameter, then you get an object,
  1461. * which is described in the function xmlrpc_date
  1462. * - "base64": a string containing binary data, automatically
  1463. * encoded/decoded automatically.
  1464. * - "string": anything else, typically a string.
  1465. * - A descriptive help string, enclosed in a t() function for translation
  1466. * purposes.
  1467. * Both forms are shown in the example.
  1468. */
  1469. function hook_xmlrpc() {
  1470. return array(
  1471. 'drupal.login' => 'drupal_login',
  1472. array(
  1473. 'drupal.site.ping',
  1474. 'drupal_directory_ping',
  1475. array('boolean', 'string', 'string', 'string', 'string', 'string'),
  1476. t('Handling ping request'))
  1477. );
  1478. }
  1479. /**
  1480. * custom_url_rewrite is not a hook. It is a function you can add to settings.php to manage aliases with some code.
  1481. *
  1482. * @param $op
  1483. * Can be 'alias' or 'source'. For 'alias', an alias need to be returned.
  1484. * For 'source', return the Drupal path based on the alias passed in.
  1485. * 'source' is first called before modules are loaded and the menu system
  1486. * is initialized and $_GET['q'] subsequently will be the value of what's
  1487. * returned from this function call.
  1488. * @param $result
  1489. * For op 'alias', this is the alias of the path from the database.
  1490. * For op 'source', this is the Drupal path based on the database.
  1491. * If there is no match in the database it'll be the same as $path for both
  1492. * ops.
  1493. * @param $path
  1494. * The path to be sourced/aliased.
  1495. * @return
  1496. * The changed path. Even if it's not changed, it must be returned.
  1497. */
  1498. function custom_url_rewrite($op, $result, $path) {
  1499. global $user;
  1500. if ($op == 'alias') {
  1501. // Overwrite a menu path already defined, with this code, if the user
  1502. // goes to 'tracker', the page 'views/tracker' will be displayed instead
  1503. // without any redirection. To achieve this, only the op source act is a
  1504. // must, this is optional.
  1505. if ($path == 'views/tracker') {
  1506. return 'tracker';
  1507. }
  1508. // Change all 'node' to 'article'.
  1509. if (preg_match('|^node/(.*)|', $path, $matches)) {
  1510. return 'article'. $matches[1];
  1511. }
  1512. // Create a path called 'e' which lands the user on her edit page.
  1513. if ($path == 'user/'. $user->uid .'/edit') {
  1514. return 'e';
  1515. }
  1516. }
  1517. if ($op == 'source') {
  1518. if ($path == 'tracker') {
  1519. // Change 'tracker' to 'views/tracker' when a request lands.
  1520. return 'views/tracker';
  1521. }
  1522. // Change all 'node' to 'article'.
  1523. if (preg_match('|^article(/.*)|', $path, $matches)) {
  1524. return 'node'. $matches[1];
  1525. }
  1526. // Create a path called 'e' which lands the user on her edit page.
  1527. if ($path == 'e') {
  1528. return 'user/'. $user->uid .'/edit';
  1529. }
  1530. }
  1531. // Do not forget to return $result!
  1532. return $result;
  1533. }
  1534. /**
  1535. * @} End of "addtogroup hooks".
  1536. */

Functions

Namesort descending Description
custom_url_rewrite custom_url_rewrite is not a hook. It is a function you can add to settings.php to manage aliases with some code.
hook_block Declare a block or set of blocks.
hook_comment Act on comments.
hook_cron Perform periodic actions.
hook_db_rewrite_sql Add JOIN and WHERE statements to queries and decide whether the primary_field shall be made DISTINCT. For node objects, primary field is always called nid. For taxonomy terms, it is tid and for vocabularies it is vid. For comments, it is cid. Primary…
hook_elements Allows modules to declare their own form element types and specify their default values.
hook_exit Perform cleanup tasks.
hook_file_download Allow file downloads.
hook_filter Define content filters.
hook_filter_tips Provide tips for using filters.
hook_footer Insert closing HTML.
hook_forms Map form_ids to builder functions.
hook_form_alter Perform alterations before a form is rendered.
hook_help Provide online user help.
hook_init Perform setup tasks.
hook_link Define internal Drupal links.
hook_link_alter Perform alterations before links on a node are rendered. One popular use of this hook is to modify/remove links from other modules. If you want to add a link to the links section of a node, use hook_link instead.
hook_mail_alter Alter any aspect of the emails sent by Drupal. You can use this hook to add a common site footer to all outgoing emails; add extra header fields and/or modify the mails sent out in any way. HTML-izing the outgoing mails is one possibility. See also…
hook_menu Define menu items and page callbacks.
hook_nodeapi Act on nodes defined by other modules.
hook_node_access_records Set permissions for a node to be written to the database.
hook_node_grants Inform the node access system what permissions the user has.
hook_node_operations Add mass node operations.
hook_perm Define user permissions.
hook_ping Ping another server.
hook_profile_alter Perform alterations profile items before they are rendered. You may omit/add/re-sort/re-categorize, etc.
hook_search Define a custom search routine.
hook_search_preprocess Preprocess text for the search index.
hook_taxonomy Act on taxonomy changes.
hook_update_index Update Drupal's full-text index for this module.
hook_user Act on user account actions.
hook_user_operations Add mass user operations.
hook_xmlrpc Register XML-RPC callbacks.