--- /dev/null
+/**
+ * Implements hook_tokens().
+ */
+function {{ machine_name }}_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
+ $token_service = \Drupal::token();
+
+ $url_options = ['absolute' => TRUE];
+ if (isset($options['langcode'])) {
+ $url_options['language'] = \Drupal::languageManager()->getLanguage($options['langcode']);
+ $langcode = $options['langcode'];
+ }
+ else {
+ $langcode = NULL;
+ }
+ $replacements = [];
+
+ if ($type == 'node' && !empty($data['node'])) {
+ /** @var \Drupal\node\NodeInterface $node */
+ $node = $data['node'];
+
+ foreach ($tokens as $name => $original) {
+ switch ($name) {
+ // Simple key values on the node.
+ case 'nid':
+ $replacements[$original] = $node->nid;
+ break;
+
+ case 'title':
+ $replacements[$original] = $node->getTitle();
+ break;
+
+ case 'edit-url':
+ $replacements[$original] = $node->url('edit-form', $url_options);
+ break;
+
+ // Default values for the chained tokens handled below.
+ case 'author':
+ $account = $node->getOwner() ? $node->getOwner() : User::load(0);
+ $replacements[$original] = $account->label();
+ $bubbleable_metadata->addCacheableDependency($account);
+ break;
+
+ case 'created':
+ $replacements[$original] = format_date($node->getCreatedTime(), 'medium', '', NULL, $langcode);
+ break;
+ }
+ }
+
+ if ($author_tokens = $token_service->findWithPrefix($tokens, 'author')) {
+ $replacements += $token_service->generate('user', $author_tokens, ['user' => $node->getOwner()], $options, $bubbleable_metadata);
+ }
+
+ if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) {
+ $replacements += $token_service->generate('date', $created_tokens, ['date' => $node->getCreatedTime()], $options, $bubbleable_metadata);
+ }
+ }
+
+ return $replacements;
+}