Custom Tokens in Drupal 8

Custom tokens are fairly simple in Drupal 8, despite how hard it was to find any useful information about them. After doing the digging, I thought it would be fun to write up a little guide on how to use them.

The Setup

First up, you’ll need a module if you don’t have one. If you do have one, you can skip to the next section. This will be bare-minimum setup to get us going.

First, create a new folder in your project’s modules/ directory and give that folder the name of your module, I’ll be using mycustommodule .

In this folder, create a new file with your module name, mycustommodule.info.yml

This file will hold some basic information about your module, fill in the details:

name: My Custom Module
type: module
description: 'Module for custom functionality'
dependencies:
package: My Custom Module
core: 8.x

Save that file, then go to the modules page in the Drupal UI and enable your new module.

The Token File

Now we’ll need a file to hold our custom tokens. Create a new file in your custom module’s directory with your modules name and the extension .tokens.inc , in my case it will be mycustommodule.tokens.inc .

The first thing we’ll need in this file is, hook_tokens_info() 

/**
 * Implements hook_token_info().
 */
function mycustommodule_token_info() {
}

This is where we’ll define our tokens for Drupal.

Defining The New Token

The first thing we need to do here is get our token to show up in the UI. You can do this by creating a new $type  array, giving it a name and description, and then returning it in the types  key of a parent array. Here’s how I do it:

/**
 * Implements hook_token_info().
 */
function mycustommodule_token_info() {
    $type = [
        'name' => t('Custom Token'),
        'description' => t('Tokens for custom things.'),
    ];
    return [
        'types' => ['customtoken' => $type],
    ];
}

Which will make your new token available.

Make It Useful

Now that we have it defined, we can make it more useful. To do that, we’ll want to add a new token to the tokens  return array key.

First, let’s define a new token to do something simple, like get the node’s title:

$node['title'] = [
    'name' => t("Node Title"),
    'description' => t('The node\'s title'),
];

But let’s also do something a little more interesting, define a dynamic  token:

$node['dateformat'] = [
    'name' => t("Custom Date Format"),
    'dynamic' => TRUE,
    'description' => t('Show a custom format for the current date'),
];

Then return the tokens:

return [
    'types' => ['customtoken' => $type],
    'tokens' => ['customtoken' => $node],
];

For a tokens file that will look something like this so far:

<?php
/**
 * Implements hook_token_info().
 */
function mycustommodule_token_info() {
    $type = [
        'name' => t('Custom Token'),
        'description' => t('Tokens for custom things.'),
    ];

    $node['title'] = [
        'name' => t("Node Title"),
        'description' => t('The node\'s title'),
    ];

    $node['dateformat'] = [
        'name' => t("Custom Date Format"),
        'dynamic' => TRUE,
        'description' => t('Show a custom format for the current date'),
    ];

    return [
        'types' => ['customtoken' => $type],
        'tokens' => ['customtoken' => $node],
    ];
}

Which will result in our two new tokens being available:

Notice in the green square there is a 😕  after the dateformat token — this is how dynamic tokens show up in the UI to indicate that you can include extra information with the token.

Doing Something with the Tokens

To do something with the tokens we’ll need to add hook_tokens()  to our .tokens.inc  file:

/**
 * Implements hook_tokens().
 */
function mycustommodule_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {

  $replacements = [];

  return $replacements;
}

The replacements array works by replacing the token value, which will be stored in the key, with the value stored in the array, so it will be in the form of $replacements[tokenName] = replacementValue; . So what does that mean for our tokens?

We’ll need to check to see if the token passed into the hook is ours, then check to see if it’s being called from a node so that we can get the title in our first token:

if ($type == 'customtoken' && !empty($data['node'])) {
  foreach ($tokens as $name => $original) {
    switch ($name) {
        'title':
            $replacements[$original] = $data['node']->getTitle();
        break;
    }
}

We loop over each token, and anywhere we see the “title” token, we replace that with the node’s title. Now we can see the title token in action!

The dynamic token is similar, but slightly more complex:

if ($dateTokens = \Drupal::token()->findWithPrefix($tokens, 'dateformat')) {
  // var_dump($dateTokens)
  // retult: array(1) { ["Y-m-d"]=> string(30) "[customtoken:dateformat:Y-m-d]" }
  foreach ($dateTokens as $format => $original) {
      $replacements[$original] = date($format);
  }
}

Here we’re using Token’s findWithPrefix()  method to get an array of our dateformat  tokens and their values.

Put it all together and you get

/**
 * Implements hook_tokens().
 */
function mycustommodule_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {

    $replacements = [];
    
    if ($type == 'customtoken' && !empty($data['node'])) {
        foreach ($tokens as $name => $original) {
            switch ($name) {
                case 'title':
                    $replacements[$original] = $data['node']->getTitle();
                break;
            }
        }
        if ($dateTokens = \Drupal::token()->findWithPrefix($tokens, 'dateformat')) {
            // var_dump($dateTokens)
            // retult: array(1) { ["Y-m-d"]=> string(30) "[customtoken:dateformat:Y-m-d]" }
            foreach ($dateTokens as $format => $original) {
                $replacements[$original] = date($format);
            }
        }
    }

    return $replacements;
}

And we can test it to make sure everything is working:

This just scratches the surface with the cool things you can do with tokens. How have you used custom tokens in your projects?

Full Code

<?php
/**
 * Implements hook_token_info().
 */
function mycustommodule_token_info() {
    $type = [
        'name' => t('Custom Token'),
        'description' => t('Tokens for custom things.'),
    ];

    $node['title'] = [
        'name' => t("Node Title"),
        'description' => t('The node\'s title'),
    ];

    $node['dateformat'] = [
        'name' => t("Custom Date Format"),
        'dynamic' => TRUE,
        'description' => t('Show a custom format for the current date'),
    ];

    return [
        'types' => ['customtoken' => $type],
        'tokens' => ['customtoken' => $node],
    ];
}

/**
 * Implements hook_tokens().
 */
function mycustommodule_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {

    $replacements = [];
    
    if ($type == 'customtoken' && !empty($data['node'])) {
        foreach ($tokens as $name => $original) {
            switch ($name) {
                case 'title':
                    $replacements[$original] = $data['node']->getTitle();
                break;
            }
        }
        if ($dateTokens = \Drupal::token()->findWithPrefix($tokens, 'dateformat')) {
            // var_dump($dateTokens)
            // retult: array(1) { ["Y-m-d"]=> string(30) "[customtoken:dateformat:Y-m-d]" }
            foreach ($dateTokens as $format => $original) {
                $replacements[$original] = date($format);
            }
        }
    }

    return $replacements;
}

 

2 thoughts on “Custom Tokens in Drupal 8

  1. Any idea why I can’t get a custom token to appear in the token list?

    I know the “_token_info()” function is being run because I can add code to break the token list. But when I apply the above simple code (without intentional errors) I get no errors and no token in the list. -I have cleared cache, but can’t figure out why I can’t even get the token reference to appear.

  2. FYI, I stumbled on a solution by looking at the tokens module. A different format for the array structure was needed for this token to display for me.

    /**
    * Implements hook_token_info().
    */

    function registria_embed_field_token_info() {
    $info[‘tokens’][‘node’][‘custom’] = array(
    ‘name’ => t(‘custom’),
    ‘description’ => t(‘This is custom.’),
    );

    return $info;
    }

Leave a Reply

Your email address will not be published. Required fields are marked *