From 8d1156f066965eabb0e16e647e220e1edce95c96 Mon Sep 17 00:00:00 2001 From: spacedmonkey Date: Tue, 6 Sep 2022 11:28:13 +0000 Subject: [PATCH] Networks and Sites: Use metadata api in ``*_network_options` functions. Replace logic found in `get_network_option`, `update_network_option` and `delete_network_option` to use the metadata api. Using the metadata api has a number of benefits, such as consistency, default values and useful filters. This change also improves performance by priming the caches of all network options in a single database request. Props spacedmonkey, swissspidy, sc0ttkclark, johnjamesjacoby, flixos90, jeremyfelt, pento, peterwilsoncc, mukesh27, desrosj. Fixes #37181 Built from https://develop.svn.wordpress.org/trunk@54080 git-svn-id: http://core.svn.wordpress.org/trunk@53639 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/class-wp-network-query.php | 87 +++++++------ wp-includes/load.php | 1 + wp-includes/ms-blogs.php | 2 + wp-includes/ms-functions.php | 4 +- wp-includes/ms-network.php | 20 ++- wp-includes/option.php | 174 ++++--------------------- wp-includes/version.php | 2 +- 7 files changed, 92 insertions(+), 198 deletions(-) diff --git a/wp-includes/class-wp-network-query.php b/wp-includes/class-wp-network-query.php index bf6323d7477a..85d8b53590dc 100644 --- a/wp-includes/class-wp-network-query.php +++ b/wp-includes/class-wp-network-query.php @@ -89,49 +89,52 @@ class WP_Network_Query { * @param string|array $query { * Optional. Array or query string of network query parameters. Default empty. * - * @type int[] $network__in Array of network IDs to include. Default empty. - * @type int[] $network__not_in Array of network IDs to exclude. Default empty. - * @type bool $count Whether to return a network count (true) or array of network objects. - * Default false. - * @type string $fields Network fields to return. Accepts 'ids' (returns an array of network IDs) - * or empty (returns an array of complete network objects). Default empty. - * @type int $number Maximum number of networks to retrieve. Default empty (no limit). - * @type int $offset Number of networks to offset the query. Used to build LIMIT clause. - * Default 0. - * @type bool $no_found_rows Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true. - * @type string|array $orderby Network status or array of statuses. Accepts 'id', 'domain', 'path', - * 'domain_length', 'path_length' and 'network__in'. Also accepts false, - * an empty array, or 'none' to disable `ORDER BY` clause. Default 'id'. - * @type string $order How to order retrieved networks. Accepts 'ASC', 'DESC'. Default 'ASC'. - * @type string $domain Limit results to those affiliated with a given domain. Default empty. - * @type string[] $domain__in Array of domains to include affiliated networks for. Default empty. - * @type string[] $domain__not_in Array of domains to exclude affiliated networks for. Default empty. - * @type string $path Limit results to those affiliated with a given path. Default empty. - * @type string[] $path__in Array of paths to include affiliated networks for. Default empty. - * @type string[] $path__not_in Array of paths to exclude affiliated networks for. Default empty. - * @type string $search Search term(s) to retrieve matching networks for. Default empty. - * @type bool $update_network_cache Whether to prime the cache for found networks. Default true. + * @type int[] $network__in Array of network IDs to include. Default empty. + * @type int[] $network__not_in Array of network IDs to exclude. Default empty. + * @type bool $count Whether to return a network count (true) or array of network objects. + * Default false. + * @type string $fields Network fields to return. Accepts 'ids' (returns an array of network IDs) + * or empty (returns an array of complete network objects). Default empty. + * @type int $number Maximum number of networks to retrieve. Default empty (no limit). + * @type int $offset Number of networks to offset the query. Used to build LIMIT clause. + * Default 0. + * @type bool $no_found_rows Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true. + * @type string|array $orderby Network status or array of statuses. Accepts 'id', 'domain', 'path', + * 'domain_length', 'path_length' and 'network__in'. Also accepts false, + * an empty array, or 'none' to disable `ORDER BY` clause. Default 'id'. + * @type string $order How to order retrieved networks. Accepts 'ASC', 'DESC'. Default 'ASC'. + * @type string $domain Limit results to those affiliated with a given domain. Default empty. + * @type string[] $domain__in Array of domains to include affiliated networks for. Default empty. + * @type string[] $domain__not_in Array of domains to exclude affiliated networks for. Default empty. + * @type string $path Limit results to those affiliated with a given path. Default empty. + * @type string[] $path__in Array of paths to include affiliated networks for. Default empty. + * @type string[] $path__not_in Array of paths to exclude affiliated networks for. Default empty. + * @type string $search Search term(s) to retrieve matching networks for. Default empty. + * @type bool $update_network_cache Whether to prime the cache for found networks. Default true. + * @type bool $update_network_meta_cache Whether to prime the metadata (option) cache for found networks. + * Default true. * } */ public function __construct( $query = '' ) { $this->query_var_defaults = array( - 'network__in' => '', - 'network__not_in' => '', - 'count' => false, - 'fields' => '', - 'number' => '', - 'offset' => '', - 'no_found_rows' => true, - 'orderby' => 'id', - 'order' => 'ASC', - 'domain' => '', - 'domain__in' => '', - 'domain__not_in' => '', - 'path' => '', - 'path__in' => '', - 'path__not_in' => '', - 'search' => '', - 'update_network_cache' => true, + 'network__in' => '', + 'network__not_in' => '', + 'count' => false, + 'fields' => '', + 'number' => '', + 'offset' => '', + 'no_found_rows' => true, + 'orderby' => 'id', + 'order' => 'ASC', + 'domain' => '', + 'domain__in' => '', + 'domain__not_in' => '', + 'path' => '', + 'path__in' => '', + 'path__not_in' => '', + 'search' => '', + 'update_network_cache' => true, + 'update_network_meta_cache' => true, ); if ( ! empty( $query ) ) { @@ -242,8 +245,8 @@ public function get_networks() { // $args can include anything. Only use the args defined in the query_var_defaults to compute the key. $_args = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ); - // Ignore the $fields, $update_network_cache arguments as the queried result will be the same regardless. - unset( $_args['fields'], $_args['update_network_cache'] ); + // Ignore the $fields, $update_network_cache, and $update_network_meta_cache arguments as the queried result will be the same regardless. + unset( $_args['fields'], $_args['update_network_cache'], $_args['update_network_meta_cache'] ); $key = md5( serialize( $_args ) ); $last_changed = wp_cache_get_last_changed( 'networks' ); @@ -285,7 +288,7 @@ public function get_networks() { } if ( $this->query_vars['update_network_cache'] ) { - _prime_network_caches( $network_ids ); + _prime_network_caches( $network_ids, $this->query_vars['update_network_meta_cache'] ); } // Fetch full network objects from the primed cache. diff --git a/wp-includes/load.php b/wp-includes/load.php index 3b0b89af8b67..d4bc58b9c2ba 100644 --- a/wp-includes/load.php +++ b/wp-includes/load.php @@ -743,6 +743,7 @@ function wp_start_object_cache() { 'site-details', 'site-options', 'site-transient', + 'site_meta', 'rss', 'users', 'useremail', diff --git a/wp-includes/ms-blogs.php b/wp-includes/ms-blogs.php index ed30cc5fe813..f8f926a4d7c4 100644 --- a/wp-includes/ms-blogs.php +++ b/wp-includes/ms-blogs.php @@ -564,6 +564,7 @@ function switch_to_blog( $new_blog_id, $deprecated = null ) { 'site-details', 'site-options', 'site-transient', + 'site_meta', 'rss', 'users', 'useremail', @@ -655,6 +656,7 @@ function restore_current_blog() { 'site-details', 'site-options', 'site-transient', + 'site_meta', 'rss', 'users', 'useremail', diff --git a/wp-includes/ms-functions.php b/wp-includes/ms-functions.php index 364b7a4cc5d0..2bb9c276dde0 100644 --- a/wp-includes/ms-functions.php +++ b/wp-includes/ms-functions.php @@ -113,7 +113,7 @@ function get_active_blog_for_user( $user_id ) { * @return int Number of active sites on the network. */ function get_blog_count( $network_id = null ) { - return get_network_option( $network_id, 'blog_count' ); + return (int) get_network_option( $network_id, 'blog_count' ); } /** @@ -2654,7 +2654,7 @@ function get_space_allowed() { * * @param int $space_allowed Upload quota in megabytes for the current blog. */ - return apply_filters( 'get_space_allowed', $space_allowed ); + return (int) apply_filters( 'get_space_allowed', $space_allowed ); } /** diff --git a/wp-includes/ms-network.php b/wp-includes/ms-network.php index 5d14d69ec72b..941d767afe1c 100644 --- a/wp-includes/ms-network.php +++ b/wp-includes/ms-network.php @@ -84,6 +84,7 @@ function clean_network_cache( $ids ) { $network_ids = (array) $ids; wp_cache_delete_multiple( $network_ids, 'networks' ); + wp_cache_delete_multiple( $network_ids, 'site_meta' ); foreach ( $network_ids as $id ) { /** @@ -107,35 +108,44 @@ function clean_network_cache( $ids ) { * cache using the network group with the key using the ID of the networks. * * @since 4.6.0 + * @since 6.1.0 Introduced the `$update_meta_cache` parameter. * - * @param array $networks Array of network row objects. + * @param array $networks Array of network row objects. + * @param bool $update_meta_cache Whether to update site meta cache. Default true. */ -function update_network_cache( $networks ) { +function update_network_cache( $networks, $update_meta_cache = true ) { $data = array(); foreach ( (array) $networks as $network ) { $data[ $network->id ] = $network; } + wp_cache_add_multiple( $data, 'networks' ); + if ( $update_meta_cache ) { + $network_ids = array_keys( $data ); + update_meta_cache( 'site', $network_ids ); + } } /** * Adds any networks from the given IDs to the cache that do not already exist in cache. * * @since 4.6.0 + * @since 6.1.0 Introduced the `$update_meta_cache` parameter. * @since 6.1.0 This function is no longer marked as "private". * * @see update_network_cache() * @global wpdb $wpdb WordPress database abstraction object. * - * @param array $network_ids Array of network IDs. + * @param array $network_ids Array of network IDs. + * @param bool $update_meta_cache Whether to update site meta cache. Default true. */ -function _prime_network_caches( $network_ids ) { +function _prime_network_caches( $network_ids, $update_meta_cache = true ) { global $wpdb; $non_cached_ids = _get_non_cached_ids( $network_ids, 'networks' ); if ( ! empty( $non_cached_ids ) ) { $fresh_networks = $wpdb->get_results( sprintf( "SELECT $wpdb->site.* FROM $wpdb->site WHERE id IN (%s)", implode( ',', array_map( 'intval', $non_cached_ids ) ) ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared - update_network_cache( $fresh_networks ); + update_network_cache( $fresh_networks, $update_meta_cache ); } } diff --git a/wp-includes/option.php b/wp-includes/option.php index 2cef038267f1..c6ecb3bfde28 100644 --- a/wp-includes/option.php +++ b/wp-includes/option.php @@ -324,15 +324,12 @@ function wp_load_alloptions( $force_cache = false ) { * Loads and caches certain often requested site options if is_multisite() and a persistent cache is not being used. * * @since 3.0.0 - * - * @global wpdb $wpdb WordPress database abstraction object. + * @since 6.1.0 Uses update_meta_cache * * @param int $network_id Optional site ID for which to query the options. Defaults to the current site. */ function wp_load_core_site_options( $network_id = null ) { - global $wpdb; - - if ( ! is_multisite() || wp_using_ext_object_cache() || wp_installing() ) { + if ( ! is_multisite() || wp_installing() ) { return; } @@ -340,20 +337,7 @@ function wp_load_core_site_options( $network_id = null ) { $network_id = get_current_network_id(); } - $core_options = array( 'site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting' ); - - $core_options_in = "'" . implode( "', '", $core_options ) . "'"; - $options = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN ($core_options_in) AND site_id = %d", $network_id ) ); - - $data = array(); - foreach ( $options as $option ) { - $key = $option->meta_key; - $cache_key = "{$network_id}:$key"; - $option->meta_value = maybe_unserialize( $option->meta_value ); - - $data[ $cache_key ] = $option->meta_value; - } - wp_cache_set_multiple( $data, 'site-options' ); + update_meta_cache( 'site', $network_id ); } /** @@ -1362,10 +1346,10 @@ function update_site_option( $option, $value ) { * Retrieves a network's option value based on the option name. * * @since 4.4.0 + * @since 6.1.0 Now uses get_metadata(). * * @see get_option() - * - * @global wpdb $wpdb WordPress database abstraction object. + * @see get_metadata() * * @param int $network_id ID of the network. Can be null to default to the current network ID. * @param string $option Name of the option to retrieve. Expected to not be SQL-escaped. @@ -1373,8 +1357,6 @@ function update_site_option( $option, $value ) { * @return mixed Value set for the option. */ function get_network_option( $network_id, $option, $default = false ) { - global $wpdb; - if ( $network_id && ! is_numeric( $network_id ) ) { return false; } @@ -1415,12 +1397,7 @@ function get_network_option( $network_id, $option, $default = false ) { return $pre; } - // Prevent non-existent options from triggering multiple queries. - $notoptions_key = "$network_id:notoptions"; - $notoptions = wp_cache_get( $notoptions_key, 'site-options' ); - - if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) { - + if ( ! is_multisite() ) { /** * Filters the value of a specific default network option. * @@ -1435,44 +1412,21 @@ function get_network_option( $network_id, $option, $default = false ) { * @param string $option Option name. * @param int $network_id ID of the network. */ - return apply_filters( "default_site_option_{$option}", $default, $option, $network_id ); - } - - if ( ! is_multisite() ) { - /** This filter is documented in wp-includes/option.php */ - $default = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id ); + $default = apply_filters( "default_site_option_{$option}", $default, $option, $network_id ); $value = get_option( $option, $default ); } else { - $cache_key = "$network_id:$option"; - $value = wp_cache_get( $cache_key, 'site-options' ); - - if ( ! isset( $value ) || false === $value ) { - $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) ); - - // Has to be get_row() instead of get_var() because of funkiness with 0, false, null values. - if ( is_object( $row ) ) { - $value = $row->meta_value; - $value = maybe_unserialize( $value ); - wp_cache_set( $cache_key, $value, 'site-options' ); - } else { - if ( ! is_array( $notoptions ) ) { - $notoptions = array(); - } - - $notoptions[ $option ] = true; - wp_cache_set( $notoptions_key, $notoptions, 'site-options' ); + $meta = get_metadata_raw( 'site', $network_id, $option ); + if ( is_array( $meta ) && ! empty( $meta ) ) { + $value = array_shift( $meta ); + } else { + /** This filter is documented in wp-includes/option.php */ + $value = apply_filters( "default_site_option_{$option}", $default, $option, $network_id ); - /** This filter is documented in wp-includes/option.php */ - $value = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id ); - } + /** This action is documented in wp-includes/meta.php */ + $value = apply_filters( 'default_site_metadata', $value, $network_id, $option, true, 'site' ); } } - if ( ! is_array( $notoptions ) ) { - $notoptions = array(); - wp_cache_set( $notoptions_key, $notoptions, 'site-options' ); - } - /** * Filters the value of an existing network option. * @@ -1496,10 +1450,10 @@ function get_network_option( $network_id, $option, $default = false ) { * Existing options will not be updated. * * @since 4.4.0 + * @since 6.1.0 Now uses add_metadata(). * * @see add_option() - * - * @global wpdb $wpdb WordPress database abstraction object. + * @see add_metadata() * * @param int $network_id ID of the network. Can be null to default to the current network ID. * @param string $option Name of the option to add. Expected to not be SQL-escaped. @@ -1507,8 +1461,6 @@ function get_network_option( $network_id, $option, $default = false ) { * @return bool True if the option was added, false otherwise. */ function add_network_option( $network_id, $option, $value ) { - global $wpdb; - if ( $network_id && ! is_numeric( $network_id ) ) { return false; } @@ -1538,48 +1490,11 @@ function add_network_option( $network_id, $option, $value ) { */ $value = apply_filters( "pre_add_site_option_{$option}", $value, $option, $network_id ); - $notoptions_key = "$network_id:notoptions"; - if ( ! is_multisite() ) { $result = add_option( $option, $value, '', 'no' ); } else { - $cache_key = "$network_id:$option"; - - // Make sure the option doesn't already exist. - // We can check the 'notoptions' cache before we ask for a DB query. - $notoptions = wp_cache_get( $notoptions_key, 'site-options' ); - - if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) { - if ( false !== get_network_option( $network_id, $option, false ) ) { - return false; - } - } - - $value = sanitize_option( $option, $value ); - - $serialized_value = maybe_serialize( $value ); - $result = $wpdb->insert( - $wpdb->sitemeta, - array( - 'site_id' => $network_id, - 'meta_key' => $option, - 'meta_value' => $serialized_value, - ) - ); - - if ( ! $result ) { - return false; - } - - wp_cache_set( $cache_key, $value, 'site-options' ); - - // This option exists now. - $notoptions = wp_cache_get( $notoptions_key, 'site-options' ); // Yes, again... we need it to be fresh. - - if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) { - unset( $notoptions[ $option ] ); - wp_cache_set( $notoptions_key, $notoptions, 'site-options' ); - } + $value = sanitize_option( $option, $value ); + $result = add_metadata( 'site', $network_id, wp_slash( $option ), wp_slash( $value ), true ); } if ( $result ) { @@ -1621,8 +1536,10 @@ function add_network_option( $network_id, $option, $value ) { * Removes a network option by name. * * @since 4.4.0 + * @since 6.1.0 Now uses delete_metadata(). * * @see delete_option() + * @see delete_metadata() * * @global wpdb $wpdb WordPress database abstraction object. * @@ -1631,8 +1548,6 @@ function add_network_option( $network_id, $option, $value ) { * @return bool True if the option was deleted, false otherwise. */ function delete_network_option( $network_id, $option ) { - global $wpdb; - if ( $network_id && ! is_numeric( $network_id ) ) { return false; } @@ -1661,20 +1576,7 @@ function delete_network_option( $network_id, $option ) { if ( ! is_multisite() ) { $result = delete_option( $option ); } else { - $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->sitemeta} WHERE meta_key = %s AND site_id = %d", $option, $network_id ) ); - if ( is_null( $row ) || ! $row->meta_id ) { - return false; - } - $cache_key = "$network_id:$option"; - wp_cache_delete( $cache_key, 'site-options' ); - - $result = $wpdb->delete( - $wpdb->sitemeta, - array( - 'meta_key' => $option, - 'site_id' => $network_id, - ) - ); + $result = delete_metadata( 'site', $network_id, wp_slash( $option ), '' ); } if ( $result ) { @@ -1714,10 +1616,10 @@ function delete_network_option( $network_id, $option ) { * Updates the value of a network option that was already added. * * @since 4.4.0 + * @since 6.1.0 Now uses update_metadata(). * * @see update_option() - * - * @global wpdb $wpdb WordPress database abstraction object. + * @see update_metadata() * * @param int $network_id ID of the network. Can be null to default to the current network ID. * @param string $option Name of the option. Expected to not be SQL-escaped. @@ -1725,8 +1627,6 @@ function delete_network_option( $network_id, $option ) { * @return bool True if the value was updated, false otherwise. */ function update_network_option( $network_id, $option, $value ) { - global $wpdb; - if ( $network_id && ! is_numeric( $network_id ) ) { return false; } @@ -1776,33 +1676,11 @@ function update_network_option( $network_id, $option, $value ) { return add_network_option( $network_id, $option, $value ); } - $notoptions_key = "$network_id:notoptions"; - $notoptions = wp_cache_get( $notoptions_key, 'site-options' ); - - if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) { - unset( $notoptions[ $option ] ); - wp_cache_set( $notoptions_key, $notoptions, 'site-options' ); - } - if ( ! is_multisite() ) { $result = update_option( $option, $value, 'no' ); } else { - $value = sanitize_option( $option, $value ); - - $serialized_value = maybe_serialize( $value ); - $result = $wpdb->update( - $wpdb->sitemeta, - array( 'meta_value' => $serialized_value ), - array( - 'site_id' => $network_id, - 'meta_key' => $option, - ) - ); - - if ( $result ) { - $cache_key = "$network_id:$option"; - wp_cache_set( $cache_key, $value, 'site-options' ); - } + $value = sanitize_option( $option, $value ); + $result = update_metadata( 'site', $network_id, wp_slash( $option ), wp_slash( $value ) ); } if ( $result ) { diff --git a/wp-includes/version.php b/wp-includes/version.php index 236456ac338c..c759f6d6f39f 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.1-alpha-54079'; +$wp_version = '6.1-alpha-54080'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.