Make WordPress Core

Changeset 56654


Ignore:
Timestamp:
09/21/2023 06:22:10 PM (3 years ago)
Author:
joedolson
Message:

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 #30685.

Location:
trunk
Files:
4 edited
2 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/css/login.css

    r55582 r56654  
    4343
    4444.login .message,
    45 .login .success,
    46 .login #login_error {
     45.login .notice,
     46.login .success {
    4747        border-left: 4px solid #72aee6;
    4848        padding: 12px;
    … …  
    5858}
    5959
    60 .login #login_error {
     60/* Match border color from common.css */
     61.login .notice-error {
    6162        border-left-color: #d63638;
     63}
     64
     65.login .login-error-list {
     66        list-style: none;
     67}
     68
     69.login .login-error-list li + li {
     70        margin-top: 4px;
    6271}
    6372
    … …  
    238247}
    239248
     249#login form .indicator-hint,
     250#login #reg_passmail {
     251        margin-bottom: 16px;
     252}
     253
    240254#login form p.submit {
    241255        margin: 0;
    … …  
    343357}
    344358
    345 .js.login input.password-input,
    346 .js.login-action-rp form .input,
    347 .js.login-action-rp input[type="text"] {
     359.js.login input.password-input {
    348360        padding-right: 2.5rem;
    349361}
    … …  
    355367}
    356368
     369.js.login-action-resetpass input[type="text"],
     370.js.login-action-resetpass input[type="password"],
    357371.js.login-action-rp input[type="text"],
    358372.js.login-action-rp input[type="password"] {
  • trunk/src/wp-admin/includes/misc.php

    r56603 r56654  
    16431643        return $response;
    16441644}
    1645 
    1646 /**
    1647  * Creates and returns the markup for an admin notice.
    1648  *
    1649  * @since 6.4.0
    1650  *
    1651  * @param string $message The message.
    1652  * @param array  $args {
    1653  *     Optional. An array of arguments for the admin notice. Default empty array.
    1654  *
    1655  *     @type string   $type               Optional. The type of admin notice.
    1656  *                                        For example, 'error', 'success', 'warning', 'info'.
    1657  *                                        Default empty string.
    1658  *     @type bool     $dismissible        Optional. Whether the admin notice is dismissible. Default false.
    1659  *     @type string   $id                 Optional. The value of the admin notice's ID attribute. Default empty string.
    1660  *     @type string[] $additional_classes Optional. A string array of class names. Default empty array.
    1661  *     @type string[] $attributes         Optional. Additional attributes for the notice div. Default empty array.
    1662  *     @type bool     $paragraph_wrap     Optional. Whether to wrap the message in paragraph tags. Default true.
    1663  * }
    1664  * @return string The markup for an admin notice.
    1665  */
    1666 function wp_get_admin_notice( $message, $args = array() ) {
    1667         $defaults = array(
    1668                 'type'               => '',
    1669                 'dismissible'        => false,
    1670                 'id'                 => '',
    1671                 'additional_classes' => array(),
    1672                 'attributes'         => array(),
    1673                 'paragraph_wrap'     => true,
    1674         );
    1675 
    1676         $args = wp_parse_args( $args, $defaults );
    1677 
    1678         /**
    1679          * Filters the arguments for an admin notice.
    1680          *
    1681          * @since 6.4.0
    1682          *
    1683          * @param array  $args    The arguments for the admin notice.
    1684          * @param string $message The message for the admin notice.
    1685          */
    1686         $args       = apply_filters( 'wp_admin_notice_args', $args, $message );
    1687         $id         = '';
    1688         $classes    = 'notice';
    1689         $attributes = '';
    1690 
    1691         if ( is_string( $args['id'] ) ) {
    1692                 $trimmed_id = trim( $args['id'] );
    1693 
    1694                 if ( '' !== $trimmed_id ) {
    1695                         $id = 'id="' . $trimmed_id . '" ';
    1696                 }
    1697         }
    1698 
    1699         if ( is_string( $args['type'] ) ) {
    1700                 $type = trim( $args['type'] );
    1701 
    1702                 if ( str_contains( $type, ' ' ) ) {
    1703                         _doing_it_wrong(
    1704                                 __FUNCTION__,
    1705                                 sprintf(
    1706                                         /* translators: %s: The "type" key. */
    1707                                         __( 'The %s key must be a string without spaces.' ),
    1708                                         '<code>type</code>'
    1709                                 ),
    1710                                 '6.4.0'
    1711                         );
    1712                 }
    1713 
    1714                 if ( '' !== $type ) {
    1715                         $classes .= ' notice-' . $type;
    1716                 }
    1717         }
    1718 
    1719         if ( true === $args['dismissible'] ) {
    1720                 $classes .= ' is-dismissible';
    1721         }
    1722 
    1723         if ( is_array( $args['additional_classes'] ) && ! empty( $args['additional_classes'] ) ) {
    1724                 $classes .= ' ' . implode( ' ', $args['additional_classes'] );
    1725         }
    1726 
    1727         if ( is_array( $args['attributes'] ) && ! empty( $args['attributes'] ) ) {
    1728                 $attributes = '';
    1729                 foreach ( $args['attributes'] as $attr => $val ) {
    1730                         if ( is_bool( $val ) ) {
    1731                                 $attributes .= $val ? ' ' . $attr : '';
    1732                         } elseif ( is_int( $attr ) ) {
    1733                                 $attributes .= ' ' . esc_attr( trim( $val ) );
    1734                         } elseif ( $val ) {
    1735                                 $attributes .= ' ' . $attr . '="' . esc_attr( trim( $val ) ) . '"';
    1736                         }
    1737                 }
    1738         }
    1739 
    1740         if ( false !== $args['paragraph_wrap'] ) {
    1741                 $message = "<p>$message</p>";
    1742         }
    1743 
    1744         $markup = sprintf( '<div %1$sclass="%2$s"%3$s>%4$s</div>', $id, $classes, $attributes, $message );
    1745 
    1746         /**
    1747          * Filters the markup for an admin notice.
    1748          *
    1749          * @since 6.4.0
    1750          *
    1751          * @param string $markup  The HTML markup for the admin notice.
    1752          * @param string $message The message for the admin notice.
    1753          * @param array  $args    The arguments for the admin notice.
    1754          */
    1755         return apply_filters( 'wp_admin_notice_markup', $markup, $message, $args );
    1756 }
    1757 
    1758 /**
    1759  * Outputs an admin notice.
    1760  *
    1761  * @since 6.4.0
    1762  *
    1763  * @param string $message The message to output.
    1764  * @param array  $args {
    1765  *     Optional. An array of arguments for the admin notice. Default empty array.
    1766  *
    1767  *     @type string   $type               Optional. The type of admin notice.
    1768  *                                        For example, 'error', 'success', 'warning', 'info'.
    1769  *                                        Default empty string.
    1770  *     @type bool     $dismissible        Optional. Whether the admin notice is dismissible. Default false.
    1771  *     @type string   $id                 Optional. The value of the admin notice's ID attribute. Default empty string.
    1772  *     @type string[] $additional_classes Optional. A string array of class names. Default empty array.
    1773  *     @type bool     $paragraph_wrap     Optional. Whether to wrap the message in paragraph tags. Default true.
    1774  * }
    1775  */
    1776 function wp_admin_notice( $message, $args = array() ) {
    1777         /**
    1778          * Fires before an admin notice is output.
    1779          *
    1780          * @since 6.4.0
    1781          *
    1782          * @param string $message The message for the admin notice.
    1783          * @param array  $args    The arguments for the admin notice.
    1784          */
    1785         do_action( 'wp_admin_notice', $message, $args );
    1786 
    1787         echo wp_kses_post( wp_get_admin_notice( $message, $args ) );
    1788 }
  • trunk/src/wp-includes/functions.php

    r56570 r56654  
    87638763        return abs( (float) $expected - (float) $actual ) <= $precision;
    87648764}
     8765
     8766/**
     8767 * Creates and returns the markup for an admin notice.
     8768 *
     8769 * @since 6.4.0
     8770 *
     8771 * @param string $message The message.
     8772 * @param array  $args {
     8773 *     Optional. An array of arguments for the admin notice. Default empty array.
     8774 *
     8775 *     @type string   $type               Optional. The type of admin notice.
     8776 *                                        For example, 'error', 'success', 'warning', 'info'.
     8777 *                                        Default empty string.
     8778 *     @type bool     $dismissible        Optional. Whether the admin notice is dismissible. Default false.
     8779 *     @type string   $id                 Optional. The value of the admin notice's ID attribute. Default empty string.
     8780 *     @type string[] $additional_classes Optional. A string array of class names. Default empty array.
     8781 *     @type string[] $attributes         Optional. Additional attributes for the notice div. Default empty array.
     8782 *     @type bool     $paragraph_wrap     Optional. Whether to wrap the message in paragraph tags. Default true.
     8783 * }
     8784 * @return string The markup for an admin notice.
     8785 */
     8786function wp_get_admin_notice( $message, $args = array() ) {
     8787        $defaults = array(
     8788                'type'               => '',
     8789                'dismissible'        => false,
     8790                'id'                 => '',
     8791                'additional_classes' => array(),
     8792                'attributes'         => array(),
     8793                'paragraph_wrap'     => true,
     8794        );
     8795
     8796        $args = wp_parse_args( $args, $defaults );
     8797
     8798        /**
     8799         * Filters the arguments for an admin notice.
     8800         *
     8801         * @since 6.4.0
     8802         *
     8803         * @param array  $args    The arguments for the admin notice.
     8804         * @param string $message The message for the admin notice.
     8805         */
     8806        $args       = apply_filters( 'wp_admin_notice_args', $args, $message );
     8807        $id         = '';
     8808        $classes    = 'notice';
     8809        $attributes = '';
     8810
     8811        if ( is_string( $args['id'] ) ) {
     8812                $trimmed_id = trim( $args['id'] );
     8813
     8814                if ( '' !== $trimmed_id ) {
     8815                        $id = 'id="' . $trimmed_id . '" ';
     8816                }
     8817        }
     8818
     8819        if ( is_string( $args['type'] ) ) {
     8820                $type = trim( $args['type'] );
     8821
     8822                if ( str_contains( $type, ' ' ) ) {
     8823                        _doing_it_wrong(
     8824                                __FUNCTION__,
     8825                                sprintf(
     8826                                        /* translators: %s: The "type" key. */
     8827                                        __( 'The %s key must be a string without spaces.' ),
     8828                                        '<code>type</code>'
     8829                                ),
     8830                                '6.4.0'
     8831                        );
     8832                }
     8833
     8834                if ( '' !== $type ) {
     8835                        $classes .= ' notice-' . $type;
     8836                }
     8837        }
     8838
     8839        if ( true === $args['dismissible'] ) {
     8840                $classes .= ' is-dismissible';
     8841        }
     8842
     8843        if ( is_array( $args['additional_classes'] ) && ! empty( $args['additional_classes'] ) ) {
     8844                $classes .= ' ' . implode( ' ', $args['additional_classes'] );
     8845        }
     8846
     8847        if ( is_array( $args['attributes'] ) && ! empty( $args['attributes'] ) ) {
     8848                $attributes = '';
     8849                foreach ( $args['attributes'] as $attr => $val ) {
     8850                        if ( is_bool( $val ) ) {
     8851                                $attributes .= $val ? ' ' . $attr : '';
     8852                        } elseif ( is_int( $attr ) ) {
     8853                                $attributes .= ' ' . esc_attr( trim( $val ) );
     8854                        } elseif ( $val ) {
     8855                                $attributes .= ' ' . $attr . '="' . esc_attr( trim( $val ) ) . '"';
     8856                        }
     8857                }
     8858        }
     8859
     8860        if ( false !== $args['paragraph_wrap'] ) {
     8861                $message = "<p>$message</p>";
     8862        }
     8863
     8864        $markup = sprintf( '<div %1$sclass="%2$s"%3$s>%4$s</div>', $id, $classes, $attributes, $message );
     8865
     8866        /**
     8867         * Filters the markup for an admin notice.
     8868         *
     8869         * @since 6.4.0
     8870         *
     8871         * @param string $markup  The HTML markup for the admin notice.
     8872         * @param string $message The message for the admin notice.
     8873         * @param array  $args    The arguments for the admin notice.
     8874         */
     8875        return apply_filters( 'wp_admin_notice_markup', $markup, $message, $args );
     8876}
     8877
     8878/**
     8879 * Outputs an admin notice.
     8880 *
     8881 * @since 6.4.0
     8882 *
     8883 * @param string $message The message to output.
     8884 * @param array  $args {
     8885 *     Optional. An array of arguments for the admin notice. Default empty array.
     8886 *
     8887 *     @type string   $type               Optional. The type of admin notice.
     8888 *                                        For example, 'error', 'success', 'warning', 'info'.
     8889 *                                        Default empty string.
     8890 *     @type bool     $dismissible        Optional. Whether the admin notice is dismissible. Default false.
     8891 *     @type string   $id                 Optional. The value of the admin notice's ID attribute. Default empty string.
     8892 *     @type string[] $additional_classes Optional. A string array of class names. Default empty array.
     8893 *     @type bool     $paragraph_wrap     Optional. Whether to wrap the message in paragraph tags. Default true.
     8894 * }
     8895 */
     8896function wp_admin_notice( $message, $args = array() ) {
     8897        /**
     8898         * Fires before an admin notice is output.
     8899         *
     8900         * @since 6.4.0
     8901         *
     8902         * @param string $message The message for the admin notice.
     8903         * @param array  $args    The arguments for the admin notice.
     8904         */
     8905        do_action( 'wp_admin_notice', $message, $args );
     8906
     8907        echo wp_kses_post( wp_get_admin_notice( $message, $args ) );
     8908}
  • trunk/src/wp-login.php

    r56628 r56654  
    229229
    230230        if ( $wp_error->has_errors() ) {
    231                 $errors   = '';
    232                 $messages = '';
     231                $error_list = array();
     232                $messages   = '';
    233233
    234234                foreach ( $wp_error->get_error_codes() as $code ) {
    … …  
    236236                        foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
    237237                                if ( 'message' === $severity ) {
    238                                         $messages .= '  ' . $error_message . "<br />\n";
     238                                        $messages .= '<p>' . $error_message . '</p>';
    239239                                } else {
    240                                         $errors .= '    ' . $error_message . "<br />\n";
     240                                        $error_list[] = $error_message;
    241241                                }
    242242                        }
    243243                }
    244244
    245                 if ( ! empty( $errors ) ) {
     245                if ( ! empty( $error_list ) ) {
     246                        $errors = '';
     247
     248                        if ( count( $error_list ) > 1 ) {
     249                                $errors .= '<ul class="login-error-list">';
     250
     251                                foreach ( $error_list as $item ) {
     252                                        $errors .= '<li>' . $item . '</li>';
     253                                }
     254
     255                                $errors .= '</ul>';
     256                        } else {
     257                                $errors .= '<p>' . $error_message . '</p>';
     258                        }
     259
    246260                        /**
    247261                         * Filters the error messages displayed above the login form.
    … …  
    251265                         * @param string $errors Login error message.
    252266                         */
    253                         echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
     267                        $errors = apply_filters( 'login_errors', $errors );
     268                        wp_admin_notice(
     269                                $errors,
     270                                array(
     271                                        'type'           => 'error',
     272                                        'id'             => 'login_error',
     273                                        'paragraph_wrap' => false,
     274                                )
     275                        );
    254276                }
    255277
    … …  
    262284                         * @param string $messages Login messages.
    263285                         */
    264                         echo '<p class="message" id="login-message">' . apply_filters( 'login_messages', $messages ) . "</p>\n";
     286                        $messages = apply_filters( 'login_messages', $messages );
     287                        wp_admin_notice(
     288                                $messages,
     289                                array(
     290                                        'type'               => 'info',
     291                                        'id'                 => 'login-message',
     292                                        'additional_classes' => array( 'message' ),
     293                                        'paragraph_wrap'     => false,
     294                                )
     295                        );
    265296                }
    266297        }
    … …  
    400431
    401432        ?>
    402         <div class="clear"></div>
    403433        </body>
    404434        </html>
    … …  
    830860                do_action( 'lost_password', $errors );
    831861
    832                 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 );
     862                login_header(
     863                        __( 'Lost Password' ),
     864                        wp_get_admin_notice(
     865                                __( 'Please enter your username or email address. You will receive an email message with instructions on how to reset your password.' ),
     866                                array(
     867                                        'type'               => 'info',
     868                                        'additional_classes' => array( 'message' ),
     869                                )
     870                        ),
     871                        $errors
     872                );
    833873
    834874                $user_login = '';
    … …  
    947987                        reset_password( $user, $_POST['pass1'] );
    948988                        setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
    949                         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>' );
     989                        login_header(
     990                                __( 'Password Reset' ),
     991                                wp_get_admin_notice(
     992                                        __( 'Your password has been reset.' ) . ' <a href="' . esc_url( wp_login_url() ) . '">' . __( 'Log in' ) . '</a>',
     993                                        array(
     994                                                'type'               => 'info',
     995                                                'additional_classes' => array( 'message', 'reset-pass' ),
     996                                        )
     997                                )
     998                        );
    950999                        login_footer();
    9511000                        exit;
    … …  
    9551004                wp_enqueue_script( 'user-profile' );
    9561005
    957                 login_header( __( 'Reset Password' ), '<p class="message reset-pass">' . __( 'Enter your new password below or generate one.' ) . '</p>', $errors );
     1006                login_header(
     1007                        __( 'Reset Password' ),
     1008                        wp_get_admin_notice(
     1009                                __( 'Enter your new password below or generate one.' ),
     1010                                array(
     1011                                        'type'               => 'info',
     1012                                        'additional_classes' => array( 'message', 'reset-pass' ),
     1013                                )
     1014                        ),
     1015                        $errors
     1016                );
    9581017
    9591018                ?>
    … …  
    9861045
    9871046                        <p class="description indicator-hint"><?php echo wp_get_password_hint(); ?></p>
    988                         <br class="clear" />
    9891047
    9901048                        <?php
    … …  
    10801138                $redirect_to = apply_filters( 'registration_redirect', $registration_redirect, $errors );
    10811139
    1082                 login_header( __( 'Registration Form' ), '<p class="message register">' . __( 'Register For This Site' ) . '</p>', $errors );
     1140                login_header(
     1141                        __( 'Registration Form' ),
     1142                        wp_get_admin_notice(
     1143                                __( 'Register For This Site' ),
     1144                                array(
     1145                                        'type'               => 'info',
     1146                                        'additional_classes' => array( 'message', 'register' ),
     1147                                )
     1148                        ),
     1149                        $errors
     1150                );
    10831151
    10841152                ?>
    … …  
    11051173                                <?php _e( 'Registration confirmation will be emailed to you.' ); ?>
    11061174                        </p>
    1107                         <br class="clear" />
    11081175                        <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
    11091176                        <p class="submit">
  • trunk/tests/phpunit/tests/functions/wpAdminNotice.php

    r56653 r56654  
    44 * Tests for `wp_admin_notice()`.
    55 *
    6  * @group admin
     6 * @group functions.php
    77 *
    88 * @covers ::wp_admin_notice
    99 */
    10 class Tests_Admin_WpAdminNotice extends WP_UnitTestCase {
     10class Tests_Functions_WpAdminNotice extends WP_UnitTestCase {
    1111
    1212        /**
  • trunk/tests/phpunit/tests/functions/wpGetAdminNotice.php

    r56653 r56654  
    44 * Tests for `wp_get_admin_notice()`.
    55 *
    6  * @group admin
     6 * @group functions.php
    77 *
    88 * @covers ::wp_get_admin_notice
    99 */
    10 class Tests_Admin_WpGetAdminNotice extends WP_UnitTestCase {
     10class Tests_Functions_WpGetAdminNotice extends WP_UnitTestCase {
    1111
    1212        /**
Note: See TracChangeset for help on using the changeset viewer.