Can I filter the list of candidates used by the menu system to determine the menu trail? I have a site with a menu structure like so:

- a
- b
  - 1
  - 2
- c
  - 1
  - 2


Now lets say that I have a node that both b2 and c2 point to (I'll call it node/4). When the user clicks either link, I want the site to display as a click on c2. That is to say that the main menu item for c should be highlighted, and the secondary menu for c should be displayed. And of course, the content of node/4 should be visible.

What actually happens is that the node/4 content is displayed, but both b &amp; c main menu items are highlighted and the secondary menu for b is displayed.

I've investigated, and found the menu_link_get_preferred function in core/includes/menu.inc. This function builds a list of candidates that can match the current path, and places them into an array keyed like this:

$candidates[MENU_ITEM_LINK_PATH][MENU_NAME]


My problem is that I have two link candidates that match the same exact criteria:

$candidates['node/4']['main']


and so I cannot control which one ends up in the candidates array. Ideally I would like to have a way of flagging the c2 link so that it was not treated as a candidate. I had thought that this would make a good module, but I cannot see a way of interrupting the execution of the function.

The bit of code I would like to alter is (D7 version, D8 is very similar):

// Sort candidates by link path and menu name.
$candidates = array();
foreach ($query-&gt;execute() as $candidate) {
  $candidate['weight'] = $candidate['link_weight'];
  $candidates[$candidate['link_path']][$candidate['menu_name']] = $candidate;
  // Add any menus not already in the menu name search list.
  if (!in_array($candidate['menu_name'], $menu_names)) {
    $menu_names[] = $candidate['menu_name'];
  }
}


In an ideal world I would have added an extra field to the database, so that a $candidate would be discarded on a certain flag. Any ideas how I could achieve this?
Unfortunately menu_link_get_preferred does not sort it's results. If two items match the same paths, it will just return the first result returned by the database. There is an ongoing issue about this: drupal.org/node/1649062

You can workaround this by ensuring the menu you want was added first in the database, but that's not a sustainable way of addressing this. The order might change after you restore a backup, when you compact your database, or after the next Drupal update if they address the issue.

If you cannot work around the issue another way, I think patching core with the patch provided in the issue is safer. The patch sorts the preferred links by mlid, which means you need to create the preferred menu item last (but unlike the workaround before, this will still work even if your database gets re-written).