From bcaaa16a1f4374d9b96ad05cee1add48f5f4d5df Mon Sep 17 00:00:00 2001 From: Joe McGill <joemcgill@git.wordpress.org> Date: Fri, 28 Feb 2025 18:19:21 +0000 Subject: [PATCH] REST API: Add support for `search_columns` to the user endpoint. This adds support for passing a `search_columns` argument to the user controller so that users with `list_users` caps can specify which field is being searched. Props youknowriad, joemcgill, ntsekouras, mreishus, mamaduka. Fixes 62596. git-svn-id: https://develop.svn.wordpress.org/trunk@59892 602fd350-edb4-49c9-b593-d223f7449a82 --- .../class-wp-rest-users-controller.php | 32 ++++++++++ .../tests/rest-api/rest-users-controller.php | 58 +++++++++++++++++++ tests/qunit/fixtures/wp-api-generated.js | 16 +++++ 3 files changed, 106 insertions(+) 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 64578c7810..fd2f061171 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 @@ -257,6 +257,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller { * Retrieves all users. * * @since 4.7.0 + * @since 6.8.0 Added support for the search_columns query param. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. @@ -331,6 +332,27 @@ class WP_REST_Users_Controller extends WP_REST_Controller { if ( ! current_user_can( 'list_users' ) ) { $prepared_args['search_columns'] = array( 'ID', 'user_login', 'user_nicename', 'display_name' ); } + $search_columns = $request->get_param( 'search_columns' ); + $valid_columns = isset( $prepared_args['search_columns'] ) + ? $prepared_args['search_columns'] + : array( 'ID', 'user_login', 'user_nicename', 'user_email', 'display_name' ); + $search_columns_mapping = array( + 'id' => 'ID', + 'username' => 'user_login', + 'slug' => 'user_nicename', + 'email' => 'user_email', + 'name' => 'display_name', + ); + $search_columns = array_map( + static function ( $column ) use ( $search_columns_mapping ) { + return $search_columns_mapping[ $column ]; + }, + $search_columns + ); + $search_columns = array_intersect( $search_columns, $valid_columns ); + if ( ! empty( $search_columns ) ) { + $prepared_args['search_columns'] = $search_columns; + } $prepared_args['search'] = '*' . $prepared_args['search'] . '*'; } /** @@ -1613,6 +1635,16 @@ class WP_REST_Users_Controller extends WP_REST_Controller { ), ); + $query_params['search_columns'] = array( + 'default' => array(), + 'description' => __( 'Array of column names to be searched.' ), + 'type' => 'array', + 'items' => array( + 'enum' => array( 'email', 'name', 'id', 'username', 'slug' ), + 'type' => 'string', + ), + ); + /** * Filters REST API collection parameters for the users controller. * diff --git a/tests/phpunit/tests/rest-api/rest-users-controller.php b/tests/phpunit/tests/rest-api/rest-users-controller.php index e9576a2c9b..b1d21cee61 100644 --- a/tests/phpunit/tests/rest-api/rest-users-controller.php +++ b/tests/phpunit/tests/rest-api/rest-users-controller.php @@ -212,6 +212,7 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase { 'search', 'slug', 'who', + 'search_columns', 'has_published_posts', ), $keys @@ -712,6 +713,63 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase { $this->assertCount( 0, $response->get_data() ); } + /** + * @ticket 62596 + */ + public function test_get_items_search_columns() { + $request = new WP_REST_Request( 'GET', '/wp/v2/users' ); + $request->set_param( 'search', 'yololololo' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertCount( 0, $response->get_data() ); + + self::factory()->user->create( + array( + 'display_name' => 'Adam', + 'user_email' => 'yololololo@example.localhost', + ) + ); + + wp_set_current_user( self::$user ); + $request = new WP_REST_Request( 'GET', '/wp/v2/users' ); + $request->set_param( 'search', 'yololololo' ); + $request->set_param( 'search_columns', 'email' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertCount( 1, $response->get_data() ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/users' ); + $request->set_param( 'search', 'yololololo' ); + $request->set_param( 'search_columns', 'name' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertCount( 0, $response->get_data() ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/users' ); + $request->set_param( 'search', 'Adam' ); + $request->set_param( 'search_columns', 'name' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertCount( 1, $response->get_data() ); + } + + /** + * @ticket 62596 + */ + public function test_get_items_search_columns_without_permission() { + self::factory()->user->create( + array( + 'display_name' => 'Adam', + 'user_email' => 'yololololo@example.localhost', + ) + ); + + // Test user without sufficient capabilities - 'list_users'. + wp_set_current_user( self::$editor ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/users' ); + $request->set_param( 'search', 'yololololo' ); + $request->set_param( 'search_columns', 'email' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertCount( 0, $response->get_data() ); + } + public function test_get_items_slug_query() { wp_set_current_user( self::$user ); diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js index 47b272c1bd..f87397b20a 100644 --- a/tests/qunit/fixtures/wp-api-generated.js +++ b/tests/qunit/fixtures/wp-api-generated.js @@ -9604,6 +9604,22 @@ mockedApiResponse.Schema = { } }, "required": false + }, + "search_columns": { + "default": [], + "description": "Array of column names to be searched.", + "type": "array", + "items": { + "enum": [ + "email", + "name", + "id", + "username", + "slug" + ], + "type": "string" + }, + "required": false } } },