Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new query args to Pattern Directory Controller #3861

Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public function get_items_permissions_check( $request ) {
*
* @since 5.8.0
* @since 6.0.0 Added 'slug' to request.
* @since 6.2.0 Added 'per_page', 'page', 'offset', 'order', and 'orderby' to request.
*
* @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.
Expand All @@ -93,31 +94,19 @@ public function get_items( $request ) {
*/
require ABSPATH . WPINC . '/version.php';

$query_args = array(
'locale' => get_user_locale(),
'wp-version' => $wp_version,
$valid_query_args = array( 'offset', 'order', 'orderby', 'page', 'per_page', 'search', 'slug' );
$query_args = array_merge(
array_intersect_key( $request->get_params(), array_flip( $valid_query_args ) ),
array(
'locale' => get_user_locale(),
'wp-version' => $wp_version, // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- it's defined in `version.php` above.
)
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code can be simplified and made more performant:

Suggested change
$valid_query_args = array( 'offset', 'order', 'orderby', 'page', 'per_page', 'search', 'slug' );
$query_args = array_merge(
array_intersect_key( $request->get_params(), array_flip( $valid_query_args ) ),
array(
'locale' => get_user_locale(),
'wp-version' => $wp_version, // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- it's defined in `version.php` above.
)
);
$valid_query_args = array(
'offset' => true,
'order' => true,
'orderby' => true,
'page' => true,
'per_page' => true,
'search' => true,
'slug' => true,
);
$query_args = array_intersect_key( $request->get_params(), $valid_query_args );
$query_args['locale'] = get_user_locale();
$query_args['wp-version'] = $wp_version;

The array_flip() creates an array with the values of $valid_query_args as the keys. Since this is used only for filtering the args, why not set up the $valid_query_args into a keyed structure? In doing so, the array_flip() is eliminated.

The array_merge() also creates another array. As 'locale' and 'wp-version' keys will not be in the array after doing the array_intersect_key(), a more performant way is to directly adding them to $query_args rather than array_merge().

The changes remove 2 unnecessary array iterations and creations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1cede3c.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See it in action https://3v4l.org/DGvja

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hellofromtonya !


$category_id = $request['category'];
$keyword_id = $request['keyword'];
$search_term = $request['search'];
$slug = $request['slug'];
$query_args['pattern-categories'] = isset( $request['category'] ) ? $request['category'] : false;
$query_args['pattern-keywords'] = isset( $request['keyword'] ) ? $request['keyword'] : false;

if ( $category_id ) {
$query_args['pattern-categories'] = $category_id;
}

if ( $keyword_id ) {
$query_args['pattern-keywords'] = $keyword_id;
}

if ( $search_term ) {
$query_args['search'] = $search_term;
}

if ( $slug ) {
$query_args['slug'] = $slug;
}
$query_args = array_filter( $query_args );

$transient_key = $this->get_transient_key( $query_args );

Expand Down Expand Up @@ -303,16 +292,14 @@ public function get_item_schema() {
* Retrieves the search parameters for the block pattern's collection.
*
* @since 5.8.0
* @since 6.2.0 Added 'per_page', 'page', 'offset', 'order', and 'orderby' to request.
*
* @return array Collection parameters.
*/
public function get_collection_params() {
$query_params = parent::get_collection_params();

// Pagination is not supported.
unset( $query_params['page'] );
unset( $query_params['per_page'] );

$query_params['per_page']['default'] = 100;
$query_params['search']['minLength'] = 1;
$query_params['context']['default'] = 'view';

Expand All @@ -333,6 +320,37 @@ public function get_collection_params() {
'type' => 'array',
);

$query_params['offset'] = array(
'description' => __( 'Offset the result set by a specific number of items.', 'gutenberg' ),
'type' => 'integer',
);

$query_params['order'] = array(
'description' => __( 'Order sort attribute ascending or descending.', 'gutenberg' ),
'type' => 'string',
'default' => 'desc',
'enum' => array( 'asc', 'desc' ),
);

$query_params['orderby'] = array(
'description' => __( 'Sort collection by post attribute.', 'gutenberg' ),
'type' => 'string',
'default' => 'date',
'enum' => array(
'author',
'date',
'id',
'include',
'modified',
'parent',
'relevance',
'slug',
'include_slugs',
'title',
'favorite_count',
),
);

/**
* Filter collection parameters for the block pattern directory controller.
*
Expand Down
132 changes: 132 additions & 0 deletions tests/phpunit/tests/rest-api/rest-pattern-directory-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ class WP_REST_Pattern_Directory_Controller_Test extends WP_Test_REST_Controller_
*/
private static $controller;

/**
* List of URLs captured.
*
* @since 6.2.0
*
* @var string[]
*/
protected static $http_request_urls;

/**
* Set up class test fixtures.
*
Expand All @@ -44,9 +53,30 @@ public static function wpSetUpBeforeClass( $factory ) {
)
);

self::$http_request_urls = array();

static::$controller = new WP_REST_Pattern_Directory_Controller();
}

/**
* Tear down after class.
*
* @since 6.2.0
*/
public static function wpTearDownAfterClass() {
self::delete_user( self::$contributor_id );
}

/**
* Clear the captured request URLs after each test.
*
* @since 6.2.0
*/
public function tear_down() {
self::$http_request_urls = array();
parent::tear_down();
}

/**
* Asserts that the pattern matches the expected response schema.
*
Expand Down Expand Up @@ -310,6 +340,108 @@ static function( $response ) {
$this->assertSame( 'modified the cache', $patterns[0] );
}

/**
* Tests if the provided query args are passed through to the wp.org API.
*
* @dataProvider data_get_items_query_args
*
* @covers WP_REST_Pattern_Directory_Controller::get_items
*
* @since 6.2.0
hellofromtonya marked this conversation as resolved.
Show resolved Hide resolved
*
* @param string $param Query parameter name (ex, page).
* @param mixed $value Query value to test.
* @param bool $is_error Whether this value should error or not.
* @param mixed $expected Expected value (or expected error code).
*/
public function test_get_items_query_args( $param, $value, $is_error, $expected ) {
wp_set_current_user( self::$contributor_id );
self::capture_http_urls();

$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
if ( $value ) {
$request->set_query_params( array( $param => $value ) );
}

$response = rest_do_request( $request );
$data = $response->get_data();
if ( $is_error ) {
$this->assertSame( $expected, $data['code'] );
$this->assertStringContainsString( $param, $data['message'] );
} else {
$this->assertCount( 1, self::$http_request_urls );
$this->assertStringContainsString( $param . '=' . $expected, self::$http_request_urls[0] );
}
}

/**
* Data provider for test_get_items_query_args.
*
* @since 6.2.0
*/
public function data_get_items_query_args() {
return array(
'per_page default' => array( 'per_page', false, false, 100 ),
'per_page custom-1' => array( 'per_page', 5, false, 5 ),
'per_page custom-2' => array( 'per_page', 50, false, 50 ),
'per_page invalid-1' => array( 'per_page', 200, true, 'rest_invalid_param' ),
'per_page invalid-2' => array( 'per_page', 'abc', true, 'rest_invalid_param' ),

'page default' => array( 'page', false, false, 1 ),
'page custom' => array( 'page', 5, false, 5 ),
'page invalid' => array( 'page', 'abc', true, 'rest_invalid_param' ),

'offset custom' => array( 'offset', 5, false, 5 ),
'offset invalid-1' => array( 'offset', 'abc', true, 'rest_invalid_param' ),

'order default' => array( 'order', false, false, 'desc' ),
'order custom' => array( 'order', 'asc', false, 'asc' ),
'order invalid-1' => array( 'order', 10, true, 'rest_invalid_param' ),
'order invalid-2' => array( 'order', 'fake', true, 'rest_invalid_param' ),

'orderby default' => array( 'orderby', false, false, 'date' ),
'orderby custom-1' => array( 'orderby', 'title', false, 'title' ),
'orderby custom-2' => array( 'orderby', 'date', false, 'date' ),
'orderby custom-3' => array( 'orderby', 'favorite_count', false, 'favorite_count' ),
'orderby invalid-1' => array( 'orderby', 10, true, 'rest_invalid_param' ),
'orderby invalid-2' => array( 'orderby', 'fake', true, 'rest_invalid_param' ),
);
}

/**
* Attach a filter to capture requested wp.org URL.
*
* @since 6.2.0
*/
private static function capture_http_urls() {
add_filter(
'pre_http_request',
function ( $preempt, $args, $url ) {
if ( 'api.wordpress.org' !== wp_parse_url( $url, PHP_URL_HOST ) ) {
return $preempt;
}

self::$http_request_urls[] = $url;

// Return a response to prevent external API request.
$response = array(
'headers' => array(),
'response' => array(
'code' => 200,
'message' => 'OK',
),
'body' => '[]',
'cookies' => array(),
'filename' => null,
);

return $response;
},
10,
3
);
}

/**
* @doesNotPerformAssertions
*/
Expand Down
49 changes: 49 additions & 0 deletions tests/qunit/fixtures/wp-api-generated.js
Original file line number Diff line number Diff line change
Expand Up @@ -10475,6 +10475,21 @@ mockedApiResponse.Schema = {
"default": "view",
"required": false
},
"page": {
"description": "Current page of the collection.",
"type": "integer",
"default": 1,
"minimum": 1,
"required": false
},
"per_page": {
"description": "Maximum number of items to be returned in result set.",
"type": "integer",
"default": 100,
"minimum": 1,
"maximum": 100,
"required": false
},
"search": {
"description": "Limit results to those matching a string.",
"type": "string",
Expand All @@ -10497,6 +10512,40 @@ mockedApiResponse.Schema = {
"description": "Limit results to those matching a pattern (slug).",
"type": "array",
"required": false
},
"offset": {
"description": "Offset the result set by a specific number of items.",
"type": "integer",
"required": false
},
"order": {
"description": "Order sort attribute ascending or descending.",
"type": "string",
"default": "desc",
"enum": [
"asc",
"desc"
],
"required": false
},
"orderby": {
"description": "Sort collection by post attribute.",
"type": "string",
"default": "date",
"enum": [
"author",
"date",
"id",
"include",
"modified",
"parent",
"relevance",
"slug",
"include_slugs",
"title",
"favorite_count"
],
"required": false
}
}
}
Expand Down