Filtrarea mai multor câmpuri personalizate cu WP REST API 2

14 mai 2016, 08:57:12
Vizualizări: 16.3K
Voturi: 18

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?

1
Comentarii

Aruncă o privire la acest articol și încearcă să-ți creezi funcția http://wordpress.stackexchange.com/questions/169408/wp-json-rest-api-ryan-mccue-how-to-query-posts-with-specific-meta-data-with-a

emilushi emilushi
25 mai 2016 16:03:00
Toate răspunsurile la întrebare 5
0

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:

https://demo.wp-api.org/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]==

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:

  1. Adăugarea suportului REST pentru tipul personalizat de postare product
  2. Permiterea argumentelor de interogare meta_query
  3. 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 );
26 mai 2016 08:00:23
8

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!

25 mai 2016 18:07:09
Comentarii

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

James Vu James Vu
26 mai 2016 04:22:15

@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ă.

emilushi emilushi
26 mai 2016 09:54:20

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

James Vu James Vu
26 mai 2016 13:33:40

@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.

emilushi emilushi
26 mai 2016 13:45:10

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?

jgraup jgraup
26 mai 2016 15:12:41

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

James Vu James Vu
26 mai 2016 16:19:55

@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.

emilushi emilushi
26 mai 2016 21:33:19

Unele servere AWS permit doar PHP 5.3, ceea ce nu e ideal, dar așa stau lucrurile. Deci este o eroare de sintaxă în PHP 5.3.

jgraup jgraup
26 mai 2016 22:04:52
Arată celelalte 3 comentarii
0
  1. 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
  2. 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]='='

7 apr. 2020 12:51:48
2

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'
        );
    };
25 mai 2016 17:20:09
Comentarii

Mulțumesc pentru răspuns, dar sunt foarte curios să încerc cu REST API v2.

James Vu James Vu
25 mai 2016 17:27:06

Ei bine, cred că varianta mea este bună, dar dacă dorești...Faptul că metoda mea nu este limitată la parametri!

Igor Fedorov Igor Fedorov
25 mai 2016 17:31:35
0

Î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.

12 ian. 2017 07:51:54