Skip to content

Function

Handle the 'resetpass' action.

tml_password_reset_handler( )

Source

function tml_password_reset_handler() {
    // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing -- mirrors wp-login.php's own resetpass-form processing, which is secured by the rp_key/rp_login cookie/hash rather than a nonce.

    list( $rp_path ) = explode( '?', wp_unslash( $_SERVER['REQUEST_URI'] ) );
    $rp_cookie       = 'wp-resetpass-' . COOKIEHASH;

    if ( isset( $_GET['key'] ) && isset( $_GET['login'] ) ) {
        $value = sprintf( '%s:%s', wp_unslash( $_GET['login'] ), wp_unslash( $_GET['key'] ) );
        setcookie( $rp_cookie, $value, 0, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
        wp_safe_redirect( remove_query_arg( array( 'key', 'login' ) ) );
        exit;
    }

    if ( isset( $_COOKIE[ $rp_cookie ] ) && 0 < strpos( $_COOKIE[ $rp_cookie ], ':' ) ) {
        list( $rp_login, $rp_key ) = explode( ':', wp_unslash( $_COOKIE[ $rp_cookie ] ), 2 );

        $user = check_password_reset_key( $rp_key, $rp_login );
        if ( isset( $_POST['pass1'] ) && ! hash_equals( $rp_key, $_POST['rp_key'] ) ) {
            $user = false;
        }
    } else {
        $user = false;
    }

    if ( ! $user || is_wp_error( $user ) ) {
        setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
        // phpcs:disable WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- matches wp-login.php's own use of plain wp_redirect() here; target is always a hardcoded site_url() string, never raw user input.
        if ( $user && $user->get_error_code() === 'expired_key' ) {
            wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=expiredkey' ) );
        } else {
            wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=invalidkey' ) );
        }
        // phpcs:enable WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
        exit;
    }

    $errors = new WP_Error();

    // phpcs:disable WordPress.WP.I18n.MissingArgDomain -- these messages intentionally reuse WP core's translated wp-login.php strings verbatim, not TML-specific strings.

    // Check if password is one or all empty spaces.
    if ( ! empty( $_POST['pass1'] ) ) {
        $_POST['pass1'] = trim( $_POST['pass1'] );

        if ( empty( $_POST['pass1'] ) ) {
            $errors->add( 'password_reset_empty_space', __( 'The password cannot be a space or all spaces.' ) );
        }
    }

    // Check if password fields do not match.
    if ( ! empty( $_POST['pass1'] ) && trim( $_POST['pass2'] ) !== $_POST['pass1'] ) {
        $errors->add( 'password_reset_mismatch', __( '<strong>Error:</strong> The passwords do not match.' ) );
    }

    // phpcs:enable WordPress.WP.I18n.MissingArgDomain

    /** This action is documented in wp-login.php */
    do_action( 'validate_password_reset', $errors, $user );

    if ( ( ! $errors->has_errors() ) && isset( $_POST['pass1'] ) && ! empty( $_POST['pass1'] ) ) {
        reset_password( $user, $_POST['pass1'] );
        setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
        // phpcs:disable WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- target is always a hardcoded site_url() string, never raw user input.
        wp_redirect( site_url( 'wp-login.php?resetpass=complete' ) );
        // phpcs:enable WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
        exit;
    } else {
        tml_set_errors( $errors );
    }
    // phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
}

Uses

Changelog

VersionDescription
7.0 Introduced.