diff --git a/src/wp-includes/user.php b/src/wp-includes/user.php index eab8fa7e00565..26bfe2be1638b 100644 --- a/src/wp-includes/user.php +++ b/src/wp-includes/user.php @@ -2501,6 +2501,14 @@ function wp_insert_user( $userdata ) { $user = new WP_User( $user_id ); + if ( ! $update ) { + // On initial creation, there is no existing user data, but `wp_set_password` expects a `WP_User` object. + $old_user_data = new WP_User(); + + /** This action is documented in wp-includes/pluggable.php */ + do_action( 'wp_set_password', $userdata['user_pass'], $user_id, $userdata ); + } + /** * Filters a user's meta values and keys immediately after the user is created or updated * and before any user meta is inserted or updated. @@ -2684,6 +2692,9 @@ function wp_update_user( $userdata ) { $plaintext_pass = $userdata['user_pass']; $userdata['user_pass'] = wp_hash_password( $userdata['user_pass'] ); + /** This action is documented in wp-includes/pluggable.php */ + do_action( 'wp_set_password', $plaintext_pass, $user_id, $user_obj ); + /** * Filters whether to send the password change email. * diff --git a/tests/phpunit/tests/user.php b/tests/phpunit/tests/user.php index df9f74b7e806a..535004ee560a8 100644 --- a/tests/phpunit/tests/user.php +++ b/tests/phpunit/tests/user.php @@ -2353,4 +2353,69 @@ function ( $meta_id, $object_id, $meta_key ) use ( &$db_update_count ) { // Verify there are no updates to 'use_ssl' user meta. $this->assertSame( 1, $db_update_count ); } + + /** + * Tests that `wp_set_password` action is triggered correctly during `wp_insert_user()`. + * + * @ticket 22114 + */ + public function test_set_password_action_fires_during_wp_insert_user() { + $mock_action = new MockAction(); + + add_action( 'wp_set_password', array( $mock_action, 'action' ), 10, 3 ); + + $userdata = array( + 'user_login' => 'testuser_' . wp_rand(), + 'user_pass' => 'initialpassword', + 'user_email' => 'testuser@example.com', + ); + + $user_id = wp_insert_user( $userdata ); + + // Assert that `wp_set_password` was triggered once during user creation. + $this->assertSame( 1, $mock_action->get_call_count(), 'wp_set_password was not triggered during user creation.' ); + + $args = $mock_action->get_args(); + + $this->assertSame( $userdata['user_pass'], $args[0][0], 'Wrong password argument in action.' ); + $this->assertSame( $user_id, $args[0][1], 'Wrong user ID in action.' ); + } + + /** + * Tests that `wp_set_password` action is triggered correctly during `wp_update_user()`. + * + * @ticket 22114 + */ + public function test_set_password_action_on_user_update() { + $mock_action = new MockAction(); + + add_action( 'wp_set_password', array( $mock_action, 'action' ), 10, 3 ); + + $user_id = $this->factory()->user->create( + array( + 'role' => 'subscriber', + 'user_login' => 'testuser_update', + 'user_email' => 'testuser_update@example.com', + 'user_pass' => 'initialpassword', + ) + ); + + $mock_action->reset(); + + $updated_password = 'newpassword123'; + + $userdata = array( + 'ID' => $user_id, + 'user_pass' => $updated_password, + ); + + wp_update_user( $userdata ); + + $this->assertSame( 1, $mock_action->get_call_count(), 'wp_set_password was not triggered during password update.' ); + + $args = $mock_action->get_args(); + + $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.' ); + } }