Dynamic local task titles in Drupal 8/9

Sometimes having static text for a local task title is not what you want. If you have to make the title dynamic, based on some condition or context, then read this article to find out how to do it in two very different ways.

Local tasks in Drupal are tabs, usually placed above content on administrative pages.

Drupal 8 and 9 local tasks
Drupal 8 and 9 local tasks

They can also be placed on the user-facing pages, like for example on the login page.

Drupal 8 and 9 local tasks
Drupal 8 and 9 local tasks

In Drupal 8 and 9, they are defined in a YML file named MY_MODULE.links.task.yml. For example, local tasks that are defined in the core's Node module look like this:

entity.node.edit_form:
  route_name: entity.node.edit_form
  base_route: entity.node.canonical
  title: Edit

entity.node.delete_form:
  route_name: entity.node.delete_form
  base_route: entity.node.canonical
  title: Delete

This defines two local tasks (or tabs), one for editing and one for deleting a node. Key route_name defines a local task route, and key base_route is used to group related tasks.

The local task can be altered by using the hook_menu_local_tasks_alter() hook. To alter the task title you can do something like this:

use \Drupal\Core\Cache\RefinableCacheableDependencyInterface;

/**
 * Implements hook_menu_local_tasks_alter().
 */
function MY_MODULE_menu_local_tasks_alter(&$data, $route_name, RefinableCacheableDependencyInterface &$cacheability) {
  if ($route_name == 'entity.node.edit_form') {
    $data['tabs'][0]['entity.node.edit_form']['#link']['title'] = '...dynamically generate title...';
  }
}

As you can see this doesn't look very pretty. I don't like using alter hooks in general, so if there is an option to do this in an OOP way, I definitely prefer that approach. Luckily in this case Drupal provides the OOP way to do it.

We can define a local task class in which we can override the getTitle() method. When not overridden, this method returns the task title that is defined in the YML file.

First, add the new key called class and then provide the class name.

entity.node.edit_form:
  route_name: entity.node.edit_form
  base_route: entity.node.canonical
  title: Edit
  class: '\Drupal\MY_MODULE\Plugin\Menu\LocalTask\DynamicTabLocalTask'

DynamicTabLocalTask must extend the LocalTaskDefault class, and all you have to do is implement the getTitle() method to override the same method in the parent class:

<?php

namespace Drupal\MY_MODULE\Plugin\Menu\LocalTask;

use Drupal\Core\Menu\LocalTaskDefault;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\HttpFoundation\Request;

class DynamicTabLocalTask extends LocalTaskDefault {

  use StringTranslationTrait;

  /**
   * {@inheritdoc}
   */
  public function getTitle(Request $request = NULL) {
    return '...dynamically generate title...';
  }

}

That's it. Now you can dynamically generate the local task title based on some condition or a context.

About the Author

Goran Nikolovski is a creator, speaker, open-source contributor, web developer specialized in Drupal and DevOps enthusiast. He is the founder of this website and he enjoys sharing his knowledge and experiences.