Filtrarea mai multor câmpuri personalizate cu WP REST API 2
Vreau să filtrez postările pe baza mai multor câmpuri personalizate ACF cu relație AND. Ceva de genul acesta:
$args = array(
'post_type' => 'product', // Tipul postării
'meta_query' => array(
'relation' => 'AND', // Relația între filtre
array(
'key' => 'color', // Câmpul personalizat
'value' => 'blue', // Valoarea căutată
'compare' => '=', // Operatorul de comparare
),
array(
'key' => 'price', // Câmpul personalizat
'value' => array( 20, 100 ), // Intervalul de valori
'type' => 'numeric', // Tipul valorilor
'compare' => 'BETWEEN', // Operatorul de comparare
),
),
);
Este posibil să am chiar mai multe filtre. Cum pot converti acestea în filtre pentru REST API 2?

Această soluție funcționează cu get_items()
din /lib/endpoints/class-wp-rest-posts-controller.php
al WP Rest API v2
.
Mai întâi, va trebui să construiești argumentele GET
așa cum ai face pentru un new WP_Query()
. Cea mai simplă metodă este folosind 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 );
Va produce ceva de genul:
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
Dacă dorești să fie lizibil, poți folosi instrumentele Chrome și decodeURIComponent('interogarea-ta-aici')
pentru a-l face mai ușor de citit când îl introduci în URL-ul JSON Rest API:
Notă: Pentru a folosi tipul tău personalizat de postare, va trebui să pui product
înainte de ?
/wp-json/wp/v2/<tipul-personalizat-de-postare>?filter[meta_query]
Deci acum ai interogarea ta, dar trebuie să instruim WP cum să gestioneze câteva aspecte:
- Adăugarea suportului REST pentru tipul personalizat de postare
product
- Permiterea argumentelor de interogare
meta_query
- Parsarea
meta_query
// 1) Adaugă suport REST pentru CPT <product>
function wpse_20160526_add_product_rest_support() {
global $wp_post_types;
//asigură-te că setezi acest lucru la numele tipului tău de postare!
$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) Adaugă suport pentru `meta_query` în cererea GET
function wpse_20160526_rest_query_vars( $valid_vars ) {
$valid_vars = array_merge( $valid_vars, array( 'meta_query' ) ); // Omitere meta_key, meta_value dacă nu ai nevoie de ele
return $valid_vars;
}
add_filter( 'rest_query_vars', 'wpse_20160526_rest_query_vars', PHP_INT_MAX, 1 );
// 3) Parsează argumentele personalizate
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;
}
// înlocuiește cu argumentele de interogare sanitizate
$args['meta_query'] = $meta_query;
}
return $args;
}
add_action( 'rest_product_query', 'wpse_20160526_rest_product_query', 10, 2 );

Iată un test pe care l-am făcut pe Localhost:
Din motive de securitate, meta query nu este permis în WP API. Primul lucru pe care trebuie să-l faci este să adaugi meta_query la rest_query permis, adăugând această funcție în fișierul functions.php
al temei tale WordPress:
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' );
După aceea, va trebui să construiești interogarea HTML folosind această funcție pe celălalt website care va prelua datele de la website-ul WordPress:
$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.com/wp-json/wp/v2/posts?' . $field_string
)
);
$result = curl_exec($curl);
echo htmlentities($result);
Am modificat array-ul fields astfel încât să semene cu argumentele tale de interogare. Șirul de interogare codat va arăta astfel:
http://yourwordpreswebssite.com/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
Folosind urldecode()
, care în acest caz va fi: urldecode('http://yourwordpreswebssite.com/wp-json/wp/v2/posts?' . $field_string);
, vei obține un URL ca acesta:
http://yourwordpreswebssite.com/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
Dacă ne poți furniza URL-ul live al website-ului tău, putem testa folosind Postman direct pe website-ul tău, deoarece pentru a testa pe localhost sau pe orice alt website WordPress existent, va fi necesar să creăm un custom post type pentru produse și să adăugăm meta câmpuri etc. Salutări!

Mulțumesc pentru răspuns, dar am testat interogarea așa cum este în întrebare pe Postman și nu a funcționat.

@Dan Am făcut câteva îmbunătățiri la soluție, valorile filtrului sunt aceleași cu argumentele interogării tale, inclusiv tipul de postare personalizată care nu era specificat în soluția anterioară.

Nu avem taxonomia product
. Funcționează perfect! Nu m-am gândit să încadrez meta_query
în interiorul filter
:)

@Dan Mă bucur să aud asta. Am scris un articol despre asta ieri, poate doriți să-l partajați :) WordPress REST API cu câmpuri meta.

Câteva observații: pe unele servere AWS, folosirea [] pentru array poate bloca cererea. Ar fi mai sigur să folosiți array() și pentru cei care ar putea copia/lipește codul. De asemenea, această soluție funcționează pentru CPT product sau doar pentru taxonomy? În cele din urmă, este necesară sanitizarea meta_query? Având în vedere că a fost extras din input, există un risc de securitate prin acceptarea oricărui input furnizat de utilizator?

@Eduart Știu cum să fac să funcționeze pentru mine pe baza ideii tale, dar ar trebui să editezi și răspunsul.

@jgraup mulțumesc mult pentru comentariul tău. Nu știam acest lucru despre serverele AWS. Tipurile de postare personalizate și taxonomia personalizată ar trebui să fie înregistrate cu REST API înainte și cu siguranță ar trebui folosită validare la intrare și escapare la ieșire. Motivul pentru care nu am folosit sanitizare este pentru că am testat-o doar la ieșire pentru câmpurile personalizate pe care le-am validat anterior la intrare. Dar ai dreptate, ar trebui îmbunătățit pentru alți utilizatori care doar vor copia și lipi codul.

- mai întâi adaugă plugin-ul sau copiază tot codul și lipește întregul plugin în functions.php de la acest link https://github.com/WP-API/rest-filter
- folosește acest cod:
?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]='='

Poți face asta fără Rest API Astfel (Este filtrul meu de articole)
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array(
'paged' => $paged,
'orderby' => 'date', // sortarea după dată va fi întotdeauna (dar poți modifica/îmbunătăți asta)
'order' => 'DESC',
);
// creăm array-ul $args['meta_query'] dacă este specificată cel puțin o preț sau este bifată o casetă
if( isset( $_GET['price_min'] ) || isset( $_GET['price_max'] ) || isset( $_GET['type'] ) )
$args['meta_query'] = array( 'relation'=>'AND' ); // AND înseamnă că toate condițiile meta_query trebuie să fie îndeplinite
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'
);
};

În WordPress 4.7 argumentul filter
a fost eliminat.
Puteți să-l reactivați instalând acest plugin oferit de echipa WordPress. Numai după aceea puteți folosi una dintre soluțiile propuse în celelalte răspunsuri.
Încă nu am găsit o soluție pentru a face același lucru fără a instala pluginul.
