Drupal 8 API: menu entries, local tasks, and other links


Menus are differently structured lists of links to routes

In Drupal (not just 8) "menus" can mean several apparently different things:

  1. Hierarchical links, in several collections (each called a menu) that can be configured in both moduled and manually in the Drupal admin UI.
  2. Local tasks, which form a collection of tabs based around one core "default task".
  3. Local actions, which supplement the local tasks and provide "common other actions" that might be useful in particular context(s).

Ultimately, the word "menu" is applied to a curated (or curatable) list of links. In Drupal 8, a link means, as a minimum: some named route (discussed previously); plus the text that needs to go in the link tag.

From top to bottom, the diagram below shows these three different menu-ish areas of the page; in Drupal 8, these are called respectively menu links, local tasks and local actions:

These three menu-ish types of component are all configurable through YAML files, just like routing. In fact, they build on the work done by routing, turning named routes into menu links, as we'll see.

(Note that the official documentation on menus also talks about a fourth menu-ish thing: contextual links. We won't discuss these here, as implementing them is quite different from implementing the other three.)

Configuring menu links, local tasks and local tabs

As with routing YAML files, the three *.links.*.yml files below consist of several bundles of configuration, each prefixed with an identifying "machine name" (again, see previous discussion of what this means.)

1. Menu links in .links.menu.yml

In the d8api module we built previously, we can add a file in the top-level folder called d8api.links.menu.yml containing the following:

  route_name: d8api.index
  title: 'Menu link to tutorial index'
  menu_name: main

After the machine name identifying the top link, the three configuration lines specify: an existing route_name from the d8api.routing.yml we saved previously; the title of the link, or rather the text that is shown on screen; and the menu_name of the menu you want to add links to.

You can add as many chunks of configuration to this file as you want to, in the same pattern as the above. There are also other configuration keys you can add, including parent to start to build a hierarchy of links, but we want to keep our example simple.

Also note that the machine name of your menu link can match the route name (and probably should, so you can keep track easier): but it needn't do so, especially if you need the same route to be present in more than one menu links hierarchy. We've made them different to show you can.

2. Local tasks in .links.task.yml

Let's define a couple of local task tabs in d8api.links.task.yml, as we've got three of our own routes to choose from:

  route_name: d8api.index
  title: 'Tutorial index'
  base_route: d8api.index
  route_name: d8api.sub_page_for_druplicon
  title: 'Tutorial subpage'
  base_route: d8api.index

The only new configuration item here is base_route. Every collection of tasks (tabs) is defined as a collection by a shared base route (default tab). And note again that you should try to make your local task's machine name (e.g. d8api.index_task) match the route it references (e.g. d8api.index): we only make them different here for clarity.

3. Local actions in .links.action.yml

Finally, we'll configure a local action. You probably won't use these very often, but when you do they can be very useful. Here's d8api.links.action.yml:

  route_name: d8api.index
  title: 'Skip to tutorial'
    - d8api.index

Again, the machine name can and should match the route name; again, there's only one new configuration line in this example: appears_on. An action is like a useful "you might also want to do this" link, that you can make appear on many other routes, if you think it will be useful there. For that reason, the value of this configuration is a YAML array: you can see the hyphen before - d8api.index. You could add another line with e.g. - d8api.sub_page_with_parameter on it, and the action would appear on both routes.

What you should see

With the files above in place, you should clear cache (see previously for how to do that.) In practice, you might need to clear caches a couple of times, for all the different YAML files to be able to cross-reference each other. [I found this to be the case when testing this tutorial, but like a lot of caching weirdnesses it was hard to repeat.]

If you then navigate to /tutorial you should then see the following:

I haven't highlighted the relevant links on this image, as I found it hard to do so while not obscuring some of the test. But you should be able to see, from the top: a second menu link, alongside "Home"; two tabs for the local tasks, with "Tutorial index" highlighted (it corresponds to the current route); and then immediately underneath them, a local action.

If you see the same thing, then congratulations! you've configured the three main types of menu in Drupal.

Further reading etc.


Thank you very much for an amazing tutorial.  You are great!  I've found a small typo in the following line:

base_route: d8apil.index

and it should be:

base_route: d8api.index

Thanks, kndr. You're quite right: the original namespace for the module in these tutorials was "tutorial", not "d8api": in the process of changing it, especially for the earlier tutorials, I occasionally introduced typos.

I'm always glad when people spot typos, though. It shows they're actually reading (and maybe even trying out) the code samples!

You can bet your bottom dollar that I am trying out every piece of your excellent tutorial :) I'm really gratefull for your clear explanations without any unnecessary overhead. IMHO your tutorial is the best I've seen on the Internet. Keep going!