I am working on a new feature for the Nodeaccess module where nodes can inherit access grants from their menu parents. As I was making tests, I ran into a bug which I traced to the core menu module.

The problem stems from a node having multiple menu locations associated with it, of which only one can be edited in the node edit form. The question is, which one should it be?

The base menu system defined in menu.inc sorts menu items according to their ID. So, if a given node has two menu locations in two different menu paths, when that node is accessed the path that gets expanded in the menu is the one containing the menu item with the lowest ID. This is consistent, and it does not matter which link was clicked to access the node. This, I believe, is how it should be, and so the same menu item should also be in the node edit form.

The menu fieldset is added to the node edit form using menu_form_alter. But when it searches for the menu item to add to the form, no sorting takes place. In most use cases it produces the one with the lowest ID, consistent with the base menu system, but in rare cases it does not.

The bug unfortunately appears at random. It all depends on the order in which the menu item records are stored in the menu table: if a node has two menu items, and the one with the higher ID is stored first in the table, the bug occurs. In my tests, I got the following table:

mysql> select * from menu where path like 'node/%';
+-----+-----+----------------+----------------+-------------+--------+------+
| mid | pid | path           | title          | description | weight | type |
+-----+-----+----------------+----------------+-------------+--------+------+
|   9 |   4 | node/add       | Create content |             |      1 |   28 | 
|  21 |   9 | node/add/page  | Page           |             |      0 |   22 | 
|  22 |   9 | node/add/story | Story          |             |      0 |   22 | 
|  53 |   1 | node/4         | test           |             |      0 |  118 | 
|  46 |  48 | node/4         | foo4           |             |      0 |  118 | 
|  47 |   1 | node/1         | foo            |             |      0 |  118 | 
|  48 |  47 | node/2         | foo2           |             |      0 |  118 | 
|  60 |  50 | node/10        | test10_3       |             |      0 |  118 | 
|  50 |   1 | node/8         | newloc         |             |      0 |  118 | 
|  51 |   1 | node/5         | testfoo        |             |      0 |  118 | 
|  58 |  51 | node/10        | test10_2       |             |      0 |  118 | 
+-----+-----+----------------+----------------+-------------+--------+------+
11 rows in set (0.00 sec)

Here, both node 4 and node 10 suffer from the bug. When I visit node 4, the path foo->foo2->foo4 is expanded in the menu, but the item in the node edit form is test. When I visit node 10, the path testfoo->test10_2 is expanded, but the item in the node edit form is test10_3 - which isn't even visible in the menu, being a child of newloc, which is not expanded.

Fixing this is very simple: all you need to do is sort the results in menu_form_alter, and the menu item in the node edit form is consistently the one with the lowest ID - the apparent primary menu location.

I included a patch, made against Drupal 5.9, which at this time equals Drupal 5.x-dev. This bug only applies to Drupal 5, so patching HEAD is unnecessary.

CommentFileSizeAuthor
menu.patch833 bytesmantyla
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

RoelandG’s picture

I could reproduced the bug which had the same inconsistency as result.

After applying the patch, I could edit the menu settings corresponding with the expanded menu item.

drumm’s picture

Status: Needs review » Fixed

Committed to 5.x.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.