<!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>[53818] trunk: Cache API: Validate cache key in `WP_Object_Cache` methods.</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/53818">53818</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/53818","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>SergeyBiryukov</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2022-08-03 14:34:58 +0000 (Wed, 03 Aug 2022)</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'>Cache API: Validate cache key in `WP_Object_Cache` methods.

Some plugins may call the `wp_cache_*()` functions with an empty string, `false`, or `null` as cache key, usually as a result of not checking the return value of another function that's used as the key.

Previously, this was silently failing, leading to odd behavior at best and often breakage due to key collisions.

A valid cache key must be either an integer number or a non-empty string.

This commit introduces a quick type check on the given cache keys and adds a `_doing_it_wrong()` message that should help plugin developers to notice these issues quicker.

Includes:
* A check in `update_user_caches()` and `clean_user_cache()` to make sure user email is not empty before being cached or removed from cache, as it is technically possible to create a user with empty email via `wp_insert_user()`.
* Some minor cleanup in unit tests where the email was passed to `wp_insert_user()` incorrectly or was unintentionally reset.

Props tillkruess, malthert, dd32, spacedmonkey, flixos90, peterwilsoncc, SergeyBiryukov.
Fixes <a href="https://core.trac.wordpress.org/ticket/56198">#56198</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesclasswpobjectcachephp">trunk/src/wp-includes/class-wp-object-cache.php</a></li>
<li><a href="#trunksrcwpincludesuserphp">trunk/src/wp-includes/user.php</a></li>
<li><a href="#trunktestsphpunittestsusergetUserCountphp">trunk/tests/phpunit/tests/user/getUserCount.php</a></li>
<li><a href="#trunktestsphpunittestsuserslashesphp">trunk/tests/phpunit/tests/user/slashes.php</a></li>
<li><a href="#trunktestsphpunittestsuserphp">trunk/tests/phpunit/tests/user.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesclasswpobjectcachephp"></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-object-cache.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-object-cache.php   2022-08-03 14:30:34 UTC (rev 53817)
+++ trunk/src/wp-includes/class-wp-object-cache.php     2022-08-03 14:34:58 UTC (rev 53818)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -130,6 +130,43 @@
</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">+         * Serves as a utility function to determine whether a key is valid.
+        *
+        * @since 6.1.0
+        *
+        * @param int|string $key Cache key to check for validity.
+        * @return bool Whether the key is valid.
+        */
+       protected function is_valid_key( $key ) {
+               if ( is_int( $key ) ) {
+                       return true;
+               }
+
+               if ( is_string( $key ) && trim( $key ) !== '' ) {
+                       return true;
+               }
+
+               $type = gettype( $key );
+
+               if ( ! function_exists( '__' ) ) {
+                       wp_load_translations_early();
+               }
+
+               $message = is_string( $key )
+                       ? __( 'Cache key must not be an empty string.' )
+                       /* translators: %s: The type of the given cache key. */
+                       : sprintf( __( 'Cache key must be integer or non-empty string, %s given.' ), $type );
+
+               _doing_it_wrong(
+                       sprintf( '%s::%s', __CLASS__, debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 )[1]['function'] ),
+                       $message,
+                       '6.1.0'
+               );
+
+               return false;
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Serves as a utility function to determine whether a key exists in the cache.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 3.4.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -163,6 +200,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        return false;
</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">+                if ( ! $this->is_valid_key( $key ) ) {
+                       return false;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( empty( $group ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $group = 'default';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -216,6 +257,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return bool True if contents were replaced, false if original value does not exist.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function replace( $key, $data, $group = 'default', $expire = 0 ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( ! $this->is_valid_key( $key ) ) {
+                       return false;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( empty( $group ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $group = 'default';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -245,14 +290,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * more for cache plugins which use files.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 2.0.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 6.1.0 Returns false if cache key is invalid.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param int|string $key    What to call the contents in the cache.
</span><span class="cx" style="display: block; padding: 0 10px">         * @param mixed      $data   The contents to store in the cache.
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string     $group  Optional. Where to group the cache contents. Default 'default'.
</span><span class="cx" style="display: block; padding: 0 10px">         * @param int        $expire Optional. Not used.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * @return true Always returns true.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  * @return bool True if contents were set, false if key is invalid.
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><span class="cx" style="display: block; padding: 0 10px">        public function set( $key, $data, $group = 'default', $expire = 0 ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( ! $this->is_valid_key( $key ) ) {
+                       return false;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( empty( $group ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $group = 'default';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -310,6 +360,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return mixed|false The cache contents on success, false on failure to retrieve contents.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function get( $key, $group = 'default', $force = false, &$found = null ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( ! $this->is_valid_key( $key ) ) {
+                       return false;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( empty( $group ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $group = 'default';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -368,6 +422,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return bool True on success, false if the contents were not deleted.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function delete( $key, $group = 'default', $deprecated = false ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( ! $this->is_valid_key( $key ) ) {
+                       return false;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( empty( $group ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $group = 'default';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -416,6 +474,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return int|false The item's new value on success, false on failure.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function incr( $key, $offset = 1, $group = 'default' ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( ! $this->is_valid_key( $key ) ) {
+                       return false;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( empty( $group ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $group = 'default';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -455,6 +517,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return int|false The item's new value on success, false on failure.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function decr( $key, $offset = 1, $group = 'default' ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( ! $this->is_valid_key( $key ) ) {
+                       return false;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( empty( $group ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $group = 'default';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span></span></pre></div>
<a id="trunksrcwpincludesuserphp"></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/user.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/user.php    2022-08-03 14:30:34 UTC (rev 53817)
+++ trunk/src/wp-includes/user.php      2022-08-03 14:34:58 UTC (rev 53818)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1850,8 +1850,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        wp_cache_add( $user->ID, $user, 'users' );
</span><span class="cx" style="display: block; padding: 0 10px">        wp_cache_add( $user->user_login, $user->ID, 'userlogins' );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        wp_cache_add( $user->user_email, $user->ID, 'useremail' );
</del><span class="cx" style="display: block; padding: 0 10px">         wp_cache_add( $user->user_nicename, $user->ID, 'userslugs' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       if ( ! empty( $user->user_email ) ) {
+               wp_cache_add( $user->user_email, $user->ID, 'useremail' );
+       }
</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">@@ -1878,9 +1881,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        wp_cache_delete( $user->ID, 'users' );
</span><span class="cx" style="display: block; padding: 0 10px">        wp_cache_delete( $user->user_login, 'userlogins' );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        wp_cache_delete( $user->user_email, 'useremail' );
</del><span class="cx" style="display: block; padding: 0 10px">         wp_cache_delete( $user->user_nicename, 'userslugs' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if ( ! empty( $user->user_email ) ) {
+               wp_cache_delete( $user->user_email, 'useremail' );
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><span class="cx" style="display: block; padding: 0 10px">         * Fires immediately after the given user's cache is cleaned.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span></span></pre></div>
<a id="trunktestsphpunittestsusergetUserCountphp"></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/user/getUserCount.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/user/getUserCount.php   2022-08-03 14:30:34 UTC (rev 53817)
+++ trunk/tests/phpunit/tests/user/getUserCount.php     2022-08-03 14:34:58 UTC (rev 53818)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -45,7 +45,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $current_network_user_count = get_user_count();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Add another user to fake the network user count to be different.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                wpmu_create_user( 'user', 'pass', 'email' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         wpmu_create_user( 'user', 'pass', 'user@example.com' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                wp_update_network_user_counts( $different_network_id );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -68,7 +68,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                wp_update_network_counts();
</span><span class="cx" style="display: block; padding: 0 10px">                $start_count = get_user_count();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                wpmu_create_user( 'user', 'pass', 'email' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         wpmu_create_user( 'user', 'pass', 'user@example.com' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // No change, cache not refreshed.
</span><span class="cx" style="display: block; padding: 0 10px">                $count = get_user_count();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -132,7 +132,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                wp_update_user_counts();
</span><span class="cx" style="display: block; padding: 0 10px">                $current_network_user_count = get_user_count();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $u1 = wpmu_create_user( 'user', 'pass', 'email' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $u1 = wpmu_create_user( 'user', 'pass', 'user@example.com' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $user_count = get_user_count();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunktestsphpunittestsuserslashesphp"></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/user/slashes.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/user/slashes.php        2022-08-03 14:30:34 UTC (rev 53817)
+++ trunk/tests/phpunit/tests/user/slashes.php  2022-08-03 14:34:58 UTC (rev 53818)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -148,7 +148,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        array(
</span><span class="cx" style="display: block; padding: 0 10px">                                'user_login'   => 'slash_example_user_3',
</span><span class="cx" style="display: block; padding: 0 10px">                                'role'         => 'subscriber',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'email'        => 'user3@example.com',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'user_email'   => 'user3@example.com',
</ins><span class="cx" style="display: block; padding: 0 10px">                                 'first_name'   => self::SLASH_1,
</span><span class="cx" style="display: block; padding: 0 10px">                                'last_name'    => self::SLASH_3,
</span><span class="cx" style="display: block; padding: 0 10px">                                'nickname'     => self::SLASH_5,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -169,7 +169,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        array(
</span><span class="cx" style="display: block; padding: 0 10px">                                'user_login'   => 'slash_example_user_4',
</span><span class="cx" style="display: block; padding: 0 10px">                                'role'         => 'subscriber',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'email'        => 'user3@example.com',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'user_email'   => 'user4@example.com',
</ins><span class="cx" style="display: block; padding: 0 10px">                                 'first_name'   => self::SLASH_2,
</span><span class="cx" style="display: block; padding: 0 10px">                                'last_name'    => self::SLASH_4,
</span><span class="cx" style="display: block; padding: 0 10px">                                'nickname'     => self::SLASH_6,
</span></span></pre></div>
<a id="trunktestsphpunittestsuserphp"></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/user.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/user.php        2022-08-03 14:30:34 UTC (rev 53817)
+++ trunk/tests/phpunit/tests/user.php  2022-08-03 14:34:58 UTC (rev 53818)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2010,6 +2010,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $update_data = array(
</span><span class="cx" style="display: block; padding: 0 10px">                        'ID'         => $create_user,
</span><span class="cx" style="display: block; padding: 0 10px">                        'user_login' => 'test_user',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'user_email' => 'user@example.com',
</ins><span class="cx" style="display: block; padding: 0 10px">                         'meta_input' => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                'test_meta_key' => 'test_meta_updated',
</span><span class="cx" style="display: block; padding: 0 10px">                                'custom_meta'   => 'updated_value',
</span></span></pre>
</div>
</div>

</body>
</html>