diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php index 08fc183167..949a66863d 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php @@ -434,6 +434,8 @@ class WP_REST_Users_Controller extends WP_REST_Controller { if ( is_wp_error( $user_id ) ) { return $user_id; } + + add_user_to_blog( get_site()->id, $user_id, '' ); } else { $user_id = wp_insert_user( $user ); @@ -558,6 +560,10 @@ class WP_REST_Users_Controller extends WP_REST_Controller { $user = get_user_by( 'id', $id ); + if ( is_multisite() && ! is_user_member_of_blog( $id ) ) { + add_user_to_blog( get_current_blog_id(), $id, '' ); + } + if ( ! empty( $request['roles'] ) ) { array_map( array( $user, 'add_role' ), $request['roles'] ); } diff --git a/tests/phpunit/includes/testcase-rest-controller.php b/tests/phpunit/includes/testcase-rest-controller.php index ad58b25a86..04e1cf2f96 100644 --- a/tests/phpunit/includes/testcase-rest-controller.php +++ b/tests/phpunit/includes/testcase-rest-controller.php @@ -40,8 +40,12 @@ abstract class WP_Test_REST_Controller_Testcase extends WP_Test_REST_TestCase { abstract public function test_get_item_schema(); public function filter_rest_url_for_leading_slash( $url, $path ) { + if ( is_multisite() ) { + return $url; + } + // Make sure path for rest_url has a leading slash for proper resolution. - $this->assertTrue( 0 === strpos( $path, '/' ) ); + $this->assertTrue( 0 === strpos( $path, '/' ), 'REST API URL should have a leading slash.' ); return $url; } diff --git a/tests/phpunit/tests/rest-api/rest-users-controller.php b/tests/phpunit/tests/rest-api/rest-users-controller.php index 08a1597fa2..a6e05155c3 100644 --- a/tests/phpunit/tests/rest-api/rest-users-controller.php +++ b/tests/phpunit/tests/rest-api/rest-users-controller.php @@ -12,6 +12,7 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase { protected static $user; protected static $editor; + protected static $site; public static function wpSetUpBeforeClass( $factory ) { self::$user = $factory->user->create( array( @@ -21,11 +22,19 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase { 'role' => 'editor', 'user_email' => 'editor@example.com', ) ); + + if ( is_multisite() ) { + self::$site = $factory->blog->create( array( 'domain' => 'rest.wordpress.org', 'path' => '/' ) ); + } } public static function wpTearDownAfterClass() { self::delete_user( self::$user ); self::delete_user( self::$editor ); + + if ( is_multisite() ) { + wpmu_delete_blog( self::$site, true ); + } } /** @@ -706,6 +715,142 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase { $this->check_add_edit_user_response( $response ); } + public function test_create_new_network_user_on_site_does_not_add_user_to_sub_site() { + if ( ! is_multisite() ) { + $this->markTestSkipped( 'Test requires multisite.' ); + } + + $this->allow_user_to_manage_multisite(); + + $params = array( + 'username' => 'testuser123', + 'password' => 'testpassword', + 'email' => 'test@example.com', + 'name' => 'Test User 123', + 'roles' => array( 'editor' ), + ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/users' ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( $params ); + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); + $user_id = $data['id']; + + $user_is_member = is_user_member_of_blog( $user_id, self::$site ); + + wpmu_delete_user( $user_id ); + + $this->assertFalse( $user_is_member ); + } + + public function test_create_new_network_user_on_sub_site_adds_user_to_site() { + if ( ! is_multisite() ) { + $this->markTestSkipped( 'Test requires multisite.' ); + } + + $this->allow_user_to_manage_multisite(); + + $params = array( + 'username' => 'testuser123', + 'password' => 'testpassword', + 'email' => 'test@example.com', + 'name' => 'Test User 123', + 'roles' => array( 'editor' ), + ); + + switch_to_blog( self::$site ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/users' ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( $params ); + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); + $user_id = $data['id']; + + restore_current_blog(); + + $user_is_member = is_user_member_of_blog( $user_id, self::$site ); + + wpmu_delete_user( $user_id ); + + $this->assertTrue( $user_is_member ); + } + + public function test_create_existing_network_user_on_sub_site_has_error() { + if ( ! is_multisite() ) { + $this->markTestSkipped( 'Test requires multisite.' ); + } + + $this->allow_user_to_manage_multisite(); + + $params = array( + 'username' => 'testuser123', + 'password' => 'testpassword', + 'email' => 'test@example.com', + 'name' => 'Test User 123', + 'roles' => array( 'editor' ), + ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/users' ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( $params ); + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); + $user_id = $data['id']; + + switch_to_blog( self::$site ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/users' ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( $params ); + $switched_response = $this->server->dispatch( $request ); + + restore_current_blog(); + + wpmu_delete_user( $user_id ); + + $this->assertErrorResponse( 'user_name', $switched_response ); + } + + public function test_update_existing_network_user_on_sub_site_adds_user_to_site() { + if ( ! is_multisite() ) { + $this->markTestSkipped( 'Test requires multisite.' ); + } + + $this->allow_user_to_manage_multisite(); + + $params = array( + 'username' => 'testuser123', + 'password' => 'testpassword', + 'email' => 'test@example.com', + 'name' => 'Test User 123', + 'roles' => array( 'editor' ), + ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/users' ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( $params ); + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); + $user_id = $data['id']; + + switch_to_blog( self::$site ); + + $request = new WP_REST_Request( 'PUT', '/wp/v2/users/' . $user_id ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( $params ); + $this->server->dispatch( $request ); + + restore_current_blog(); + + $user_is_member = is_user_member_of_blog( $user_id, self::$site ); + + wpmu_delete_user( $user_id ); + + $this->assertTrue( $user_is_member ); + } + public function test_json_create_user() { $this->allow_user_to_manage_multisite(); wp_set_current_user( self::$user );