Skip to main content

Altering menu links

drupal
module
ui
back-end
Let's say that you want to add some HTML code before the menu link text. Maybe you want to insert Font Awesome code or something like that. Unfortunately, there is no easy way to do that out of box in the CMS. But, you can use the hook_link_alter().

Let's say that you want to add some HTML code before the menu link text. Maybe you want to insert Font Awesome code that looks something like this:

<i class="fas fa-home"></i>

Unfortunately, there is no easy way to do that out of box in the CMS. You can enter HTML code in the Menu link title field like this:

Menu link title


but that code will be escaped, so there is no point of doing that. This is what you'll get:
 

Escaped HTML


That looks really bad, so we obviously need another solution. And, as in some many situations in Drupal -- hooks to the rescue!

In Drupal 8 you can use the hook_link_alter(&$variables) hook to alter menu links. This is what the $variables argument looks like:

Menu link dpm


As you can see, you can modify the link text here. But, there is no easy way to identify this menu link. You cannot tell which menu contains this link, so unless you want to alter all links on your site, using this hook to precisely target menu links is a bad idea.

Unless, you somehow add an identifier.

Fortunately, you can easily do just that and make all this more dynamic. You can use form_alter() hook to alter menu link edit form, and add something like this:

Alter menu link edit form


Pretty cool, right? Not only that you can associate HTML code with a specific menu link, you can even choose where you want to place it.

You can save the new field values (HTML and Position) to menu link options. Menu link options is a serialized array of options for the link, so you can modify this array as you wish.

Now it's much easier to use hook_link_alter(), because you can get the HTML code and alter the link title like this:

/**
 * Implements hook_link_alter().
 */
function link_alter_link_alter(&$variables) {

...

  $html = $variables['options']['html'];

  $variables['text'] = new FormattableMarkup($html . ' @title', [
    '@title' => $variables['text'],
  ]);

...

}

I put together a small module, so you can check it out and see how all this works.

https://github.com/gnikolovski/link_alter