diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index f6f53f210c..9a9b902dea 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -87,6 +87,7 @@ class WP_Term_Query { * @since 4.6.0 * @since 4.6.0 Introduced 'term_taxonomy_id' parameter. * @since 4.7.0 Introduced 'object_ids' parameter. + * @since 4.9.0 Added 'slug__in' support for 'orderby'. * * @param string|array $query { * Optional. Array or query string of term query parameters. Default empty. @@ -98,7 +99,8 @@ class WP_Term_Query { * @type string $orderby Field(s) to order terms by. Accepts term fields ('name', * 'slug', 'term_group', 'term_id', 'id', 'description', 'parent'), * 'count' for term taxonomy count, 'include' to match the - * 'order' of the $include param, 'meta_value', 'meta_value_num', + * 'order' of the $include param, 'slug__in' to match the + * 'order' of the $slug param, 'meta_value', 'meta_value_num', * the value of `$meta_key`, the array keys of `$meta_query`, or * 'none' to omit the ORDER BY clause. Defaults to 'name'. * @type string $order Whether to order terms in ascending or descending order. @@ -841,6 +843,9 @@ class WP_Term_Query { } elseif ( 'include' == $_orderby && ! empty( $this->query_vars['include'] ) ) { $include = implode( ',', wp_parse_id_list( $this->query_vars['include'] ) ); $orderby = "FIELD( t.term_id, $include )"; + } elseif ( 'slug__in' == $_orderby && ! empty( $this->query_vars['slug'] ) && is_array( $this->query_vars['slug'] ) ) { + $slugs = implode( "', '", array_map( 'sanitize_title_for_query', $this->query_vars['slug__in'] ) ); + $orderby = "FIELD( t.slug, '" . $slugs . "')"; } elseif ( 'none' == $_orderby ) { $orderby = ''; } elseif ( empty( $_orderby ) || 'id' == $_orderby || 'term_id' === $_orderby ) { diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index 8d65252537..93a2b8db0d 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php @@ -874,9 +874,10 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { // Map to proper WP_Query orderby param. if ( isset( $query_args['orderby'] ) && isset( $request['orderby'] ) ) { $orderby_mappings = array( - 'id' => 'ID', - 'include' => 'post__in', - 'slug' => 'post_name', + 'id' => 'ID', + 'include' => 'post__in', + 'slug' => 'post_name', + 'include_slugs' => 'post_name__in', ); if ( isset( $orderby_mappings[ $request['orderby'] ] ) ) { @@ -2109,6 +2110,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { 'parent', 'relevance', 'slug', + 'include_slugs', 'title', ), ); diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php index 826902a164..749a6d6870 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php @@ -188,6 +188,16 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { } } + if ( isset( $prepared_args['orderby'] ) && isset( $request['orderby'] ) ) { + $orderby_mappings = array( + 'include_slugs' => 'slug__in', + ); + + if ( isset( $orderby_mappings[ $request['orderby'] ] ) ) { + $prepared_args['orderby'] = $orderby_mappings[ $request['orderby'] ]; + } + } + if ( isset( $registered['offset'] ) && ! empty( $request['offset'] ) ) { $prepared_args['offset'] = $request['offset']; } else { @@ -932,6 +942,7 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { 'include', 'name', 'slug', + 'include_slugs', 'term_group', 'description', 'count', 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 44d6367a54..c7c32a73db 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 @@ -243,6 +243,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller { 'name' => 'display_name', 'registered_date' => 'registered', 'slug' => 'user_nicename', + 'include_slugs' => 'nicename__in', 'email' => 'user_email', 'url' => 'user_url', ); @@ -1338,6 +1339,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller { 'name', 'registered_date', 'slug', + 'include_slugs', 'email', 'url', ), diff --git a/tests/phpunit/tests/rest-api/rest-categories-controller.php b/tests/phpunit/tests/rest-api/rest-categories-controller.php index d706e25556..68e8ff0b2d 100644 --- a/tests/phpunit/tests/rest-api/rest-categories-controller.php +++ b/tests/phpunit/tests/rest-api/rest-categories-controller.php @@ -287,6 +287,22 @@ class WP_Test_REST_Categories_Controller extends WP_Test_REST_Controller_Testcas $this->assertEquals( 'Cantaloupe', $data[2]['name'] ); } + public function test_get_items_orderby_slugs() { + $this->factory->category->create( array( 'name' => 'Burrito' ) ); + $this->factory->category->create( array( 'name' => 'Taco' ) ); + $this->factory->category->create( array( 'name' => 'Chalupa' ) ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/categories' ); + $request->set_param( 'orderby', 'include_slugs' ); + $request->set_param( 'slug', array( 'taco', 'burrito', 'chalupa' ) ); + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( 'taco', $data[0]['slug'] ); + $this->assertEquals( 'burrito', $data[1]['slug'] ); + $this->assertEquals( 'chalupa', $data[2]['slug'] ); + } + protected function post_with_categories() { $post_id = $this->factory->post->create(); $category1 = $this->factory->category->create( array( diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index c86879cffc..cf82fe5b0d 100644 --- a/tests/phpunit/tests/rest-api/rest-posts-controller.php +++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php @@ -598,6 +598,24 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te $this->assertPostsOrderedBy( '{posts}.post_name DESC' ); } + public function test_get_items_with_orderby_slugs() { + $slugs = array( 'burrito', 'taco', 'chalupa' ); + foreach ( $slugs as $slug ) { + $this->factory->post->create( array( 'post_title' => $slug, 'post_name' => $slug, 'post_status' => 'publish' ) ); + } + + $request = new WP_REST_Request( 'GET', '/wp/v2/posts' ); + $request->set_param( 'orderby', 'include_slugs' ); + $request->set_param( 'slug', array( 'taco', 'chalupa', 'burrito' ) ); + + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); + + $this->assertEquals( 'taco', $data[0]['slug'] ); + $this->assertEquals( 'chalupa', $data[1]['slug'] ); + $this->assertEquals( 'burrito', $data[2]['slug'] ); + } + public function test_get_items_with_orderby_relevance() { $id1 = $this->factory->post->create( array( 'post_title' => 'Title is more relevant', 'post_content' => 'Content is', 'post_status' => 'publish' ) ); $id2 = $this->factory->post->create( array( 'post_title' => 'Title is', 'post_content' => 'Content is less relevant', 'post_status' => 'publish' ) ); diff --git a/tests/phpunit/tests/rest-api/rest-tags-controller.php b/tests/phpunit/tests/rest-api/rest-tags-controller.php index fccc4d702d..904e826751 100644 --- a/tests/phpunit/tests/rest-api/rest-tags-controller.php +++ b/tests/phpunit/tests/rest-api/rest-tags-controller.php @@ -250,6 +250,22 @@ class WP_Test_REST_Tags_Controller extends WP_Test_REST_Controller_Testcase { $this->assertEquals( 'Cantaloupe', $data[2]['name'] ); } + public function test_get_items_orderby_slugs() { + $this->factory->tag->create( array( 'name' => 'Burrito' ) ); + $this->factory->tag->create( array( 'name' => 'Taco' ) ); + $this->factory->tag->create( array( 'name' => 'Chalupa' ) ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/tags' ); + $request->set_param( 'orderby', 'include_slugs' ); + $request->set_param( 'slug', array( 'taco', 'burrito', 'chalupa' ) ); + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( 'taco', $data[0]['slug'] ); + $this->assertEquals( 'burrito', $data[1]['slug'] ); + $this->assertEquals( 'chalupa', $data[2]['slug'] ); + } + public function test_get_items_post_args() { $post_id = $this->factory->post->create(); $tag1 = $this->factory->tag->create( array( 'name' => 'DC' ) ); diff --git a/tests/phpunit/tests/rest-api/rest-users-controller.php b/tests/phpunit/tests/rest-api/rest-users-controller.php index d04cbcb7f7..cd4f761788 100644 --- a/tests/phpunit/tests/rest-api/rest-users-controller.php +++ b/tests/phpunit/tests/rest-api/rest-users-controller.php @@ -409,6 +409,24 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase { $this->assertEquals( $low_id, $data[0]['id'] ); } + public function test_get_items_orderby_slugs() { + wp_set_current_user( self::$user ); + + $this->factory->user->create( array( 'user_nicename' => 'burrito' ) ); + $this->factory->user->create( array( 'user_nicename' => 'taco' ) ); + $this->factory->user->create( array( 'user_nicename' => 'chalupa' ) ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/users' ); + $request->set_param( 'orderby', 'include_slugs' ); + $request->set_param( 'slug', array( 'taco', 'burrito', 'chalupa' ) ); + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); + + $this->assertEquals( 'taco', $data[0]['slug'] ); + $this->assertEquals( 'burrito', $data[1]['slug'] ); + $this->assertEquals( 'chalupa', $data[2]['slug'] ); + } + public function test_get_items_orderby_email() { 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 72bcc5e12c..38c7179274 100644 --- a/tests/qunit/fixtures/wp-api-generated.js +++ b/tests/qunit/fixtures/wp-api-generated.js @@ -284,6 +284,7 @@ mockedApiResponse.Schema = { "parent", "relevance", "slug", + "include_slugs", "title" ], "description": "Sort collection by object attribute.", @@ -905,6 +906,7 @@ mockedApiResponse.Schema = { "parent", "relevance", "slug", + "include_slugs", "title", "menu_order" ], @@ -1443,6 +1445,7 @@ mockedApiResponse.Schema = { "parent", "relevance", "slug", + "include_slugs", "title" ], "description": "Sort collection by object attribute.", @@ -2023,6 +2026,7 @@ mockedApiResponse.Schema = { "include", "name", "slug", + "include_slugs", "term_group", "description", "count" @@ -2266,6 +2270,7 @@ mockedApiResponse.Schema = { "include", "name", "slug", + "include_slugs", "term_group", "description", "count" @@ -2495,6 +2500,7 @@ mockedApiResponse.Schema = { "name", "registered_date", "slug", + "include_slugs", "email", "url" ],