An alternative to Menu Token module

An alternative to Menu Token module

I had some issues with 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 web shop with Drupal Commerce and that you want to create a link to 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 (/admin/structure/menu/manage/account). 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 highly experienced Drupal developer with an extensive skill set that includes PHP, MySQL, HTML, CSS and Javascript. He has experience with large Drupal sites and Drupal Commerce 2.x integration, and he is author of several Drupal modules.