Make WordPress Core

Opened 18 months ago

Closed 17 months ago

Last modified 15 months ago

#58185 closed enhancement (fixed)

Lazy load site meta

Reported by: spacedmonkey's profile spacedmonkey Owned by: spacedmonkey's profile spacedmonkey
Milestone: 6.3 Priority: normal
Severity: normal Version: 5.1
Component: Networks and Sites Keywords: has-patch has-unit-tests has-dev-note
Focuses: multisite, performance Cc:

Description

Added in #37923, site meta was added to allow for developers to extend site ( blog ) data.

WordPress has supported lazy loading meta data since 4.4. Extend this functionalty to support site meta as well.

Follow on from #57801, #57496 #57645

Change History (27)

This ticket was mentioned in PR #4382 on WordPress/wordpress-develop by @spacedmonkey.


18 months ago
#1

  • Keywords has-patch has-unit-tests added; needs-patch removed

#2 @spacedmonkey
18 months ago

  • Milestone changed from Awaiting Review to 6.3

#3 @spacedmonkey
18 months ago

  • Keywords needs-unit-tests added; has-unit-tests removed

This ticket was mentioned in Slack in #core-multisite by spacedmonkey. View the logs.


17 months ago

#5 @spacedmonkey
17 months ago

  • Keywords has-unit-tests commit added; needs-unit-tests removed
  • Owner set to spacedmonkey
  • Status changed from new to assigned

#6 @spacedmonkey
17 months ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 55747:

Networks and Sites: Lazy load site meta.

In [36566] a framework to lazily load metadata was introduced. This supported term and comment meta by default. In this commit, extends support for site ( blog ) meta. Site meta is not heavily used by core and is used by developers to extend multisite. In this change, _prime_site_caches and WP_Site_Query now call the new function wp_lazyload_site_meta. The function wp_lazyload_site_meta accepts an array of ids and adds them to the queue of metadata to be lazily loaded. The function get_blogs_of_user was updated to now lazily load site meta.

Follow on from [55671].

Props spacedmonkey, johnjamesjacoby, peterwilsoncc, mukesh27.
Fixes #58185.

#8 @dd32
17 months ago

  • Resolution fixed deleted
  • Status changed from closed to reopened

[55747] caused an issue on WordPress.org, we were using get_sites() within sunrise.php which no longer works with this change.

( ! ) Fatal error: Uncaught Error: Class 'WP_Metadata_Lazyloader' not found in wp-includes/meta.php on line 1217

The metadata lazyloader is included much later than sunrise:
https://core.trac.wordpress.org/browser/trunk/src/wp-settings.php?marks=140-141,191#L136

Changing it to the following does resolve it though.

$sites = get_sites( [
   ...
   'update_site_meta_cache' => false,
] );

@spacedmonkey what's your thoughts here? I somewhat feel like running get_sites() within sunrise is maybe an intended thing to be able to do.
Unfortunately a simple function_exists() is not viable here as the functions are loaded, it's just the classes that aren't, and I think the classes can be filtered?

Full stack trace:

( ! ) Error: Class 'WP_Metadata_Lazyloader' not found in wp-includes/meta.php on line 1217
Call Stack
#	Time	Memory	Function	Location
1	0.0001	368304	{main}( )	.../index.php:0
2	0.0001	368584	require( 'wp-blog-header.php )	.../index.php:18
3	0.0001	369192	require_once( 'wp-load.php )	.../wp-blog-header.php:13
4	0.0002	369984	require_once( 'wp-config.php )	.../wp-load.php:50
5	0.0008	403768	require_once( 'wp-settings.php )	.../wp-config.php:124
6	0.0094	1297488	require( 'wp-includes/ms-settings.php )	.../wp-settings.php:141
# Sunrise here, some filters added.
7	0.0102	1309120	ms_load_current_site_and_network( $domain = 'test.wordpress.org', $path = '/plugins/hello-dolly/', $subdomain = TRUE )	.../ms-settings.php:72
8	0.0102	1309120	get_site_by_path( $domain = 'test.wordpress.org', $path = '/plugins/hello-dolly/', $segments = 1 )	.../ms-load.php:366
9	0.0102	1309944	apply_filters( $hook_name = 'pre_get_site_by_path', $value = NULL, ...$args = variadic('test.wordpress.org', '/plugins/hello-dolly/', 1, [0 => '/plugins/', 1 => '/']) )	.../ms-load.php:212
10	0.0102	1310728	WP_Hook->apply_filters( $value = NULL, $args = [0 => NULL, 1 => 'test.wordpress.org', 2 => '/plugins/hello-dolly/', 3 => 1, 4 => [0 => '/plugins/', 1 => '/']] )	.../plugin.php:205
# Filter added via sunrise.php
11	0.0103	1312232	wporg_sites_on_rosetta_domains( $site = NULL, $domain = 'test.wordpress.org', $path = '/plugins/hello-dolly/', $segments = 1 )	.../class-wp-hook.php:312
12	0.0103	1312608	wporg_get_locale_site( $domain = 'test.wordpress.org', $path = ??? )	.../sunrise.php:134
# get_sites() called prior to the Lazyloader being loaded.
13	0.0103	1312984	get_sites( $args = ['network_id' => 6, 'number' => 1, 'domain' => 'test.wordpress.org', 'path' => '/'] )	.../sunrise.php:36
14	0.0103	1313208	WP_Site_Query->query( $query = ['network_id' => 6, 'number' => 1, 'domain' => 'test.wordpress.org', 'path' => '/'] )	.../ms-site.php:446
15	0.0103	1313208	WP_Site_Query->get_sites( )	.../class-wp-site-query.php:272
16	0.0112	1325664	wp_lazyload_site_meta( $site_ids = [0 => 161] )	.../class-wp-site-query.php:392
17	0.0112	1325664	wp_metadata_lazyloader( )	.../ms-site.php:377
Last edited 17 months ago by dd32 (previous) (diff)

#9 @spacedmonkey
17 months ago

@dd32 Good catchup.

We have a number of options.

  1. Require the class-wp-metadata-lazyloader.php file before line 138. Maybe 135.
  2. In wp_metadata_lazyloader function check if WP_Metadata_Lazyloader class exists and require the file there. We could even remove line in wp-settings.php as well if we do this.
  3. In wp_lazyload_site_meta check it WP_Metadata_Lazyloader classes exists and fallback to update_sitemeta_cache.

All of which have up sides and down sides. Personally like option 2, but option 3 might be the simplest fixes.

#11 follow-up: @spacedmonkey
17 months ago

I put together a PR that should fix the issue. See #4454.

#12 @spacedmonkey
17 months ago

  • Keywords needs-dev-note added

This ticket was mentioned in Slack in #core-multisite by spacedmonkey. View the logs.


17 months ago

#14 in reply to: ↑ 11 @dd32
17 months ago

Replying to spacedmonkey:

I put together a PR that should fix the issue. See #4454.

This is a reasonably simple straight forward change, and I think should work for WordPress.org and others.

When the future of class autoloading happens, this could be removed at that time without any other changes required.

#15 @spacedmonkey
17 months ago

@dd32 @peterwilsoncc I am good to commit #4454 PR?

#16 @spacedmonkey
17 months ago

In 55818:

Networks and Sites: Load WP_Metadata_Lazyloader class file if class does not exist.

Follow on from [55747].

As get_sites can be called very early in the bootstrap process, like in the sunrise.php file, it means that the WP_Metadata_Lazyloader may not have been loaded yet in the wp-settings.php file. Add a simple check to see if the class exists and if it does not exist then load the class file in.

Props spacedmonkey, peterwilsoncc, dd32.
See #58185.

#18 @spacedmonkey
17 months ago

  • Resolution set to fixed
  • Status changed from reopened to closed

Now that [55818] is committed, I am marking this as fixed again.

@dd32 Can you test again and make sure this fixes the issue.

#19 @ryelle
17 months ago

  • Resolution fixed deleted
  • Status changed from closed to reopened

There's still something broken on wp.org, I imagine because the file included in wp-settings.php is not conditional, so loading the file when it's requested in sunrise creates the class before it's redeclared by the wp-settings import.

( ! ) Fatal error: Cannot declare class WP_Metadata_Lazyloader, because the name is already in use in wp-includes/class-wp-metadata-lazyloader.php on line 32
Call Stack
#	Time	Memory	Function	Location
1	0.0001	368944	{main}( )	.../index.php:0
2	0.0001	369224	require( 'wp-blog-header.php )	.../index.php:18
3	0.0001	369832	require_once( 'wp-load.php )	.../wp-blog-header.php:13
4	0.0001	370560	require_once( 'wp-config.php )	.../wp-load.php:50
5	0.0007	403656	require_once( 'wp-settings.php )	.../wp-config.php:119

Commenting out the require ABSPATH . WPINC . '/class-wp-metadata-lazyloader.php'; in wp-settings fixes the issue, but I don't know if that would have other effects.

#21 @spacedmonkey
17 months ago

Thanks for flagging this @ryelle .

I have a fix on this PR. If you could take look.

#22 @spacedmonkey
17 months ago

Pinging @dd32 @peterwilsoncc for review of the new fix.

#23 @ryelle
17 months ago

I applied the patch to my wordpress.org sandbox and it does work now 👍🏻

#24 @spacedmonkey
17 months ago

In 55826:

Networks and Sites: Load WP_Metadata_Lazyloader class file if class in meta.php.

In [55818] did a check to see if WP_Metadata_Lazyloader class existed and the loaded in the class file if it did not. However, require in wp-settings.php was not removed and resulted in the class being loaded twice. To be safe, only include the class file in meta.php and remove from wp-settings.php file.

Props spacedmonkey, ryelle.
See #58185.

#26 @spacedmonkey
17 months ago

  • Resolution set to fixed
  • Status changed from reopened to closed
Note: See TracTickets for help on using tickets.