13.11.2025 | Nikolas Kopp, Pascal Crott

Token Chaining – How to access tokens for nested information

my_group.module
/**
 * Implements hook_tokens().
 */
function example_group_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
  $replacements = [];

  // Automatically expose related entities to group_relationships.
  if ($type == 'group_relationship' && !empty($data[$type])) {
    $token_service = \Drupal::token();

    /** @var \Drupal\example\GroupRelationshipTypeServiceInterface $group_relationship_type_service */
    $group_relationship_type_service = \Drupal::service('example.group_relationship_type_service');

    $group_relationship = $data['group_relationship'];
    assert($group_relationship instanceof GroupRelationshipInterface);

    foreach ($tokens as $name => $original) {
      /** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
      foreach ($group_relationship_type_service->getConfiguredEntityTypes() as $entity_type_id => $entity_type) {
        if ($name == $entity_type_id) {
          $entity = $group_relationship->getEntity();
          $bubbleable_metadata->addCacheableDependency($entity);
          $replacements[$original] = $entity->label();
        }

        // Actual chaining of tokens handled below.
        if ($entity_tokens = $token_service->findWithPrefix($tokens, $entity_type_id)) {
          $replacements += $token_service->generate($entity_type_id, $entity_tokens, [$entity_type_id => $group_relationship->getEntity()], $options, $bubbleable_metadata);
        }
      }
    }
  }

  return $replacements;
}

Issue:

Out of the box there are plenty of tokens available from the group module. In case those don't fit your needs, you can chain the group_relationship's entity tokens to get the desired value from the referenced entity.

Solution:

Use the snippet to gain access to chained tokens, e.g. users via group relationships.

This snippet has been turned into the group_relationships_tokens module.

Weitere DevBits

16.07.2026 | Lothar Ferreira Neumann

How to translate the Maxlength Countdown message label globally

A Drupal backend screenshot showing the "Count down message" field

Leave this field empty to allow for translation via Drupal interface translation.


Example configuration created by enabling Maxlength:

core.entity_form_display.node.article_not_translatable.default.yml
# ...
content:
  field_copyright:
    type: text_textarea
    weight: 3
    region: content
    settings:
      rows: 2
      placeholder: ''
    third_party_settings:
      allowed_formats:
        hide_help: '1'
        hide_guidelines: '1'
      maxlength:
        maxlength_js: null
        maxlength_js_label: 'Content limited to @limit characters, remaining: <strong>@remaining</strong>'
        maxlength_js_enforce: false
# ...

However, the module already contains fallback logic for this label in maxlength.module: 

maxlength.module
$maxlength_js_label = !empty($thirdPartySettings['maxlength']['maxlength_js_label']) ? $thirdPartySettings['maxlength']['maxlength_js_label'] : t('Content limited to @limit characters, remaining: <strong>@remaining</strong>');
$maxlength_js = $thirdPartySettings['maxlength']['maxlength_js'];

Working configuration: empty the label

core.entity_form_display.node.article_translatable.default.yml
# ...
content:
  field_copyright:
    type: text_textarea
    weight: 3
    region: content
    settings:
      rows: 2
      placeholder: ''
    third_party_settings:
      allowed_formats:
        hide_help: '1'
        hide_guidelines: '1'
      maxlength:
        maxlength_js: null
        maxlength_js_label: ''
        maxlength_js_enforce: false
# ...

With the label empty, the module falls back to its internal t() string, which can then be translated normally via the interface translation system.

yml
module
maxlength
translation
13.11.2025 | Michael Ebert

How to alter the langcode of a field for accessibility reasons

my_module.module
function my_module_preprocess_field(&$variables): void {
  if ($variables['element']['#bundle'] == 'my_bundle') {
    if (in_array($variables['element']['#field_name'], ['my_field'])) {
      $variables['attributes']['lang'] = 'en';
    }
  }
}

module
accessibility
multi-language
field management