Drupal will load unnecessary entities (non-node) if a menu link to them is in the main menu. The reason I say it's loading them unnecessarily has to do with the fact that if a menu item is disabled it will still do an entity_load on it.

How to repo:
Standard Drupal Install
Create a new user
Link to user/2 in Main menu (admin/structure/menu/manage/main-menu)
Disable that link in the menu.
user/2 is still loaded on every page load even though that menu item is disabled.

Comments

mikeytown2’s picture

Status: Active » Needs review
StatusFileSize
new617 bytes

Status: Needs review » Needs work

The last submitted patch, drupal-1710656-1-skip-hidden-menu-items-D7.patch, failed testing.

mikeytown2’s picture

Status: Needs work » Needs review
StatusFileSize
new702 bytes

This patch should take care of the breadcrumb issue.

mikeytown2’s picture

menu_tree_check_access() on a logged out (anonymous) front page hit
Without Patch
cumulative time: 29ms
calls: 3

With Patch
cumulative time: 4.4ms
calls: 3

Results will vary depending on the site, but overall this should reduce the amount of code being ran.

mikeytown2’s picture

Version: 7.x-dev » 8.x-dev
StatusFileSize
new722 bytes

Patch for Drupal 8 attached below

mikeytown2’s picture

Patch for D6 after seeing this issue here http://drupal.stackexchange.com/questions/42232/ubercart-entries-in-menu...

Benchmark
Before: 22ms
After: 20ms
So a slight improvement on our site, but depending on the menu structure it could have a big improvement. I can verify that less code is being ran because the cachegrind file shrunk by 300kb with this patch.

oliverpolden’s picture

The Drupal 6 patch works a treat. Is it safe to apply in a live environment?

mikeytown2’s picture

The patch passed all D7 & D8 tests, so that's a good sign. My guess is it is safe to apply to D6 but I can't guarantee that its 100% safe.

mukesh_k_see_node_1875610’s picture

Yes Mike, it works. After apply in D7, I have also found some noticeable difference in profiling results.

AntiNSA’s picture

Subscribing. can anyone verify they tested drupal 6 no problems?

mikeytown2’s picture

I use the D6 patch on our production boxes. No issues have been reported.

th3m1773n’s picture

The last submitted patch, 3: drupal-1710656-3-skip-hidden-menu-items-D7.patch, failed testing.

th3m1773n’s picture

The last submitted patch, 3: drupal-1710656-3-skip-hidden-menu-items-D7.patch, failed testing.

mikeytown2’s picture

Version: 8.x-dev » 7.x-dev
Issue summary: View changes

To test on D7, you need to change the issue version # to D7

mikeytown2’s picture

mikeytown2’s picture

Version: 7.x-dev » 8.x-dev

Patch in #3 still passes. Moving this back to D8 for core inclusion.

dawehner’s picture

Status: Needs review » Needs work

The last submitted patch, 5: drupal-1710656-5-skip-hidden-menu-items-D8.patch, failed testing.

joelpittet’s picture

The D7 patch saved me a nice ~50ms, thank you:)

mikeytown2’s picture

Version: 8.0.x-dev » 7.x-dev
Status: Needs work » Reviewed & tested by the community

I think this no longer is applicable to D8. Closest thing I can find to D7's _menu_tree_check_access() in D8 is BookManager::doBookTreeCheckAccess() & DefaultMenuLinkTreeManipulators::generateIndexAndSort(). I have a feeling that the book module will get updated so the $item = &$tree[$key]['link']; portion gets factored out.

#3 for D7 and #6 for D6

joseph.olstad’s picture

RTBC ++

I've thoroughly tested this patch on a complex multi-lingual site with over 500 modules and features and it works great. We've followed Joelpittets' recommended low risk patches and achieved amazing performance gains. Also thanks to Joelpittets' review of patches we've gotten incredible improvements in authenticated user site performance with his patch recommendations. I suggest to others using D7 to check out Joelpittets' recommended patches.

David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs review

It would be great to get this kind of performance improvement in, but I'm not sure we can do it like this.

With this patch, the return value of some public API functions is going to change (for example, menu_build_tree()), kind of arbitrarily. Before they would include disabled links if the user had access to them, and afterwards they won't necessarily. It is hard to predict the consequences of that kind of change.

Maybe we can do this with some API additions that allow particular menu functions to request that hidden menu items never be loaded (in the case where they are building the menu for display purposes only)? For example, I haven't checked this carefully but it looks to me like both menu_navigation_links() and menu_tree() build the entire menu and then throw away the hidden links afterwards? If there were a way for those specific functions to signal that hidden menu items can be thrown away during the tree-building itself (without bothering to translate or check access for them) then I think we potentially get the same performance benefit but without any unexpected API changes.

joseph.olstad’s picture

We've been using this with drupal core 7.35, drupal core 7.37 and the latest drupal core 7.38 and it's working as expected.

joseph.olstad’s picture

We're still running this on production sites now with drupal core 7.39.

Have not noticed any problem or conflict and we're running full i18n multilingual D7 . Appreciate the performance gain especially on sites with lots of menu links.

mikeytown2’s picture

@David_Rothstein
Is there a test for the situation you're describing with menu_build_tree()?

joseph.olstad’s picture

Status: Needs review » Reviewed & tested by the community

RTBC
This patch is still working on Drupal 7 core 7.50 , used it also with Drupal core 7.44

We're doing multilingual sites and have created content programmatically , used it with entity translation or node translation , menu link translation.

Great work @mikeytown2 , your gaining quite a fabulous reputation for yourself here in the core queue.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 6: drupal-1710656-6-skip-hidden-menu-items-D6-do-not-test.patch, failed testing.

joseph.olstad’s picture

as for API changes, I'm speaking empirically here, after several years of this patch being used it dosen't have any reported conflict with any contrib module, meaning its compatible with contrib as is. If we change the API that *might* mean forced changes to contrib.

RTBC from a production use standpoint on our end, I keep using this patch over and over again on all core upgrades I do.

joseph.olstad’s picture

I resubmitted @mikeytown2 patches because of the new drupal.org option to select which version of core to test against. I specified 7x-1.x core for the D7 patches and 8.1.x for the D8 patch

no changes to the patches,

*** EDIT *** patch #6 is for Drupal 6, ***EDIT***

we've always used patch #3

joseph.olstad’s picture

The last submitted patch, 31: D8-drupal-1710656-31-skip-hidden-menu-items.patch, failed testing.

Status: Reviewed & tested by the community » Needs work
joseph.olstad’s picture

I checked the D8 core code, has changed radically since the earlier patch, looks like D8 does not have this performance issue and if it did it'd be a new issue.

WAITING FOR PATCH 3 to finish tests....

joseph.olstad’s picture

Status: Needs work » Reviewed & tested by the community

Ok, PATCH 3 is still good, we keep using it. PATCH 3 is for Drupal 7, patch 6 is for Drupal 6 so I hid it as it won't apply to D7. Drupal 8 doesn't need this.

joseph.olstad’s picture

***EDIT*** whats up with the testbot ? Unreliable, it passes one time, 2 hours later same code same core, fails. Test again, then it passes? flakey jenkins/testbot. ***EDIT***

reran php 5.3 test, works this time. ALL TESTS ARE GREEN

stefan.r’s picture

I think this may pose a BC break -- can we address #25?

joseph.olstad’s picture

hidden, in active trail and administer menu are checked, this explains why patch 3 passes all tests.

From a security standpoint I don't want hidden menu links to be loaded and translated for those that don't have administrate menu access.

The only use case I can think of where you might want to allow this is if we want to switch menu language without another bootstrap for an authenticated user that does not have administrate menu access. The other is a migration but migrate migrations are always done by an admin type account that has 'administrate menu' access.

From a performance standpoint it is a bonus reason for this change. Less calls to the database, less processing.

From a security standpoint this works. Passes all known tests and works with contrib .

I understand the reluctance and fear however after several years it's not even one report about a fringe case of failure. This patch is in use by keeners like @mikeytown2. I will continue to use this patch until it's included in core. Life on the wild side is faster.

***EDIT***
Maybe a new api function could be added, where all menu links are processed regardless of permissions including hidden menu items, it could be called "_menu_tree_bypass_access" a change record could be added to add this in. However I don't think this function is necessary as someone can just add the 'administer menu' permission and achieve the same result. So to save time, keep the code base tighter and more secure lets >not< create this new api function ***EDIT***

stefan.r’s picture

Status: Reviewed & tested by the community » Needs review

We don't do BC breaking API changes in Drupal 7 anymore, so rather than change the existing behavior and adding a parameter/function for excluding hidden menu items I'd rather do the opposite (keep the existing behavior for menu_build_tree, add a parameter $skip_hidden that defaults to false).

joseph.olstad’s picture

@stefan.r , sounds like your idea could work well, so you're saying the caller of that in core (where the performance is to be gained) might/could/should/would/ have the extra param $skip_hidden as true and thus not affecting the API as the updated menu_build_tree would consider this extra param .

stefan.r’s picture

Yes, that sounds fine -- with contrib being able to use that flag as well.

joseph.olstad’s picture

Status: Needs review » Needs work
joseph.olstad’s picture

Status: Needs work » Needs review
StatusFileSize
new7.48 KB
new3.17 KB

try new patch based on #45, see interdiff

joseph.olstad’s picture

Status: Needs review » Needs work

joseph.olstad’s picture

Fixed it, I am expecting this to pass.

This interdiff shows difference between 45 and 51 (ignore my other interdiffs)

Status: Needs review » Needs work

joseph.olstad’s picture

Status: Needs work » Needs review
StatusFileSize
new10.23 KB
new3.25 KB

try this

Status: Needs review » Needs work

joseph.olstad’s picture

Status: Needs work » Needs review

ok, patch 55 (from comment #54) passes, adding the $skip_hidden flag, backwards compatible change.

This is how I interpreted the recommendation made by @stefan.r

joseph.olstad’s picture

I still prefer patch #3 though, but just for giggles I followed the low-risk backwards compatible option layed out by @stefan.r that will basically allow contrib to take advantage of the $skip_hidden.

Patch #3 however will give you an immediate performance improvement. Patch #55 gives you the 'opportunity' to get you what patch #3 does but from a 'contrib' perspective but does not actually skip hidden links unless called via contrib using core api with $skip_hidden as true from the caller. In Patch #55 $skip_hidden is false by default, meaning it actually does completely process hidden menu items right through to render, as it did before without patching.

ccjjmartin’s picture

Until this has a resolution here is a reroll of #3 based on 7.52 core.

Status: Needs review » Needs work

The last submitted patch, 59: D7-drupal-1710656-59-skip-hidden-menu-items.diff, failed testing.

osopolar’s picture

FWIW: This:

+    // Do not load hidden menu items if not in active breadcrumb trail and
+    // user can't administer the menu.
+    if (!empty($item['hidden']) && empty($item['in_active_trail']) && !user_access('administer menu')) {
+      continue;
+    }

Means, if somebody without "administer menu" permission disables a menu item (s)he can't enable it again, as after disabling, the item will disapear.

Status: Needs work » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.