Filtrowanie wielu niestandardowych pól za pomocą WP REST API 2

14

Chcę filtrować posty na podstawie wielu niestandardowych pól acf z relacją AND. Coś takiego:

$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',
            ),
        ),
    );

Mogę nawet mieć więcej filtrów. Jak przekonwertować je na filtry REST API 2?

Sohrab Taee
źródło
Spójrz na ten post i spróbuj utworzyć swoją funkcję wordpress.stackexchange.com/questions/169408/…
emilushi

Odpowiedzi:

3

To rozwiązanie sprawdza się get_items()w /lib/endpoints/class-wp-rest-posts-controller.phpz v2 WP Rest API.


Po pierwsze, będziesz chciał skonstruować GETargumenty tak, jak dla new WP_Query(). Najłatwiej to zrobić za pomocą 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 );

Wyprodukuje coś takiego:

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

Które, jeśli chcesz, aby były czytelne, możesz również użyć narzędzi Chrome i decodeURIComponent('your-query-here')ułatwić czytanie, gdy wrzucisz je do adresu URL 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]==

Uwaga: aby użyć niestandardowego typu posta, który umieściłeś productwcześniej?

/wp-json/wp/v2/<custom-post-type>?filter[meta_query]


Więc masz zapytanie, ale musimy pouczyć WP, jak postępować z kilkoma rzeczami:

  1. Dodanie obsługi REST dla niestandardowego typu postu product
  2. Zezwalanie na argumenty zapytania meta_query
  3. Rozbiór gramatyczny zdania 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 );
jgraup
źródło
2

Oto test, który wykonałem na Localhost:

Ze względów bezpieczeństwa meta kwerenda nie jest dozwolona w WP Api, najpierw musisz dodać meta_query do dozwolonego rest_query, dodając tę ​​funkcję do motywu wordpress 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' );

po tym będziesz musiał zbudować zapytanie HTML za pomocą tej funkcji na drugiej stronie internetowej, która pobierze dane ze strony 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);

Zmieniam tablicę pól, aby wyglądały teraz jak argumenty zapytania. Zakodowany ciąg zapytania będzie wyglądał następująco:

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

Korzystając z tego urldecode(), co w tym przypadku będzie: urldecode('http://yourwordpreswebssite.com/wp-json/wp/v2/posts?' . $field_string);będziesz mieć URL taki jak ten:

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

Jeśli możesz podać nam swój adres URL na żywo, abyśmy mogli przetestować go za pomocą listonosza bezpośrednio na Twojej stronie, ponieważ aby go przetestować na localhost lub dowolnej istniejącej stronie WordPress, konieczne będzie utworzenie niestandardowego typu postu produktu i dodanie pól meta itp. Na zdrowie!

emilushi
źródło
Dzięki za odpowiedź, ale przetestowałem zapytanie, tak jak w pytaniu dotyczącym Listonosza, i nie zadziałało.
MinhTri
@ Dan zrobiłem kilka ulepszeń w rozwiązaniu, wartości filtrów są takie same jak argumenty zapytania, w tym niestandardowy typ postu, który nie został określony w poprzednim rozwiązaniu.
emilushi
Nie mamy producttaksonomii. Działa świetnie! Nie myślałem o zawijaniu w meta_queryśrodku filter:)
MinhTri
@ Dan Cieszę się, że to słyszę. Wczoraj napisałem o tym post, możesz rozważyć udostępnienie go :) WordPress REST API z polami meta .
emilushi
1
Kilka rzeczy, na niektórych serwerach AWS, użycie [] jako tablicy zabije żądanie. Powinieneś po prostu użyć array (), aby być bezpiecznym i dla tych, którzy mogą kopiować / wklejać. Czy to również obsługuje produkt CPT, czy tylko systematykę? I na koniec, czy musisz dezynfekować meta_query? Widząc, że został wyciągnięty, czy narażasz się na ryzyko związane z bezpieczeństwem, akceptując coś, co dostarcza użytkownik?
jgraup
1

Możesz to zrobić bez Rest API Tak jak to (to jest filtr moich postów)

    $ paged = (get_query_var ('paged'))? get_query_var ('paged'): 1;
$ args = tablica (
        „paged” => $ paged,
        'orderby' => 'date', // сортировка по дате у нас будет в любом случае (но вы можете изменить / доработать это)
        „zamówienie” => „DESC”,
    );

    // создаём массив $ args ['meta_query'] если указана хотя бы одна цена или отмечен чекбокс
    if (isset ($ _GET ['price_min']) || isset ($ _GET ['price_max']) || isset ($ _GET ['type']))
        $ args ['meta_query'] = array ('relations' => 'AND'); // ORAZ значит все условия meta_query должны выполняться


    if (typ $) {
        $ args ['meta_query'] [] = array (
            „klucz” => „typ”,
            „wartość” => typ $,
        );
    };

    if ($ plan) {
        $ args ['meta_query'] [] = array (
            „klucz” => „plan”,
            „wartość” => $ plan,
        );
    };

    if ($ room_num) {
        $ args ['meta_query'] [] = array (
            „key” => „room_num”,
            „wartość” => $ numer_pokoju,
        );
    };

    if ($ etage) {
        $ args ['meta_query'] [] = array (
            „key” => „etage”,
            „wartość” => $ etage,
        );
    };  

    if ($ price_min || $ price_max) {
        $ args ['meta_query'] [] = array (
            „klucz” => „cena”,
            „wartość” => tablica ($ price_min, $ price_max),
            „typ” => „numeryczny”,
            „porównaj” => „MIĘDZY”
        );
    };  

    if ($ area_min || $ area_max) {
        $ args ['meta_query'] [] = array (
            „klucz” => „obszar”,
            „wartość” => tablica ($ area_min, $ area_max),
            „typ” => „numeryczny”,
            „porównaj” => „MIĘDZY”
        );
    };
Igor Fiodorow
źródło
1
Dziękuję za odpowiedź, ale jestem naprawdę ciekawy, czy mogę to zrobić z REST API v2.
MinhTri
Cóż, myślę, że mój wariant jest dobry, ale jeśli chcesz ... Fakt, że moja metoda nie ogranicza się do parametrów!
Igor Fiodorow
1

W Wordpress 4.7 filterargument został usunięty.

Możesz aktywować to zainstalowanie tej wtyczki dostarczone przez zespół Wordpress. Dopiero potem możesz skorzystać z jednego z rozwiązań zaproponowanych w pozostałych odpowiedziach.

Nie znalazłem rozwiązania, aby zrobić to samo bez instalacji wtyczki.

Michele Fortunato
źródło