diff --git a/src/wp-login.php b/src/wp-login.php index abedea82c3589..44021657ac460 100644 --- a/src/wp-login.php +++ b/src/wp-login.php @@ -602,6 +602,14 @@ function wp_login_viewport_meta() { } if ( current_user_can( 'manage_options' ) ) { + /** This filter is documented in wp-login.php */ + $show_verification = (bool) apply_filters( 'show_admin_email_verification', true, wp_get_current_user() ); + + if ( ! $show_verification ) { + wp_safe_redirect( $redirect_to ); + exit; + } + $admin_email = get_option( 'admin_email' ); } else { wp_safe_redirect( $redirect_to ); @@ -641,9 +649,10 @@ function wp_login_viewport_meta() { } /** - * Filters the interval for redirecting the user to the admin email confirmation screen. + * Filters the interval for redirecting the user to the admin email verification screen. * - * If `0` (zero) is returned, the user will not be redirected. + * If `0` or a negative value is returned, the email verification screen will + * be shown again next time an administrator logs in. * * @since 5.3.0 * @@ -651,9 +660,7 @@ function wp_login_viewport_meta() { */ $admin_email_check_interval = (int) apply_filters( 'admin_email_check_interval', 6 * MONTH_IN_SECONDS ); - if ( $admin_email_check_interval > 0 ) { - update_option( 'admin_email_lifespan', time() + $admin_email_check_interval ); - } + update_option( 'admin_email_lifespan', time() + $admin_email_check_interval ); wp_safe_redirect( $redirect_to ); exit; @@ -1386,25 +1393,31 @@ function wp_login_viewport_meta() { exit; } - // Check if it is time to add a redirect to the admin email confirmation screen. + // Check if it is time to add a redirect to the admin email verification screen. if ( $user instanceof WP_User && $user->exists() && $user->has_cap( 'manage_options' ) ) { - $admin_email_lifespan = (int) get_option( 'admin_email_lifespan' ); - - /* - * If `0` (or anything "falsey" as it is cast to int) is returned, the user will not be redirected - * to the admin email confirmation screen. + /** + * Filters whether the user should be redirected to the admin email verification screen. + * Can also be used to disable this functionality completely. + * + * @since 7.1.0 + * + * @param bool $show Whether to show the admin email verification screen. Default true. + * @param WP_User $user The current user object. */ - /** This filter is documented in wp-login.php */ - $admin_email_check_interval = (int) apply_filters( 'admin_email_check_interval', 6 * MONTH_IN_SECONDS ); - - if ( $admin_email_check_interval > 0 && time() > $admin_email_lifespan ) { - $redirect_to = add_query_arg( - array( - 'action' => 'confirm_admin_email', - 'wp_lang' => get_user_locale( $user ), - ), - wp_login_url( $redirect_to ) - ); + $show_verification = (bool) apply_filters( 'show_admin_email_verification', true, $user ); + + if ( $show_verification ) { + $admin_email_lifespan = (int) get_option( 'admin_email_lifespan' ); + + if ( time() > $admin_email_lifespan ) { + $redirect_to = add_query_arg( + array( + 'action' => 'confirm_admin_email', + 'wp_lang' => get_user_locale( $user ), + ), + wp_login_url( $redirect_to ) + ); + } } } diff --git a/tests/phpunit/tests/admin/adminEmailVerification.php b/tests/phpunit/tests/admin/adminEmailVerification.php new file mode 100644 index 0000000000000..84409b5fccba2 --- /dev/null +++ b/tests/phpunit/tests/admin/adminEmailVerification.php @@ -0,0 +1,114 @@ +user->create( array( 'role' => 'administrator' ) ); + } + + /** + * @ticket 48153 + */ + public function test_show_admin_email_verification_filter_can_disable_verification() { + wp_set_current_user( self::$admin_id ); + $user = wp_get_current_user(); + + add_filter( 'show_admin_email_verification', '__return_false' ); + $result = (bool) apply_filters( 'show_admin_email_verification', true, $user ); + remove_filter( 'show_admin_email_verification', '__return_false' ); + + $this->assertFalse( $result ); + } + + /** + * @ticket 48153 + */ + public function test_show_admin_email_verification_filter_receives_user_object() { + wp_set_current_user( self::$admin_id ); + $user = wp_get_current_user(); + + $captured_user = null; + $callback = function ( $show, $user ) use ( &$captured_user ) { + $captured_user = $user; + return $show; + }; + + add_filter( 'show_admin_email_verification', $callback, 10, 2 ); + apply_filters( 'show_admin_email_verification', true, $user ); + remove_filter( 'show_admin_email_verification', $callback ); + + $this->assertInstanceOf( 'WP_User', $captured_user ); + $this->assertSame( self::$admin_id, $captured_user->ID ); + } + + /** + * @ticket 48153 + */ + public function test_show_admin_email_verification_filter_prevents_redirect() { + $user = get_userdata( self::$admin_id ); + $redirect_to = admin_url(); + + // Set the lifespan to the past so it would be expired. + update_option( 'admin_email_lifespan', time() - 100 ); + + add_filter( 'show_admin_email_verification', '__return_false' ); + + // Simulate the redirect logic from wp-login.php. + $original_redirect = $redirect_to; + if ( is_a( $user, 'WP_User' ) && $user->exists() && $user->has_cap( 'manage_options' ) ) { + $show_verification = (bool) apply_filters( 'show_admin_email_verification', true, $user ); + if ( $show_verification && time() > (int) get_option( 'admin_email_lifespan' ) ) { + $redirect_to = add_query_arg( 'action', 'confirm_admin_email', wp_login_url( $redirect_to ) ); + } + } + + remove_filter( 'show_admin_email_verification', '__return_false' ); + + $this->assertSame( $original_redirect, $redirect_to ); + $this->assertStringNotContainsString( 'confirm_admin_email', $redirect_to ); + } + + /** + * @ticket 48153 + */ + public function test_admin_email_check_interval_zero_still_updates_lifespan() { + add_filter( 'admin_email_check_interval', '__return_zero' ); + + $before = time(); + + $admin_email_check_interval = (int) apply_filters( 'admin_email_check_interval', 6 * MONTH_IN_SECONDS ); + update_option( 'admin_email_lifespan', time() + $admin_email_check_interval ); + + $lifespan = (int) get_option( 'admin_email_lifespan' ); + + remove_filter( 'admin_email_check_interval', '__return_zero' ); + + $this->assertGreaterThanOrEqual( $before, $lifespan ); + $this->assertLessThanOrEqual( $before + 5, $lifespan ); + } + + /** + * @ticket 48153 + */ + public function test_confirm_admin_email_action_respects_show_verification_filter() { + wp_set_current_user( self::$admin_id ); + + $this->assertTrue( current_user_can( 'manage_options' ) ); + + $show_verification = (bool) apply_filters( 'show_admin_email_verification', true, wp_get_current_user() ); + $this->assertTrue( $show_verification ); + + // When the filter returns false, the screen should be skipped. + add_filter( 'show_admin_email_verification', '__return_false' ); + $show_verification = (bool) apply_filters( 'show_admin_email_verification', true, wp_get_current_user() ); + remove_filter( 'show_admin_email_verification', '__return_false' ); + + $this->assertFalse( $show_verification ); + } +}