<!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>[60524] trunk: Feeds: Cache RSS feeds in global transients.</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 { white-space: pre-line; 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/60524">60524</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/60524","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>peterwilsoncc</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2025-07-30 23:01:58 +0000 (Wed, 30 Jul 2025)</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'>Feeds: Cache RSS feeds in global transients.

Moves the caching of RSS feeds requested via `fetch_feed()` from single site transients (`get|set|delete_transient()`) to global transients (`get|set|delete_site_transient()`).

On multisite installs of WordPress, this replaces per site caching with the global multisite cache to allow a single cache to be shared between all sites. This reduces the amount of data stored in the database and improves performance of feeds when multiple sites are ingesting the same URL.

Props rollybueno, spacedmonkey, peterwilsoncc.
Fixes <a href="https://core.trac.wordpress.org/ticket/63719">#63719</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesclasswpfeedcachetransientphp">trunk/src/wp-includes/class-wp-feed-cache-transient.php</a></li>
<li><a href="#trunktestsphpunittestsfeedfetchFeedphp">trunk/tests/phpunit/tests/feed/fetchFeed.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesclasswpfeedcachetransientphp"></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/class-wp-feed-cache-transient.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-feed-cache-transient.php   2025-07-30 12:47:27 UTC (rev 60523)
+++ trunk/src/wp-includes/class-wp-feed-cache-transient.php     2025-07-30 23:01:58 UTC (rev 60524)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12,6 +12,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 2.8.0
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 6.7.0 Now properly implements the SimplePie\Cache\Base interface.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.9.0 Switched to Multisite's global cache via the `*_site_transient()` functions.
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> #[AllowDynamicProperties]
</span><span class="cx" style="display: block; padding: 0 10px"> class WP_Feed_Cache_Transient implements SimplePie\Cache\Base {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -84,8 +85,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $data = $data->data;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                set_transient( $this->name, $data, $this->lifetime );
-               set_transient( $this->mod_name, time(), $this->lifetime );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         set_site_transient( $this->name, $data, $this->lifetime );
+               set_site_transient( $this->mod_name, time(), $this->lifetime );
</ins><span class="cx" style="display: block; padding: 0 10px">                 return true;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -97,7 +98,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return array Data for `SimplePie::$data`.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function load() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return get_transient( $this->name );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         return get_site_transient( $this->name );
</ins><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><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -108,7 +109,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return int Timestamp.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function mtime() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return get_transient( $this->mod_name );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         return get_site_transient( $this->mod_name );
</ins><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><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -119,7 +120,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return bool False if value was not set and true if value was set.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function touch() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return set_transient( $this->mod_name, time(), $this->lifetime );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         return set_site_transient( $this->mod_name, time(), $this->lifetime );
</ins><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><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -130,8 +131,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return true Always true.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function unlink() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                delete_transient( $this->name );
-               delete_transient( $this->mod_name );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         delete_site_transient( $this->name );
+               delete_site_transient( $this->mod_name );
</ins><span class="cx" style="display: block; padding: 0 10px">                 return true;
</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="trunktestsphpunittestsfeedfetchFeedphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/feed/fetchFeed.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/feed/fetchFeed.php      2025-07-30 12:47:27 UTC (rev 60523)
+++ trunk/tests/phpunit/tests/feed/fetchFeed.php        2025-07-30 23:01:58 UTC (rev 60524)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -58,6 +58,31 @@
</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">+         * Ensure that fetch_feed uses the global cache on Multisite.
+        *
+        * @ticket 63719
+        *
+        * @group feed
+        * @group ms-required
+        *
+        * @covers ::fetch_feed
+        * @covers WP_Feed_Cache_Transient
+        */
+       public function test_fetch_feed_uses_global_cache() {
+               $second_blog_id = self::factory()->blog->create();
+
+               $filter = new MockAction();
+               add_filter( 'pre_http_request', array( $filter, 'filter' ) );
+
+               fetch_feed( 'https://wordpress.org/news/feed/' );
+
+               switch_to_blog( $second_blog_id );
+
+               fetch_feed( 'https://wordpress.org/news/feed/' );
+               $this->assertEquals( 1, $filter->get_call_count(), 'The feed cache should be global.' );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Mock response for `fetch_feed()`.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * This simulates a response from WordPress.org's server for the news feed
</span></span></pre>
</div>
</div>

</body>
</html>