<!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>[56654] trunk: Login and Registration: Improve HTML for errors and notices.</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/56654">56654</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/56654","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>joedolson</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2023-09-21 18:22:10 +0000 (Thu, 21 Sep 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'>Login and Registration: Improve HTML for errors and notices.

Improve markup on Login and Registration errors. Use list markup for multiple issues, paragraph when only one to reduce semantic burden in the most common case. Normalize classes and markup for wrapper using `wp_admin_notice()` and `wp_get_admin_notice()` functions. Move definition of those functions from `wp-admin\includes\misc.php` to `wp-includes\functions.php`. Move tests to functions group. 

Props extendwings, sabernhardt, afercia, lukecavanagh, rianrietveld, oglekler, sergeybiryukov, costdev, joedolson.
Fixes <a href="https://core.trac.wordpress.org/ticket/30685">#30685</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadmincsslogincss">trunk/src/wp-admin/css/login.css</a></li>
<li><a href="#trunksrcwpadminincludesmiscphp">trunk/src/wp-admin/includes/misc.php</a></li>
<li><a href="#trunksrcwpincludesfunctionsphp">trunk/src/wp-includes/functions.php</a></li>
<li><a href="#trunksrcwploginphp">trunk/src/wp-login.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunktestsphpunittestsfunctionswpAdminNoticephp">trunk/tests/phpunit/tests/functions/wpAdminNotice.php</a></li>
<li><a href="#trunktestsphpunittestsfunctionswpGetAdminNoticephp">trunk/tests/phpunit/tests/functions/wpGetAdminNotice.php</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunktestsphpunittestsadminwpAdminNoticephp">trunk/tests/phpunit/tests/admin/wpAdminNotice.php</a></li>
<li><a href="#trunktestsphpunittestsadminwpGetAdminNoticephp">trunk/tests/phpunit/tests/admin/wpGetAdminNotice.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadmincsslogincss"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/css/login.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/css/login.css  2023-09-21 18:02:22 UTC (rev 56653)
+++ trunk/src/wp-admin/css/login.css    2023-09-21 18:22:10 UTC (rev 56654)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42,8 +42,8 @@
</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"> .login .message,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.login .success,
-.login #login_error {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.login .notice,
+.login .success {
</ins><span class="cx" style="display: block; padding: 0 10px">         border-left: 4px solid #72aee6;
</span><span class="cx" style="display: block; padding: 0 10px">        padding: 12px;
</span><span class="cx" style="display: block; padding: 0 10px">        margin-left: 0;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -57,10 +57,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">        border-left-color: #00a32a;
</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">-.login #login_error {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/* Match border color from common.css */
+.login .notice-error {
</ins><span class="cx" style="display: block; padding: 0 10px">         border-left-color: #d63638;
</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">+.login .login-error-list {
+       list-style: none;
+}
+
+.login .login-error-list li + li {
+       margin-top: 4px;
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> #loginform p.submit,
</span><span class="cx" style="display: block; padding: 0 10px"> .login-action-lostpassword p.submit {
</span><span class="cx" style="display: block; padding: 0 10px">        border: none;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -237,6 +246,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">        margin-bottom: 0;
</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">+#login form .indicator-hint,
+#login #reg_passmail {
+       margin-bottom: 16px;
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> #login form p.submit {
</span><span class="cx" style="display: block; padding: 0 10px">        margin: 0;
</span><span class="cx" style="display: block; padding: 0 10px">        padding: 0;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -342,9 +356,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        font-family: Consolas, Monaco, monospace;
</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">-.js.login input.password-input,
-.js.login-action-rp form .input,
-.js.login-action-rp input[type="text"] {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.js.login input.password-input {
</ins><span class="cx" style="display: block; padding: 0 10px">         padding-right: 2.5rem;
</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">@@ -354,6 +366,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">        background: #fff;
</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">+.js.login-action-resetpass input[type="text"],
+.js.login-action-resetpass input[type="password"],
</ins><span class="cx" style="display: block; padding: 0 10px"> .js.login-action-rp input[type="text"],
</span><span class="cx" style="display: block; padding: 0 10px"> .js.login-action-rp input[type="password"] {
</span><span class="cx" style="display: block; padding: 0 10px">        margin-bottom: 0;
</span></span></pre></div>
<a id="trunksrcwpadminincludesmiscphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/misc.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/misc.php      2023-09-21 18:02:22 UTC (rev 56653)
+++ trunk/src/wp-admin/includes/misc.php        2023-09-21 18:22:10 UTC (rev 56654)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1642,147 +1642,3 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        return $response;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-/**
- * Creates and returns the markup for an admin notice.
- *
- * @since 6.4.0
- *
- * @param string $message The message.
- * @param array  $args {
- *     Optional. An array of arguments for the admin notice. Default empty array.
- *
- *     @type string   $type               Optional. The type of admin notice.
- *                                        For example, 'error', 'success', 'warning', 'info'.
- *                                        Default empty string.
- *     @type bool     $dismissible        Optional. Whether the admin notice is dismissible. Default false.
- *     @type string   $id                 Optional. The value of the admin notice's ID attribute. Default empty string.
- *     @type string[] $additional_classes Optional. A string array of class names. Default empty array.
- *     @type string[] $attributes         Optional. Additional attributes for the notice div. Default empty array.
- *     @type bool     $paragraph_wrap     Optional. Whether to wrap the message in paragraph tags. Default true.
- * }
- * @return string The markup for an admin notice.
- */
-function wp_get_admin_notice( $message, $args = array() ) {
-       $defaults = array(
-               'type'               => '',
-               'dismissible'        => false,
-               'id'                 => '',
-               'additional_classes' => array(),
-               'attributes'         => array(),
-               'paragraph_wrap'     => true,
-       );
-
-       $args = wp_parse_args( $args, $defaults );
-
-       /**
-        * Filters the arguments for an admin notice.
-        *
-        * @since 6.4.0
-        *
-        * @param array  $args    The arguments for the admin notice.
-        * @param string $message The message for the admin notice.
-        */
-       $args       = apply_filters( 'wp_admin_notice_args', $args, $message );
-       $id         = '';
-       $classes    = 'notice';
-       $attributes = '';
-
-       if ( is_string( $args['id'] ) ) {
-               $trimmed_id = trim( $args['id'] );
-
-               if ( '' !== $trimmed_id ) {
-                       $id = 'id="' . $trimmed_id . '" ';
-               }
-       }
-
-       if ( is_string( $args['type'] ) ) {
-               $type = trim( $args['type'] );
-
-               if ( str_contains( $type, ' ' ) ) {
-                       _doing_it_wrong(
-                               __FUNCTION__,
-                               sprintf(
-                                       /* translators: %s: The "type" key. */
-                                       __( 'The %s key must be a string without spaces.' ),
-                                       '<code>type</code>'
-                               ),
-                               '6.4.0'
-                       );
-               }
-
-               if ( '' !== $type ) {
-                       $classes .= ' notice-' . $type;
-               }
-       }
-
-       if ( true === $args['dismissible'] ) {
-               $classes .= ' is-dismissible';
-       }
-
-       if ( is_array( $args['additional_classes'] ) && ! empty( $args['additional_classes'] ) ) {
-               $classes .= ' ' . implode( ' ', $args['additional_classes'] );
-       }
-
-       if ( is_array( $args['attributes'] ) && ! empty( $args['attributes'] ) ) {
-               $attributes = '';
-               foreach ( $args['attributes'] as $attr => $val ) {
-                       if ( is_bool( $val ) ) {
-                               $attributes .= $val ? ' ' . $attr : '';
-                       } elseif ( is_int( $attr ) ) {
-                               $attributes .= ' ' . esc_attr( trim( $val ) );
-                       } elseif ( $val ) {
-                               $attributes .= ' ' . $attr . '="' . esc_attr( trim( $val ) ) . '"';
-                       }
-               }
-       }
-
-       if ( false !== $args['paragraph_wrap'] ) {
-               $message = "<p>$message</p>";
-       }
-
-       $markup = sprintf( '<div %1$sclass="%2$s"%3$s>%4$s</div>', $id, $classes, $attributes, $message );
-
-       /**
-        * Filters the markup for an admin notice.
-        *
-        * @since 6.4.0
-        *
-        * @param string $markup  The HTML markup for the admin notice.
-        * @param string $message The message for the admin notice.
-        * @param array  $args    The arguments for the admin notice.
-        */
-       return apply_filters( 'wp_admin_notice_markup', $markup, $message, $args );
-}
-
-/**
- * Outputs an admin notice.
- *
- * @since 6.4.0
- *
- * @param string $message The message to output.
- * @param array  $args {
- *     Optional. An array of arguments for the admin notice. Default empty array.
- *
- *     @type string   $type               Optional. The type of admin notice.
- *                                        For example, 'error', 'success', 'warning', 'info'.
- *                                        Default empty string.
- *     @type bool     $dismissible        Optional. Whether the admin notice is dismissible. Default false.
- *     @type string   $id                 Optional. The value of the admin notice's ID attribute. Default empty string.
- *     @type string[] $additional_classes Optional. A string array of class names. Default empty array.
- *     @type bool     $paragraph_wrap     Optional. Whether to wrap the message in paragraph tags. Default true.
- * }
- */
-function wp_admin_notice( $message, $args = array() ) {
-       /**
-        * Fires before an admin notice is output.
-        *
-        * @since 6.4.0
-        *
-        * @param string $message The message for the admin notice.
-        * @param array  $args    The arguments for the admin notice.
-        */
-       do_action( 'wp_admin_notice', $message, $args );
-
-       echo wp_kses_post( wp_get_admin_notice( $message, $args ) );
-}
</del></span></pre></div>
<a id="trunksrcwpincludesfunctionsphp"></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/functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/functions.php       2023-09-21 18:02:22 UTC (rev 56653)
+++ trunk/src/wp-includes/functions.php 2023-09-21 18:22:10 UTC (rev 56654)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -8762,3 +8762,147 @@
</span><span class="cx" style="display: block; padding: 0 10px"> function wp_fuzzy_number_match( $expected, $actual, $precision = 1 ) {
</span><span class="cx" style="display: block; padding: 0 10px">        return abs( (float) $expected - (float) $actual ) <= $precision;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+/**
+ * Creates and returns the markup for an admin notice.
+ *
+ * @since 6.4.0
+ *
+ * @param string $message The message.
+ * @param array  $args {
+ *     Optional. An array of arguments for the admin notice. Default empty array.
+ *
+ *     @type string   $type               Optional. The type of admin notice.
+ *                                        For example, 'error', 'success', 'warning', 'info'.
+ *                                        Default empty string.
+ *     @type bool     $dismissible        Optional. Whether the admin notice is dismissible. Default false.
+ *     @type string   $id                 Optional. The value of the admin notice's ID attribute. Default empty string.
+ *     @type string[] $additional_classes Optional. A string array of class names. Default empty array.
+ *     @type string[] $attributes         Optional. Additional attributes for the notice div. Default empty array.
+ *     @type bool     $paragraph_wrap     Optional. Whether to wrap the message in paragraph tags. Default true.
+ * }
+ * @return string The markup for an admin notice.
+ */
+function wp_get_admin_notice( $message, $args = array() ) {
+       $defaults = array(
+               'type'               => '',
+               'dismissible'        => false,
+               'id'                 => '',
+               'additional_classes' => array(),
+               'attributes'         => array(),
+               'paragraph_wrap'     => true,
+       );
+
+       $args = wp_parse_args( $args, $defaults );
+
+       /**
+        * Filters the arguments for an admin notice.
+        *
+        * @since 6.4.0
+        *
+        * @param array  $args    The arguments for the admin notice.
+        * @param string $message The message for the admin notice.
+        */
+       $args       = apply_filters( 'wp_admin_notice_args', $args, $message );
+       $id         = '';
+       $classes    = 'notice';
+       $attributes = '';
+
+       if ( is_string( $args['id'] ) ) {
+               $trimmed_id = trim( $args['id'] );
+
+               if ( '' !== $trimmed_id ) {
+                       $id = 'id="' . $trimmed_id . '" ';
+               }
+       }
+
+       if ( is_string( $args['type'] ) ) {
+               $type = trim( $args['type'] );
+
+               if ( str_contains( $type, ' ' ) ) {
+                       _doing_it_wrong(
+                               __FUNCTION__,
+                               sprintf(
+                                       /* translators: %s: The "type" key. */
+                                       __( 'The %s key must be a string without spaces.' ),
+                                       '<code>type</code>'
+                               ),
+                               '6.4.0'
+                       );
+               }
+
+               if ( '' !== $type ) {
+                       $classes .= ' notice-' . $type;
+               }
+       }
+
+       if ( true === $args['dismissible'] ) {
+               $classes .= ' is-dismissible';
+       }
+
+       if ( is_array( $args['additional_classes'] ) && ! empty( $args['additional_classes'] ) ) {
+               $classes .= ' ' . implode( ' ', $args['additional_classes'] );
+       }
+
+       if ( is_array( $args['attributes'] ) && ! empty( $args['attributes'] ) ) {
+               $attributes = '';
+               foreach ( $args['attributes'] as $attr => $val ) {
+                       if ( is_bool( $val ) ) {
+                               $attributes .= $val ? ' ' . $attr : '';
+                       } elseif ( is_int( $attr ) ) {
+                               $attributes .= ' ' . esc_attr( trim( $val ) );
+                       } elseif ( $val ) {
+                               $attributes .= ' ' . $attr . '="' . esc_attr( trim( $val ) ) . '"';
+                       }
+               }
+       }
+
+       if ( false !== $args['paragraph_wrap'] ) {
+               $message = "<p>$message</p>";
+       }
+
+       $markup = sprintf( '<div %1$sclass="%2$s"%3$s>%4$s</div>', $id, $classes, $attributes, $message );
+
+       /**
+        * Filters the markup for an admin notice.
+        *
+        * @since 6.4.0
+        *
+        * @param string $markup  The HTML markup for the admin notice.
+        * @param string $message The message for the admin notice.
+        * @param array  $args    The arguments for the admin notice.
+        */
+       return apply_filters( 'wp_admin_notice_markup', $markup, $message, $args );
+}
+
+/**
+ * Outputs an admin notice.
+ *
+ * @since 6.4.0
+ *
+ * @param string $message The message to output.
+ * @param array  $args {
+ *     Optional. An array of arguments for the admin notice. Default empty array.
+ *
+ *     @type string   $type               Optional. The type of admin notice.
+ *                                        For example, 'error', 'success', 'warning', 'info'.
+ *                                        Default empty string.
+ *     @type bool     $dismissible        Optional. Whether the admin notice is dismissible. Default false.
+ *     @type string   $id                 Optional. The value of the admin notice's ID attribute. Default empty string.
+ *     @type string[] $additional_classes Optional. A string array of class names. Default empty array.
+ *     @type bool     $paragraph_wrap     Optional. Whether to wrap the message in paragraph tags. Default true.
+ * }
+ */
+function wp_admin_notice( $message, $args = array() ) {
+       /**
+        * Fires before an admin notice is output.
+        *
+        * @since 6.4.0
+        *
+        * @param string $message The message for the admin notice.
+        * @param array  $args    The arguments for the admin notice.
+        */
+       do_action( 'wp_admin_notice', $message, $args );
+
+       echo wp_kses_post( wp_get_admin_notice( $message, $args ) );
+}
</ins></span></pre></div>
<a id="trunksrcwploginphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-login.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-login.php    2023-09-21 18:02:22 UTC (rev 56653)
+++ trunk/src/wp-login.php      2023-09-21 18:22:10 UTC (rev 56654)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -228,21 +228,35 @@
</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">        if ( $wp_error->has_errors() ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $errors   = '';
-               $messages = '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $error_list = array();
+               $messages   = '';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                foreach ( $wp_error->get_error_codes() as $code ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $severity = $wp_error->get_error_data( $code );
</span><span class="cx" style="display: block; padding: 0 10px">                        foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                if ( 'message' === $severity ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        $messages .= '  ' . $error_message . "<br />\n";
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 $messages .= '<p>' . $error_message . '</p>';
</ins><span class="cx" style="display: block; padding: 0 10px">                                 } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        $errors .= '    ' . $error_message . "<br />\n";
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 $error_list[] = $error_message;
</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="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( ! empty( $errors ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( ! empty( $error_list ) ) {
+                       $errors = '';
+
+                       if ( count( $error_list ) > 1 ) {
+                               $errors .= '<ul class="login-error-list">';
+
+                               foreach ( $error_list as $item ) {
+                                       $errors .= '<li>' . $item . '</li>';
+                               }
+
+                               $errors .= '</ul>';
+                       } else {
+                               $errors .= '<p>' . $error_message . '</p>';
+                       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         /**
</span><span class="cx" style="display: block; padding: 0 10px">                         * Filters the error messages displayed above the login form.
</span><span class="cx" style="display: block; padding: 0 10px">                         *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -250,7 +264,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">                         *
</span><span class="cx" style="display: block; padding: 0 10px">                         * @param string $errors Login error message.
</span><span class="cx" style="display: block; padding: 0 10px">                         */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $errors = apply_filters( 'login_errors', $errors );
+                       wp_admin_notice(
+                               $errors,
+                               array(
+                                       'type'           => 'error',
+                                       'id'             => 'login_error',
+                                       'paragraph_wrap' => false,
+                               )
+                       );
</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">                if ( ! empty( $messages ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -261,7 +283,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                         *
</span><span class="cx" style="display: block; padding: 0 10px">                         * @param string $messages Login messages.
</span><span class="cx" style="display: block; padding: 0 10px">                         */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        echo '<p class="message" id="login-message">' . apply_filters( 'login_messages', $messages ) . "</p>\n";
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $messages = apply_filters( 'login_messages', $messages );
+                       wp_admin_notice(
+                               $messages,
+                               array(
+                                       'type'               => 'info',
+                                       'id'                 => 'login-message',
+                                       'additional_classes' => array( 'message' ),
+                                       'paragraph_wrap'     => false,
+                               )
+                       );
</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"> } // End of login_header().
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -399,7 +430,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">        do_action( 'login_footer' );
</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">-        <div class="clear"></div>
</del><span class="cx" style="display: block; padding: 0 10px">         </body>
</span><span class="cx" style="display: block; padding: 0 10px">        </html>
</span><span class="cx" style="display: block; padding: 0 10px">        <?php
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -829,7 +859,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">                 */
</span><span class="cx" style="display: block; padding: 0 10px">                do_action( 'lost_password', $errors );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                login_header( __( 'Lost Password' ), '<p class="message">' . __( 'Please enter your username or email address. You will receive an email message with instructions on how to reset your password.' ) . '</p>', $errors );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         login_header(
+                       __( 'Lost Password' ),
+                       wp_get_admin_notice(
+                               __( 'Please enter your username or email address. You will receive an email message with instructions on how to reset your password.' ),
+                               array(
+                                       'type'               => 'info',
+                                       'additional_classes' => array( 'message' ),
+                               )
+                       ),
+                       $errors
+               );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $user_login = '';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -946,7 +986,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ( ! $errors->has_errors() ) && isset( $_POST['pass1'] ) && ! empty( $_POST['pass1'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        reset_password( $user, $_POST['pass1'] );
</span><span class="cx" style="display: block; padding: 0 10px">                        setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        login_header( __( 'Password Reset' ), '<p class="message reset-pass">' . __( 'Your password has been reset.' ) . ' <a href="' . esc_url( wp_login_url() ) . '">' . __( 'Log in' ) . '</a></p>' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 login_header(
+                               __( 'Password Reset' ),
+                               wp_get_admin_notice(
+                                       __( 'Your password has been reset.' ) . ' <a href="' . esc_url( wp_login_url() ) . '">' . __( 'Log in' ) . '</a>',
+                                       array(
+                                               'type'               => 'info',
+                                               'additional_classes' => array( 'message', 'reset-pass' ),
+                                       )
+                               )
+                       );
</ins><span class="cx" style="display: block; padding: 0 10px">                         login_footer();
</span><span class="cx" style="display: block; padding: 0 10px">                        exit;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -954,7 +1003,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">                wp_enqueue_script( 'utils' );
</span><span class="cx" style="display: block; padding: 0 10px">                wp_enqueue_script( 'user-profile' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                login_header( __( 'Reset Password' ), '<p class="message reset-pass">' . __( 'Enter your new password below or generate one.' ) . '</p>', $errors );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         login_header(
+                       __( 'Reset Password' ),
+                       wp_get_admin_notice(
+                               __( 'Enter your new password below or generate one.' ),
+                               array(
+                                       'type'               => 'info',
+                                       'additional_classes' => array( 'message', 'reset-pass' ),
+                               )
+                       ),
+                       $errors
+               );
</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">                <form name="resetpassform" id="resetpassform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=resetpass', 'login_post' ) ); ?>" method="post" autocomplete="off">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -985,7 +1044,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        </p>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        <p class="description indicator-hint"><?php echo wp_get_password_hint(); ?></p>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        <br class="clear" />
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        <?php
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1079,7 +1137,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">                 */
</span><span class="cx" style="display: block; padding: 0 10px">                $redirect_to = apply_filters( 'registration_redirect', $registration_redirect, $errors );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                login_header( __( 'Registration Form' ), '<p class="message register">' . __( 'Register For This Site' ) . '</p>', $errors );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         login_header(
+                       __( 'Registration Form' ),
+                       wp_get_admin_notice(
+                               __( 'Register For This Site' ),
+                               array(
+                                       'type'               => 'info',
+                                       'additional_classes' => array( 'message', 'register' ),
+                               )
+                       ),
+                       $errors
+               );
</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">                <form name="registerform" id="registerform" action="<?php echo esc_url( site_url( 'wp-login.php?action=register', 'login_post' ) ); ?>" method="post" novalidate="novalidate">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1104,7 +1172,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        <p id="reg_passmail">
</span><span class="cx" style="display: block; padding: 0 10px">                                <?php _e( 'Registration confirmation will be emailed to you.' ); ?>
</span><span class="cx" style="display: block; padding: 0 10px">                        </p>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        <br class="clear" />
</del><span class="cx" style="display: block; padding: 0 10px">                         <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
</span><span class="cx" style="display: block; padding: 0 10px">                        <p class="submit">
</span><span class="cx" style="display: block; padding: 0 10px">                                <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Register' ); ?>" />
</span></span></pre></div>
<a id="trunktestsphpunittestsadminwpAdminNoticephp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/tests/phpunit/tests/admin/wpAdminNotice.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/admin/wpAdminNotice.php 2023-09-21 18:02:22 UTC (rev 56653)
+++ trunk/tests/phpunit/tests/admin/wpAdminNotice.php   2023-09-21 18:22:10 UTC (rev 56654)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,326 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-
-/**
- * Tests for `wp_admin_notice()`.
- *
- * @group admin
- *
- * @covers ::wp_admin_notice
- */
-class Tests_Admin_WpAdminNotice extends WP_UnitTestCase {
-
-       /**
-        * Tests that `wp_admin_notice()` outputs the expected admin notice markup.
-        *
-        * @ticket 57791
-        *
-        * @dataProvider data_should_output_admin_notice
-        *
-        * @param string $message  The message to output.
-        * @param array  $args     Arguments for the admin notice.
-        * @param string $expected The expected admin notice markup.
-        */
-       public function test_should_output_admin_notice( $message, $args, $expected ) {
-               ob_start();
-               wp_admin_notice( $message, $args );
-               $actual = ob_get_clean();
-
-               $this->assertSame( $expected, $actual );
-       }
-
-       /**
-        * Data provider.
-        *
-        * @return array[]
-        */
-       public function data_should_output_admin_notice() {
-               return array(
-                       'defaults'                                  => array(
-                               'message'  => 'A notice with defaults.',
-                               'args'     => array(),
-                               'expected' => '<div class="notice"><p>A notice with defaults.</p></div>',
-                       ),
-                       'an empty message (used for templates)'     => array(
-                               'message'  => '',
-                               'args'     => array(
-                                       'type'               => 'error',
-                                       'dismissible'        => true,
-                                       'id'                 => 'message',
-                                       'additional_classes' => array( 'inline', 'hidden' ),
-                               ),
-                               'expected' => '<div id="message" class="notice notice-error is-dismissible inline hidden"><p></p></div>',
-                       ),
-                       'an empty message (used for templates) without paragraph wrapping' => array(
-                               'message'  => '',
-                               'args'     => array(
-                                       'type'               => 'error',
-                                       'dismissible'        => true,
-                                       'id'                 => 'message',
-                                       'additional_classes' => array( 'inline', 'hidden' ),
-                                       'paragraph_wrap'     => false,
-                               ),
-                               'expected' => '<div id="message" class="notice notice-error is-dismissible inline hidden"></div>',
-                       ),
-                       'an "error" notice'                         => array(
-                               'message'  => 'An "error" notice.',
-                               'args'     => array(
-                                       'type' => 'error',
-                               ),
-                               'expected' => '<div class="notice notice-error"><p>An "error" notice.</p></div>',
-                       ),
-                       'a "success" notice'                        => array(
-                               'message'  => 'A "success" notice.',
-                               'args'     => array(
-                                       'type' => 'success',
-                               ),
-                               'expected' => '<div class="notice notice-success"><p>A "success" notice.</p></div>',
-                       ),
-                       'a "warning" notice'                        => array(
-                               'message'  => 'A "warning" notice.',
-                               'args'     => array(
-                                       'type' => 'warning',
-                               ),
-                               'expected' => '<div class="notice notice-warning"><p>A "warning" notice.</p></div>',
-                       ),
-                       'an "info" notice'                          => array(
-                               'message'  => 'An "info" notice.',
-                               'args'     => array(
-                                       'type' => 'info',
-                               ),
-                               'expected' => '<div class="notice notice-info"><p>An "info" notice.</p></div>',
-                       ),
-                       'a type that already starts with "notice-"' => array(
-                               'message'  => 'A type that already starts with "notice-".',
-                               'args'     => array(
-                                       'type' => 'notice-info',
-                               ),
-                               'expected' => '<div class="notice notice-notice-info"><p>A type that already starts with "notice-".</p></div>',
-                       ),
-                       'a dismissible notice'                      => array(
-                               'message'  => 'A dismissible notice.',
-                               'args'     => array(
-                                       'dismissible' => true,
-                               ),
-                               'expected' => '<div class="notice is-dismissible"><p>A dismissible notice.</p></div>',
-                       ),
-                       'no type and an ID'                         => array(
-                               'message'  => 'A notice with an ID.',
-                               'args'     => array(
-                                       'id' => 'message',
-                               ),
-                               'expected' => '<div id="message" class="notice"><p>A notice with an ID.</p></div>',
-                       ),
-                       'a type and an ID'                          => array(
-                               'message'  => 'A warning notice with an ID.',
-                               'args'     => array(
-                                       'type' => 'warning',
-                                       'id'   => 'message',
-                               ),
-                               'expected' => '<div id="message" class="notice notice-warning"><p>A warning notice with an ID.</p></div>',
-                       ),
-                       'no type and additional classes'            => array(
-                               'message'  => 'A notice with additional classes.',
-                               'args'     => array(
-                                       'additional_classes' => array( 'error', 'notice-alt' ),
-                               ),
-                               'expected' => '<div class="notice error notice-alt"><p>A notice with additional classes.</p></div>',
-                       ),
-                       'a type and additional classes'             => array(
-                               'message'  => 'A warning notice with additional classes.',
-                               'args'     => array(
-                                       'type'               => 'warning',
-                                       'additional_classes' => array( 'error', 'notice-alt' ),
-                               ),
-                               'expected' => '<div class="notice notice-warning error notice-alt"><p>A warning notice with additional classes.</p></div>',
-                       ),
-                       'a dismissible notice with a type and additional classes' => array(
-                               'message'  => 'A dismissible warning notice with a type and additional classes.',
-                               'args'     => array(
-                                       'type'               => 'warning',
-                                       'dismissible'        => true,
-                                       'additional_classes' => array( 'error', 'notice-alt' ),
-                               ),
-                               'expected' => '<div class="notice notice-warning is-dismissible error notice-alt"><p>A dismissible warning notice with a type and additional classes.</p></div>',
-                       ),
-                       'a notice without paragraph wrapping'       => array(
-                               'message'  => '<span>A notice without paragraph wrapping.</span>',
-                               'args'     => array(
-                                       'paragraph_wrap' => false,
-                               ),
-                               'expected' => '<div class="notice"><span>A notice without paragraph wrapping.</span></div>',
-                       ),
-                       'an unsafe type'                            => array(
-                               'message'  => 'A notice with an unsafe type.',
-                               'args'     => array(
-                                       'type' => '"><script>alert("Howdy,admin!");</script>',
-                               ),
-                               'expected' => '<div class="notice notice-">alert("Howdy,admin!");"&gt;<p>A notice with an unsafe type.</p></div>',
-                       ),
-                       'an unsafe ID'                              => array(
-                               'message'  => 'A notice with an unsafe ID.',
-                               'args'     => array(
-                                       'id' => '"><script>alert( "Howdy, admin!" );</script> <div class="notice',
-                               ),
-                               'expected' => '<div id="">alert( "Howdy, admin!" ); <div class="notice"><p>A notice with an unsafe ID.</p></div>',
-                       ),
-                       'unsafe additional classes'                 => array(
-                               'message'  => 'A notice with unsafe additional classes.',
-                               'args'     => array(
-                                       'additional_classes' => array( '"><script>alert( "Howdy, admin!" );</script> <div class="notice' ),
-                               ),
-                               'expected' => '<div class="notice ">alert( "Howdy, admin!" ); <div class="notice"><p>A notice with unsafe additional classes.</p></div>',
-                       ),
-                       'a type that is not a string'               => array(
-                               'message'  => 'A notice with a type that is not a string.',
-                               'args'     => array(
-                                       'type' => array(),
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with a type that is not a string.</p></div>',
-                       ),
-                       'a type with only empty space'              => array(
-                               'message'  => 'A notice with a type with only empty space.',
-                               'args'     => array(
-                                       'type' => " \t\r\n",
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with a type with only empty space.</p></div>',
-                       ),
-                       'an ID that is not a string'                => array(
-                               'message'  => 'A notice with an ID that is not a string.',
-                               'args'     => array(
-                                       'id' => array( 'message' ),
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with an ID that is not a string.</p></div>',
-                       ),
-                       'an ID with only empty space'               => array(
-                               'message'  => 'A notice with an ID with only empty space.',
-                               'args'     => array(
-                                       'id' => " \t\r\n",
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with an ID with only empty space.</p></div>',
-                       ),
-                       'dismissible as a truthy value rather than (bool) true' => array(
-                               'message'  => 'A notice with dismissible as a truthy value rather than (bool) true.',
-                               'args'     => array(
-                                       'dismissible' => 1,
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with dismissible as a truthy value rather than (bool) true.</p></div>',
-                       ),
-                       'additional classes that are not an array'  => array(
-                               'message'  => 'A notice with additional classes that are not an array.',
-                               'args'     => array(
-                                       'additional_classes' => 'class-1 class-2 class-3',
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with additional classes that are not an array.</p></div>',
-                       ),
-                       'additional attribute with a value'         => array(
-                               'message'  => 'A notice with an additional attribute with a value.',
-                               'args'     => array(
-                                       'attributes' => array( 'aria-live' => 'assertive' ),
-                               ),
-                               'expected' => '<div class="notice" aria-live="assertive"><p>A notice with an additional attribute with a value.</p></div>',
-                       ),
-                       'additional hidden attribute'               => array(
-                               'message'  => 'A notice with the hidden attribute.',
-                               'args'     => array(
-                                       'attributes' => array( 'hidden' => true ),
-                               ),
-                               'expected' => '<div class="notice" hidden><p>A notice with the hidden attribute.</p></div>',
-                       ),
-                       'additional attribute no associative keys'  => array(
-                               'message'  => 'A notice with a boolean attribute without an associative key.',
-                               'args'     => array(
-                                       'attributes' => array( 'hidden' ),
-                               ),
-                               'expected' => '<div class="notice" hidden><p>A notice with a boolean attribute without an associative key.</p></div>',
-                       ),
-                       'additional attribute with role'            => array(
-                               'message'  => 'A notice with an additional attribute role.',
-                               'args'     => array(
-                                       'attributes' => array( 'role' => 'alert' ),
-                               ),
-                               'expected' => '<div class="notice" role="alert"><p>A notice with an additional attribute role.</p></div>',
-                       ),
-                       'multiple additional attributes'            => array(
-                               'message'  => 'A notice with multiple additional attributes.',
-                               'args'     => array(
-                                       'attributes' => array(
-                                               'role'      => 'alert',
-                                               'data-test' => -1,
-                                       ),
-                               ),
-                               'expected' => '<div class="notice" role="alert" data-test="-1"><p>A notice with multiple additional attributes.</p></div>',
-                       ),
-                       'data attribute with unsafe value'          => array(
-                               'message'  => 'A notice with an additional attribute with an unsafe value.',
-                               'args'     => array(
-                                       'attributes' => array( 'data-unsafe' => '<script>alert( "Howdy, admin!" );</script>' ),
-                               ),
-                               'expected' => '<div class="notice" data-unsafe="&lt;script&gt;alert( &quot;Howdy, admin!&quot; );&lt;/script&gt;"><p>A notice with an additional attribute with an unsafe value.</p></div>',
-                       ),
-                       'additional invalid attribute'              => array(
-                               'message'  => 'A notice with an additional attribute that is invalid.',
-                               'args'     => array(
-                                       'attributes' => array( 'not-valid' => 'not-valid' ),
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with an additional attribute that is invalid.</p></div>',
-                       ),
-                       'multiple attributes with "role", invalid, data-*, numeric, and boolean' => array(
-                               'message'  => 'A notice with multiple attributes with "role", invalid, "data-*", numeric, and boolean.',
-                               'args'     => array(
-                                       'attributes' => array(
-                                               'role'      => 'alert',
-                                               'disabled'  => 'disabled',
-                                               'data-name' => 'my-name',
-                                               'data-id'   => 1,
-                                               'hidden',
-                                       ),
-                               ),
-                               'expected' => '<div class="notice" role="alert" data-name="my-name" data-id="1" hidden><p>A notice with multiple attributes with "role", invalid, "data-*", numeric, and boolean.</p></div>',
-                       ),
-                       'paragraph wrapping as a falsy value rather than (bool) false' => array(
-                               'message'  => 'A notice with paragraph wrapping as a falsy value rather than (bool) false.',
-                               'args'     => array(
-                                       'paragraph_wrap' => 0,
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with paragraph wrapping as a falsy value rather than (bool) false.</p></div>',
-                       ),
-               );
-       }
-
-       /**
-        * Tests that `_doing_it_wrong()` is thrown when a 'type' containing spaces is passed.
-        *
-        * @ticket 57791
-        *
-        * @expectedIncorrectUsage wp_get_admin_notice
-        */
-       public function test_should_throw_doing_it_wrong_with_a_type_containing_spaces() {
-               ob_start();
-               wp_admin_notice(
-                       'A type containing spaces.',
-                       array( 'type' => 'first second third fourth' )
-               );
-               $actual = ob_get_clean();
-
-               $this->assertSame(
-                       '<div class="notice notice-first second third fourth"><p>A type containing spaces.</p></div>',
-                       $actual
-               );
-       }
-
-       /**
-        * Tests that `wp_admin_notice()` fires the 'wp_admin_notice' action.
-        *
-        * @ticket 57791
-        */
-       public function test_should_fire_wp_admin_notice_action() {
-               $action = new MockAction();
-               add_action( 'wp_admin_notice', array( $action, 'action' ) );
-
-               ob_start();
-               wp_admin_notice( 'A notice.', array( 'type' => 'success' ) );
-               ob_end_clean();
-
-               $this->assertSame( 1, $action->get_call_count() );
-       }
-}
</del></span></pre></div>
<a id="trunktestsphpunittestsadminwpGetAdminNoticephp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/tests/phpunit/tests/admin/wpGetAdminNotice.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/admin/wpGetAdminNotice.php      2023-09-21 18:02:22 UTC (rev 56653)
+++ trunk/tests/phpunit/tests/admin/wpGetAdminNotice.php        2023-09-21 18:22:10 UTC (rev 56654)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,326 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-
-/**
- * Tests for `wp_get_admin_notice()`.
- *
- * @group admin
- *
- * @covers ::wp_get_admin_notice
- */
-class Tests_Admin_WpGetAdminNotice extends WP_UnitTestCase {
-
-       /**
-        * Tests that `wp_get_admin_notice()` returns the expected admin notice markup.
-        *
-        * @ticket 57791
-        *
-        * @dataProvider data_should_return_admin_notice
-        *
-        * @param string $message  The message.
-        * @param array  $args     Arguments for the admin notice.
-        * @param string $expected The expected admin notice markup.
-        */
-       public function test_should_return_admin_notice( $message, $args, $expected ) {
-               $this->assertSame( $expected, wp_get_admin_notice( $message, $args ) );
-       }
-
-       /**
-        * Data provider.
-        *
-        * @return array[]
-        */
-       public function data_should_return_admin_notice() {
-               return array(
-                       'defaults'                                  => array(
-                               'message'  => 'A notice with defaults.',
-                               'args'     => array(),
-                               'expected' => '<div class="notice"><p>A notice with defaults.</p></div>',
-                       ),
-                       'an empty message (used for templates)'     => array(
-                               'message'  => '',
-                               'args'     => array(
-                                       'type'               => 'error',
-                                       'dismissible'        => true,
-                                       'id'                 => 'message',
-                                       'additional_classes' => array( 'inline', 'hidden' ),
-                               ),
-                               'expected' => '<div id="message" class="notice notice-error is-dismissible inline hidden"><p></p></div>',
-                       ),
-                       'an empty message (used for templates) without paragraph wrapping' => array(
-                               'message'  => '',
-                               'args'     => array(
-                                       'type'               => 'error',
-                                       'dismissible'        => true,
-                                       'id'                 => 'message',
-                                       'additional_classes' => array( 'inline', 'hidden' ),
-                                       'paragraph_wrap'     => false,
-                               ),
-                               'expected' => '<div id="message" class="notice notice-error is-dismissible inline hidden"></div>',
-                       ),
-                       'an "error" notice'                         => array(
-                               'message'  => 'An "error" notice.',
-                               'args'     => array(
-                                       'type' => 'error',
-                               ),
-                               'expected' => '<div class="notice notice-error"><p>An "error" notice.</p></div>',
-                       ),
-                       'a "success" notice'                        => array(
-                               'message'  => 'A "success" notice.',
-                               'args'     => array(
-                                       'type' => 'success',
-                               ),
-                               'expected' => '<div class="notice notice-success"><p>A "success" notice.</p></div>',
-                       ),
-                       'a "warning" notice'                        => array(
-                               'message'  => 'A "warning" notice.',
-                               'args'     => array(
-                                       'type' => 'warning',
-                               ),
-                               'expected' => '<div class="notice notice-warning"><p>A "warning" notice.</p></div>',
-                       ),
-                       'an "info" notice'                          => array(
-                               'message'  => 'An "info" notice.',
-                               'args'     => array(
-                                       'type' => 'info',
-                               ),
-                               'expected' => '<div class="notice notice-info"><p>An "info" notice.</p></div>',
-                       ),
-                       'a type that already starts with "notice-"' => array(
-                               'message'  => 'A type that already starts with "notice-".',
-                               'args'     => array(
-                                       'type' => 'notice-info',
-                               ),
-                               'expected' => '<div class="notice notice-notice-info"><p>A type that already starts with "notice-".</p></div>',
-                       ),
-                       'a dismissible notice'                      => array(
-                               'message'  => 'A dismissible notice.',
-                               'args'     => array(
-                                       'dismissible' => true,
-                               ),
-                               'expected' => '<div class="notice is-dismissible"><p>A dismissible notice.</p></div>',
-                       ),
-                       'no type and an ID'                         => array(
-                               'message'  => 'A notice with an ID.',
-                               'args'     => array(
-                                       'id' => 'message',
-                               ),
-                               'expected' => '<div id="message" class="notice"><p>A notice with an ID.</p></div>',
-                       ),
-                       'a type and an ID'                          => array(
-                               'message'  => 'A warning notice with an ID.',
-                               'args'     => array(
-                                       'type' => 'warning',
-                                       'id'   => 'message',
-                               ),
-                               'expected' => '<div id="message" class="notice notice-warning"><p>A warning notice with an ID.</p></div>',
-                       ),
-                       'no type and additional classes'            => array(
-                               'message'  => 'A notice with additional classes.',
-                               'args'     => array(
-                                       'additional_classes' => array( 'error', 'notice-alt' ),
-                               ),
-                               'expected' => '<div class="notice error notice-alt"><p>A notice with additional classes.</p></div>',
-                       ),
-                       'a type and additional classes'             => array(
-                               'message'  => 'A warning notice with additional classes.',
-                               'args'     => array(
-                                       'type'               => 'warning',
-                                       'additional_classes' => array( 'error', 'notice-alt' ),
-                               ),
-                               'expected' => '<div class="notice notice-warning error notice-alt"><p>A warning notice with additional classes.</p></div>',
-                       ),
-                       'a dismissible notice with a type and additional classes' => array(
-                               'message'  => 'A dismissible warning notice with a type and additional classes.',
-                               'args'     => array(
-                                       'type'               => 'warning',
-                                       'dismissible'        => true,
-                                       'additional_classes' => array( 'error', 'notice-alt' ),
-                               ),
-                               'expected' => '<div class="notice notice-warning is-dismissible error notice-alt"><p>A dismissible warning notice with a type and additional classes.</p></div>',
-                       ),
-                       'a notice without paragraph wrapping'       => array(
-                               'message'  => '<span>A notice without paragraph wrapping.</span>',
-                               'args'     => array(
-                                       'paragraph_wrap' => false,
-                               ),
-                               'expected' => '<div class="notice"><span>A notice without paragraph wrapping.</span></div>',
-                       ),
-                       'an unsafe type'                            => array(
-                               'message'  => 'A notice with an unsafe type.',
-                               'args'     => array(
-                                       'type' => '"><script>alert("Howdy,admin!");</script>',
-                               ),
-                               'expected' => '<div class="notice notice-"><script>alert("Howdy,admin!");</script>"><p>A notice with an unsafe type.</p></div>',
-                       ),
-                       'an unsafe ID'                              => array(
-                               'message'  => 'A notice with an unsafe ID.',
-                               'args'     => array(
-                                       'id' => '"><script>alert( "Howdy, admin!" );</script> <div class="notice',
-                               ),
-                               'expected' => '<div id=""><script>alert( "Howdy, admin!" );</script> <div class="notice" class="notice"><p>A notice with an unsafe ID.</p></div>',
-                       ),
-                       'unsafe additional classes'                 => array(
-                               'message'  => 'A notice with unsafe additional classes.',
-                               'args'     => array(
-                                       'additional_classes' => array( '"><script>alert( "Howdy, admin!" );</script> <div class="notice' ),
-                               ),
-                               'expected' => '<div class="notice "><script>alert( "Howdy, admin!" );</script> <div class="notice"><p>A notice with unsafe additional classes.</p></div>',
-                       ),
-                       'a type that is not a string'               => array(
-                               'message'  => 'A notice with a type that is not a string.',
-                               'args'     => array(
-                                       'type' => array(),
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with a type that is not a string.</p></div>',
-                       ),
-                       'a type with only empty space'              => array(
-                               'message'  => 'A notice with a type with only empty space.',
-                               'args'     => array(
-                                       'type' => " \t\r\n",
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with a type with only empty space.</p></div>',
-                       ),
-                       'an ID that is not a string'                => array(
-                               'message'  => 'A notice with an ID that is not a string.',
-                               'args'     => array(
-                                       'id' => array( 'message' ),
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with an ID that is not a string.</p></div>',
-                       ),
-                       'an ID with only empty space'               => array(
-                               'message'  => 'A notice with an ID with only empty space.',
-                               'args'     => array(
-                                       'id' => " \t\r\n",
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with an ID with only empty space.</p></div>',
-                       ),
-                       'dismissible as a truthy value rather than (bool) true' => array(
-                               'message'  => 'A notice with dismissible as a truthy value rather than (bool) true.',
-                               'args'     => array(
-                                       'dismissible' => 1,
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with dismissible as a truthy value rather than (bool) true.</p></div>',
-                       ),
-                       'additional classes that are not an array'  => array(
-                               'message'  => 'A notice with additional classes that are not an array.',
-                               'args'     => array(
-                                       'additional_classes' => 'class-1 class-2 class-3',
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with additional classes that are not an array.</p></div>',
-                       ),
-                       'additional attribute with a value'         => array(
-                               'message'  => 'A notice with an additional attribute with a value.',
-                               'args'     => array(
-                                       'attributes' => array( 'aria-live' => 'assertive' ),
-                               ),
-                               'expected' => '<div class="notice" aria-live="assertive"><p>A notice with an additional attribute with a value.</p></div>',
-                       ),
-                       'additional hidden attribute'               => array(
-                               'message'  => 'A notice with the hidden attribute.',
-                               'args'     => array(
-                                       'attributes' => array( 'hidden' => true ),
-                               ),
-                               'expected' => '<div class="notice" hidden><p>A notice with the hidden attribute.</p></div>',
-                       ),
-                       'additional attribute no associative keys'  => array(
-                               'message'  => 'A notice with a boolean attribute without an associative key.',
-                               'args'     => array(
-                                       'attributes' => array( 'hidden' ),
-                               ),
-                               'expected' => '<div class="notice" hidden><p>A notice with a boolean attribute without an associative key.</p></div>',
-                       ),
-                       'additional attribute with role'            => array(
-                               'message'  => 'A notice with an additional attribute role.',
-                               'args'     => array(
-                                       'attributes' => array( 'role' => 'alert' ),
-                               ),
-                               'expected' => '<div class="notice" role="alert"><p>A notice with an additional attribute role.</p></div>',
-                       ),
-                       'multiple additional attributes'            => array(
-                               'message'  => 'A notice with multiple additional attributes.',
-                               'args'     => array(
-                                       'attributes' => array(
-                                               'role'      => 'alert',
-                                               'data-test' => -1,
-                                       ),
-                               ),
-                               'expected' => '<div class="notice" role="alert" data-test="-1"><p>A notice with multiple additional attributes.</p></div>',
-                       ),
-                       'data attribute with unsafe value'          => array(
-                               'message'  => 'A notice with an additional attribute with an unsafe value.',
-                               'args'     => array(
-                                       'attributes' => array( 'data-unsafe' => '<script>alert( "Howdy, admin!" );</script>' ),
-                               ),
-                               'expected' => '<div class="notice" data-unsafe="&lt;script&gt;alert( &quot;Howdy, admin!&quot; );&lt;/script&gt;"><p>A notice with an additional attribute with an unsafe value.</p></div>',
-                       ),
-                       'multiple attributes with "role", invalid, data-*, numeric, and boolean' => array(
-                               'message'  => 'A notice with multiple attributes with "role", invalid, "data-*", numeric, and boolean.',
-                               'args'     => array(
-                                       'attributes' => array(
-                                               'role'      => 'alert',
-                                               'disabled'  => 'disabled',
-                                               'data-name' => 'my-name',
-                                               'data-id'   => 1,
-                                               'hidden',
-                                       ),
-                               ),
-                               'expected' => '<div class="notice" role="alert" disabled="disabled" data-name="my-name" data-id="1" hidden><p>A notice with multiple attributes with "role", invalid, "data-*", numeric, and boolean.</p></div>',
-                       ),
-                       'paragraph wrapping as a falsy value rather than (bool) false' => array(
-                               'message'  => 'A notice with paragraph wrapping as a falsy value rather than (bool) false.',
-                               'args'     => array(
-                                       'paragraph_wrap' => 0,
-                               ),
-                               'expected' => '<div class="notice"><p>A notice with paragraph wrapping as a falsy value rather than (bool) false.</p></div>',
-                       ),
-               );
-       }
-
-       /**
-        * Tests that `wp_get_admin_notice()` throws a `_doing_it_wrong()` when
-        * a 'type' containing spaces is passed.
-        *
-        * @ticket 57791
-        *
-        * @expectedIncorrectUsage wp_get_admin_notice
-        */
-       public function test_should_throw_doing_it_wrong_with_a_type_containing_spaces() {
-               $this->assertSame(
-                       '<div class="notice notice-first second third fourth"><p>A type containing spaces.</p></div>',
-                       wp_get_admin_notice(
-                               'A type containing spaces.',
-                               array( 'type' => 'first second third fourth' )
-                       )
-               );
-       }
-
-       /**
-        * Tests that `wp_get_admin_notice()` applies filters.
-        *
-        * @ticket 57791
-        *
-        * @dataProvider data_should_apply_filters
-        *
-        * @param string $hook_name The name of the filter hook.
-        */
-       public function test_should_apply_filters( $hook_name ) {
-               $filter = new MockAction();
-               add_filter( $hook_name, array( $filter, 'filter' ) );
-
-               wp_get_admin_notice( 'A notice.', array( 'type' => 'success' ) );
-
-               $this->assertSame( 1, $filter->get_call_count() );
-       }
-
-       /**
-        * Data provider.
-        *
-        * @return array[]
-        */
-       public function data_should_apply_filters() {
-               return array(
-                       'wp_admin_notice_args'   => array( 'hook_name' => 'wp_admin_notice_args' ),
-                       'wp_admin_notice_markup' => array( 'hook_name' => 'wp_admin_notice_markup' ),
-               );
-       }
-}
</del></span></pre></div>
<a id="trunktestsphpunittestsfunctionswpAdminNoticephpfromrev56653trunktestsphpunittestsadminwpAdminNoticephp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/tests/phpunit/tests/functions/wpAdminNotice.php (from rev 56653, trunk/tests/phpunit/tests/admin/wpAdminNotice.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/functions/wpAdminNotice.php                             (rev 0)
+++ trunk/tests/phpunit/tests/functions/wpAdminNotice.php       2023-09-21 18:22:10 UTC (rev 56654)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,326 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * Tests for `wp_admin_notice()`.
+ *
+ * @group functions.php
+ *
+ * @covers ::wp_admin_notice
+ */
+class Tests_Functions_WpAdminNotice extends WP_UnitTestCase {
+
+       /**
+        * Tests that `wp_admin_notice()` outputs the expected admin notice markup.
+        *
+        * @ticket 57791
+        *
+        * @dataProvider data_should_output_admin_notice
+        *
+        * @param string $message  The message to output.
+        * @param array  $args     Arguments for the admin notice.
+        * @param string $expected The expected admin notice markup.
+        */
+       public function test_should_output_admin_notice( $message, $args, $expected ) {
+               ob_start();
+               wp_admin_notice( $message, $args );
+               $actual = ob_get_clean();
+
+               $this->assertSame( $expected, $actual );
+       }
+
+       /**
+        * Data provider.
+        *
+        * @return array[]
+        */
+       public function data_should_output_admin_notice() {
+               return array(
+                       'defaults'                                  => array(
+                               'message'  => 'A notice with defaults.',
+                               'args'     => array(),
+                               'expected' => '<div class="notice"><p>A notice with defaults.</p></div>',
+                       ),
+                       'an empty message (used for templates)'     => array(
+                               'message'  => '',
+                               'args'     => array(
+                                       'type'               => 'error',
+                                       'dismissible'        => true,
+                                       'id'                 => 'message',
+                                       'additional_classes' => array( 'inline', 'hidden' ),
+                               ),
+                               'expected' => '<div id="message" class="notice notice-error is-dismissible inline hidden"><p></p></div>',
+                       ),
+                       'an empty message (used for templates) without paragraph wrapping' => array(
+                               'message'  => '',
+                               'args'     => array(
+                                       'type'               => 'error',
+                                       'dismissible'        => true,
+                                       'id'                 => 'message',
+                                       'additional_classes' => array( 'inline', 'hidden' ),
+                                       'paragraph_wrap'     => false,
+                               ),
+                               'expected' => '<div id="message" class="notice notice-error is-dismissible inline hidden"></div>',
+                       ),
+                       'an "error" notice'                         => array(
+                               'message'  => 'An "error" notice.',
+                               'args'     => array(
+                                       'type' => 'error',
+                               ),
+                               'expected' => '<div class="notice notice-error"><p>An "error" notice.</p></div>',
+                       ),
+                       'a "success" notice'                        => array(
+                               'message'  => 'A "success" notice.',
+                               'args'     => array(
+                                       'type' => 'success',
+                               ),
+                               'expected' => '<div class="notice notice-success"><p>A "success" notice.</p></div>',
+                       ),
+                       'a "warning" notice'                        => array(
+                               'message'  => 'A "warning" notice.',
+                               'args'     => array(
+                                       'type' => 'warning',
+                               ),
+                               'expected' => '<div class="notice notice-warning"><p>A "warning" notice.</p></div>',
+                       ),
+                       'an "info" notice'                          => array(
+                               'message'  => 'An "info" notice.',
+                               'args'     => array(
+                                       'type' => 'info',
+                               ),
+                               'expected' => '<div class="notice notice-info"><p>An "info" notice.</p></div>',
+                       ),
+                       'a type that already starts with "notice-"' => array(
+                               'message'  => 'A type that already starts with "notice-".',
+                               'args'     => array(
+                                       'type' => 'notice-info',
+                               ),
+                               'expected' => '<div class="notice notice-notice-info"><p>A type that already starts with "notice-".</p></div>',
+                       ),
+                       'a dismissible notice'                      => array(
+                               'message'  => 'A dismissible notice.',
+                               'args'     => array(
+                                       'dismissible' => true,
+                               ),
+                               'expected' => '<div class="notice is-dismissible"><p>A dismissible notice.</p></div>',
+                       ),
+                       'no type and an ID'                         => array(
+                               'message'  => 'A notice with an ID.',
+                               'args'     => array(
+                                       'id' => 'message',
+                               ),
+                               'expected' => '<div id="message" class="notice"><p>A notice with an ID.</p></div>',
+                       ),
+                       'a type and an ID'                          => array(
+                               'message'  => 'A warning notice with an ID.',
+                               'args'     => array(
+                                       'type' => 'warning',
+                                       'id'   => 'message',
+                               ),
+                               'expected' => '<div id="message" class="notice notice-warning"><p>A warning notice with an ID.</p></div>',
+                       ),
+                       'no type and additional classes'            => array(
+                               'message'  => 'A notice with additional classes.',
+                               'args'     => array(
+                                       'additional_classes' => array( 'error', 'notice-alt' ),
+                               ),
+                               'expected' => '<div class="notice error notice-alt"><p>A notice with additional classes.</p></div>',
+                       ),
+                       'a type and additional classes'             => array(
+                               'message'  => 'A warning notice with additional classes.',
+                               'args'     => array(
+                                       'type'               => 'warning',
+                                       'additional_classes' => array( 'error', 'notice-alt' ),
+                               ),
+                               'expected' => '<div class="notice notice-warning error notice-alt"><p>A warning notice with additional classes.</p></div>',
+                       ),
+                       'a dismissible notice with a type and additional classes' => array(
+                               'message'  => 'A dismissible warning notice with a type and additional classes.',
+                               'args'     => array(
+                                       'type'               => 'warning',
+                                       'dismissible'        => true,
+                                       'additional_classes' => array( 'error', 'notice-alt' ),
+                               ),
+                               'expected' => '<div class="notice notice-warning is-dismissible error notice-alt"><p>A dismissible warning notice with a type and additional classes.</p></div>',
+                       ),
+                       'a notice without paragraph wrapping'       => array(
+                               'message'  => '<span>A notice without paragraph wrapping.</span>',
+                               'args'     => array(
+                                       'paragraph_wrap' => false,
+                               ),
+                               'expected' => '<div class="notice"><span>A notice without paragraph wrapping.</span></div>',
+                       ),
+                       'an unsafe type'                            => array(
+                               'message'  => 'A notice with an unsafe type.',
+                               'args'     => array(
+                                       'type' => '"><script>alert("Howdy,admin!");</script>',
+                               ),
+                               'expected' => '<div class="notice notice-">alert("Howdy,admin!");"&gt;<p>A notice with an unsafe type.</p></div>',
+                       ),
+                       'an unsafe ID'                              => array(
+                               'message'  => 'A notice with an unsafe ID.',
+                               'args'     => array(
+                                       'id' => '"><script>alert( "Howdy, admin!" );</script> <div class="notice',
+                               ),
+                               'expected' => '<div id="">alert( "Howdy, admin!" ); <div class="notice"><p>A notice with an unsafe ID.</p></div>',
+                       ),
+                       'unsafe additional classes'                 => array(
+                               'message'  => 'A notice with unsafe additional classes.',
+                               'args'     => array(
+                                       'additional_classes' => array( '"><script>alert( "Howdy, admin!" );</script> <div class="notice' ),
+                               ),
+                               'expected' => '<div class="notice ">alert( "Howdy, admin!" ); <div class="notice"><p>A notice with unsafe additional classes.</p></div>',
+                       ),
+                       'a type that is not a string'               => array(
+                               'message'  => 'A notice with a type that is not a string.',
+                               'args'     => array(
+                                       'type' => array(),
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with a type that is not a string.</p></div>',
+                       ),
+                       'a type with only empty space'              => array(
+                               'message'  => 'A notice with a type with only empty space.',
+                               'args'     => array(
+                                       'type' => " \t\r\n",
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with a type with only empty space.</p></div>',
+                       ),
+                       'an ID that is not a string'                => array(
+                               'message'  => 'A notice with an ID that is not a string.',
+                               'args'     => array(
+                                       'id' => array( 'message' ),
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with an ID that is not a string.</p></div>',
+                       ),
+                       'an ID with only empty space'               => array(
+                               'message'  => 'A notice with an ID with only empty space.',
+                               'args'     => array(
+                                       'id' => " \t\r\n",
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with an ID with only empty space.</p></div>',
+                       ),
+                       'dismissible as a truthy value rather than (bool) true' => array(
+                               'message'  => 'A notice with dismissible as a truthy value rather than (bool) true.',
+                               'args'     => array(
+                                       'dismissible' => 1,
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with dismissible as a truthy value rather than (bool) true.</p></div>',
+                       ),
+                       'additional classes that are not an array'  => array(
+                               'message'  => 'A notice with additional classes that are not an array.',
+                               'args'     => array(
+                                       'additional_classes' => 'class-1 class-2 class-3',
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with additional classes that are not an array.</p></div>',
+                       ),
+                       'additional attribute with a value'         => array(
+                               'message'  => 'A notice with an additional attribute with a value.',
+                               'args'     => array(
+                                       'attributes' => array( 'aria-live' => 'assertive' ),
+                               ),
+                               'expected' => '<div class="notice" aria-live="assertive"><p>A notice with an additional attribute with a value.</p></div>',
+                       ),
+                       'additional hidden attribute'               => array(
+                               'message'  => 'A notice with the hidden attribute.',
+                               'args'     => array(
+                                       'attributes' => array( 'hidden' => true ),
+                               ),
+                               'expected' => '<div class="notice" hidden><p>A notice with the hidden attribute.</p></div>',
+                       ),
+                       'additional attribute no associative keys'  => array(
+                               'message'  => 'A notice with a boolean attribute without an associative key.',
+                               'args'     => array(
+                                       'attributes' => array( 'hidden' ),
+                               ),
+                               'expected' => '<div class="notice" hidden><p>A notice with a boolean attribute without an associative key.</p></div>',
+                       ),
+                       'additional attribute with role'            => array(
+                               'message'  => 'A notice with an additional attribute role.',
+                               'args'     => array(
+                                       'attributes' => array( 'role' => 'alert' ),
+                               ),
+                               'expected' => '<div class="notice" role="alert"><p>A notice with an additional attribute role.</p></div>',
+                       ),
+                       'multiple additional attributes'            => array(
+                               'message'  => 'A notice with multiple additional attributes.',
+                               'args'     => array(
+                                       'attributes' => array(
+                                               'role'      => 'alert',
+                                               'data-test' => -1,
+                                       ),
+                               ),
+                               'expected' => '<div class="notice" role="alert" data-test="-1"><p>A notice with multiple additional attributes.</p></div>',
+                       ),
+                       'data attribute with unsafe value'          => array(
+                               'message'  => 'A notice with an additional attribute with an unsafe value.',
+                               'args'     => array(
+                                       'attributes' => array( 'data-unsafe' => '<script>alert( "Howdy, admin!" );</script>' ),
+                               ),
+                               'expected' => '<div class="notice" data-unsafe="&lt;script&gt;alert( &quot;Howdy, admin!&quot; );&lt;/script&gt;"><p>A notice with an additional attribute with an unsafe value.</p></div>',
+                       ),
+                       'additional invalid attribute'              => array(
+                               'message'  => 'A notice with an additional attribute that is invalid.',
+                               'args'     => array(
+                                       'attributes' => array( 'not-valid' => 'not-valid' ),
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with an additional attribute that is invalid.</p></div>',
+                       ),
+                       'multiple attributes with "role", invalid, data-*, numeric, and boolean' => array(
+                               'message'  => 'A notice with multiple attributes with "role", invalid, "data-*", numeric, and boolean.',
+                               'args'     => array(
+                                       'attributes' => array(
+                                               'role'      => 'alert',
+                                               'disabled'  => 'disabled',
+                                               'data-name' => 'my-name',
+                                               'data-id'   => 1,
+                                               'hidden',
+                                       ),
+                               ),
+                               'expected' => '<div class="notice" role="alert" data-name="my-name" data-id="1" hidden><p>A notice with multiple attributes with "role", invalid, "data-*", numeric, and boolean.</p></div>',
+                       ),
+                       'paragraph wrapping as a falsy value rather than (bool) false' => array(
+                               'message'  => 'A notice with paragraph wrapping as a falsy value rather than (bool) false.',
+                               'args'     => array(
+                                       'paragraph_wrap' => 0,
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with paragraph wrapping as a falsy value rather than (bool) false.</p></div>',
+                       ),
+               );
+       }
+
+       /**
+        * Tests that `_doing_it_wrong()` is thrown when a 'type' containing spaces is passed.
+        *
+        * @ticket 57791
+        *
+        * @expectedIncorrectUsage wp_get_admin_notice
+        */
+       public function test_should_throw_doing_it_wrong_with_a_type_containing_spaces() {
+               ob_start();
+               wp_admin_notice(
+                       'A type containing spaces.',
+                       array( 'type' => 'first second third fourth' )
+               );
+               $actual = ob_get_clean();
+
+               $this->assertSame(
+                       '<div class="notice notice-first second third fourth"><p>A type containing spaces.</p></div>',
+                       $actual
+               );
+       }
+
+       /**
+        * Tests that `wp_admin_notice()` fires the 'wp_admin_notice' action.
+        *
+        * @ticket 57791
+        */
+       public function test_should_fire_wp_admin_notice_action() {
+               $action = new MockAction();
+               add_action( 'wp_admin_notice', array( $action, 'action' ) );
+
+               ob_start();
+               wp_admin_notice( 'A notice.', array( 'type' => 'success' ) );
+               ob_end_clean();
+
+               $this->assertSame( 1, $action->get_call_count() );
+       }
+}
</ins></span></pre></div>
<a id="trunktestsphpunittestsfunctionswpGetAdminNoticephpfromrev56653trunktestsphpunittestsadminwpGetAdminNoticephp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/tests/phpunit/tests/functions/wpGetAdminNotice.php (from rev 56653, trunk/tests/phpunit/tests/admin/wpGetAdminNotice.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/functions/wpGetAdminNotice.php                          (rev 0)
+++ trunk/tests/phpunit/tests/functions/wpGetAdminNotice.php    2023-09-21 18:22:10 UTC (rev 56654)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,326 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * Tests for `wp_get_admin_notice()`.
+ *
+ * @group functions.php
+ *
+ * @covers ::wp_get_admin_notice
+ */
+class Tests_Functions_WpGetAdminNotice extends WP_UnitTestCase {
+
+       /**
+        * Tests that `wp_get_admin_notice()` returns the expected admin notice markup.
+        *
+        * @ticket 57791
+        *
+        * @dataProvider data_should_return_admin_notice
+        *
+        * @param string $message  The message.
+        * @param array  $args     Arguments for the admin notice.
+        * @param string $expected The expected admin notice markup.
+        */
+       public function test_should_return_admin_notice( $message, $args, $expected ) {
+               $this->assertSame( $expected, wp_get_admin_notice( $message, $args ) );
+       }
+
+       /**
+        * Data provider.
+        *
+        * @return array[]
+        */
+       public function data_should_return_admin_notice() {
+               return array(
+                       'defaults'                                  => array(
+                               'message'  => 'A notice with defaults.',
+                               'args'     => array(),
+                               'expected' => '<div class="notice"><p>A notice with defaults.</p></div>',
+                       ),
+                       'an empty message (used for templates)'     => array(
+                               'message'  => '',
+                               'args'     => array(
+                                       'type'               => 'error',
+                                       'dismissible'        => true,
+                                       'id'                 => 'message',
+                                       'additional_classes' => array( 'inline', 'hidden' ),
+                               ),
+                               'expected' => '<div id="message" class="notice notice-error is-dismissible inline hidden"><p></p></div>',
+                       ),
+                       'an empty message (used for templates) without paragraph wrapping' => array(
+                               'message'  => '',
+                               'args'     => array(
+                                       'type'               => 'error',
+                                       'dismissible'        => true,
+                                       'id'                 => 'message',
+                                       'additional_classes' => array( 'inline', 'hidden' ),
+                                       'paragraph_wrap'     => false,
+                               ),
+                               'expected' => '<div id="message" class="notice notice-error is-dismissible inline hidden"></div>',
+                       ),
+                       'an "error" notice'                         => array(
+                               'message'  => 'An "error" notice.',
+                               'args'     => array(
+                                       'type' => 'error',
+                               ),
+                               'expected' => '<div class="notice notice-error"><p>An "error" notice.</p></div>',
+                       ),
+                       'a "success" notice'                        => array(
+                               'message'  => 'A "success" notice.',
+                               'args'     => array(
+                                       'type' => 'success',
+                               ),
+                               'expected' => '<div class="notice notice-success"><p>A "success" notice.</p></div>',
+                       ),
+                       'a "warning" notice'                        => array(
+                               'message'  => 'A "warning" notice.',
+                               'args'     => array(
+                                       'type' => 'warning',
+                               ),
+                               'expected' => '<div class="notice notice-warning"><p>A "warning" notice.</p></div>',
+                       ),
+                       'an "info" notice'                          => array(
+                               'message'  => 'An "info" notice.',
+                               'args'     => array(
+                                       'type' => 'info',
+                               ),
+                               'expected' => '<div class="notice notice-info"><p>An "info" notice.</p></div>',
+                       ),
+                       'a type that already starts with "notice-"' => array(
+                               'message'  => 'A type that already starts with "notice-".',
+                               'args'     => array(
+                                       'type' => 'notice-info',
+                               ),
+                               'expected' => '<div class="notice notice-notice-info"><p>A type that already starts with "notice-".</p></div>',
+                       ),
+                       'a dismissible notice'                      => array(
+                               'message'  => 'A dismissible notice.',
+                               'args'     => array(
+                                       'dismissible' => true,
+                               ),
+                               'expected' => '<div class="notice is-dismissible"><p>A dismissible notice.</p></div>',
+                       ),
+                       'no type and an ID'                         => array(
+                               'message'  => 'A notice with an ID.',
+                               'args'     => array(
+                                       'id' => 'message',
+                               ),
+                               'expected' => '<div id="message" class="notice"><p>A notice with an ID.</p></div>',
+                       ),
+                       'a type and an ID'                          => array(
+                               'message'  => 'A warning notice with an ID.',
+                               'args'     => array(
+                                       'type' => 'warning',
+                                       'id'   => 'message',
+                               ),
+                               'expected' => '<div id="message" class="notice notice-warning"><p>A warning notice with an ID.</p></div>',
+                       ),
+                       'no type and additional classes'            => array(
+                               'message'  => 'A notice with additional classes.',
+                               'args'     => array(
+                                       'additional_classes' => array( 'error', 'notice-alt' ),
+                               ),
+                               'expected' => '<div class="notice error notice-alt"><p>A notice with additional classes.</p></div>',
+                       ),
+                       'a type and additional classes'             => array(
+                               'message'  => 'A warning notice with additional classes.',
+                               'args'     => array(
+                                       'type'               => 'warning',
+                                       'additional_classes' => array( 'error', 'notice-alt' ),
+                               ),
+                               'expected' => '<div class="notice notice-warning error notice-alt"><p>A warning notice with additional classes.</p></div>',
+                       ),
+                       'a dismissible notice with a type and additional classes' => array(
+                               'message'  => 'A dismissible warning notice with a type and additional classes.',
+                               'args'     => array(
+                                       'type'               => 'warning',
+                                       'dismissible'        => true,
+                                       'additional_classes' => array( 'error', 'notice-alt' ),
+                               ),
+                               'expected' => '<div class="notice notice-warning is-dismissible error notice-alt"><p>A dismissible warning notice with a type and additional classes.</p></div>',
+                       ),
+                       'a notice without paragraph wrapping'       => array(
+                               'message'  => '<span>A notice without paragraph wrapping.</span>',
+                               'args'     => array(
+                                       'paragraph_wrap' => false,
+                               ),
+                               'expected' => '<div class="notice"><span>A notice without paragraph wrapping.</span></div>',
+                       ),
+                       'an unsafe type'                            => array(
+                               'message'  => 'A notice with an unsafe type.',
+                               'args'     => array(
+                                       'type' => '"><script>alert("Howdy,admin!");</script>',
+                               ),
+                               'expected' => '<div class="notice notice-"><script>alert("Howdy,admin!");</script>"><p>A notice with an unsafe type.</p></div>',
+                       ),
+                       'an unsafe ID'                              => array(
+                               'message'  => 'A notice with an unsafe ID.',
+                               'args'     => array(
+                                       'id' => '"><script>alert( "Howdy, admin!" );</script> <div class="notice',
+                               ),
+                               'expected' => '<div id=""><script>alert( "Howdy, admin!" );</script> <div class="notice" class="notice"><p>A notice with an unsafe ID.</p></div>',
+                       ),
+                       'unsafe additional classes'                 => array(
+                               'message'  => 'A notice with unsafe additional classes.',
+                               'args'     => array(
+                                       'additional_classes' => array( '"><script>alert( "Howdy, admin!" );</script> <div class="notice' ),
+                               ),
+                               'expected' => '<div class="notice "><script>alert( "Howdy, admin!" );</script> <div class="notice"><p>A notice with unsafe additional classes.</p></div>',
+                       ),
+                       'a type that is not a string'               => array(
+                               'message'  => 'A notice with a type that is not a string.',
+                               'args'     => array(
+                                       'type' => array(),
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with a type that is not a string.</p></div>',
+                       ),
+                       'a type with only empty space'              => array(
+                               'message'  => 'A notice with a type with only empty space.',
+                               'args'     => array(
+                                       'type' => " \t\r\n",
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with a type with only empty space.</p></div>',
+                       ),
+                       'an ID that is not a string'                => array(
+                               'message'  => 'A notice with an ID that is not a string.',
+                               'args'     => array(
+                                       'id' => array( 'message' ),
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with an ID that is not a string.</p></div>',
+                       ),
+                       'an ID with only empty space'               => array(
+                               'message'  => 'A notice with an ID with only empty space.',
+                               'args'     => array(
+                                       'id' => " \t\r\n",
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with an ID with only empty space.</p></div>',
+                       ),
+                       'dismissible as a truthy value rather than (bool) true' => array(
+                               'message'  => 'A notice with dismissible as a truthy value rather than (bool) true.',
+                               'args'     => array(
+                                       'dismissible' => 1,
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with dismissible as a truthy value rather than (bool) true.</p></div>',
+                       ),
+                       'additional classes that are not an array'  => array(
+                               'message'  => 'A notice with additional classes that are not an array.',
+                               'args'     => array(
+                                       'additional_classes' => 'class-1 class-2 class-3',
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with additional classes that are not an array.</p></div>',
+                       ),
+                       'additional attribute with a value'         => array(
+                               'message'  => 'A notice with an additional attribute with a value.',
+                               'args'     => array(
+                                       'attributes' => array( 'aria-live' => 'assertive' ),
+                               ),
+                               'expected' => '<div class="notice" aria-live="assertive"><p>A notice with an additional attribute with a value.</p></div>',
+                       ),
+                       'additional hidden attribute'               => array(
+                               'message'  => 'A notice with the hidden attribute.',
+                               'args'     => array(
+                                       'attributes' => array( 'hidden' => true ),
+                               ),
+                               'expected' => '<div class="notice" hidden><p>A notice with the hidden attribute.</p></div>',
+                       ),
+                       'additional attribute no associative keys'  => array(
+                               'message'  => 'A notice with a boolean attribute without an associative key.',
+                               'args'     => array(
+                                       'attributes' => array( 'hidden' ),
+                               ),
+                               'expected' => '<div class="notice" hidden><p>A notice with a boolean attribute without an associative key.</p></div>',
+                       ),
+                       'additional attribute with role'            => array(
+                               'message'  => 'A notice with an additional attribute role.',
+                               'args'     => array(
+                                       'attributes' => array( 'role' => 'alert' ),
+                               ),
+                               'expected' => '<div class="notice" role="alert"><p>A notice with an additional attribute role.</p></div>',
+                       ),
+                       'multiple additional attributes'            => array(
+                               'message'  => 'A notice with multiple additional attributes.',
+                               'args'     => array(
+                                       'attributes' => array(
+                                               'role'      => 'alert',
+                                               'data-test' => -1,
+                                       ),
+                               ),
+                               'expected' => '<div class="notice" role="alert" data-test="-1"><p>A notice with multiple additional attributes.</p></div>',
+                       ),
+                       'data attribute with unsafe value'          => array(
+                               'message'  => 'A notice with an additional attribute with an unsafe value.',
+                               'args'     => array(
+                                       'attributes' => array( 'data-unsafe' => '<script>alert( "Howdy, admin!" );</script>' ),
+                               ),
+                               'expected' => '<div class="notice" data-unsafe="&lt;script&gt;alert( &quot;Howdy, admin!&quot; );&lt;/script&gt;"><p>A notice with an additional attribute with an unsafe value.</p></div>',
+                       ),
+                       'multiple attributes with "role", invalid, data-*, numeric, and boolean' => array(
+                               'message'  => 'A notice with multiple attributes with "role", invalid, "data-*", numeric, and boolean.',
+                               'args'     => array(
+                                       'attributes' => array(
+                                               'role'      => 'alert',
+                                               'disabled'  => 'disabled',
+                                               'data-name' => 'my-name',
+                                               'data-id'   => 1,
+                                               'hidden',
+                                       ),
+                               ),
+                               'expected' => '<div class="notice" role="alert" disabled="disabled" data-name="my-name" data-id="1" hidden><p>A notice with multiple attributes with "role", invalid, "data-*", numeric, and boolean.</p></div>',
+                       ),
+                       'paragraph wrapping as a falsy value rather than (bool) false' => array(
+                               'message'  => 'A notice with paragraph wrapping as a falsy value rather than (bool) false.',
+                               'args'     => array(
+                                       'paragraph_wrap' => 0,
+                               ),
+                               'expected' => '<div class="notice"><p>A notice with paragraph wrapping as a falsy value rather than (bool) false.</p></div>',
+                       ),
+               );
+       }
+
+       /**
+        * Tests that `wp_get_admin_notice()` throws a `_doing_it_wrong()` when
+        * a 'type' containing spaces is passed.
+        *
+        * @ticket 57791
+        *
+        * @expectedIncorrectUsage wp_get_admin_notice
+        */
+       public function test_should_throw_doing_it_wrong_with_a_type_containing_spaces() {
+               $this->assertSame(
+                       '<div class="notice notice-first second third fourth"><p>A type containing spaces.</p></div>',
+                       wp_get_admin_notice(
+                               'A type containing spaces.',
+                               array( 'type' => 'first second third fourth' )
+                       )
+               );
+       }
+
+       /**
+        * Tests that `wp_get_admin_notice()` applies filters.
+        *
+        * @ticket 57791
+        *
+        * @dataProvider data_should_apply_filters
+        *
+        * @param string $hook_name The name of the filter hook.
+        */
+       public function test_should_apply_filters( $hook_name ) {
+               $filter = new MockAction();
+               add_filter( $hook_name, array( $filter, 'filter' ) );
+
+               wp_get_admin_notice( 'A notice.', array( 'type' => 'success' ) );
+
+               $this->assertSame( 1, $filter->get_call_count() );
+       }
+
+       /**
+        * Data provider.
+        *
+        * @return array[]
+        */
+       public function data_should_apply_filters() {
+               return array(
+                       'wp_admin_notice_args'   => array( 'hook_name' => 'wp_admin_notice_args' ),
+                       'wp_admin_notice_markup' => array( 'hook_name' => 'wp_admin_notice_markup' ),
+               );
+       }
+}
</ins></span></pre>
</div>
</div>

</body>
</html>