For some reason, I created a main menu item "Admin" linking to the admin path. I also exported this item to a feature module which works fine when exporting via the UI at /admin/structure/features. However, drush diff will show an override like this:
< 'parent_identifier' => 'main-menu_admin:admin',
---
> 'parent_identifier' => 'main-menu_administration:admin',
As the parent identifier seems to be created by the menu title, this is wrong as the title is "Admin" and not "Administration". Updating the feature with drush and reverting it does nothing, the override is still shown.
Notes for commiters
Commit credit should be shared with people who participated in relevant comments in #927566, e.g. #927566-79: Add link title to menu link identifiers to make them more unique.
Comments
Comment #2
ronino commentedThe reason seems to be menu_link_load() which joins data from the menu_links and menu_router tables based on the item path which leads to the "title" being from a different menu item in case my custom item uses the same path as an existing (the original) item defined by a module and contained in menu_router.
So the "Administration" title used for creating the wrong parent identifier comes from the item with the "admin" path defined in system.module.
I attached a patch to fix menu_links_features_export_render() to use the correct "title" instead of the wrong "link_title" of the original item.
Comment #3
donquixote commentedIn menu_links_features_identifier() the $clean_title is computed like so:
https://git.drupalcode.org/project/features/blob/7.x-2.11/includes/featu...
The parent identifier, without this patch, is/was computed like this:
With this patch it would be like this instead:
It seems both of them are wrong, and the correct thing would be like so:
Or perhaps not?
Comment #4
donquixote commentedSee also these comments:
#927566-75: Add link title to menu link identifiers to make them more unique.
#927566-77: Add link title to menu link identifiers to make them more unique. ff
Comment #5
damienmckennaShould the menu exports be rewritten to depend upon UUID? There are just so many different possible flaws in the logic if each menu item is not treated uniquely.
Comment #6
damienmckennaConsider a menu structure like this:
If this menu structure is exported, all of the third level items from the Vegetables menu will be relocated to the Fruit menu, so Fruit -> Shapes and Fruit -> Colors will have four items each while Vegetables -> Shapes and Vegetables -> Colors will not have any items.
Comment #7
sgdev commentedI think all of us in the referenced thread (https://www.drupal.org/project/features/issues/927566) agree that UUID is the right solution, but there hasn't been a concerted effort to make it happen:
Proof-of-concept which adds UUID: https://www.drupal.org/project/features/issues/927566#comment-9690957
Comment #8
damienmckennaThe fun thing is that if Features depended upon CTools it could have UUID support! UUID support was added to CTools 7.x-1.4 via #2155825: Add UUID generation functionality to CTools. Thanks for referencing other comments, I'll review them tomorrow and try to come up with a solution that leverages CTools.
Comment #9
donquixote commentedHi,
please have a look at #3085880: Revisit UUID handling for menu links.
The menu links integration are currently the reason why I am not releasing a new tagged release.
Some history (from memory)
In the last stable version 7.x-2.11, exported menu links are/were identified by some generated id based on the path and perhaps other criteria
Over time, more criteria were added to make this identifier more unique.
Of course this has some inherent problems:
- No matter which criteria you choose, there could always be two distinct menu links which share all those criteria and thus would have the same export id.
- If you change the values in that menu link, it will no longer be exported in the same generated id. Is this a problem? Not sure.
But there is another problem:
The path itself can contain auto-increment ids. E.g. a link to a node would contain the node id, which we would expect to be different on distinct environments (local, staging, etc).
This was "fixed" in #2353585: UUID export and import of menu items linking to nodes, terms and users, which is now part of the -dev version since a long enough time that we have to assume a significant number of people are already using it. Irresponsible? Perhaps..
Also, some code style fixes have been applied since then. So to revert it would at least be not fully trivial.
As I see it, this implementation is flawed and should not have been committed in this way.
Discussion in #3085880: Revisit UUID handling for menu links. This discussion itself is a while ago, so perhaps I will misrepresent some details.
One flaw I remember is that the entity uuid is saved as
$link['uuid']in the exported link.It seems wrong..
I cannot currently say if this is a big problem or not.
There might also be some BC problems.
Alternatives
For my taste, I would prefer to leave the menu_links implementation alone, or rather, produce a version that preserves maximum backwards compatibility both for users of the last stable version 7.x-2.11 and for users of 7.x-2.x.
If anyone really wants this fixed, I would recommend to write a new implementation from scratch, in a new module, which does not need to concern itself with BC.
Maybe I am missing something here, it has been a while since I last looked at this.
Comment #10
donquixote commentedDoes your idea involve adding a uuid column to the menu_links table? Or would we have to store this in some other obscure way?
Changing the actual database storage to add UUID support would do more than features would normally do. So perhaps this should happen in a dedicated module e.g. menu_links_uuid.
Or is some contrib module already doing this?
This commit in uuid module looks interesting:
https://git.drupalcode.org/project/uuid/commit/8b6d70f1764a83896e7997121...
This points to this module:
https://www.drupal.org/project/entity_menu_links
I see this for the first time now :)
How would this work with features? Not sure, look at #1945760: How to deploy menu_links with this module.
Comment #11
damienmckennaLet's postpone this in favor of the other issue.
Comment #12
donquixote commented$link['link_title'] vs $link['title']
In #3 I found a discrepancy between the code that creates a link identifier, vs the code that creates the parent identifier.
For the link itself:
For the parent:
This is already a problem, but only half of the story.
menu_link_load() vs features_menu_link_load()
The other difference is where the
$linkarray comes from.In some cases it comes from
menu_link_load($mlid). In this case it will contain the 'link' key from menu_router table. Also it will pass through_menu_link_translate().In other cases it comes from
features_menu_link_load($identifier). In this case it does NOT contain the 'link' entry.Or it comes from the exported code in a feature:
Solution: Always use 'link_title', always use features_menu_link_load().
I think the only safe solution is to always use 'link_title' and never 'title'.
Also always use features_menu_link_load() to avoid
By doing this, it no longer matters how the link was loaded.
Comment #13
donquixote commentedLet's fix this specific problem here.
The goal (for me) is to make features' own menu_links component more stable and predictable, while avoiding disruptive changes.
The more adventurous and disruptive changes can happen in the features_menu_uuid module.
Comment #14
donquixote commentedI think we should return
FALSEto be consistent withmenu_link_load()andfeatures_menu_link_load().The first
if ()is mostly to prevent the IDE from complaining about possibleNULLreturned from->execute().Comment #15
donquixote commentedComment #17
donquixote commented