From 8cda3a2f550f95d4b52d394a2eb2f7ff6aeae0a3 Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Thu, 5 Oct 2017 00:36:43 +0000 Subject: [PATCH] REST API: Support ordering response collection by listed slugs. Adds an "include_slug" orderby value for REST API collections to permit returning a collection filtered by slugs in the same order in which those slugs are specified. Previously, the order of slugs provided with the ?slug query parameter had no effect on the order of the returned records. Props wonderboymusic, ocean90, boonebgorges. Fixes #40826. git-svn-id: https://develop.svn.wordpress.org/trunk@41760 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-term-query.php | 7 ++++++- .../class-wp-rest-posts-controller.php | 8 +++++--- .../class-wp-rest-terms-controller.php | 11 +++++++++++ .../class-wp-rest-users-controller.php | 2 ++ .../rest-api/rest-categories-controller.php | 16 ++++++++++++++++ .../tests/rest-api/rest-posts-controller.php | 18 ++++++++++++++++++ .../tests/rest-api/rest-tags-controller.php | 16 ++++++++++++++++ .../tests/rest-api/rest-users-controller.php | 18 ++++++++++++++++++ tests/qunit/fixtures/wp-api-generated.js | 6 ++++++ 9 files changed, 98 insertions(+), 4 deletions(-) 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" ],