1

Thanks to the Pathauto module and tokens, it is very easy to generate URLs with [node:field_product_category:entity:parents:join-path]/[node:field_product_category:entity]/[node:title], but I would like to start at the 2nd level.

Is it possible to exclude the root level from [node:field_product_category:entity:parents:join-path]?

Instead of http://www.example.com/redundant_root_category/category_from_level_2/category_from_level_3/super_product, I would like to get http://www.example.com/category_from_level_2/category_from_level_3/super_product.

2 Answers 2

3

The default tokens won't allow you to do this, but the only thing you're missing I think is an array token that removes the first element, I'd call it "tail". See token_token_info(), which defines for example a 'reversed and other array tokens:

$info['tokens']['array']['reversed'] = array(
  'name' => t('Reversed'),
  'description' => t('The array reversed.'),
'type' => 'array',
);

And the implementation for that is in token_tokens():

// [array:reversed:*] chained tokens.
if ($reversed_tokens = \Drupal::token()->findWithPrefix($tokens, 'reversed')) {
  $replacements += \Drupal::token()->generate('array', $reversed_tokens, array('array' => array_reverse($array, TRUE)), array('array sort' => FALSE) + $options, $bubbleable_metadata);
}

Instead of array_reverse(), you'd call array_shift() on the array first and then pass that along.

Might also be a useful standard token to have in the token.module, if someone wants to provide a patch.

Your token would then look like this:

[node:field_product_category:entity:parents:tail:join-path]
0
0

You have to create a custom module. I made this module for a Drupal 10 site I'm developing and my quick tests show it working. For this example we'll name our custom module all_but_first_token_modifier

  1. Create dir /web/modules/custom/all_but_first_token_modifier. All subsequent steps are inside of this directory.
  2. Create file all_but_first_token_modifier.info.yml with this content:
    name: All But First Array Token Modifier
    type: module
    description: 'Token modifier to get the array of items without the first element'
    package: All But First Array Token Modifier
    core_version_requirement: ^8 || ^9 || ^10
    dependencies:
      - token:token
    
  3. Create file all_but_first_token_modifier.module with this content:
    <?php
    use Drupal\Core\Routing\RouteMatchInterface;
    use Drupal\Core\Render\BubbleableMetadata;
    
    function all_but_first_token_modifier_help($route_name, RouteMatchInterface $route_match) {
      switch ($route_name) {
        // Main module help for the custom_token module.
        case 'help.page.all_but_first_token_modifier':
          $output = '';
          $output .= '<h3>' . t('About') . '</h3>';
          $output .= '<p>' . t('Custom token module to get the array without the first element') . '</p>';
          return $output;
    
        default:
      }
    }
    
    
    function all_but_first_token_modifier_token_info() {
    
      $info['tokens']['array']['all_but_first'] = array(
        'name' => t('All But First'),
        'description' => t('The array without the first element.'),
        'type' => 'array',
      );
    
      return $info;
    }
    
    function all_but_first_token_modifier_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
      $replacements=[];
      // Array tokens.
      if ($type == 'array' && !empty($data['array']) && is_array($data['array'])) {
        $array = $data['array'];
    
        //$sort = isset($options['array sort']) ? $options['array sort'] : TRUE;
        //$keys = token_element_children($array, $sort);
    
        /** @var \Drupal\Core\Render\RendererInterface $renderer */
        $renderer = \Drupal::service('renderer');
    
        foreach ($tokens as $name => $original) {
          switch ($name) {
            case 'all_but_first':
              $all_but_first = array_slice($array,1);
              $replacements[$original] = token_render_array($all_but_first, $options);
              break;
          }
        }
    
        // [array:all_but_first:*] chained tokens.
        if ($all_but_first_tokens = \Drupal::token()->findWithPrefix($tokens, 'all_but_first')) {
          $replacements += \Drupal::token()->generate('array', $all_but_first_tokens, ['array' => array_slice($array,1)], ['array sort' => FALSE] + $options, $bubbleable_metadata);
        }
    
      }
    
    
      return $replacements;
    }
    
    
    
  4. Enable the module in your Drupal admin interface and you'll now have an additional option for array tokens. It can be used the same as the reverse token modifier. Example: [term:parents:all_but_first:join-path]

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.