An alternative to Menu Token module

I had some issues with the Menu Token module, so I looked into an alternative. I found that there is an easy way to add dynamic components in menu links. Let's say that you are creating a webshop with Drupal Commerce and that you want to create a link to the user's orders. The link would have to look something like this:

/user/{{ currentUserID }}/orders

As you can probably guess, {{ currentUserID }} is a dynamic component. Each user has a different ID. You can create such a link by creating two files inside your custom module.

First, you need to create a my_module.links.menu.yml file in the root directory of your module:

my_module.user_orders:
  weight: -50
  menu_name: account
  class: Drupal\my_module\Plugin\Menu\UserOrdersMenuLink

As you can see this link will appear in the User account menu. The link path is generated in the UserOrdersMenuLink class. Let's see how that class looks like:

<?php

namespace Drupal\my_module\Plugin\Menu;

use Drupal\Core\Menu\MenuLinkDefault;
use Drupal\Core\Menu\StaticMenuLinkOverridesInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;

class UserOrdersMenuLink extends MenuLinkDefault {

  protected $currentUser;

  public function __construct(array $configuration, $plugin_id, $plugin_definition, StaticMenuLinkOverridesInterface $static_override, AccountInterface $current_user) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $static_override);

    $this->currentUser = $current_user;
  }

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('menu_link.static.overrides'),
      $container->get('current_user')
    );
  }

  public function getTitle() {
    return $this->t('My Orders');
  }

  public function getUrlObject($title_attribute = TRUE) {
    return Url::fromUri('internal:/user/' . $this->currentUser->id() . '/orders');
  }

}

And that's it. Clear the cache and go to the user menu: Structure -> Menus -> User account menu. You should see your new dynamic link there.

Please note that Drupal 8 adheres to PSR-4. This means that files must be named in certain ways and placed in specific folders. Here is what the module structure should look like:

my_module
├── my_module.info.yml
├── my_module.links.menu.yml
└── src
    └── Plugin
        └── Menu
            └── UserOrdersMenuLink.php

About the Author

Goran Nikolovski is a web and AI developer with over 10 years of expertise in PHP, Drupal, Python, JavaScript, React, and React Native. He founded this website and enjoys sharing his knowledge.