I have a content type with some entity reference fields to another content types. I want to add local task tabs to the node view page, to link those referenced node. However I cannot figure it out how to do it only for the specific content type.

I have created a my_module.links.task.yml file with following contents:

  route_name: entity.node.canonical
  title: Overview
  parent_id: entity.node.canonical
  weight: 0
  class: '\Drupal\my_module\Plugin\Menu\MyContentTab'

  route_name: entity.node.canonical
  title: Referenced content
  parent_id: entity.node.canonical
  weight: 10
  class: '\Drupal\my_module\Plugin\Menu\MyReferencedContentTab'
# ... More tabs to the other referenced nodes

The classes are working as they should, and providing the tabs to the referenced nodes correctly. However the tabs are also showing on all content types.

How can I make them show only on the specific content type?

  • I'd probably set up a custom permission for the tab pages, that checks the type, and denies access if the type is incorrect. Tabs will not be rendered if access is denied. – Jaypan Mar 9 '20 at 16:06

The reason these tabs show up on all of your content types is that entity.node.canonical is the base route for all nodes. Since you're setting entity.node.canonical as the parent_id, Drupal thinks you want these tabs displayed on every node page.

The easiest way to achieve your goal is probably to implement hook_menu_local_tasks_alter() with code similar to this:

  if ($route_name === 'entity.node.canonical') {
    /** @var \Drupal\node\Entity\Node $node */
    $node = \Drupal::routeMatch()->getParameter('node');
    if ($node->bundle() !== 'my_bundle') {
      $data['tabs']['my_module.my_content.my_content_type']['#access'] = FALSE;
      $data['tabs']['my_module.my_content.my_referenced_node']['#access'] = FALSE;

Because Drupal performs upcasting on this route, you can get a reference to the current node directly from routeMatch() as a parameter, and then compare its bundle to your custom content type. When they don't match up, we set access to FALSE for those tabs.

I think another approach that would probably work is to override the getRouteParameters() method of your LocalTaskDefault classes and use similar logic; if the current node isn't your custom content type, then return an empty array of route parameters.

A third approach might be to create a custom route for your specific content type and then assign that route as the parent_id for these tabs.

  • Thanks Beau! hook_menu_local_tasks_alter() did it as your sample code. – Елин Й. Mar 10 '20 at 14:52
  • Just to make it complete for the other readers, the code I used to deny access was: $accessForbidden = new AccessResultForbidden(); $data['tabs'][1]['my_content.my_content_type']['#access'] = $accessForbidden; $data['tabs'][1]['my_module.my_content.my_referenced_node']['#access'] = $accessForbidden; Which has two differences, AccessResultForbidden object instead of FALSE, and the tab level 1 for the second level which I was actually using. For the first level it should be 0. – Елин Й. Mar 11 '20 at 9:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.