Skip to content
This repository was archived by the owner on Sep 24, 2018. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d5eb371
Merge remote-tracking branch 'refs/remotes/WP-API/develop' into Add-t…
BE-Webdesign Feb 13, 2016
652df81
Add-tax-query-#2145
BE-Webdesign Feb 13, 2016
0cd2163
Fix post controller test with comma
BE-Webdesign Feb 13, 2016
80cea68
Reverting yoda conditions
BE-Webdesign Feb 14, 2016
c9bd0f1
Merge remote-tracking branch 'refs/remotes/WP-API/develop' into Add-t…
BE-Webdesign Feb 19, 2016
4bd65f6
Merge remote-tracking branch 'refs/remotes/WP-API/develop' into Add-t…
BE-Webdesign Feb 19, 2016
d82675c
Resolve Conflicts
BE-Webdesign Feb 19, 2016
a48089a
Exposing tax_query in the filter as opposed to a query param.
BE-Webdesign Feb 19, 2016
03a066e
Adding validation back in.
BE-Webdesign Feb 20, 2016
5ff8675
Merge remote-tracking branch 'refs/remotes/WP-API/develop' into Add-t…
BE-Webdesign Mar 16, 2016
e29beb4
Simplifying Validation
BE-Webdesign Mar 16, 2016
8e39e49
Adding Tests.
BE-Webdesign Mar 17, 2016
082e111
Simplify validation more.
BE-Webdesign Mar 17, 2016
f3b37e1
Merge remote-tracking branch 'refs/remotes/WP-API/develop' into Add-t…
BE-Webdesign Mar 18, 2016
aa8f6a2
Merge remote-tracking branch 'refs/remotes/WP-API/develop' into Add-t…
BE-Webdesign Mar 18, 2016
2b00395
Add in WPCS whitelisting tax_queries
BE-Webdesign Mar 18, 2016
226cf9d
Merge remote-tracking branch 'refs/remotes/WP-API/develop' into Add-t…
BE-Webdesign Aug 8, 2016
5ce7a28
Fixing Tests
BE-Webdesign Aug 8, 2016
ab14e3b
Merge remote-tracking branch 'refs/remotes/WP-API/develop' into Add-t…
BE-Webdesign Aug 8, 2016
9289110
Fix tests again.
BE-Webdesign Aug 8, 2016
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
84 changes: 84 additions & 0 deletions lib/endpoints/class-wp-rest-posts-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ protected function get_allowed_query_vars() {
'post_parent__not_in',
'posts_per_page',
'date_query',
'tax_query',
);
$valid_vars = array_merge( $valid_vars, $rest_valid );

Expand Down Expand Up @@ -1749,6 +1750,7 @@ public function get_collection_params() {
);
$params['filter'] = array(
'description' => __( 'Use WP Query arguments to modify the response; private query vars require appropriate authorization.' ),
'validate_callback' => array( $this, 'rest_validate_query_filter' ),
);

$taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
Expand Down Expand Up @@ -1784,4 +1786,86 @@ public function validate_user_can_query_private_statuses( $value, $request, $par
return new WP_Error( 'rest_forbidden_status', __( 'Status is forbidden' ), array( 'status' => rest_authorization_required_code() ) );
}

/**
* Validate filter param.
*
* This function can be used to validate query params passed by the filter request param.
*
* @param mixed $value Value of the parameter.
* @param WP_REST_Request $request Request body.
* @param string $parameter Name of the parameter. Should be tax_query.
* @return WP_Error|boolean
*/
public function rest_validate_query_filter( $values, $request, $parameter ) {
// Returns true for validation by default if $values is empty or if a filter param is not being validated.
$is_valid = true;
if ( ! empty( $values ) ) {
foreach ( $values as $filter_param => $value ) {
switch ( $filter_param ) {
case 'tax_query' :
$is_valid = $this->rest_validate_tax_query( $value, $request, $filter_param );
// If an error is found exit early and it will throw an error for request->has_valid_params();
if ( is_wp_error( $is_valid ) ) {
return $is_valid;
}
continue;
default :
continue;
Copy link
Contributor

@kadamwhite kadamwhite Sep 12, 2016

Choose a reason for hiding this comment

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

Nitpick, but for a single-case switch I'd vote in favor of an if. (unless this is a code standard of which I was not aware)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah it was originally an entire validation of tax_query, but now it handles only one case. If this ever wanted to be expanded though it should go back to switch. I can make a modification to it sometime soon.

}
}
}
return $is_valid;
Copy link
Contributor

Choose a reason for hiding this comment

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

If there are no $values then would't this code throw an error since $is_valid is not declared anywhere? I would just return true here if you want that to be the default value, or declare $is_valid = true before the foreach.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ya I should put an empty check there and have some declaration of $is_valid, most likely this is being tossed anyways for something simpler. This is more of an experiment rather than what is being merged. But thank you for pointing that out because that is a glaring mistake haha 😄

}

/**
* Validate tax query.
*
* @param mixed $value Value of the parameter.
* @param WP_REST_Request $request Request body.
* @param string $parameter Name of the parameter. Should be tax_query.
* @param array $taxonomies Taxonomies that are to be shown in the REST API.
* @return WP_Error|boolean
*/
public function rest_validate_tax_query( $values, $request, $parameter, $taxonomies = array() ) {
if ( 'tax_query' !== $parameter ) {
return new WP_Error( 'rest_invalid_param', __( 'This validation method is only used to validate a tax query.' ), array( 'status' => 400 ) );
}
$valid = true;
if ( ! empty( $values ) ) {
foreach ( $values as $key => $value ) {
if ( empty( $value ) ) {
//return new WP_Error( 'rest_invalid_param', __( 'A tax query parameter in the filter was empty.' ), array( 'status' => 400 ) );
}
// Switch statement to handle different cases.
// Recursive call to function to handle nested taxonomy queries.
if ( is_array( $value ) && 'terms' !== $key ) {
$valid = $this->rest_validate_tax_query( $value, $request, $parameter, $taxonomies );
// If an error is found keep returning it up the chain.
if ( is_wp_error( $valid ) ) {
return $valid;
}
}
if ( ! is_numeric( $key ) ) {
switch ( $key ) {
case 'taxonomy' :
// If $taxonomies is empty by default set it. On reoccurring calls the function overhead is avoided.
if ( empty( $taxonomies ) ) {
$taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
}
// Validate taxonomy.
if ( array_key_exists( $value, $taxonomies ) ) {
$valid = true;
} else {
/* translators: %s equals taxonomy name being checked. */
return new WP_Error( 'rest_invalid_param', sprintf( __( 'The taxonomy %s specified in the filter does not exist.' ), $value ), array( 'status' => 400 ) );
}
continue;
default :
continue;
}
}
}
}
return $valid;
}
}
61 changes: 61 additions & 0 deletions tests/test-rest-posts-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,67 @@ public function test_get_items_valid_date() {
$this->assertEquals( $post2, $data[0]['id'] );
}

public function test_get_items_valid_tax_query_in_filter() {
$term1 = $this->factory->term->create( array( 'taxonomy' => 'category', 'name' => 'basie' ) );
$post1 = $this->factory->post->create();
$post2 = $this->factory->post->create( array( 'post_category' => array( $term1 ) ) );
$post3 = $this->factory->post->create();

$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$request->set_param( 'filter', array(
// @codingStandardsIgnoreStart
'tax_query' => array( // WPCS: tax_query ok.
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => 'basie',
),
),
// @codingStandardsIgnoreEnd
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertCount( 1, $data );
$this->assertEquals( $post2, $data[0]['id'] );
$this->assertEquals( $term1, $data[0]['categories'][0] );
}

public function test_get_items_invalid_tax_query_in_filter() {
$post1 = $this->factory->post->create();

$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$request->set_param( 'filter', array(
// @codingStandardsIgnoreStart
'tax_query' => array( // WPCS: tax_query ok.
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => 'duke',
),
),
// @codingStandardsIgnoreEnd
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertCount( 0, $data );
$this->assertEquals( array(), $data );

$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$request->set_param( 'filter', array(
// @codingStandardsIgnoreStart
'tax_query' => array( // WPCS: tax_query ok.
array(
'taxonomy' => 'mingus',
'field' => 'slug',
'terms' => 'duke',
),
),
// @codingStandardsIgnoreEnd
) );
$response = $this->server->dispatch( $request );
$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
}

public function test_get_item() {
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $this->post_id ) );
$response = $this->server->dispatch( $request );
Expand Down