I want to filter posts based on multiple acf custom fields with AND relation. Something like this:
$args = array(
'post_type' => 'product',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'color',
'value' => 'blue',
'compare' => '=',
),
array(
'key' => 'price',
'value' => array( 20, 100 ),
'type' => 'numeric',
'compare' => 'BETWEEN',
),
),
);
I might even have more filters. How can I convert these to REST API 2 filters?
I want to filter posts based on multiple acf custom fields with AND relation. Something like this:
$args = array(
'post_type' => 'product',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'color',
'value' => 'blue',
'compare' => '=',
),
array(
'key' => 'price',
'value' => array( 20, 100 ),
'type' => 'numeric',
'compare' => 'BETWEEN',
),
),
);
I might even have more filters. How can I convert these to REST API 2 filters?
Share Improve this question asked May 14, 2016 at 5:57 Sohrab TaeeSohrab Taee 2811 gold badge2 silver badges6 bronze badges 1- Take a look at this post and try to create your function wordpress.stackexchange/questions/169408/… – emilushi Commented May 25, 2016 at 13:03
5 Answers
Reset to default 6This solution works with get_items()
in /lib/endpoints/class-wp-rest-posts-controller.php
of the v2 WP Rest API
.
First, you'll want to construct the GET
arguments like you would for a new WP_Query()
. The easiest way to do this is with http_build_query()
.
$args = array (
'filter' => array (
'meta_query' => array (
'relation' => 'AND',
array (
'key' => 'color',
'value' => 'blue',
'compare' => '=',
),
array (
'key' => 'test',
'value' => 'testing',
'compare' => '=',
),
),
),
);
$field_string = http_build_query( $args );
It'll produce something like:
filter%5Bmeta_query%5D%5Brelation%5D=AND&filter%5Bmeta_query%5D%5B0%5D%5Bkey%5D=color&filter%5Bmeta_query%5D%5B0%5D%5Bvalue%5D=blue&filter%5Bmeta_query%5D%5B0%5D%5Bcompare%5D=%3D&filter%5Bmeta_query%5D%5B1%5D%5Bkey%5D=test&filter%5Bmeta_query%5D%5B1%5D%5Bvalue%5D=testing&filter%5Bmeta_query%5D%5B1%5D%5Bcompare%5D=%3D
Which, if you want readable, you can also use Chrome tools and decodeURIComponent('your-query-here')
to make it a easier to read when you throw it into your JSON Rest API URL:
https://demo.wp-api/wp-json/wp/v2/product?filter[meta_query][relation]=AND&filter[meta_query][0][key]=color&filter[meta_query][0][value]=blue&filter[meta_query][0][compare]==&filter[meta_query][1][key]=test&filter[meta_query][1][value]=testing&filter[meta_query][1][compare]==
Note: To use your custom post type you would put product
before ?
/wp-json/wp/v2/<custom-post-type>?filter[meta_query]
So you have your query but we need to instruct WP how to handle a few things:
- Adding REST support for the custom post type
product
- Allowing the query args
meta_query
- Parsing
meta_query
// 1) Add CPT Support <product>
function wpse_20160526_add_product_rest_support() {
global $wp_post_types;
//be sure to set this to the name of your post type!
$post_type_name = 'product';
if( isset( $wp_post_types[ $post_type_name ] ) ) {
$wp_post_types[$post_type_name]->show_in_rest = true;
$wp_post_types[$post_type_name]->rest_base = $post_type_name;
$wp_post_types[$post_type_name]->rest_controller_class = 'WP_REST_Posts_Controller';
}
}
add_action( 'init', 'wpse_20160526_add_product_rest_support', 25 );
// 2) Add `meta_query` support in the GET request
function wpse_20160526_rest_query_vars( $valid_vars ) {
$valid_vars = array_merge( $valid_vars, array( 'meta_query' ) ); // Omit meta_key, meta_value if you don't need them
return $valid_vars;
}
add_filter( 'rest_query_vars', 'wpse_20160526_rest_query_vars', PHP_INT_MAX, 1 );
// 3) Parse Custom Args
function wpse_20160526_rest_product_query( $args, $request ) {
if ( isset( $args[ 'meta_query' ] ) ) {
$relation = 'AND';
if( isset($args['meta_query']['relation']) && in_array($args['meta_query']['relation'], array('AND', 'OR'))) {
$relation = sanitize_text_field( $args['meta_query']['relation'] );
}
$meta_query = array(
'relation' => $relation
);
foreach ( $args['meta_query'] as $inx => $query_req ) {
/*
Array (
[key] => test
[value] => testing
[compare] => =
)
*/
$query = array();
if( is_numeric($inx)) {
if( isset($query_req['key'])) {
$query['key'] = sanitize_text_field($query_req['key']);
}
if( isset($query_req['value'])) {
$query['value'] = sanitize_text_field($query_req['value']);
}
if( isset($query_req['type'])) {
$query['type'] = sanitize_text_field($query_req['type']);
}
if( isset($query_req['compare']) && in_array($query_req['compare'], array('=', '!=', '>','>=','<','<=','LIKE','NOT LIKE','IN','NOT IN','BETWEEN','NOT BETWEEN', 'NOT EXISTS')) ) {
$query['compare'] = sanitize_text_field($query_req['compare']);
}
}
if( ! empty($query) ) $meta_query[] = $query;
}
// replace with sanitized query args
$args['meta_query'] = $meta_query;
}
return $args;
}
add_action( 'rest_product_query', 'wpse_20160526_rest_product_query', 10, 2 );
Here is a test i made on Localhost:
For security reasons meta query is not allowed on WP Api, first what you have to do is to add meta_query to allowed rest_query by adding this function on your wordpress theme functions.php
function api_allow_meta_query( $valid_vars ) {
$valid_vars = array_merge( $valid_vars, array( 'meta_query') );
return $valid_vars;
}
add_filter( 'rest_query_vars', 'api_allow_meta_query' );
after that you will need build the html query by using this function on the other website that will get the data from the wordpress website
$curl = curl_init();
$fields = array (
'filter[meta_query]' => array (
'relation' => 'AND',
array (
'key' => 'color',
'value' => 'blue',
'compare' => '='
),
array (
'key' => 'price',
'value' => array ( 20, 100 ),
'type' => 'numeric',
'compare' => 'BETWEEN'
),
),
);
$field_string = http_build_query($fields);
curl_setopt_array($curl, array (
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => 'http://yourwordpreswebssite/wp-json/wp/v2/posts?' . $field_string
)
);
$result = curl_exec($curl);
echo htmlentities($result);
I change the fields array so the look now like your query arguments. The encoded query string will look like this:
http://yourwordpreswebssite/wp-json/wp/v2/posts?filter%5Btaxonomy%5D=product&filter%5Bmeta_query%5D%5Brelation%5D=AND&filter%5Bmeta_query%5D%5B0%5D%5Bkey%5D=color&filter%5Bmeta_query%5D%5B0%5D%5Bvalue%5D=blue&filter%5Bmeta_query%5D%5B0%5D%5Bcompare%5D=%3D&filter%5Bmeta_query%5D%5B1%5D%5Bkey%5D=price&filter%5Bmeta_query%5D%5B1%5D%5Bvalue%5D%5B0%5D=20&filter%5Bmeta_query%5D%5B1%5D%5Bvalue%5D%5B1%5D=100&filter%5Bmeta_query%5D%5B1%5D%5Btype%5D=numeric&filter%5Bmeta_query%5D%5B1%5D%5Bcompare%5D=BETWEEN
By using urldecode()
, which in this case will be: urldecode('http://yourwordpreswebssite/wp-json/wp/v2/posts?' . $field_string);
you will have an URL like this one:
http://yourwordpreswebssite/wp-json/wp/v2/posts?filter[taxonomy]=product&filter[meta_query][relation]=AND&filter[meta_query][0][key]=color&filter[meta_query][0][value]=blue&filter[meta_query][0][compare]==&filter[meta_query][1][key]=price&filter[meta_query][1][value][0]=20&filter[meta_query][1][value][1]=100&filter[meta_query][1][type]=numeric&filter[meta_query][1][compare]=BETWEEN
If you can provide us your live website URL so we can test it using postman directly on your website, because to test it on localhost or any existing WordPress site will be needed to create product custom post type and add meta fields etc etc. Cheers!
- first add plugin or copy all code and paste all plugin in functions.php of this link https://github/WP-API/rest-filter
- use this
?filter[meta_query][relation]=AND
&filter[meta_query][0][key]=REAL_HOMES_property_price
&filter[meta_query][0][value][0]=10
&filter[meta_query][0][value][1]=10000001
&filter[meta_query][0][compare]=''
&filter[meta_query][1][key]=REAL_HOMES_property_price
&filter[meta_query][1][value]=10
&filter[meta_query][1][compare]='='
You can do it without Rest API Like this (It is my posts filter)
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1; $args = array( 'paged' => $paged, 'orderby' => 'date', // сортировка по дате у нас будет в любом случае (но вы можете изменить/доработать это) 'order' => 'DESC', ); // создаём массив $args['meta_query'] если указана хотя бы одна цена или отмечен чекбокс if( isset( $_GET['price_min'] ) || isset( $_GET['price_max'] ) || isset( $_GET['type'] ) ) $args['meta_query'] = array( 'relation'=>'AND' ); // AND значит все условия meta_query должны выполняться if( $type ){ $args['meta_query'][] = array( 'key' => 'type', 'value' => $type, ); }; if( $plan ){ $args['meta_query'][] = array( 'key' => 'plan', 'value' => $plan, ); }; if( $room_num ){ $args['meta_query'][] = array( 'key' => 'room_num', 'value' => $room_num, ); }; if( $etage ){ $args['meta_query'][] = array( 'key' => 'etage', 'value' => $etage, ); }; if( $price_min || $price_max ){ $args['meta_query'][] = array( 'key' => 'price', 'value' => array( $price_min, $price_max ), 'type' => 'numeric', 'compare' => 'BETWEEN' ); }; if( $area_min || $area_max ){ $args['meta_query'][] = array( 'key' => 'area', 'value' => array( $area_min, $area_max ), 'type' => 'numeric', 'compare' => 'BETWEEN' ); };
In Wordpress 4.7 the filter
argument has been removed.
You can reactivate it installing this plugin provided by the Wordpress team. Only after that you can use one of the solutions proposed in the other answers.
I've haven't found a solution to do the same without installing the plugin, yet.