<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[40305] trunk: Multisite: Handle sites cache invalidation more granularly for option updates.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/40305">40305</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/40305","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>flixos90</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2017-03-19 16:21:38 +0000 (Sun, 19 Mar 2017)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>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 <a href="https://core.trac.wordpress.org/ticket/40063">#40063</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesmsblogsphp">trunk/src/wp-includes/ms-blogs.php</a></li>
<li><a href="#trunksrcwpincludesmsdefaultfiltersphp">trunk/src/wp-includes/ms-default-filters.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunktestsphpunittestsmultisitesiteDetailsphp">trunk/tests/phpunit/tests/multisite/siteDetails.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesmsblogsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/ms-blogs.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/ms-blogs.php        2017-03-19 00:03:36 UTC (rev 40304)
+++ trunk/src/wp-includes/ms-blogs.php  2017-03-19 16:21:38 UTC (rev 40305)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -473,6 +473,24 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * 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' );
+}
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Retrieves site data given a site ID or site object.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Site data will be cached and returned after being passed through a filter.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -736,8 +754,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">        $return = update_option( $option, $value );
</span><span class="cx" style="display: block; padding: 0 10px">        restore_current_blog();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        refresh_blog_details( $id );
-
</del><span class="cx" style="display: block; padding: 0 10px">         return $return;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpincludesmsdefaultfiltersphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/ms-default-filters.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/ms-default-filters.php      2017-03-19 00:03:36 UTC (rev 40304)
+++ trunk/src/wp-includes/ms-default-filters.php        2017-03-19 16:21:38 UTC (rev 40305)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -84,10 +84,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> remove_filter( 'option_siteurl', '_config_wp_siteurl' );
</span><span class="cx" style="display: block; padding: 0 10px"> remove_filter( 'option_home',    '_config_wp_home'    );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-// 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 );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+// 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 );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // If the network upgrade hasn't run yet, assume ms-files.php rewriting is used.
</span><span class="cx" style="display: block; padding: 0 10px"> add_filter( 'default_site_option_ms_files_rewriting', '__return_true' );
</span></span></pre></div>
<a id="trunktestsphpunittestsmultisitesiteDetailsphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/multisite/siteDetails.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/multisite/siteDetails.php                               (rev 0)
+++ trunk/tests/phpunit/tests/multisite/siteDetails.php 2017-03-19 16:21:38 UTC (rev 40305)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,130 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?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;
</ins></span></pre>
</div>
</div>

</body>
</html>