token.inc

Drupal placeholder/token replacement system.

API functions for replacing placeholders in text with meaningful values.

For example: When configuring automated emails, an administrator enters standard text for the email. Variables like the title of a node and the date the email was sent can be entered as placeholders like [node:title] and [date:short]. When a Drupal module prepares to send the email, it can call the token_replace() function, passing in the text. The token system will scan the text for placeholder tokens, give other modules an opportunity to replace them with meaningful text, then return the final product to the original module.

Tokens follow the form: [$type:$name], where $type is a general class of tokens like 'node', 'user', or 'comment' and $name is the name of a given placeholder. For example, [node:title] or [node:created:since].

In addition to raw text containing placeholders, modules may pass in an array of objects to be used when performing the replacement. The objects should be keyed by the token type they correspond to. For example:

// Load a node and a user, then replace tokens in the text.
$text = 'On [date:short], [user:name] read [node:title].';
$node = node_load(1);
$user = user_load(1);

// [date:...] tokens use the current date automatically.
$data = array('node' => $node, 'user' => $user);
return token_replace($text, $data);

Some tokens may be chained in the form of [$type:$pointer:$name], where $type is a normal token type, $pointer is a reference to another token type, and $name is the name of a given placeholder. For example, [node:author:mail]. In that example, 'author' is a pointer to the 'user' account that created the node, and 'mail' is a placeholder available for any 'user'.

See also

token_replace()

hook_tokens()

hook_token_info()

File

drupal-7.x/includes/token.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Drupal placeholder/token replacement system.
  5. *
  6. * API functions for replacing placeholders in text with meaningful values.
  7. *
  8. * For example: When configuring automated emails, an administrator enters
  9. * standard text for the email. Variables like the title of a node and the date
  10. * the email was sent can be entered as placeholders like [node:title] and
  11. * [date:short]. When a Drupal module prepares to send the email, it can call
  12. * the token_replace() function, passing in the text. The token system will
  13. * scan the text for placeholder tokens, give other modules an opportunity to
  14. * replace them with meaningful text, then return the final product to the
  15. * original module.
  16. *
  17. * Tokens follow the form: [$type:$name], where $type is a general class of
  18. * tokens like 'node', 'user', or 'comment' and $name is the name of a given
  19. * placeholder. For example, [node:title] or [node:created:since].
  20. *
  21. * In addition to raw text containing placeholders, modules may pass in an array
  22. * of objects to be used when performing the replacement. The objects should be
  23. * keyed by the token type they correspond to. For example:
  24. *
  25. * @code
  26. * // Load a node and a user, then replace tokens in the text.
  27. * $text = 'On [date:short], [user:name] read [node:title].';
  28. * $node = node_load(1);
  29. * $user = user_load(1);
  30. *
  31. * // [date:...] tokens use the current date automatically.
  32. * $data = array('node' => $node, 'user' => $user);
  33. * return token_replace($text, $data);
  34. * @endcode
  35. *
  36. * Some tokens may be chained in the form of [$type:$pointer:$name], where $type
  37. * is a normal token type, $pointer is a reference to another token type, and
  38. * $name is the name of a given placeholder. For example, [node:author:mail]. In
  39. * that example, 'author' is a pointer to the 'user' account that created the
  40. * node, and 'mail' is a placeholder available for any 'user'.
  41. *
  42. * @see token_replace()
  43. * @see hook_tokens()
  44. * @see hook_token_info()
  45. */
  46. /**
  47. * Replaces all tokens in a given string with appropriate values.
  48. *
  49. * @param $text
  50. * A string potentially containing replaceable tokens.
  51. * @param $data
  52. * (optional) An array of keyed objects. For simple replacement scenarios
  53. * 'node', 'user', and others are common keys, with an accompanying node or
  54. * user object being the value. Some token types, like 'site', do not require
  55. * any explicit information from $data and can be replaced even if it is
  56. * empty.
  57. * @param $options
  58. * (optional) A keyed array of settings and flags to control the token
  59. * replacement process. Supported options are:
  60. * - language: A language object to be used when generating locale-sensitive
  61. * tokens.
  62. * - callback: A callback function that will be used to post-process the array
  63. * of token replacements after they are generated. For example, a module
  64. * using tokens in a text-only email might provide a callback to strip HTML
  65. * entities from token values before they are inserted into the final text.
  66. * - clear: A boolean flag indicating that tokens should be removed from the
  67. * final text if no replacement value can be generated.
  68. * - sanitize: A boolean flag indicating that tokens should be sanitized for
  69. * display to a web browser. Defaults to TRUE. Developers who set this
  70. * option to FALSE assume responsibility for running filter_xss(),
  71. * check_plain() or other appropriate scrubbing functions before displaying
  72. * data to users.
  73. *
  74. * @return
  75. * Text with tokens replaced.
  76. */
  77. function token_replace($text, array $data = array(), array $options = array()) {
  78. $text_tokens = token_scan($text);
  79. if (empty($text_tokens)) {
  80. return $text;
  81. }
  82. $replacements = array();
  83. foreach ($text_tokens as $type => $tokens) {
  84. $replacements += token_generate($type, $tokens, $data, $options);
  85. if (!empty($options['clear'])) {
  86. $replacements += array_fill_keys($tokens, '');
  87. }
  88. }
  89. // Optionally alter the list of replacement values.
  90. if (!empty($options['callback']) && function_exists($options['callback'])) {
  91. $function = $options['callback'];
  92. $function($replacements, $data, $options);
  93. }
  94. $tokens = array_keys($replacements);
  95. $values = array_values($replacements);
  96. return str_replace($tokens, $values, $text);
  97. }
  98. /**
  99. * Builds a list of all token-like patterns that appear in the text.
  100. *
  101. * @param $text
  102. * The text to be scanned for possible tokens.
  103. *
  104. * @return
  105. * An associative array of discovered tokens, grouped by type.
  106. */
  107. function token_scan($text) {
  108. // Matches tokens with the following pattern: [$type:$name]
  109. // $type and $name may not contain [ ] characters.
  110. // $type may not contain : or whitespace characters, but $name may.
  111. preg_match_all('/
  112. \[ # [ - pattern start
  113. ([^\s\[\]:]*) # match $type not containing whitespace : [ or ]
  114. : # : - separator
  115. ([^\[\]]*) # match $name not containing [ or ]
  116. \] # ] - pattern end
  117. /x', $text, $matches);
  118. $types = $matches[1];
  119. $tokens = $matches[2];
  120. // Iterate through the matches, building an associative array containing
  121. // $tokens grouped by $types, pointing to the version of the token found in
  122. // the source text. For example, $results['node']['title'] = '[node:title]';
  123. $results = array();
  124. for ($i = 0; $i < count($tokens); $i++) {
  125. $results[$types[$i]][$tokens[$i]] = $matches[0][$i];
  126. }
  127. return $results;
  128. }
  129. /**
  130. * Generates replacement values for a list of tokens.
  131. *
  132. * @param $type
  133. * The type of token being replaced. 'node', 'user', and 'date' are common.
  134. * @param $tokens
  135. * An array of tokens to be replaced, keyed by the literal text of the token
  136. * as it appeared in the source text.
  137. * @param $data
  138. * (optional) An array of keyed objects. For simple replacement scenarios
  139. * 'node', 'user', and others are common keys, with an accompanying node or
  140. * user object being the value. Some token types, like 'site', do not require
  141. * any explicit information from $data and can be replaced even if it is
  142. * empty.
  143. * @param $options
  144. * (optional) A keyed array of settings and flags to control the token
  145. * replacement process. Supported options are:
  146. * - language: A language object to be used when generating locale-sensitive
  147. * tokens.
  148. * - callback: A callback function that will be used to post-process the
  149. * array of token replacements after they are generated. Can be used when
  150. * modules require special formatting of token text, for example URL
  151. * encoding or truncation to a specific length.
  152. * - sanitize: A boolean flag indicating that tokens should be sanitized for
  153. * display to a web browser. Developers who set this option to FALSE assume
  154. * responsibility for running filter_xss(), check_plain() or other
  155. * appropriate scrubbing functions before displaying data to users.
  156. *
  157. * @return
  158. * An associative array of replacement values, keyed by the original 'raw'
  159. * tokens that were found in the source text. For example:
  160. * $results['[node:title]'] = 'My new node';
  161. *
  162. * @see hook_tokens()
  163. * @see hook_tokens_alter()
  164. */
  165. function token_generate($type, array $tokens, array $data = array(), array $options = array()) {
  166. $options += array('sanitize' => TRUE);
  167. $replacements = module_invoke_all('tokens', $type, $tokens, $data, $options);
  168. // Allow other modules to alter the replacements.
  169. $context = array(
  170. 'type' => $type,
  171. 'tokens' => $tokens,
  172. 'data' => $data,
  173. 'options' => $options,
  174. );
  175. drupal_alter('tokens', $replacements, $context);
  176. return $replacements;
  177. }
  178. /**
  179. * Returns a list of tokens that begin with a specific prefix.
  180. *
  181. * Used to extract a group of 'chained' tokens (such as [node:author:name])
  182. * from the full list of tokens found in text. For example:
  183. * @code
  184. * $data = array(
  185. * 'author:name' => '[node:author:name]',
  186. * 'title' => '[node:title]',
  187. * 'created' => '[node:created]',
  188. * );
  189. * $results = token_find_with_prefix($data, 'author');
  190. * $results == array('name' => '[node:author:name]');
  191. * @endcode
  192. *
  193. * @param $tokens
  194. * A keyed array of tokens, and their original raw form in the source text.
  195. * @param $prefix
  196. * A textual string to be matched at the beginning of the token.
  197. * @param $delimiter
  198. * An optional string containing the character that separates the prefix from
  199. * the rest of the token. Defaults to ':'.
  200. *
  201. * @return
  202. * An associative array of discovered tokens, with the prefix and delimiter
  203. * stripped from the key.
  204. */
  205. function token_find_with_prefix(array $tokens, $prefix, $delimiter = ':') {
  206. $results = array();
  207. foreach ($tokens as $token => $raw) {
  208. $parts = explode($delimiter, $token, 2);
  209. if (count($parts) == 2 && $parts[0] == $prefix) {
  210. $results[$parts[1]] = $raw;
  211. }
  212. }
  213. return $results;
  214. }
  215. /**
  216. * Returns metadata describing supported tokens.
  217. *
  218. * The metadata array contains token type, name, and description data as well
  219. * as an optional pointer indicating that the token chains to another set of
  220. * tokens.
  221. *
  222. * For example:
  223. * @code
  224. * $data['types']['node'] = array(
  225. * 'name' => t('Nodes'),
  226. * 'description' => t('Tokens related to node objects.'),
  227. * );
  228. * $data['tokens']['node']['title'] = array(
  229. * 'name' => t('Title'),
  230. * 'description' => t('The title of the current node.'),
  231. * );
  232. * $data['tokens']['node']['author'] = array(
  233. * 'name' => t('Author'),
  234. * 'description' => t('The author of the current node.'),
  235. * 'type' => 'user',
  236. * );
  237. * @endcode
  238. *
  239. * @return
  240. * An associative array of token information, grouped by token type.
  241. */
  242. function token_info() {
  243. $data = &drupal_static(__FUNCTION__);
  244. if (!isset($data)) {
  245. $data = module_invoke_all('token_info');
  246. drupal_alter('token_info', $data);
  247. }
  248. return $data;
  249. }