From 96a158b1384f33380c9a95437e871a15e5ea4b9b Mon Sep 17 00:00:00 2001 From: David Baumwald Date: Tue, 18 Oct 2022 18:14:01 +0000 Subject: [PATCH] Networks and Sites: Revert the use of the metadata API for `*_network_options` functions. [54080] refactored the logic in `get_network_option()`, `update_network_option()` and `delete_network_option()` to use the metadata API. However, this change resulted in issues with large multisite installs that utilize memcached having network options > 1MB in size. This change reverts [54080] and all related follow-up changes. Reverts [54080], [54081], and [54082]. Partially reverts [54267] and [54402]. Props pavelschoffer, rebasaurus, johnbillion, spacedmonkey, desrosj, rinatkhaziev. Fixes #56845. See #37181. git-svn-id: https://develop.svn.wordpress.org/trunk@54637 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-network-query.php | 88 +++--- src/wp-includes/class-wp-site-query.php | 2 +- src/wp-includes/load.php | 1 - src/wp-includes/ms-blogs.php | 2 - src/wp-includes/ms-functions.php | 4 +- src/wp-includes/ms-network.php | 20 +- src/wp-includes/option.php | 174 ++++++++++-- tests/phpunit/tests/ajax/Compression.php | 8 +- tests/phpunit/tests/multisite/network.php | 4 +- tests/phpunit/tests/option/multisite.php | 22 ++ tests/phpunit/tests/option/networkOption.php | 284 ++++--------------- 11 files changed, 275 insertions(+), 334 deletions(-) diff --git a/src/wp-includes/class-wp-network-query.php b/src/wp-includes/class-wp-network-query.php index 4f8a2a3a2e..1c72322a38 100644 --- a/src/wp-includes/class-wp-network-query.php +++ b/src/wp-includes/class-wp-network-query.php @@ -86,57 +86,53 @@ class WP_Network_Query { * Sets up the network query, based on the query vars passed. * * @since 4.6.0 - * @since 6.1.0 Introduced the 'update_network_meta_cache' parameter. * * @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 bool $update_network_meta_cache Whether to prime the metadata (option) 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. * } */ 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, - 'update_network_meta_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, ); if ( ! empty( $query ) ) { @@ -247,8 +243,8 @@ class WP_Network_Query { // $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 these arguments, as the queried result will be the same regardless. - unset( $_args['fields'], $_args['update_network_cache'], $_args['update_network_meta_cache'] ); + // Ignore the $fields, $update_network_cache arguments as the queried result will be the same regardless. + unset( $_args['fields'], $_args['update_network_cache'] ); $key = md5( serialize( $_args ) ); $last_changed = wp_cache_get_last_changed( 'networks' ); @@ -290,7 +286,7 @@ class WP_Network_Query { } if ( $this->query_vars['update_network_cache'] ) { - _prime_network_caches( $network_ids, $this->query_vars['update_network_meta_cache'] ); + _prime_network_caches( $network_ids ); } // Fetch full network objects from the primed cache. diff --git a/src/wp-includes/class-wp-site-query.php b/src/wp-includes/class-wp-site-query.php index a90cc9de8d..83bb52405e 100644 --- a/src/wp-includes/class-wp-site-query.php +++ b/src/wp-includes/class-wp-site-query.php @@ -351,7 +351,7 @@ class WP_Site_Query { // $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 these arguments, as the queried result will be the same regardless. + // Ignore the $fields, $update_site_cache, $update_site_meta_cache argument as the queried result will be the same regardless. unset( $_args['fields'], $_args['update_site_cache'], $_args['update_site_meta_cache'] ); $key = md5( serialize( $_args ) ); diff --git a/src/wp-includes/load.php b/src/wp-includes/load.php index 183144ef9b..4986603e9e 100644 --- a/src/wp-includes/load.php +++ b/src/wp-includes/load.php @@ -743,7 +743,6 @@ function wp_start_object_cache() { 'site-details', 'site-options', 'site-transient', - 'site_meta', 'rss', 'users', 'useremail', diff --git a/src/wp-includes/ms-blogs.php b/src/wp-includes/ms-blogs.php index f8f926a4d7..ed30cc5fe8 100644 --- a/src/wp-includes/ms-blogs.php +++ b/src/wp-includes/ms-blogs.php @@ -564,7 +564,6 @@ function switch_to_blog( $new_blog_id, $deprecated = null ) { 'site-details', 'site-options', 'site-transient', - 'site_meta', 'rss', 'users', 'useremail', @@ -656,7 +655,6 @@ function restore_current_blog() { 'site-details', 'site-options', 'site-transient', - 'site_meta', 'rss', 'users', 'useremail', diff --git a/src/wp-includes/ms-functions.php b/src/wp-includes/ms-functions.php index d5cc63ebe6..127e115c0b 100644 --- a/src/wp-includes/ms-functions.php +++ b/src/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 (int) get_network_option( $network_id, 'blog_count' ); + return get_network_option( $network_id, 'blog_count' ); } /** @@ -2563,7 +2563,7 @@ function get_space_allowed() { * * @param int $space_allowed Upload quota in megabytes for the current blog. */ - return (int) apply_filters( 'get_space_allowed', $space_allowed ); + return apply_filters( 'get_space_allowed', $space_allowed ); } /** diff --git a/src/wp-includes/ms-network.php b/src/wp-includes/ms-network.php index 941d767afe..5d14d69ec7 100644 --- a/src/wp-includes/ms-network.php +++ b/src/wp-includes/ms-network.php @@ -84,7 +84,6 @@ 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 ) { /** @@ -108,44 +107,35 @@ 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 bool $update_meta_cache Whether to update site meta cache. Default true. + * @param array $networks Array of network row objects. */ -function update_network_cache( $networks, $update_meta_cache = true ) { +function update_network_cache( $networks ) { $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 bool $update_meta_cache Whether to update site meta cache. Default true. + * @param array $network_ids Array of network IDs. */ -function _prime_network_caches( $network_ids, $update_meta_cache = true ) { +function _prime_network_caches( $network_ids ) { 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_meta_cache ); + update_network_cache( $fresh_networks ); } } diff --git a/src/wp-includes/option.php b/src/wp-includes/option.php index fa2a9a5b01..9952514733 100644 --- a/src/wp-includes/option.php +++ b/src/wp-includes/option.php @@ -348,12 +348,15 @@ 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 - * @since 6.1.0 Now uses update_meta_cache(). + * + * @global wpdb $wpdb WordPress database abstraction object. * * @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 ) { - if ( ! is_multisite() || wp_installing() ) { + global $wpdb; + + if ( ! is_multisite() || wp_using_ext_object_cache() || wp_installing() ) { return; } @@ -361,7 +364,20 @@ function wp_load_core_site_options( $network_id = null ) { $network_id = get_current_network_id(); } - update_meta_cache( 'site', $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' ); } /** @@ -1370,10 +1386,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() - * @see get_metadata() + * + * @global wpdb $wpdb WordPress database abstraction object. * * @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. @@ -1381,6 +1397,8 @@ 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; } @@ -1421,7 +1439,12 @@ function get_network_option( $network_id, $option, $default = false ) { return $pre; } - if ( ! is_multisite() ) { + // 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 ] ) ) { + /** * Filters the value of a specific default network option. * @@ -1436,21 +1459,44 @@ function get_network_option( $network_id, $option, $default = false ) { * @param string $option Option name. * @param int $network_id ID of the network. */ - $default = apply_filters( "default_site_option_{$option}", $default, $option, $network_id ); + 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 ); $value = get_option( $option, $default ); } else { - $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 ); + $cache_key = "$network_id:$option"; + $value = wp_cache_get( $cache_key, 'site-options' ); - /** This action is documented in wp-includes/meta.php */ - $value = apply_filters( 'default_site_metadata', $value, $network_id, $option, true, 'site' ); + 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' ); + + /** This filter is documented in wp-includes/option.php */ + $value = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id ); + } } } + if ( ! is_array( $notoptions ) ) { + $notoptions = array(); + wp_cache_set( $notoptions_key, $notoptions, 'site-options' ); + } + /** * Filters the value of an existing network option. * @@ -1474,10 +1520,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() - * @see add_metadata() + * + * @global wpdb $wpdb WordPress database abstraction object. * * @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. @@ -1485,6 +1531,8 @@ 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; } @@ -1514,11 +1562,48 @@ 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 { - $value = sanitize_option( $option, $value ); - $result = add_metadata( 'site', $network_id, wp_slash( $option ), wp_slash( $value ), true ); + $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' ); + } } if ( $result ) { @@ -1560,10 +1645,8 @@ 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. * @@ -1572,6 +1655,8 @@ 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; } @@ -1600,7 +1685,20 @@ function delete_network_option( $network_id, $option ) { if ( ! is_multisite() ) { $result = delete_option( $option ); } else { - $result = delete_metadata( 'site', $network_id, wp_slash( $option ), '' ); + $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, + ) + ); } if ( $result ) { @@ -1640,10 +1738,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() - * @see update_metadata() + * + * @global wpdb $wpdb WordPress database abstraction object. * * @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. @@ -1651,6 +1749,8 @@ 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; } @@ -1700,11 +1800,33 @@ 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 ); - $result = update_metadata( 'site', $network_id, wp_slash( $option ), wp_slash( $value ) ); + $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' ); + } } if ( $result ) { diff --git a/tests/phpunit/tests/ajax/Compression.php b/tests/phpunit/tests/ajax/Compression.php index 9c4b369ebb..4de6c2d154 100644 --- a/tests/phpunit/tests/ajax/Compression.php +++ b/tests/phpunit/tests/ajax/Compression.php @@ -154,7 +154,7 @@ class Tests_Ajax_CompressionTest extends WP_Ajax_UnitTestCase { } // Check the site option is not changed due to lack of nonce. - $this->assertSame( 0, (int) get_site_option( 'can_compress_scripts' ) ); + $this->assertSame( 0, get_site_option( 'can_compress_scripts' ) ); // Add a nonce. $_GET['_ajax_nonce'] = wp_create_nonce( 'update_can_compress_scripts' ); @@ -167,7 +167,7 @@ class Tests_Ajax_CompressionTest extends WP_Ajax_UnitTestCase { } // Check the site option is changed. - $this->assertSame( 1, (int) get_site_option( 'can_compress_scripts' ) ); + $this->assertSame( 1, get_site_option( 'can_compress_scripts' ) ); } /** @@ -194,7 +194,7 @@ class Tests_Ajax_CompressionTest extends WP_Ajax_UnitTestCase { } // Check the site option is not changed due to lack of nonce. - $this->assertSame( 1, (int) get_site_option( 'can_compress_scripts' ) ); + $this->assertSame( 1, get_site_option( 'can_compress_scripts' ) ); // Add a nonce. $_GET['_ajax_nonce'] = wp_create_nonce( 'update_can_compress_scripts' ); @@ -207,7 +207,7 @@ class Tests_Ajax_CompressionTest extends WP_Ajax_UnitTestCase { } // Check the site option is changed. - $this->assertSame( 0, (int) get_site_option( 'can_compress_scripts' ) ); + $this->assertSame( 0, get_site_option( 'can_compress_scripts' ) ); } /** diff --git a/tests/phpunit/tests/multisite/network.php b/tests/phpunit/tests/multisite/network.php index 3dcbcfb5c5..630f76ebaf 100644 --- a/tests/phpunit/tests/multisite/network.php +++ b/tests/phpunit/tests/multisite/network.php @@ -171,7 +171,7 @@ if ( is_multisite() ) : } wp_update_network_counts(); - $this->assertSame( $site_count_start, $actual ); + $this->assertEquals( $site_count_start, $actual ); } /** @@ -202,7 +202,7 @@ if ( is_multisite() ) : $site_count = get_blog_count( self::$different_network_id ); - $this->assertSame( count( self::$different_site_ids ), $site_count ); + $this->assertEquals( count( self::$different_site_ids ), $site_count ); } public function test_active_network_plugins() { diff --git a/tests/phpunit/tests/option/multisite.php b/tests/phpunit/tests/option/multisite.php index 05ee5f9555..98c28fbf50 100644 --- a/tests/phpunit/tests/option/multisite.php +++ b/tests/phpunit/tests/option/multisite.php @@ -152,6 +152,28 @@ if ( is_multisite() ) : // $this->assertFalse( get_option( $key2 ) ); // Check get_option(). } + /** + * @group multisite + * + * @covers ::get_site_option + */ + public function test_site_notoptions() { + $network_id = get_current_network_id(); + $notoptions_key = "{$network_id}:notoptions"; + + $_notoptions = wp_cache_get( 'notoptions', 'site-options' ); + $this->assertEmpty( $_notoptions ); + $_notoptions1 = wp_cache_get( $notoptions_key, 'site-options' ); + $this->assertEmpty( $_notoptions1 ); + + get_site_option( 'burrito' ); + + $notoptions = wp_cache_get( 'notoptions', 'site-options' ); + $this->assertEmpty( $notoptions ); + $notoptions1 = wp_cache_get( $notoptions_key, 'site-options' ); + $this->assertNotEmpty( $notoptions1 ); + } + /** * @covers ::users_can_register_signup_filter * @covers ::get_site_option diff --git a/tests/phpunit/tests/option/networkOption.php b/tests/phpunit/tests/option/networkOption.php index 0c39867109..bfce484a8d 100644 --- a/tests/phpunit/tests/option/networkOption.php +++ b/tests/phpunit/tests/option/networkOption.php @@ -137,124 +137,58 @@ class Tests_Option_NetworkOption extends WP_UnitTestCase { } /** - * @ticket 37181 - * + * @ticket 43506 * @group ms-required * * @covers ::get_network_option * @covers ::wp_cache_get * @covers ::wp_cache_delete */ - public function test_meta_api_use_values_in_network_option() { - $network_id = self::factory()->network->create(); - $option = __FUNCTION__; - $value = __FUNCTION__; + public function test_get_network_option_sets_notoptions_if_option_found() { + $network_id = get_current_network_id(); + $notoptions_key = "$network_id:notoptions"; - add_metadata( 'site', $network_id, $option, $value, true ); - $this->assertEqualSets( get_metadata( 'site', $network_id, $option ), array( get_network_option( $network_id, $option, true ) ) ); + $original_cache = wp_cache_get( $notoptions_key, 'site-options' ); + if ( false !== $original_cache ) { + wp_cache_delete( $notoptions_key, 'site-options' ); + } + + // Retrieve any existing option. + get_network_option( $network_id, 'site_name' ); + + $cache = wp_cache_get( $notoptions_key, 'site-options' ); + if ( false !== $original_cache ) { + wp_cache_set( $notoptions_key, $original_cache, 'site-options' ); + } + + $this->assertSame( array(), $cache ); } /** - * @ticket 37181 - * - * @group ms-required - */ - function test_funky_network_meta() { - $network_id = self::factory()->network->create(); - $option = __FUNCTION__; - $classy = new StdClass(); - $classy->ID = 1; - $classy->stringy = 'I love slashes\\\\'; - $funky_meta[] = $classy; - - $classy = new StdClass(); - $classy->ID = 2; - $classy->stringy = 'I love slashes\\\\ more'; - $funky_meta[] = $classy; - - // Add a network meta item. - $this->assertIsInt( add_metadata( 'site', $network_id, $option, $funky_meta, true ) ); - - // Check they exists. - $this->assertEqualSets( $funky_meta, get_network_option( $network_id, $option ) ); - } - - /** - * @ticket 37181 - * - * @group ms-required - */ - public function test_meta_api_multiple_values_in_network_option() { - $network_id = self::factory()->network->create(); - $option = __FUNCTION__; - add_metadata( 'site', $network_id, $option, 'monday', true ); - add_metadata( 'site', $network_id, $option, 'tuesday', true ); - add_metadata( 'site', $network_id, $option, 'wednesday', true ); - $this->assertSame( 'monday', get_network_option( $network_id, $option, true ) ); - } - - /** - * @ticket 37181 - * + * @ticket 43506 * @group ms-required * * @covers ::get_network_option * @covers ::wp_cache_get */ - public function test_network_option_count_queries_on_non_existing() { - $network_id = self::factory()->network->create(); - $option = __FUNCTION__; - add_network_option( $network_id, $option, 'monday' ); - get_network_option( $network_id, $option ); - $num_queries_pre_get = get_num_queries(); - get_network_option( $network_id, 'do_not_exist' ); - $num_queries_after_get = get_num_queries(); + public function test_get_network_option_sets_notoptions_if_option_not_found() { + $network_id = get_current_network_id(); + $notoptions_key = "$network_id:notoptions"; - $this->assertSame( $num_queries_pre_get, $num_queries_after_get ); - } + $original_cache = wp_cache_get( $notoptions_key, 'site-options' ); + if ( false !== $original_cache ) { + wp_cache_delete( $notoptions_key, 'site-options' ); + } - /** - * @ticket 37181 - * - * @group ms-required - */ - public function test_register_meta_network_option_single_false() { - $network_id = self::factory()->network->create(); - $option = __FUNCTION__; - $value = __FUNCTION__; - register_meta( - 'site', - $option, - array( - 'type' => 'string', - 'default' => $value, - 'single' => false, - ) - ); + // Retrieve any non-existing option. + get_network_option( $network_id, 'this_does_not_exist' ); - $this->assertSame( $value, get_network_option( $network_id, $option ) ); - } + $cache = wp_cache_get( $notoptions_key, 'site-options' ); + if ( false !== $original_cache ) { + wp_cache_set( $notoptions_key, $original_cache, 'site-options' ); + } - /** - * @ticket 37181 - * - * @group ms-required - */ - public function test_register_meta_network_option_single_true() { - $network_id = self::factory()->network->create(); - $option = __FUNCTION__; - $value = __FUNCTION__; - register_meta( - 'site', - $option, - array( - 'type' => 'string', - 'default' => $value, - 'single' => true, - ) - ); - - $this->assertSame( $value, get_network_option( $network_id, $option ) ); + $this->assertSame( array( 'this_does_not_exist' => true ), $cache ); } /** @@ -262,13 +196,9 @@ class Tests_Option_NetworkOption extends WP_UnitTestCase { * * @ticket 44956 * - * @group ms-required - * * @covers ::update_network_option */ public function test_update_network_option_array_with_object() { - $network_id = self::factory()->network->create(); - $option = __FUNCTION__; $array_w_object = array( 'url' => 'http://src.wordpress-develop.dev/wp-content/uploads/2016/10/cropped-Blurry-Lights.jpg', 'meta_data' => (object) array( @@ -278,140 +208,24 @@ class Tests_Option_NetworkOption extends WP_UnitTestCase { ), ); - add_metadata( 'site', $network_id, $option, $array_w_object, true ); - $this->assertEqualSets( $array_w_object, get_network_option( $network_id, $option ) ); - } - - /** - * @ticket 37181 - * - * @group ms-required - * - * @covers ::add_network_option - * - * @dataProvider data_types_options - */ - public function test_type_add_network_option( $name, $value, $expected ) { - $result = add_network_option( null, $name, $value ); - $this->assertTrue( $result, 'Network option was not added' ); - - $test_value = get_network_option( null, $name ); - $this->assertSame( $expected, $test_value, 'Values do not match' ); - } - - /** - * @ticket 37181 - * - * @covers ::add_network_option - * - * @dataProvider data_slashed_options - */ - public function test_slash_add_network_option( $name, $value ) { - $result = add_network_option( null, $name, $value ); - $this->assertTrue( $result, 'Network option was not added' ); - $this->assertSame( $value, get_network_option( null, $name ), 'Values do not match' ); - } - - /** - * @ticket 37181 - * - * @covers ::update_network_option - * - * @dataProvider data_slashed_options - */ - public function test_slash_update_network_option( $name, $value ) { - $result = update_network_option( null, $name, $value ); - $this->assertTrue( $result, 'Network option was not updated' ); - $this->assertSame( $value, get_network_option( null, $name ), 'Values do not match' ); - } - - /** - * @ticket 37181 - * - * @covers ::delete_network_option() - * - * @dataProvider data_slashed_options - */ - public function test_slash_delete_network_option( $name, $value ) { - $result = add_network_option( null, $name, $value ); - $this->assertTrue( $result, 'Network option was not added' ); - $this->assertSame( $value, get_network_option( null, $name ) ); - $result = delete_network_option( null, $name ); - $this->assertTrue( $result, 'Network option was not deleted' ); - $this->assertFalse( get_network_option( null, $name ), 'Network option was not deleted' ); - } - - public function data_slashed_options() { - return array( - 'slashed option name' => array( - 'option' => 'String with 1 slash \\', - 'value' => 'foo', - ), - 'slashed in middle option name' => array( - 'option' => 'String\\thing', - 'value' => 'foo', - ), - 'slashed option value' => array( - 'option' => 'bar', - 'value' => 'String with 1 slash \\', - ), - 'slashed option name and value' => array( - 'option' => 'String with 1 slash \\', - 'value' => 'String with 1 slash \\', - ), - 'slashed 4 times option name and value' => array( - 'option' => 'String with 4 slashes \\\\\\\\', - 'value' => 'String with 4 slashes \\\\\\\\', - ), - 'slashed 7 times option name and value' => array( - 'option' => 'String with 7 slashes \\\\\\\\\\\\\\', - 'value' => 'String with 7 slashes \\\\\\\\\\\\\\', + $array_w_object_2 = array( + 'url' => 'http://src.wordpress-develop.dev/wp-content/uploads/2016/10/cropped-Blurry-Lights.jpg', + 'meta_data' => (object) array( + 'attachment_id' => 292, + 'height' => 708, + 'width' => 1260, ), ); - } - public function data_types_options() { - return array( - 'array' => array( - 'option' => 'array', - 'value' => array(), - 'expected' => array(), - ), - 'array_keys' => array( - 'option' => 'array', - 'value' => array( 'key' => 'value' ), - 'expected' => array( 'key' => 'value' ), - ), - 'int' => array( - 'option' => 'int', - 'value' => 33, - 'expected' => '33', - ), - 'string' => array( - 'option' => 'string', - 'value' => 'foo', - 'expected' => 'foo', - ), - 'string_bool' => array( - 'option' => 'string', - 'value' => 'true', - 'expected' => 'true', - ), - 'float' => array( - 'option' => 'float', - 'value' => 33.5555, - 'expected' => '33.5555', - ), - 'bool' => array( - 'option' => 'bool', - 'value' => true, - 'expected' => '1', - ), - 'null' => array( - 'option' => 'null', - 'value' => null, - 'expected' => null, - ), - ); + // Add the option, it did not exist before this. + add_network_option( null, 'array_w_object', $array_w_object ); + + $num_queries_pre_update = get_num_queries(); + + // Update the option using the same array with an object for the value. + $this->assertFalse( update_network_option( null, 'array_w_object', $array_w_object_2 ) ); + + // Check that no new database queries were performed. + $this->assertSame( $num_queries_pre_update, get_num_queries() ); } }