Just got a nasty surprise after breadcrumbs/page title stop working at 8 levels, and after a bit of digging into the code noticed the menu system has a maximum depth set using MENU_MAX_DEPTH = 9.
Can anyone expand on the future of this, and is this going to be increased or made more dynamic in the future.
While nesting this deep seems crazy, a simple global regional breakdown quickly consumes these... I have estimated that I am going to need 14 levels on a current project.
Eg: Home › Regions › Australasia › New Zealand › Canterbury › Castle Hill Basin > ...
Thx in advance
Comments
Comment #1
pwolanin CreditAttribution: pwolanin commentedDo you really want to put all these levels in the menu? I'm not sure that's going to look very good in a block. Did you consider using taxonomy instead? You'd have to generate the BC (or maybe there is an existing module for it), but that would also give you term pages and such.
The hard limit is a tradeoff - every level requires an int column in the DB. So, you could potentially change this on your own install by adding more columns to {menu_links} (i.e. p10, p11, p12, p13, p14) and changing the MENU_MAX_DEPTH to match.
Whether 9 is the right number is subject to debate - it probably won't be changed in 6.x unless there is a groundswell of people hitting this limit. For 7.x, the possibilities are more open.
Comment #2
Alan D. CreditAttribution: Alan D. commentedThx for the response.
I found very little on this when searching for the issue. I only discovered this after seeing that the title was not being correctly set on a couple deeper items. It actually took a bit of time tracking this down debugging from drupal_set_title to see what was the cause!
The menu is generated via a taxonomy, vocab/..../p2_tid/p1_tid/tid that has custom additions to make them pseudo-nodes with a blurb, and some custom fields indicated the level, ... Only the first and last items are actually used for the callback. The rest are for the breadcrumbs and path.
The menu is dynamically loaded via a drop down menu, with a secondary level that will be displayed via a custom view showing the next couple levels in a multicolumn list. I was hoping to do this without having to generate the custom breadcrumbs and title, thus the query about the depth. This is also related to SEO in that any number of the terms in the path could be used to search for the particular destination.
I had a quick look at menu.inc and I'm holding off hacking into it, but would prefer this to if path > 8, trim less important terms or if path > 8 set_breadcrumbs, ...
Bumping down the priority
Comment #3
pwolanin CreditAttribution: pwolanin commentedok - there are also a few queries that would need to be modified I think - at the least, the insert/update queries for links.
Comment #4
Alan D. CreditAttribution: Alan D. commentedThx Peter
I keep track of the changes and post these for others if they need them. Currently minor priority as many more features to implement in the next few weeks...
Comment #5
Alan D. CreditAttribution: Alan D. commentedA quick investigation shows that the number is used very dynamically. The developers look extremely close to be able to define a user configurable max depth, and have everything else dynamically generated. Fingers crossed for the future.
For those that simply can not wait, try the following. Report back with any errors. :) This is for 15 levels.
THIS IS FOR DRUPAL 6.2 ONLY.
Update the menu links table: (Postgres users note the phpmyadmin special quotes)
And the following patches for Drupal 6.2
And not sure if needed, the system install. Guessing that this is only required if patched pre-installation. Anyone?
Currently I have only tested on a menu that is generated from a hacked taxonomy menu, but the things are working well so far.
A word of warning about the YUI Menu module. This will crash if you run this on a larger menu system, maybe unless you have a real fast server with heaps of memory to spare. The way that they generate the menu involves multiple recursive menu get tree calls. 15 levels and 250 items simply killed my install until I disabled it.
The book module will also require patching if you use this. I don't so I didn't attempt it.
It would pay to search for the three terms to make sure that other modules don't require modifications: "MENU_MAX_PARTS", "MENU_MAX_DEPTH", and "p4"
Cheers
Comment #6
pwolanin CreditAttribution: pwolanin commentedDon't change MENU_MAX_PARTS! That's totally unrelated to the links.
Also, there is probably a query or two in book module that would need to change.
Comment #7
Alan D. CreditAttribution: Alan D. commentedIf MENU_MAX_PARTS is not changed, the breadcrumbs and page title don't get set to the final menu item. They get chopped off at 7 items:
For example the page "http://rctopos6/region/4/17/20/35/42/46/50/52/72/73/74"
points to
"Home › Regions › Australasia › New Zealand › Canterbury › Castle Hill Basin › Flock Hill Station › Flock Hill › The Far Side › The Figurehead Group › test 10 › test 11 {title}test 12"
But changing MENU_MAX_PARTS back to seven cause the default menu created items to fail:
"Home › Regions › Australasia › New Zealand › Canterbury › Castle Hill Basin › Flock Hill Station {title} Flock Hill"
Being 2am after a long week, I'm not reading the router bits that clearly, but the path needs to be split into the length that these elements require? Doing a test of a full 15 items deep, I had to change this to 15 as well without strange things happening to the menu.
The taxonomy menu generates the items like this:
thus the strong coupling between the two maybe? This is my first look at the menu system outside of generating menu items.
Comment #8
pwolanin CreditAttribution: pwolanin commentedRight, MENU_MAX_PARTS controls how many elements a path in the router has.
If you are actually making paths like this - I think you are doing something wrong, and are potentially going to have performance problems.
Note - you SHOULD NOT, NOT, NOT - be putting items in the router just to get a link. They are decoupled - items in the router should define page callbacks. What you are doing above will mean your PHP will quickly exhaust its memory.
use the menu module interface - or in code with menu_link_save().
Comment #9
Alan D. CreditAttribution: Alan D. commentedThx Peter
I rewrote my already modified taxonomy_menu module to take into account your warning. I think I only nuked the installation 8 or 9 times before getting things right.
menu_link_save triggered a recursive loop from hook_menu, so I assigned the custom menu tree creation to a registered shut down function via register_shutdown_function. This brings up the need for a post-build hook, but there are only 4 or so items whose router path differs from their link_path, so that'd be a bit of over-engineerring I think ;)
Comment #10
pwolanin CreditAttribution: pwolanin commentedwhy in the world would you call menu_link_save from hook_menu? Obviously my explanation above was not clear. I'd call it from hook_taxonomy or some such if that's what you are trying to achieve.
Comment #11
Alan D. CreditAttribution: Alan D. commentedThat was simply how the tax_menu had done it processing. A link similar to reset to alphabetical would probably make more sense with hooks on insert and delete operations. I have had problems with stale data when saving data via hook_taxonomy when moving things around via the dnd list terms page. Different project, but similar need to keep track of the exact hierarchical nature of the items. Well, maybe not stale, but only certain items triggered the update operation, so sections in the chain didn't have their paths updated.
bty, the increase in the menu_max_depth is working great so far.
Comment #12
pwolanin CreditAttribution: pwolanin commented@Alan D. - if it was doing any such thing in hook_menu in D6, it's broken and incorrectly updated from D5.
Comment #13
Alan D. CreditAttribution: Alan D. commentedI meant to say "where" not "how". This is where they generated the router links for the entire tree, which I modified and added (incorrectly) the menu set links
Comment #14
pwolanin CreditAttribution: pwolanin commentedright, but if they are adding lots of router items for the one existing callback, that's incorrect. They should use func_get_args in this case.
also, there should be no t() in there.
I'd suggest you file a bug report against that module - I would not use it if that's how it's working.
Comment #15
steve.colson CreditAttribution: steve.colson commentedI would just like to chime in to say having a statically set maximum is quite contrary to the whole point of a flexible system like Drupal to begin with. Who is anyone here to say what anyone else's business needs are with regards to their information architecture and how to display it? There will always be another site where they need MAX_MENU_DEPTH + 1. If you're that worried about performance, you could easily serialize an array of menu parents and have a single 'p' column; that said, complex and large menu structures slowing down a system is what caching is for.
Comment #16
ainigma32 CreditAttribution: ainigma32 commentedLooks like the answer was given - no and no - so I'm setting this to fixed.
Feel free to reopen if you want to pursue this any further.
- Arie
Comment #18
natukI am sorry to reopen this after a month but I, too, think that such a limitation on the number of levels is unreasonable. In more than one cases of Drupal installations I need a lot deeper hierarchies and have been stuck to D5 because of this. I agree with stephen.colson about alternative ways of achieving performance.
Comment #19
ainigma32 CreditAttribution: ainigma32 commentedNo problem, like I said: "Feel free" ;-)
I would suggest you also take this up on IRC and/or the developers mailing list.
- Arie
Comment #20
ainigma32 CreditAttribution: ainigma32 commented@natuk: Any progress on this?
- Arie
Comment #21
ainigma32 CreditAttribution: ainigma32 commentedLooks like natuk won't be posting any feedback so I'm setting this to fixed.
Feel free to reopen if you think that is wrong.
- Arie
Comment #22
Alan D. CreditAttribution: Alan D. commentedHi Arie
I've bumped this back to active, just so the issue isn't forgotten about, and any future development of the menu system may allow this issue to be resolved.
I am fairly sure that this will only ever effect < 0.1% of users, so setting priority to minor. It would be nice but there are workarounds - like manually creating deep menus and storing the structure in the taxonomy.
Comment #23
natukSorry for the delay in following this up. I have posted a message in the developer's list:
http://lists.drupal.org/pipermail/development/2009-February/031875.html
I got a couple of answers which I think confirm my scepticism on this limitation. I was pointed to this thread:
http://drupal.org/node/344019
as a possible way to resolve the limitation and sort out the tree-structuring in drupal in general. So I too agree that the issue should not be marked as fixed, but keep it open until the limitation is shifted, hopefully with this new proposed implementation for hierarchies.
Comment #24
greenSkin CreditAttribution: greenSkin commentedI'm am developing a module that I need a bigger menu depth for. Is there a way currently for a module developer to programmatically increase the MAX_MENU_DEPTH? I'm looking to also keep the dynamic menu breadcrumbs intact.
My max menu depth would look something like this:
'admin/{module}/accounts/%/folders/%/contacts/%/edit'
Comment #25
Alan D. CreditAttribution: Alan D. commentedIt requires a core hack, I made the depth 15 for a project that required it, see above.
Firstly, do you really need it?
"{module}/accounts" could be reduced to just a single item "{module}_accounts", and if the contracts are assigned to accounts, have you thought about "accounts/%/contracts?folder=xxxx"
There is another issue with load arguments that you may need to know about, these need to be passed down to every child router item after being used for an item, (for "project" in the example below), and all wildcard loaders need to share the same arguments as these can only be defined once.
For an inhouse cmr, our router paths were something like this:
Comment #26
greenSkin CreditAttribution: greenSkin commentedI would really like to maintain the menu structure as much as possible to the example I gave. I could change '{module}/accounts' to '{module}_accounts' but feels messy and it only brings me down to 8 elements whereas I need to be at no more then 7. The path workflow would really work best by following the 'admin/{module}/accounts/%/folders/%/contacts/%/edit' structure. Each account can have multiple folders and each folder can have multiple contacts, so this is the best way to manage them. I use the tabs 'list' and 'add' for each the accounts, folders, and contacts pages which is really the main issue for the max menu depth for me.
Also @Alan, I didn't quite understand what you meant about an issue with load arguments, if you could elaborate or point me to another issue that talks more in-depth about the issue.
Sorry, I'm off topic, I should start a separate issue. I would like to see there not necessarily be a limit of elements in the menu router unless it can be changed programatically. I understand something is in store in Drupal 7 where this is not an issue?
Comment #27
Alan D. CreditAttribution: Alan D. commented@greenSkin That was just an aside that gave me headaches when having multiple loaders in a nested menu router path. Hope these give more insight, but these are not an issue for standard wildcard placeholders, just the wildcard loaders, see http://drupal.org/node/316971 & http://drupal.org/node/367343
Comment #28
sun.core CreditAttribution: sun.core commentedComment #29
Jaypan CreditAttribution: Jaypan commentedBump
Not sure if this is changed in 7 or not, but it should be. It's causing me headaches right now. I see no valid reason for limiting us on the depth. I have a situation right now where I need 10.
Comment #30
CKoch CreditAttribution: CKoch commentedIs there any means of neatly updating the menu limit that would work? We've hit this limit many times, and having to fake local-tasks in the heirarchy for the depth travelsal is has hit a number of projjects.
Comment #31
pwolanin CreditAttribution: pwolanin commentedIn order to remove the limit we would need to totally rewrite the hierarchy handling. This will almost certainly not happen for Drupal 7, which is why this is flagged for Drupal 8.
Are you coming to Drupalcon and participating in the core conversations?
Can you commit to working on making such a change work and doing performance and other tests?
Comment #32
wjaspers CreditAttribution: wjaspers commentedWhy not just throw out the p1, p2....etc implementation on the menu_link tables. It's totally illogical, and limiting to boot.
Just create a few weak entities (table....not a drupal entity), and compile the menu link with both chunks of data where required:
menu links
menu_structure
NOTE: the # means make this a compound key. If you really want to get creative, push an md5 or sha1 hash as an extra field onto the end of menu_links, and use that at the foreign key in menu_structure.
In this way, its drastically easier to find link siblings, parents, and children, weights are managed properly in EACH relationship, and, depending on how the key structure is defined in (menu_structure), menu items can have multiple parents.
Comment #33
casey CreditAttribution: casey commentedsubscribe
Comment #34
wjaspers CreditAttribution: wjaspers commentedThinking a little more about #32, if Menu's were entities, we could construct things with hierarchy and make them field-able. Other thoughts?
Comment #35
pwolanin CreditAttribution: pwolanin commented@wjaspers - please describe in detail the algorithms you would use for retrieving and manipulating tree structures from SQL, and compare their efficiency to the implementation we have now.
Comment #36
wjaspers CreditAttribution: wjaspers commentedI guess I can't explain an algorithm behind it, but, here goes:
Taking the tree out of the single table design opens menus to deeper capacity.
They become easier to manage.
They become easier to query.
The table design is easier to understand.
Most importantly:
Less overhead is required to build out a single menu because fewer columns are required per tuple (row) of the database.
(If I can find the article, one of the folks over at MySQL (before Oracle bought MySQL AB) explained how much faster indexes work when there aren't a slew of them on just one table.
Is there efficiency information available in the current Drupal doc?
Comment #37
Alan D. CreditAttribution: Alan D. commentedSadly the tree structure has it draw-backs too.
For example, what sql would you use to generate a tree of the menu items? This normally is done via "select level x", then foreach item "select level y where pmid = x". So you need to do hundreds of i/o operations which are terribly slow....
I'd love to hear alternatives for getting the entire tree efficiently, as I'm implementing this model in a regional database ATM. When displaying a tree of only a few thousand items makes my processor shudder as it goes into overdrive!
Comment #38
pwolanin CreditAttribution: pwolanin commentedWe researched several alternative algorithms when we first wrote this code. What we have is a variant of the materialized path, where we are using columns for each path element instead of a string representation.
So, the schema we have now is very efficient for selecting trees and sub-trees as well as for getting partially expanded tress as we show in menu block. But it has a fixed depth limit. that's the trade-off.
Since this is designed for navigation, having a site structure more than 9 levels deep seemed like bad for UX in any case. One also has to consider the size of the SQL index being generated.
EclipseGC has an alternative hierarchy system with an extra table of ancestor relationships, though I'm not sure how well that performs or scales, nor whether it's easy to relocate a sub-tree.
Comment #39
tedbowI created a related issue to document the path parts limit in hook_menu docs. #1983832: Document the limit of 9 parts for paths
Comment #40
YesCT CreditAttribution: YesCT commented#2035877: URL with more than 10 slashes is not working in new routing system was just marked duplicate of this issue.
and
#2028137: Integrate field configuration translation on the user interface had to work around this.
Comment #41
Gábor HojtsySo looks like we need to rely on custom GET arguments instead of path parts on the core proposed config translation module due to this limitation. Any chance a fairy is working on this one? :)
Comment #42
fubhy CreditAttribution: fubhy commentedThere is a good chance that we can remove the p1, p2, p3, p4, ... stuff from menu links by adding a generic solution for hierarchical data. I am particularly peering at either a Nested Sets or a Closure Table solution. Both have their advantages and disadvantages. @amateescu/@DamZ/@fgm got some code for D7 involving entity reference (it's the "Tree" module) which we could probably introduce to D8. Not sure how that would comply with the API freeze rules though... Gabor?!
At the moment it looks like menu links are really the only thing that block the removal of that MAX_PARTS barrier. Routing does not actually care about the number of parts/does not really need a limit. All it cares about is the number of parts. So unless I am mistaken or missing something here we could solve all this by re-factoring our hierarchy solution for menu links.
Comment #43
fubhy CreditAttribution: fubhy commentedI persuaded @amateescu to pick up his work and comment about his work on a unified solution for hierarchical data structures: #1915056: Use entity reference for taxonomy parents
Battleplan included.
Comment #44
Gábor HojtsyThe only way to get a tab is to have a menu link via hook_menu, so although you can define a 10+ component path, you cannot expose it as a tab.
Comment #45
fubhy CreditAttribution: fubhy commentedYou are looking for this issue then: #2004334: Separate Tabs (MENU_LOCAL_TASK) from hook_menu()
@pwolanin wrote a patch that makes local tasks (tabs) plugins that target route names instead of hook menu entries/menu item paths. I hope we can get that committed soon.
Comment #46
Crell CreditAttribution: Crell at Palantir.net commentedThis doesn't need to be WSCCI, since menu and routing are now distinct.
Comment #47
dawehnerWell, due to the fact that there is still a max router depth, its still relevant, IMHO.
Comment #51
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedThere is no router max depth now is there?
Comment #52
mstrelan CreditAttribution: mstrelan commentedComment #56
wombatbuddy CreditAttribution: wombatbuddy commentedJust in case, if someone needs a menu with unlimited depth, than you can use 'Hierarchical Taxonomy Menu' module.
Comment #62
afschI've been dealing with this menu functionality and found a temporary solution that could help other developers.
The requirement here was to limit the menu depth to 5, in case this is not valid then show an error message. This validation works for add/edit menu item via Menu form and Node form.
Here is the code:
File: `my_module.module`
Related ticket https://www.drupal.org/project/drupal/issues/2302043
Comment #64
klonosShould we move any comments that are still relevant in this issue over to #2302043: Make the maximum menu depth configurable and then close this one as duplicate/outdated?