I having an issue with the installation logic of a custom module. I am trying to add menu links using menu_link_save() that link to a view that is defined in my module in hook_views_default_views().

I am creating a new site using a installation profile that installs this custom module by default. I'm not sure if this is related to being in the install/update environment instead of the normal page environment.

The problem I am having is that the view hasn't created any route in the menu_router table. When I add a link I get a row in menu_links, but the router_path column is empty and the row gets deleted by Drupal when it decides to rebuild the menus.

Is there way to cause the view to populate the menu_router table so that I can add links normally? Is there another way I can use for this? I would like to be able to keep my profile and, rely on a single site install action instead of having to do something after installing, as follow up.

The link never appears; Drupal deletes it from the menu_links table.

  • Any success on solving this? I just ran into the very same problem. Jan 20, 2017 at 13:42
  • This is awfully hacky but I ended up explicitly defining the route I needed in HOOK_menu() for the module that defines the view with the 'page callback' being 'drupal_goto' and the 'page arguments' being the same route name. It seems to have tricked drupal into registering the route but also allowed the view to take over the route when it was ready to. If this works for you I'll post it as an answer so it's easier for other people to find. Jan 20, 2017 at 18:54
  • See solution below. Jan 24, 2017 at 14:51

1 Answer 1


Problem background

I actually found an answer to this problem. Drupal has a rather aggressive way of deleting menu items that has the router_path field set to NULL (or empty) in table menu_links. If Drupal finds such a record it will delete the record upon the next run of menu_rebuild(); (see docs) or documentation block below.

 * Populates the database tables used by various menu functions.
 * This function will clear and populate the {menu_router} table, add entries
 * to {menu_links} for new router items, and then remove stale items from
 * {menu_links}. If called from update.php or install.php, it will also
 * schedule a call to itself on the first real page load from
 * menu_execute_active_handler(), because the maintenance page environment
 * is different and leaves stale data in the menu tables.
 * @return
 *   TRUE if the menu was rebuilt, FALSE if another thread was rebuilding
 *   in parallel and the current thread just waited for completion.


Each menu item created this way must contain the property customized and have its value set to to 1. This forces Drupal to update the record in table menu_links with the matching router_path instead of deleting it. See function _menu_navigation_links_rebuild($menu) around line 2929 in menu.inc. _menu_navigation_links_rebuild($menu) is called from menu_rebuild().


This will create a new link on the top level in a menu named 'your-menu-name'.

$ls = array(
  'menu_name' => 'your-menu-name',
  'link_title' => 'Your Link Title,
  'link_path' => 'your/link/path',
  'plid' => 0, 
  'weight' => 0, 
  'customized' => 1, // "The magic property"

$newpid = menu_link_save($ls);

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.