<!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>[57030] branches/6.4/tests/phpunit/tests/option: Options, Meta APIs: Fast follow fixes for option cache priming functions.</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/57030">57030</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/57030","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>2023-10-30 23:21:03 +0000 (Mon, 30 Oct 2023)</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'>Options, Meta APIs: Fast follow fixes for option cache priming functions.

A collection of fixes for `wp_prime_option_caches()`:

* cache arrays and objects in their serialized form for consistency with `get_option()` and `wp_load_alloptions()`
* prevent repeat database queries for falsey and known non-existent options (notoptions)

Additional tests for `wp_prime_option_caches()` to ensure:

* additional database queries are not made repriming options (known, known-unknown and alloptions)
* cache is primed consistently
* `get_option()` returns a consistent value regardless of how it is primed
* database queries do not contain earlier primed options
* `get_option` does not prime the cache when testing the cache has been successfully primed

Fixes a test for `wp_prime_option_caches_by_group()` to ensure `get_option` does not prime the cache when testing the cache has been successfully primed.

Follow up to <a href="https://core.trac.wordpress.org/changeset/56445">[56445]</a>,<a href="https://core.trac.wordpress.org/changeset/56990">[56990]</a>,<a href="https://core.trac.wordpress.org/changeset/57013">[57013]</a>.

Reviewed by flixos90, hellofromTonya, joemcgill.
Merges <a href="https://core.trac.wordpress.org/changeset/57029">[57029]</a> to the 6.4 branch.

Props peterwilsoncc, costdev, flixos90, hellofromTonya, mikeschroder, joemcgill.
Fixes <a href="https://core.trac.wordpress.org/ticket/59738">#59738</a>. See <a href="https://core.trac.wordpress.org/ticket/58962">#58962</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branches64srcwpincludesoptionphp">branches/6.4/src/wp-includes/option.php</a></li>
<li><a href="#branches64testsphpunittestsoptionwpPrimeOptionCachesphp">branches/6.4/tests/phpunit/tests/option/wpPrimeOptionCaches.php</a></li>
<li><a href="#branches64testsphpunittestsoptionwpPrimeOptionCachesByGroupphp">branches/6.4/tests/phpunit/tests/option/wpPrimeOptionCachesByGroup.php</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#branches64">branches/6.4/</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<span class="cx" style="display: block; padding: 0 10px">Index: branches/6.4
</span><span class="cx" style="display: block; padding: 0 10px">===================================================================
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">--- branches/6.4 2023-10-30 22:56:25 UTC (rev 57029)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+++ branches/6.4  2023-10-30 23:21:03 UTC (rev 57030)
</ins><a id="branches64"></a>
<div class="propset"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Property changes: branches/6.4</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: svn:mergeinfo</h4></div>
<span class="cx" style="display: block; padding: 0 10px"> /branches/5.0:43681-43682,43684-43688,43719-43720,43723,43726-43727,43729-43731,43734-43744,43747,43751-43754,43758,43760-43765,43767-43770,43772,43774-43781,43783,43785,43790-43806,43808-43821,43825,43828,43830-43834,43836-43843,43846-43863,43867-43889,43891-43894,43897-43905,43908-43909,43911-43929,43931-43942,43946-43947,43949-43956,43959-43964,43967-43969,43988,43994,44014,44017,44047,44183,44185,44187-44206,44208-44213,44231-44232,44235,44248,44284,44287-44288
</span><span class="cx" style="display: block; padding: 0 10px"> /branches/5.5:49373-49379,49381
</span><span class="cx" style="display: block; padding: 0 10px"> /branches/5.8:51889
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/trunk:56974,56978,56984,56987,56990-56992,56996,56999,57003,57009,57012-57013,57018-57019,57021-57022
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/trunk:56974,56978,56984,56987,56990-56992,56996,56999,57003,57009,57012-57013,57018-57019,57021-57022,57029
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="branches64srcwpincludesoptionphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/6.4/src/wp-includes/option.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/6.4/src/wp-includes/option.php   2023-10-30 22:56:25 UTC (rev 57029)
+++ branches/6.4/src/wp-includes/option.php     2023-10-30 23:21:03 UTC (rev 57030)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -261,11 +261,19 @@
</span><span class="cx" style="display: block; padding: 0 10px"> function wp_prime_option_caches( $options ) {
</span><span class="cx" style="display: block; padding: 0 10px">        $alloptions     = wp_load_alloptions();
</span><span class="cx" style="display: block; padding: 0 10px">        $cached_options = wp_cache_get_multiple( $options, 'options' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $notoptions     = wp_cache_get( 'notoptions', 'options' );
+       if ( ! is_array( $notoptions ) ) {
+               $notoptions = array();
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        // Filter options that are not in the cache.
</span><span class="cx" style="display: block; padding: 0 10px">        $options_to_prime = array();
</span><span class="cx" style="display: block; padding: 0 10px">        foreach ( $options as $option ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( ( ! isset( $cached_options[ $option ] ) || ! $cached_options[ $option ] ) && ! isset( $alloptions[ $option ] ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if (
+                       ( ! isset( $cached_options[ $option ] ) || false === $cached_options[ $option ] )
+                       && ! isset( $alloptions[ $option ] )
+                       && ! isset( $notoptions[ $option ] )
+               ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         $options_to_prime[] = $option;
</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">@@ -288,7 +296,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $options_found = array();
</span><span class="cx" style="display: block; padding: 0 10px">        foreach ( $results as $result ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $options_found[ $result->option_name ] = maybe_unserialize( $result->option_value );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         /*
+                * The cache is primed with the raw value (i.e. not maybe_unserialized).
+                *
+                * `get_option()` will handle unserializing the value as needed.
+                */
+               $options_found[ $result->option_name ] = $result->option_value;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">        wp_cache_set_multiple( $options_found, 'options' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -299,12 +312,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $options_not_found = array_diff( $options_to_prime, array_keys( $options_found ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $notoptions = wp_cache_get( 'notoptions', 'options' );
-
-       if ( ! is_array( $notoptions ) ) {
-               $notoptions = array();
-       }
-
</del><span class="cx" style="display: block; padding: 0 10px">         // Add the options that were not found to the cache.
</span><span class="cx" style="display: block; padding: 0 10px">        $update_notoptions = false;
</span><span class="cx" style="display: block; padding: 0 10px">        foreach ( $options_not_found as $option_name ) {
</span></span></pre></div>
<a id="branches64testsphpunittestsoptionwpPrimeOptionCachesphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/6.4/tests/phpunit/tests/option/wpPrimeOptionCaches.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/6.4/tests/phpunit/tests/option/wpPrimeOptionCaches.php   2023-10-30 22:56:25 UTC (rev 57029)
+++ branches/6.4/tests/phpunit/tests/option/wpPrimeOptionCaches.php     2023-10-30 23:21:03 UTC (rev 57030)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -41,15 +41,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // Check that options are only in the 'options' cache group.
</span><span class="cx" style="display: block; padding: 0 10px">                foreach ( $options_to_prime as $option ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertSame(
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                "value_$option",
</ins><span class="cx" style="display: block; padding: 0 10px">                                 wp_cache_get( $option, 'options' ),
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                get_option( $option ),
</del><span class="cx" style="display: block; padding: 0 10px">                                 "$option was not primed in the 'options' cache group."
</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">-                        $this->assertFalse(
-                               wp_cache_get( $option, 'notoptions' ),
-                               get_option( $option ),
-                               "$option was primed in the 'notoptions' cache group."
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $new_notoptions = wp_cache_get( $option, 'notoptions' );
+                       if ( ! is_array( $new_notoptions ) ) {
+                               $new_notoptions = array();
+                       }
+                       $this->assertArrayNotHasKey(
+                               $option,
+                               $new_notoptions,
+                               "$option was primed in the 'notoptions' cache."
</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">@@ -62,9 +66,69 @@
</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">+         * Tests that wp_prime_option_caches() handles a mix of primed and unprimed options.
+        *
+        * @ticket 58962
+        */
+       public function test_wp_prime_option_caches_handles_a_mix_of_primed_and_unprimed_options() {
+               global $wpdb;
+               // Create some options to prime.
+               $options_to_prime = array(
+                       'option1',
+                       'option2',
+                       'option3',
+               );
+
+               /*
+                * Set values for the options,
+                * clear the cache for the options,
+                * check options are not in cache initially.
+                */
+               foreach ( $options_to_prime as $option ) {
+                       update_option( $option, "value_$option", false );
+                       wp_cache_delete( $option, 'options' );
+                       $this->assertFalse( wp_cache_get( $option, 'options' ), "$option was not deleted from the cache." );
+               }
+
+               // Add non-existent option to the options to prime.
+               $options_to_prime[] = 'option404notfound';
+
+               // Prime the first option with a non-existent option.
+               wp_prime_option_caches( array( 'option1', 'option404notfound' ) );
+
+               // Store the initial database query count.
+               $initial_query_count = get_num_queries();
+
+               // Prime all the options, including the pre-primed option.
+               wp_prime_option_caches( $options_to_prime );
+
+               // Ensure an additional database query was made.
+               $this->assertSame(
+                       1,
+                       get_num_queries() - $initial_query_count,
+                       'Additional database queries were not made.'
+               );
+
+               // Ensure the last query does not contain the pre-primed option.
+               $this->assertStringNotContainsString(
+                       "\'option1\'",
+                       $wpdb->last_query,
+                       'The last query should not contain the pre-primed option.'
+               );
+
+               // Ensure the last query does not contain the pre-primed notoption.
+               $this->assertStringNotContainsString(
+                       "\'option404notfound\'",
+                       $wpdb->last_query,
+                       'The last query should not contain the pre-primed non-existent option.'
+               );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Tests wp_prime_option_caches() with options that do not exist in the database.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 58962
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @ticket 59738
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><span class="cx" style="display: block; padding: 0 10px">        public function test_wp_prime_option_caches_with_nonexistent_options() {
</span><span class="cx" style="display: block; padding: 0 10px">                // Create some options to prime.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -96,6 +160,24 @@
</span><span class="cx" style="display: block; padding: 0 10px">                foreach ( $options_to_prime as $option ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertArrayHasKey( $option, $new_notoptions, "$option was not added to the notoptions cache." );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               // Check getting and re-priming the options does not result in additional database queries.
+               $initial_query_count = get_num_queries();
+               foreach ( $options_to_prime as $option ) {
+                       get_option( $option );
+                       $this->assertSame(
+                               0,
+                               get_num_queries() - $initial_query_count,
+                               "Additional database queries were made getting option $option."
+                       );
+               }
+
+               wp_prime_option_caches( $options_to_prime );
+               $this->assertSame(
+                       0,
+                       get_num_queries() - $initial_query_count,
+                       'Additional database queries were made re-priming the options.'
+               );
</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">@@ -102,15 +184,24 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Tests wp_prime_option_caches() with an empty array.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 58962
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @ticket 59738
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><span class="cx" style="display: block; padding: 0 10px">        public function test_wp_prime_option_caches_with_empty_array() {
</span><span class="cx" style="display: block; padding: 0 10px">                $alloptions = wp_load_alloptions();
</span><span class="cx" style="display: block; padding: 0 10px">                $notoptions = wp_cache_get( 'notoptions', 'options' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $initial_query_count = get_num_queries();
</ins><span class="cx" style="display: block; padding: 0 10px">                 wp_prime_option_caches( array() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( $alloptions, wp_cache_get( 'alloptions', 'options' ), 'The alloptions cache was modified.' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( $notoptions, wp_cache_get( 'notoptions', 'options' ), 'The notoptions cache was modified.' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               // Check priming an empty array does not result in additional database queries.
+               $this->assertSame(
+                       0,
+                       get_num_queries() - $initial_query_count,
+                       'Additional database queries were made.'
+               );
</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">@@ -117,6 +208,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Tests that wp_prime_option_caches() handles an empty "notoptions" cache.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 58962
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @ticket 59738
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><span class="cx" style="display: block; padding: 0 10px">        public function test_wp_prime_option_caches_handles_empty_notoptions_cache() {
</span><span class="cx" style="display: block; padding: 0 10px">                wp_cache_delete( 'notoptions', 'options' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -126,5 +218,244 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $notoptions = wp_cache_get( 'notoptions', 'options' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertIsArray( $notoptions, 'The notoptions cache should be an array.' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertArrayHasKey( 'nonexistent_option', $notoptions, 'nonexistent_option was not added to notoptions.' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               // Check getting and re-priming the options does not result in additional database queries.
+               $initial_query_count = get_num_queries();
+
+               get_option( 'nonexistent_option' );
+               $this->assertSame(
+                       0,
+                       get_num_queries() - $initial_query_count,
+                       'Additional database queries were made getting nonexistent_option.'
+               );
+
+               wp_prime_option_caches( array( 'nonexistent_option' ) );
+               $this->assertSame(
+                       0,
+                       get_num_queries() - $initial_query_count,
+                       'Additional database queries were made.'
+               );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * Test options primed by the wp_prime_option_caches() function are identical to those primed by get_option().
+        *
+        * @ticket 59738
+        *
+        * @dataProvider data_option_types
+        *
+        * @param mixed $option_value An option value.
+        */
+       public function test_get_option_should_return_identical_value_when_pre_primed_by_wp_prime_option_caches( $option_value ) {
+               // As this includes a test setting the value to `(bool) false`, update_option() can not be used so add_option() is used instead.
+               add_option( 'type_of_option', $option_value, '', false );
+               wp_cache_delete( 'type_of_option', 'options' );
+
+               $this->assertFalse( wp_cache_get( 'type_of_option', 'options' ), 'type_of_option was not deleted from the cache for priming.' );
+
+               // Call the wp_prime_option_caches function to prime the options.
+               wp_prime_option_caches( array( 'type_of_option' ) );
+               $value_after_pre_priming = get_option( 'type_of_option' );
+
+               // Clear the cache and call get_option directly.
+               wp_cache_delete( 'type_of_option', 'options' );
+               $this->assertFalse( wp_cache_get( 'type_of_option', 'options' ), 'type_of_option was not deleted from the cache for get_option.' );
+               $value_after_get_option = get_option( 'type_of_option' );
+
+               /*
+                * If the option value is an object, use assertEquals() to compare the values.
+                *
+                * This is to compare the shape of the object rather than the identity of the object.
+                */
+               if ( is_object( $option_value ) ) {
+                       $this->assertEquals( $value_after_get_option, $value_after_pre_priming, 'The values should be equal.' );
+               } else {
+                       $this->assertSame( $value_after_get_option, $value_after_pre_priming, 'The values should be identical.' );
+               }
+       }
+
+       /**
+        * Tests that wp_prime_option_caches() shapes the cache in the same fashion as get_option()
+        *
+        * @ticket 59738
+        *
+        * @dataProvider data_option_types
+        *
+        * @param mixed $option_value An option value.
+        */
+       public function test_wp_prime_option_caches_cache_should_be_identical_to_get_option_cache( $option_value ) {
+               // As this includes a test setting the value to `(bool) false`, update_option() can not be used so add_option() is used instead.
+               add_option( 'type_of_option', $option_value, '', false );
+               wp_cache_delete( 'type_of_option', 'options' );
+
+               $this->assertFalse( wp_cache_get( 'type_of_option', 'options' ), 'type_of_option was not deleted from the cache for wp_prime_option_caches().' );
+
+               // Call the wp_prime_option_caches function to prime the options.
+               wp_prime_option_caches( array( 'type_of_option' ) );
+               $value_from_priming = wp_cache_get( 'type_of_option', 'options' );
+
+               wp_cache_delete( 'type_of_option', 'options' );
+               $this->assertFalse( wp_cache_get( 'type_of_option', 'options' ), 'type_of_option was not deleted from the cache for get_option().' );
+
+               // Call get_option() to prime the options.
+               get_option( 'type_of_option' );
+               $value_from_get_option = wp_cache_get( 'type_of_option', 'options' );
+
+               $this->assertIsString( $value_from_get_option, 'Cache from get_option() should always be a string' );
+               $this->assertIsString( $value_from_priming, 'Cache from wp_prime_option_caches() should always be a string' );
+               $this->assertSame( $value_from_get_option, $value_from_priming, 'The values should be identical.' );
+       }
+
+       /**
+        * Tests that wp_prime_option_caches() doesn't trigger DB queries on already primed options.
+        *
+        * @ticket 59738
+        *
+        * @dataProvider data_option_types
+        *
+        * @param mixed $option_value An option value.
+        */
+       public function test_wp_prime_option_caches_does_not_trigger_db_queries_repriming_options( $option_value ) {
+               // As this includes a test setting the value to `(bool) false`, update_option() can not be used so add_option() is used instead.
+               add_option( 'double_primed_option', $option_value, '', false );
+               wp_cache_delete( 'double_primed_option', 'options' );
+               $options_to_prime = array( 'double_primed_option' );
+
+               $this->assertFalse( wp_cache_get( 'double_primed_option', 'options' ), 'double_primed_option was not deleted from the cache.' );
+
+               // Call the wp_prime_option_caches function to prime the options.
+               wp_prime_option_caches( $options_to_prime );
+
+               // Store the initial database query count.
+               $initial_query_count = get_num_queries();
+
+               // Check that options are only in the 'options' cache group.
+               foreach ( $options_to_prime as $option ) {
+                       $this->assertNotFalse(
+                               wp_cache_get( $option, 'options' ),
+                               "$option was not primed in the 'options' cache group."
+                       );
+
+                       $new_notoptions = wp_cache_get( $option, 'notoptions' );
+                       if ( ! is_array( $new_notoptions ) ) {
+                               $new_notoptions = array();
+                       }
+                       $this->assertArrayNotHasKey(
+                               $option,
+                               $new_notoptions,
+                               "$option was primed in the 'notoptions' cache."
+                       );
+               }
+
+               // Call the wp_prime_option_caches function to prime the options.
+               wp_prime_option_caches( $options_to_prime );
+
+               // Ensure no additional database queries were made.
+               $this->assertSame(
+                       $initial_query_count,
+                       get_num_queries(),
+                       'Additional database queries were made.'
+               );
+       }
+
+       /**
+        * Tests that wp_prime_option_caches() doesn't trigger DB queries for items primed in alloptions.
+        *
+        * @ticket 59738
+        *
+        * @dataProvider data_option_types
+        *
+        * @param mixed $option_value An option value.
+        */
+       public function test_wp_prime_option_caches_does_not_trigger_db_queries_for_alloptions( $option_value ) {
+               // As this includes a test setting the value to `(bool) false`, update_option() can not be used so add_option() is used instead.
+               add_option( 'option_in_alloptions', $option_value, '', true );
+               wp_cache_delete( 'alloptions', 'options' );
+               wp_cache_delete( 'option_in_alloptions', 'options' );
+               $options_to_prime = array( 'option_in_alloptions' );
+
+               $this->assertFalse( wp_cache_get( 'option_in_alloptions', 'options' ), 'option_in_alloptions was not deleted from the cache.' );
+               $this->assertFalse( wp_cache_get( 'alloptions', 'options' ), 'alloptions was not deleted from the cache.' );
+
+               // Prime the alloptions cache.
+               wp_load_alloptions();
+
+               // Store the initial database query count.
+               $initial_query_count = get_num_queries();
+
+               // Call the wp_prime_option_caches function to reprime the option.
+               wp_prime_option_caches( $options_to_prime );
+
+               // Check that options are in the 'alloptions' cache only.
+               foreach ( $options_to_prime as $option ) {
+                       $this->assertFalse(
+                               wp_cache_get( $option, 'options' ),
+                               "$option was primed in the 'options' cache group."
+                       );
+
+                       $new_notoptions = wp_cache_get( $option, 'notoptions' );
+                       if ( ! is_array( $new_notoptions ) ) {
+                               $new_notoptions = array();
+                       }
+                       $this->assertArrayNotHasKey(
+                               $option,
+                               $new_notoptions,
+                               "$option was primed in the 'notoptions' cache."
+                       );
+
+                       $new_alloptions = wp_cache_get( 'alloptions', 'options' );
+                       if ( ! is_array( $new_alloptions ) ) {
+                               $new_alloptions = array();
+                       }
+                       $this->assertArrayHasKey(
+                               $option,
+                               $new_alloptions,
+                               "$option was not primed in the 'alloptions' cache."
+                       );
+               }
+
+               // Ensure no additional database queries were made.
+               $this->assertSame(
+                       0,
+                       get_num_queries() - $initial_query_count,
+                       'Additional database queries were made.'
+               );
+       }
+
+       /**
+        * Data provider.
+        *
+        * @return array[]
+        */
+       public function data_option_types() {
+               return array(
+                       'null'                              => array( null ),
+                       '(bool) false'                      => array( false ),
+                       '(bool) true'                       => array( true ),
+                       '(int) 0'                           => array( 0 ),
+                       '(int) -0'                          => array( -0 ),
+                       '(int) 1'                           => array( 1 ),
+                       '(int) -1'                          => array( -1 ),
+                       '(float) 0.0'                       => array( 0.0 ),
+                       '(float) -0.0'                      => array( -0.0 ),
+                       '(float) 1.0'                       => array( 1.0 ),
+                       'empty string'                      => array( '' ),
+                       'string with only tabs'             => array( "\t\t" ),
+                       'string with only newlines'         => array( "\n\n" ),
+                       'string with only carriage returns' => array( "\r\r" ),
+                       'string with only spaces'           => array( '   ' ),
+                       'populated string'                  => array( 'string' ),
+                       'string (1)'                        => array( '1' ),
+                       'string (0)'                        => array( '0' ),
+                       'string (0.0)'                      => array( '0.0' ),
+                       'string (-0)'                       => array( '-0' ),
+                       'string (-0.0)'                     => array( '-0.0' ),
+                       'empty array'                       => array( array() ),
+                       'populated array'                   => array( array( 'string' ) ),
+                       'empty object'                      => array( new stdClass() ),
+                       'populated object'                  => array( (object) array( 'string' ) ),
+                       'INF'                               => array( INF ),
+                       'NAN'                               => array( NAN ),
+               );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="branches64testsphpunittestsoptionwpPrimeOptionCachesByGroupphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/6.4/tests/phpunit/tests/option/wpPrimeOptionCachesByGroup.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/6.4/tests/phpunit/tests/option/wpPrimeOptionCachesByGroup.php    2023-10-30 22:56:25 UTC (rev 57029)
+++ branches/6.4/tests/phpunit/tests/option/wpPrimeOptionCachesByGroup.php      2023-10-30 23:21:03 UTC (rev 57030)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47,9 +47,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // Call the wp_prime_option_caches_by_group function to prime the options.
</span><span class="cx" style="display: block; padding: 0 10px">                wp_prime_option_caches_by_group( 'group1' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Check that options are now in the cache.
-               $this->assertSame( get_option( 'option1' ), wp_cache_get( 'option1', 'options' ), 'option1\'s cache was not primed.' );
-               $this->assertSame( get_option( 'option2' ), wp_cache_get( 'option2', 'options' ), 'option2\'s cache was not primed.' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         /*
+                * Check that options are now in the cache.
+                *
+                * Repeat the string here rather than using get_option as get_option
+                * will prime the cache before the call to wp_cache_get if the option
+                * is not in the cache. Thus causing the tests to pass when they should
+                * fail.
+                */
+               $this->assertSame( 'value_option1', wp_cache_get( 'option1', 'options' ), 'option1\'s cache was not primed.' );
+               $this->assertSame( 'value_option2', wp_cache_get( 'option2', 'options' ), 'option2\'s cache was not primed.' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Make sure option3 is still not in cache.
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertFalse( wp_cache_get( 'option3', 'options' ), 'option3 was not deleted from the cache.' );
</span></span></pre>
</div>
</div>

</body>
</html>