[wp-trac] [WordPress Trac] #60199: update_menu_item_cache appears to load postmeta for all linked posts

WordPress Trac noreply at wordpress.org
Sat Jan 6 00:17:26 UTC 2024


#60199: update_menu_item_cache appears to load postmeta for all linked posts
--------------------------+-----------------------------
 Reporter:  huemordave    |      Owner:  (none)
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  Menus         |    Version:  6.4.2
 Severity:  normal        |   Keywords:
  Focuses:  performance   |
--------------------------+-----------------------------
 Discovered this debugging a memory limit error that was causing a staging
 site to WSoD on every page. The root cause was that loading the site
 header menu triggered loads of all postmeta.

 For context, this site has 35 posts in its menu. If I run the query that
 killed the site, it returns ~240MB of postmeta (which trips our server's
 ~512MB memory limit). Yes, 7MB of meta_values per post sounds high; this
 is because we use a page builder (Beaver Builder) that stores serialized
 post design configuration in postmeta.

 While this sounds excessive, it *would* be fine. Except that when
 WordPress needs to load menu items (via `wp_get_nav_menu_items`), it
 updates a number of related caches. First we update the menu item cache,
 then the post cache for any posts that are linked from a menu item, then
 the postmeta cache for all the postmeta of those linked posts, then we run
 out of memory and crash.

 `_prime_post_caches`, the function that updates the post cache, does
 provide parameters to enable or disable term and postmeta cache priming.
 `update_menu_item_cache` disables term priming but not postmeta priming.
 This appears to be an oversight: normal nav menu processing doesn't use
 any of the postmeta we're priming the cache with, so there's no point in
 loading any of it into the object cache.

 The website I diagnosed this problem in is running WordPress 6.4.2 on PHP
 8.2. It's hosted on WP Engine which does automatic core and PHP updates.
 As part of an earlier diagnosis phase, I disabled every plugin that wasn't
 absolutely necessary for rendering this header. I still got the memory
 limit error. I was *not* able to disable Beaver Builder or the custom
 theme we developed for this client as those are responsible for loading
 the template that calls `wp_nav_menu`. I don't think there's any plugin
 hooks in Beaver Builder doing anything funny either; I made PHP print out
 a stacktrace right before the memory error and the trace goes straight
 from my header code to WPDB:

 {{{
 #0 /wp-includes/class-wpdb.php(2263): wpdb->_do_query('SELECT
 post_id,...')
 #1 /wp-includes/class-wpdb.php(3152): wpdb->query('SELECT post_id,...')
 #2 /wp-includes/meta.php(1177): wpdb->get_results('SELECT post_id,...',
 'ARRAY_A')
 #3 /wp-includes/post.php(7421): update_meta_cache('post', Array)
 #4 /wp-includes/post.php(7808): update_postmeta_cache(Array)
 #5 /wp-includes/nav-menu.php(804): _prime_post_caches(Array, false)
 #6 /wp-includes/class-wp-query.php(3560): update_menu_item_cache(Array)
 #7 /wp-includes/class-wp-query.php(3824): WP_Query->get_posts()
 #8 /wp-includes/post.php(2460): WP_Query->query(Array)
 #9 /wp-includes/nav-menu.php(729): get_posts(Array)
 #10 /wp-includes/nav-menu-template.php(165):
 wp_get_nav_menu_items(Object(WP_Term), Array)
 #11 /wp-content/themes/beaverwarrior/components/CustomHeader/custom-
 header/includes/frontend.php(19): wp_nav_menu(Object(stdClass))
 }}}

 The way I'm currently fixing this problem is modifying
 `update_menu_item_cache`. Yes, this is corehacking, and I understand that
 it will be overwritten and break with the next core update.

 I specifically changed this line:

 {{{#!php
         if ( ! empty( $post_ids ) ) {
                 _prime_post_caches( $post_ids, false );
         }
 }}}

 to instead be:

 {{{#!php
         if ( ! empty( $post_ids ) ) {
                 _prime_post_caches( $post_ids, false, false );
         }
 }}}

 This disables postmeta cache priming for linked posts in nav menus and
 fixes the memory limit I was running into. I would like to know if there's
 any further implications from doing this that I'm not aware of. If not, I
 can submit a pull request to have this merged in.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/60199>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list