-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Menus: Fix performance issue with tons of duplicated queries #8140
Conversation
The start_el() method in Walker_Nav_Menu currently calls get_privacy_policy_url() for every menu item when building menus. This results in redundant queries, particularly for menus with many items. This patch memoizes the get_privacy_policy_url() result, improving performance while maintaining existing functionality.
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN:
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Hi @arzola! 👋 Thank you for your contribution to WordPress! 💖 It looks like this is your first pull request to No one monitors this repository for new pull requests. Pull requests must be attached to a Trac ticket to be considered for inclusion in WordPress Core. To attach a pull request to a Trac ticket, please include the ticket's full URL in your pull request description. Pull requests are never merged on GitHub. The WordPress codebase continues to be managed through the SVN repository that this GitHub repository mirrors. Please feel free to open pull requests to work on any contribution you are making. More information about how GitHub pull requests can be used to contribute to WordPress can be found in the Core Handbook. Please include automated tests. Including tests in your pull request is one way to help your patch be considered faster. To learn about WordPress' test suites, visit the Automated Testing page in the handbook. If you have not had a chance, please review the Contribute with Code page in the WordPress Core Handbook. The Developer Hub also documents the various coding standards that are followed:
Thank you, |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
* | ||
* @return string The URL to the privacy policy page. | ||
*/ | ||
public static function check_privacy_policy_url() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no reason for this to be public
. This can be a private
method.
Also, I would rename to get_privacy_policy_url()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes I agree, also I fixed the tests to behave as expected
* This method caches the URL to avoid multiple database queries and shared the URL between all instances of the class. | ||
* Single query is performed on the first call to this method. | ||
* | ||
* @since 6.7.2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not something for a point release, as this is not a bug introduced in 6.7. (It was added in 6.2)
Let's change this to 6.8.0
public static function set_up_before_class() { | ||
parent::set_up_before_class(); | ||
|
||
$post_id = self::factory()->post->create( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I centralized the privacy policy page generation to run only once for the entire test class, it was the same code in each test and there was no side effects
I just fixed the tests behaviour, they were running well in isolation but failing when running all |
* @since 6.2.0 | ||
* @var string | ||
*/ | ||
private static $privacy_policy_url = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be static
? It seems like it could be non-static, as this would solve potential problems with unit testing down the road, as well as the unlikely scenario where the privacy policy URL changes between different nav menu instances.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is having this static allow us to share the same data across any instance of the class, if this "state" is not shared between instances we would query the database each time get_privacy_policy_url() is called in each instance of the Walker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's exactly the thing I want to prevent with this change because the privacy url is not a thing that changes regularly or that can be different across Walker instances, I feel is more performant and the right way to do it, probably we can just having one database call per walker (with a non static attribute), but if users uses several wp_nav_menu
calls with the default walker this will sum up
I'm ok of having this non static if we consider that it's ok to query the database for each walker instance, maybe is not a big deal, I'm suffering with the test suite 🤡 not entirely sure why it fails when running the entire test suite considering I'm cleaning up the things I created
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On that case I think this could be better and cleaner
/**
* The URL to the privacy policy page.
*
* @since 6.2.0
* @var string
*/
private $privacy_policy_url = null;
/**
* Constructor.
*/
public function __construct() {
$this->privacy_policy_url = get_privacy_policy_url();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many walker instances are there on a typical page though? Two?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL I found the issue because a website I was trying to fix uses 6 wp_nav_menu
some for mobile and some for desktop, but still I think this is needed because if a single menu has a lot of subitems only one walker instance will trigger N-menu-items queries. I'll remove the static I'm ok keeping the things simple and a little bit more performant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like your suggestion in #8140 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the PR with the constructor approach, thanks for your feedback
Co-authored-by: Weston Ruter <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thank you @westonruter I'm kinda lost what's the next step hahaha, should I open a SVN PR?, not sure what to do |
Ah, the next step is for a committer to take your code and commit to SVN. So your work here is done! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two minor feedbacks
Co-authored-by: Mukesh Panchal <[email protected]>
Co-authored-by: Mukesh Panchal <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
The
start_el()
method in Walker_Nav_Menu currently callsget_privacy_policy_url()
for every menu item when building menus. This results in redundant queries, particularly for menus with many items. This patch initialize the get_privacy_policy_url() result in the Walker constructor, improving performance while maintaining existing functionality.Trac ticket: https://core.trac.wordpress.org/ticket/62818
How to Test
Before applying the patch:
After applying the patch:
Commit Message
Menus: Improve performance by calling
get_privacy_policy_url()
once perWalker_Nav_Menu
instance rather than for every nav menu item.The
start_el()
method inWalker_Nav_Menu
was callingget_privacy_policy_url()
for every menu item when building menus. This resulted in redundant queries, particularly for menus with many items. This patch obtains theget_privacy_policy_url()
value in the constructor for reuse in thestart_el()
method to improve performance.Redundant code to construct the privacy policy page is also refactored into the
set_up
method during tests.Props arzola, swissspidy, westonruter, mukesh27.
Fixes #62818.