Multisite: Handle sites cache invalidation more granularly for option updates.

Previously `update_blog_option()` would trigger an invalidation of that site's entire cache although these changes did not affect the content of these caches. Furthermore changes to the special options `blogname`, `siteurl` and `post_count` should not invalidate the entire cache of that site, but only their respective site details cache. The option `home` now has the same behavior as it also belongs to the site details, but did not invalidate the cache at all previously.

Several new unit tests confirm these changes work as expected.

Fixes #40063.


git-svn-id: https://develop.svn.wordpress.org/trunk@40305 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Felix Arntz 2017-03-19 16:21:38 +00:00
parent bba28d7f77
commit e6fda09261
3 changed files with 153 additions and 6 deletions

View File

@ -472,6 +472,24 @@ function clean_blog_cache( $blog ) {
wp_cache_set( 'last_changed', microtime(), 'sites' );
}
/**
* Cleans the site details cache for a site.
*
* @since 4.7.4
* @private
*
* @param int $site_id Optional. Site ID. Default is the current site ID.
*/
function _clean_site_details_cache( $site_id = 0 ) {
$site_id = (int) $site_id;
if ( ! $site_id ) {
$site_id = get_current_blog_id();
}
wp_cache_delete( $site_id, 'site-details' );
wp_cache_delete( $site_id, 'blog-details' );
}
/**
* Retrieves site data given a site ID or site object.
*
@ -736,8 +754,6 @@ function update_blog_option( $id, $option, $value, $deprecated = null ) {
$return = update_option( $option, $value );
restore_current_blog();
refresh_blog_details( $id );
return $return;
}

View File

@ -84,10 +84,11 @@ add_filter( 'force_filtered_html_on_import', '__return_true' );
remove_filter( 'option_siteurl', '_config_wp_siteurl' );
remove_filter( 'option_home', '_config_wp_home' );
// Some options changes should trigger blog details refresh.
add_action( 'update_option_blogname', 'refresh_blog_details', 10, 0 );
add_action( 'update_option_siteurl', 'refresh_blog_details', 10, 0 );
add_action( 'update_option_post_count', 'refresh_blog_details', 10, 0 );
// Some options changes should trigger site details refresh.
add_action( 'update_option_blogname', '_clean_site_details_cache', 10, 0 );
add_action( 'update_option_siteurl', '_clean_site_details_cache', 10, 0 );
add_action( 'update_option_post_count', '_clean_site_details_cache', 10, 0 );
add_action( 'update_option_home', '_clean_site_details_cache', 10, 0 );
// If the network upgrade hasn't run yet, assume ms-files.php rewriting is used.
add_filter( 'default_site_option_ms_files_rewriting', '__return_true' );

View File

@ -0,0 +1,130 @@
<?php
if ( is_multisite() ) :
/**
* Test 'site_details' functionality.
*
* @group ms-site
* @group multisite
*/
class Tests_Multisite_Site_Details extends WP_UnitTestCase {
/**
* @dataProvider data_whitelisted_options
*
* @ticket 40063
*/
public function test_update_whitelisted_option_deletes_site_details_cache( $whitelisted_option, $temporary_value ) {
$site = get_site();
$original_value = $site->$whitelisted_option;
update_option( $whitelisted_option, $temporary_value );
$cached_result = wp_cache_get( $site->id, 'site-details' );
/* Reset to original value. */
update_option( $whitelisted_option, $original_value );
$this->assertFalse( $cached_result );
}
/**
* @dataProvider data_whitelisted_options
*
* @ticket 40063
*/
public function test_update_whitelisted_option_deletes_blog_details_cache( $whitelisted_option, $temporary_value ) {
$blog_details = get_blog_details();
$original_value = $blog_details->$whitelisted_option;
update_option( $whitelisted_option, $temporary_value );
$cached_result = wp_cache_get( $blog_details->id, 'blog-details' );
/* Reset to original value. */
update_option( $whitelisted_option, $original_value );
$this->assertFalse( $cached_result );
}
/**
* @dataProvider data_whitelisted_options
*
* @ticket 40063
*/
public function test_update_whitelisted_option_does_not_delete_site_cache( $whitelisted_option, $temporary_value ) {
$site = get_site();
$original_value = $site->$whitelisted_option;
update_option( $whitelisted_option, $temporary_value );
$cached_result = wp_cache_get( $site->id, 'sites' );
/* Reset to original value. */
update_option( $whitelisted_option, $original_value );
$this->assertNotFalse( $cached_result );
}
/**
* @dataProvider data_whitelisted_options
*
* @ticket 40063
*/
public function test_update_whitelisted_option_does_not_delete_short_blog_details_cache( $whitelisted_option, $temporary_value ) {
$blog_details = get_blog_details( null, false );
$original_value = get_option( $whitelisted_option );
update_option( $whitelisted_option, $temporary_value );
$cached_result = wp_cache_get( $blog_details->id . 'short', 'blog-details' );
/* Reset to original value. */
update_option( $whitelisted_option, $original_value );
$this->assertNotFalse( $cached_result );
}
/**
* @dataProvider data_whitelisted_options
*
* @ticket 40063
*/
public function test_update_whitelisted_option_does_not_update_sites_last_changed( $whitelisted_option, $temporary_value ) {
$last_changed = wp_cache_get_last_changed( 'sites' );
$original_value = get_option( $whitelisted_option );
update_option( $whitelisted_option, $temporary_value );
$new_last_changed = wp_cache_get_last_changed( 'sites' );
/* Reset to original value. */
update_option( $whitelisted_option, $original_value );
$this->assertSame( $new_last_changed, $last_changed );
}
public function data_whitelisted_options() {
return array(
array( 'blogname', 'Custom Site' ),
array( 'home', 'http://custom-site-url.org' ),
array( 'siteurl', 'http://custom-site-url.org' ),
array( 'post_count', '4' ),
);
}
/**
* @ticket 40063
*/
public function test_update_random_blog_option_does_not_delete_cache() {
$site = get_site();
update_option( 'foobar_option', 'foobar_value' );
$cached_result = wp_cache_get( $site->id, 'sites' );
delete_option( 'foobar_option' );
$this->assertNotFalse( $cached_result );
}
}
endif;