diff --git a/src/wp-includes/user.php b/src/wp-includes/user.php index 92d091165525b..c175fc87d65be 100644 --- a/src/wp-includes/user.php +++ b/src/wp-includes/user.php @@ -2595,7 +2595,7 @@ function wp_insert_user( $userdata ) { } if ( $update ) { - if ( $user_email !== $old_user_data->user_email || $user_pass !== $old_user_data->user_pass ) { + if ( 0 !== strcasecmp( $user_email, $old_user_data->user_email ) || $user_pass !== $old_user_data->user_pass ) { $data['user_activation_key'] = ''; } $wpdb->update( $wpdb->users, $data, array( 'ID' => $user_id ) ); @@ -2811,7 +2811,7 @@ function wp_update_user( $userdata ) { $send_password_change_email = apply_filters( 'send_password_change_email', true, $user, $userdata ); } - if ( isset( $userdata['user_email'] ) && $user['user_email'] !== $userdata['user_email'] ) { + if ( isset( $userdata['user_email'] ) && 0 !== strcasecmp( $user['user_email'], $userdata['user_email'] ) ) { /** * Filters whether to send the email change email. * diff --git a/tests/phpunit/tests/user.php b/tests/phpunit/tests/user.php index caf570a36cab5..b7c6bac977328 100644 --- a/tests/phpunit/tests/user.php +++ b/tests/phpunit/tests/user.php @@ -2881,4 +2881,105 @@ public function test_set_password_action_on_user_update() { $this->assertSame( $updated_password, $args[0][0], 'Invalid password in wp_set_password action.' ); $this->assertSame( $user_id, $args[0][1], 'Invalid user ID in wp_set_password action.' ); } + + /** + * Changing only the case of an email should not trigger the email change notification. + * + * @ticket 52976 + * @covers ::wp_update_user + */ + public function test_case_only_email_change_does_not_trigger_email_change_notification() { + $user_id = self::factory()->user->create( + array( + 'user_email' => 'testcase@example.com', + ) + ); + + $email_change_fired = false; + $callback = static function () use ( &$email_change_fired ) { + $email_change_fired = true; + return false; + }; + + add_filter( 'send_email_change_email', $callback ); + + wp_update_user( + array( + 'ID' => $user_id, + 'user_email' => 'TestCase@Example.COM', + ) + ); + + remove_filter( 'send_email_change_email', $callback ); + + $this->assertFalse( $email_change_fired, 'Email change notification should not fire for case-only email change.' ); + } + + /** + * Changing to a genuinely different email should still trigger the notification. + * + * @ticket 52976 + * @covers ::wp_update_user + */ + public function test_real_email_change_triggers_email_change_notification() { + $user_id = self::factory()->user->create( + array( + 'user_email' => 'original@example.com', + ) + ); + + $email_change_fired = false; + $callback = static function () use ( &$email_change_fired ) { + $email_change_fired = true; + return false; + }; + + add_filter( 'send_email_change_email', $callback ); + + wp_update_user( + array( + 'ID' => $user_id, + 'user_email' => 'different@example.com', + ) + ); + + remove_filter( 'send_email_change_email', $callback ); + + $this->assertTrue( $email_change_fired, 'Email change notification should fire for a genuinely different email.' ); + } + + /** + * Changing only the case of an email should not clear the user_activation_key. + * + * Complements `test_changing_email_invalidates_password_reset_key()`, which covers the case + * where a genuinely different email clears the key. + * + * @ticket 52976 + * @covers ::wp_insert_user + */ + public function test_case_only_email_change_does_not_clear_user_activation_key() { + global $wpdb; + + $user_id = self::factory()->user->create( + array( + 'user_email' => 'keytest@example.com', + ) + ); + + $wpdb->update( $wpdb->users, array( 'user_activation_key' => 'key' ), array( 'ID' => $user_id ) ); + clean_user_cache( $user_id ); + + $user = get_userdata( $user_id ); + $this->assertSame( 'key', $user->user_activation_key, 'Precondition: activation key should be set.' ); + + wp_update_user( + array( + 'ID' => $user_id, + 'user_email' => 'KeyTest@Example.COM', + ) + ); + + $user = get_userdata( $user_id ); + $this->assertSame( 'key', $user->user_activation_key, 'user_activation_key should not be cleared on case-only email change.' ); + } }