5 * Builds placeholder replacement tokens for node-related data.
8 use Drupal\Core\Datetime\Entity\DateFormat;
9 use Drupal\Core\Language\LanguageInterface;
10 use Drupal\Core\Render\BubbleableMetadata;
11 use Drupal\user\Entity\User;
14 * Implements hook_token_info().
16 function node_token_info() {
19 'description' => t('Tokens related to individual content items, or "nodes".'),
20 'needs-data' => 'node',
23 // Core tokens for nodes.
25 'name' => t("Content ID"),
26 'description' => t('The unique ID of the content item, or "node".'),
29 'name' => t("Revision ID"),
30 'description' => t("The unique ID of the node's latest revision."),
33 'name' => t("Content type"),
35 $node['type-name'] = [
36 'name' => t("Content type name"),
37 'description' => t("The human-readable name of the node type."),
44 'description' => t("The main body text of the node."),
47 'name' => t("Summary"),
48 'description' => t("The summary of the node's main body text."),
51 'name' => t('Language code'),
52 'description' => t('The language code of the language the node is written in.'),
56 'description' => t("The URL of the node."),
59 'name' => t("Edit URL"),
60 'description' => t("The URL of the node's edit page."),
63 // Chained tokens for nodes.
65 'name' => t("Date created"),
69 'name' => t("Date changed"),
70 'description' => t("The date the node was most recently updated."),
74 'name' => t("Author"),
79 'types' => ['node' => $type],
80 'tokens' => ['node' => $node],
85 * Implements hook_tokens().
87 function node_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
88 $token_service = \Drupal::token();
90 $url_options = ['absolute' => TRUE];
91 if (isset($options['langcode'])) {
92 $url_options['language'] = \Drupal::languageManager()->getLanguage($options['langcode']);
93 $langcode = $options['langcode'];
96 $langcode = LanguageInterface::LANGCODE_DEFAULT;
100 if ($type == 'node' && !empty($data['node'])) {
101 /** @var \Drupal\node\NodeInterface $node */
102 $node = $data['node'];
104 foreach ($tokens as $name => $original) {
106 // Simple key values on the node.
108 $replacements[$original] = $node->id();
112 $replacements[$original] = $node->getRevisionId();
116 $replacements[$original] = $node->getType();
120 $type_name = node_get_type_label($node);
121 $replacements[$original] = $type_name;
125 $replacements[$original] = $node->getTitle();
130 $translation = \Drupal::entityManager()->getTranslationFromContext($node, $langcode, ['operation' => 'node_tokens']);
131 if ($translation->hasField('body') && ($items = $translation->get('body')) && !$items->isEmpty()) {
133 // If the summary was requested and is not empty, use it.
134 if ($name == 'summary' && !empty($item->summary)) {
135 $output = $item->summary_processed;
137 // Attempt to provide a suitable version of the 'body' field.
139 $output = $item->processed;
140 // A summary was requested.
141 if ($name == 'summary') {
142 // Generate an optionally trimmed summary of the body field.
144 // Get the 'trim_length' size used for the 'teaser' mode, if
145 // present, or use the default trim_length size.
146 $display_options = entity_get_display('node', $node->getType(), 'teaser')->getComponent('body');
147 if (isset($display_options['settings']['trim_length'])) {
148 $length = $display_options['settings']['trim_length'];
151 $settings = \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings('text_summary_or_trimmed');
152 $length = $settings['trim_length'];
155 $output = text_summary($output, $item->format, $length);
158 // "processed" returns a \Drupal\Component\Render\MarkupInterface
159 // via check_markup().
160 $replacements[$original] = $output;
165 $replacements[$original] = $node->language()->getId();
169 $replacements[$original] = $node->url('canonical', $url_options);
173 $replacements[$original] = $node->url('edit-form', $url_options);
176 // Default values for the chained tokens handled below.
178 $account = $node->getOwner() ? $node->getOwner() : User::load(0);
179 $bubbleable_metadata->addCacheableDependency($account);
180 $replacements[$original] = $account->label();
184 $date_format = DateFormat::load('medium');
185 $bubbleable_metadata->addCacheableDependency($date_format);
186 $replacements[$original] = format_date($node->getCreatedTime(), 'medium', '', NULL, $langcode);
190 $date_format = DateFormat::load('medium');
191 $bubbleable_metadata->addCacheableDependency($date_format);
192 $replacements[$original] = format_date($node->getChangedTime(), 'medium', '', NULL, $langcode);
197 if ($author_tokens = $token_service->findWithPrefix($tokens, 'author')) {
198 $replacements += $token_service->generate('user', $author_tokens, ['user' => $node->getOwner()], $options, $bubbleable_metadata);
201 if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) {
202 $replacements += $token_service->generate('date', $created_tokens, ['date' => $node->getCreatedTime()], $options, $bubbleable_metadata);
205 if ($changed_tokens = $token_service->findWithPrefix($tokens, 'changed')) {
206 $replacements += $token_service->generate('date', $changed_tokens, ['date' => $node->getChangedTime()], $options, $bubbleable_metadata);
210 return $replacements;