I have seen How do I create menu links programmatically? but how do I update or delete menu items in Drupal 8?

By programmatically, I mean dynamically; YAML configuration files are not going to help.


5 Answers 5


First you will have to load the entity. Either way works:

$menu_link = MenuLinkContent::load($menu_link_id);

or ...

$menu_link = \Drupal::entityTypeManager()->getStorage('menu_link_content')->load($menu_link_id);

Next you can update value using set() method or through the magic method __set...

$menu_link->expanded = TRUE;

To save, simply call the save() method. To delete, simply call the delete() method.

  • 1
    You are using a mlid there, might seem like I am appending an additional question but where would you get that from, ie. how do you traverse a menu's tree?
    – Duncanmoo
    May 4, 2017 at 12:20
  • In which hook we need to do all these? I am creating a theme and I override menu--main.html.twig file to style the menu. This code has to go in .theme file? in which hook?
    – siddiq
    Dec 11, 2017 at 1:37

I had to do some thing like ....

 //menuLinkManager = 'plugin.manager.menu.link'
$result = $this->menuLinkManager->loadLinksByRoute('entity.node.canonical', ['node' => $node->id()]);
foreach ($result as $menu_item) {
          if (is_object($menu_item)) {
            $id = $menu_item->getPluginDefinition()['metadata']['entity_id'];
$menu_link = $this->entityTypeManager->getStorage('menu_link_content')->load($id);
$menu_link->enabled = 0;


Probably too late I did like:

$menu_handler = \Drupal::service('menu.link_tree')
    ->load("menu-name", new \Drupal\Core\Menu\MenuTreeParameters());
foreach($menu_handler as $key=>$value) {
  if('Name' == $value->link->getTitle()) {
    $link = $value->link;
        'title'=>'New Name'

This is how i delete all the links in a particular menu like footer

$old_menu_links = \Drupal::entityTypeManager()->getStorage('menu_link_content')
  ->loadByProperties(['menu_name' => 'footer']);
foreach ($old_menu_links as $old_menu_link) {

And to update existing menu,

$menu_links = \Drupal::entityTypeManager()->getStorage('menu_link_content')
  ->loadByProperties(['menu_name' => 'footer']);
foreach ($menu_links as $menu_link) {

  if ($menu_link->gettitle() == 'old-title') {
    $menu_link->set('title', 'new-title');

This turned out to be insanely complicated. Apparently not every menu link is a MenuLinkContent object. Sometimes it is a MenuLinkDefault object. In that case, you cannot use ->set() or ->save(). This is the most complete answer to cover both cases. Put this inside of an hook_update_n() and change $disabled_routes and $menu to your needs. In this example I am disabling menu links.

  $disable_routes = [

  $menu_name = 'main';

  $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
  $menu_link_tree_elements = \Drupal::service('menu.link_tree')
    ->load($menu_name, new \Drupal\Core\Menu\MenuTreeParameters());

  foreach ($disable_routes as $disable_route) {
    foreach ($menu_link_tree_elements as $key => $menu_link_tree_element) {
      $menu_link_default = $menu_link_tree_element->link;
      $plugin_definition = $menu_link_default->getPluginDefinition();
      $link_route = $plugin_definition['route_name'];
      if ($link_route == $disable_route) {
        $uuid = $menu_link_default->getDerivativeId();
        if (!empty($uuid)) {
          $menu_link_content = \Drupal::service('entity.repository')
            ->loadEntityByUuid('menu_link_content', $uuid);
          $menu_link_content->set('enabled', 0);
        else {
          $menu_link = $menu_link_manager->getDefinition($key);
          $menu_link['enabled'] = 0;
          $menu_link_manager->updateDefinition($key, $menu_link);

          // Not sure if this is necessary.
              'enabled' => 0,

Your Answer

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

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