3

I am trying to create sub tokens in a group off of existing Users token (sometimes referred to as "chaining"). So there are 2 parts to this. Creating the subgroup off the existing User tokens group and creating tokens within that group. I really only need the hook_token_info() part of this; not the actual token code.

I am trying to create a set of tokens of the form: [user:state:{token_id}]. Examples:

  • [user:state:big]
  • [user:state:small]

I am able to create [user:state-big] and [user:state-small] but would like to know how to have these grouped in the token browser under Users -> State.

From documentation linked to by Clive it would suggest this:

  $types['state'] = array(
    'name' => t('State'),
    'description' => t('Tokens related to user state.'),
    'needs-data' => 'user',
  );

  $tokens['user']['state']['big'] = array(
    'name' => t('User State (Big)'),
    'description' => t('The big state of the user.'),
    'type' => 'user',
  );

  $tokens['user']['state']['small'] = array(
    'name' => t('User State (Small)'),
    'description' => t('The small state of the user.'),
    'type' => 'user',
  );

  return array(
    'types' => $types,
    'tokens' => $tokens,
  );

this code gives me these in the token browser:

State   state   Tokens related to user state.

and under Users:

       [user:state]
0

1 Answer 1

3

Your tokens/types aren't structured quite right. You want big and small to be tokens in the state type (not the user), and you want the token you're adding to the user type to be of type state.

The code explains it better:

$types['state'] = array(
  'name' => t('State'),
  'description' => t('Tokens related to user state.'),
  'needs-data' => 'user',
);

$tokens['state']['big'] = array(
  'name' => t('User State (Big)'),
  'description' => t('The big state of the user.'),
);

$tokens['state']['small'] = array(
  'name' => t('User State (Small)'),
  'description' => t('The small state of the user.'),
);

$tokens['user']['state'] = array(
  'name' => t('User State'),
  'description' => t('The user state.'),
  'type' => 'state',
);

return array(
  'types' => $types,
  'tokens' => $tokens,
);

That will enable, e.g., [user:state:big] for use, and show the expected hierarchy in the token browser.

As an aside, you'll also need to populate the data for the state type in hook_tokens().

For example:

function module_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
  $token_service = \Drupal::token();
  $replacements = [];

  if ($type == 'user' && !empty($data['user'])) {
    if ($state_tokens = $token_service->findWithPrefix($tokens, 'state')) {
      $replacements += $token_service->generate(
        'state', 
        $state_tokens, 
        ['user' => $data['user']], 
        $options, 
        $bubbleable_metadata
      );
    }
  }

  return $replacements;
}

Also bear in mind that varying cache by individual user, which is happening here, can result in a lot of cache entries (depending on the number of users and how/where this token is used).

If you can find a solution which varies the content based on role, or even change the implementation so that it incorporates a render array with a lazy builder, you might see better cache performance.

2
  • 1
    This is awesome. Thank you for this and hopefully this serves as a clear example for others trying to do this. One small issue with it though is that although the [user:state:big/small] tokens do show up under Users top level token group; there is also a top level State token group which has [state:big/small] tokens. I removed the name/desc from the $types['state'] array and this fixed that.
    – liquidcms
    May 11, 2023 at 2:47
  • Ah, my bad. Removing Name attr from token info just removes the name in the browser, which causes it to sort to the top of the list. Would be good to know how to not include it in the browser.
    – liquidcms
    May 12, 2023 at 21:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.