Skip to main content
Home
Drupal life hacks

Main navigation

  • Drupal
  • React
  • WP
  • Contact
  • About
User account menu
  • Log in

Breadcrumb

  1. Home

Creating a Custom Token Decorator in Drupal: Extend and Control Token Replacement

By admin, 3 October, 2025

🔹 How to Create a Custom Decorator for Token in Drupal

In Drupal, tokens allow dynamic values to be substituted into text, email templates, fields, and more. There are two main Token classes:

ClassNamespaceSourceRole
Drupal\Core\Utility\TokenCoreDrupal coreMinimal implementation: basic replace() and hook_token_info() support.
Drupal\token\TokenContrib module TokencontribExtended functionality: token sorting, global token types, validation (getInvalidTokens*), caching, better API for UI.

⚠️ Core remains lightweight, while the contrib Token module adds full features.


1️⃣ Why are there two Token classes?

Drupal Core provides minimal functionality to avoid adding extra complexity.

The Token module extends the core class by adding:

  • sorting tokens by name,
  • global tokens that are always valid,
  • token validation in different contexts,
  • caching and UI support.

Which Token class is used depends on the installed modules:

$token_service = \Drupal::service('token');
dump(get_class($token_service)); 
// Outputs: Drupal\Core\Utility\Token or Drupal\token\Token

2️⃣ Why create a custom decorator?

You might want to:

  • log all replace() calls,
  • filter or block specific tokens,
  • add custom prefixes or dynamic tokens,
  • implement a "dry-run" mode (scan tokens without replacing them).

A service decorator over Token is the best approach.


3️⃣ How to create a Token decorator

Step 1. Register the service

In mymodule.services.yml:

services:
  mymodule.token_decorator:
    decorates: token
    class: Drupal\mymodule\TokenDecorator
    arguments: ['@mymodule.token_decorator.inner']

⚡ decorates wraps the existing service without changing core or contrib.


Step 2. Create the TokenDecorator class

File: src/TokenDecorator.php

<?php

namespace Drupal\mymodule;

use Drupal\token\Token as ContribToken;

/
 * Decorator for the token service.
 */
class TokenDecorator extends ContribToken {

  /
   * @var \Drupal\token\Token
   */
  protected $inner;

  public function __construct(ContribToken $inner) {
    $this->inner = $inner;
  }

  /
   * Extend replace() to add custom logic.
   */
  public function replace($markup, array $data = [], array $options = [], $bubbleable_metadata = NULL) {
    // 🔹 Log before replacement
    \Drupal::logger('mymodule')->debug('Before replace: @markup', ['@markup' => $markup]);

    // Use the original Token service
    $result = $this->inner->replace($markup, $data, $options, $bubbleable_metadata);

    // 🔹 Log after replacement
    \Drupal::logger('mymodule')->debug('After replace: @result', ['@result' => $result]);

    // 🔹 Custom filter: block specific tokens
    $result = str_replace('[bad:token]', '[REMOVED]', $result);

    return $result;
  }

  /
   * Example: return all tokens for a specific type.
   */
  public function getTokenVariants($type) {
    $info = $this->inner->getInfo();
    if (empty($info['tokens'][$type])) {
      return [];
    }

    $variants = [];
    foreach ($info['tokens'][$type] as $token => $data) {
      $variants[$token] = $data['name'] ?? '';
    }

    return $variants;
  }
}

4️⃣ What this decorator gives you

FeatureImplemented?
Preserves base Token API behavior✅
Logging tokens before/after replace()✅
Custom token filtering✅
Extendable getInfo(), scan(), getInvalidTokens()✅
Globally overrides token service✅

5️⃣ Possible improvements

  • Custom prefixes: [env:...], [custom:...]
  • Role-based blocking: e.g., anonymous users cannot see [user:email]
  • Dry-run mode: scan tokens without replacing
  • JSON API for UI: provide all tokens and descriptions for autocomplete

6️⃣ Testing it

$token_service = \Drupal::service('token');
$markup = "Hello [node:title], bad token: [bad:token]";
echo $token_service->replace($markup, ['node' => $node]);

Log output:

Before replace: Hello [node:title], bad token: [bad:token]
After replace: Hello Example node title, bad token: [REMOVED]

✅ This gives a fully working custom Token decorator in Drupal.

 

Tags

  • #Drupal Planet
  • Token

Comments

About text formats

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
Powered by Drupal