13

I need to add some links to existing menu (or to new) programmatically in Drupal 8.

4 Answers 4

28

In order to create a menu item automatically this can be placed in a hook_update_N() implementation in the .install file; it will run when the database is updated.

/**
 * Put the following line on the top of the file containing the
 * following code.
/*
use Drupal\menu_link_content\Entity\MenuLinkContent;

$items = [
  '1' => 'Menuitem 1',
  '2' => 'Menuitem 2',
  '3' => 'Menuitem 3'
];

foreach($items as $nid => $title) {
  $menu_link = MenuLinkContent::create([
    'title' => $title,
    'link' => ['uri' => 'internal:/node/' . $nid],
    'menu_name' => 'main',
    'expanded' => TRUE,
  ]);
  $menu_link->save();
}

You can also programmatically create an entire menu.

$menu = \Drupal::entityTypeManager()
  ->getStorage('menu')
  ->create([
    'id' => 'menu_test',
    'label' => 'Test menu',
    'description' => 'Description text',
  ]);
$menu->save();
4
  • 1
    I think that the correct solution should use the menu yamls
    – Eyal
    Commented Apr 6, 2016 at 11:48
  • 6
    How would you add a menu link as a child to a parent link?
    – Amy
    Commented Apr 14, 2017 at 17:56
  • Note. For external links, use the syntax 'link' => ['uri' => 'example.com'] Commented Apr 26, 2018 at 22:30
  • As of 8.6 and 8.7, I ran into problems using "internal:/node/123". It seems to read 'internal' and flag the link for re-discovery. Instead, using "entity:node/123" seems to work as expected. That is what is stored in the DB when you create a link via menu UI as well.
    – BWagner
    Commented Jun 21, 2019 at 16:27
12

If you would like to create module-defined menu links, add something like this example to your custom_module.links.menu.yml file:

custom_module.admin_item_1:
  title: 'New Admin Item 1'
  parent: system.admin
  description: 'Description of link goes here.'
  route_name: view.some_view_id.page_1

parent (optional) is the id column of the parent in the menu_tree table, and route_name is Drupal's internal route ID for where you'd like the menu item to link to. It's in the menu_tree table as route_name.

See Providing module-defined menu links and Add a menu link for more details and options.

2
  • 3
    Menu yamls only help if you know in advance what menu items you want to create, Programmatic creation may be on node save.
    – Duncanmoo
    Commented May 4, 2017 at 8:04
  • 1
    How to add translatable menu item that way? Like one menu item, but in 3 languages (different menu item titles and paths).
    – MilanG
    Commented Sep 10, 2018 at 9:39
5

To expand on @skorzh answer and reply to the comment from @Matt, if you want to nest a menu item inside another you have to get the parent id and set it as 'parent'. As an example this code nests the item inside the top level using the variable $top_level below.

$menu_link_storage = \Drupal::entityTypeManager()->getStorage('menu_link_content');

$my_menu = $menu_link_storage->loadByProperties(['menu_name' => 'my-menu-name']);

foreach ($my_menu as $menu_item) {
  $parent_id = $menu_item->getParentId();
  if (!empty($parent_id)) {
    $top_level = $parent_id;
    break;
  }
}

$menu_link_storage->create([
  'title' => 'My menu link title',
  'link' => ['uri' => 'internal:/my/path'],
  'menu_name' => 'my-menu-name',
  'parent' => $top_level,
  'expanded' => TRUE,
  'weight' => 0,
])->save();
1
  • 2
    The parent ID is a concatenated string containing menu_link_content: and a menu item's UUID. For example$parent_id = 'menu_link_content:' . $menu_item->uuid();.
    – leymannx
    Commented Aug 17, 2021 at 21:12
0

For anyone who want to create a menu link associated with a node, you should put the format below for the link URI

entity:node/{node-id}

instead of

internal:/node/{node-id}

For example:

MenuLinkContent::create([
  'title' => 'Menu Title',
  'link' => [
    'uri' => "entity:node/{$node_id}",
  ],  
  'menu_name' => $menu_name,
  'parent' => "$menu_name:",
])->save();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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