Memfilter beberapa bidang khusus dengan WP REST API 2

14

Saya ingin memfilter posting berdasarkan beberapa bidang khusus acf dengan hubungan AND. Sesuatu seperti ini:

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

Saya bahkan mungkin memiliki lebih banyak filter. Bagaimana saya bisa mengonversikan ini ke filter REST API 2?

Sohrab Taee
sumber
Lihatlah posting ini dan cobalah untuk membuat fungsi Anda wordpress.stackexchange.com/questions/169408/…
emilushi

Jawaban:

3

Solusi ini berfungsi dengan get_items()di /lib/endpoints/class-wp-rest-posts-controller.phpdalam v2 WP Rest API.


Pertama, Anda ingin membuat GETargumen seperti yang Anda inginkan untuk a new WP_Query(). Cara termudah untuk melakukannya adalah dengan 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 );

Ini akan menghasilkan sesuatu seperti:

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

Yang, jika Anda ingin dibaca, Anda juga dapat menggunakan alat Chrome dan decodeURIComponent('your-query-here')membuatnya lebih mudah dibaca ketika Anda memasukkannya ke URL JSON Rest API Anda :

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]==

Catatan: Untuk menggunakan jenis posting kustom Anda, Anda akan meletakkan productsebelumnya?

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


Jadi, Anda memiliki permintaan Anda, tetapi kami perlu memberi tahu WP cara menangani beberapa hal:

  1. Menambahkan dukungan REST untuk jenis posting khusus product
  2. Mengizinkan argumen permintaan meta_query
  3. 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 );
jgraup
sumber
2

Ini adalah tes yang saya buat di Localhost:

Untuk alasan keamanan, permintaan meta tidak diizinkan di WP Api, pertama-tama yang harus Anda lakukan adalah menambahkan meta_query ke diizinkan rest_query dengan menambahkan fungsi ini pada tema wordpress Anda 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' );

setelah itu Anda perlu membangun kueri html dengan menggunakan fungsi ini di situs web lain yang akan mendapatkan data dari situs 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);

Saya mengubah array bidang sehingga tampilannya sekarang seperti argumen kueri Anda. String kueri yang disandikan akan terlihat seperti ini:

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

Dengan menggunakan urldecode(), yang dalam hal ini adalah: urldecode('http://yourwordpreswebssite.com/wp-json/wp/v2/posts?' . $field_string);Anda akan memiliki URL seperti ini:

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

Jika Anda dapat memberikan kami URL situs web langsung Anda sehingga kami dapat mengujinya menggunakan tukang pos langsung di situs web Anda, karena untuk mengujinya di localhost atau situs WordPress yang ada akan diperlukan untuk membuat jenis posting khusus produk dan menambahkan bidang meta dll. Dll. Cheers!

emilushi
sumber
Terima kasih atas jawaban Anda, tetapi saya telah menguji dengan kueri seperti pada pertanyaan pada Postman dan tidak berhasil.
MinhTri
@Dan saya membuat beberapa perbaikan pada solusi, nilai filternya sama dengan argumen kueri Anda, termasuk tipe posting kustom yang tidak ditentukan dalam solusi sebelumnya.
emilushi
Kami tidak memiliki producttaksonomi. Ini sangat bagus! Tidak berpikir tentang membungkus meta_querydi dalam filter:)
MinhTri
@Dan saya senang mendengarnya. Saya telah menulis posting tentang itu kemarin, Anda dapat mempertimbangkan untuk berbagi :) WordPress REST API dengan bidang meta .
emilushi
1
Beberapa hal, pada beberapa server AWS, menggunakan [] sebagai larik akan mematikan permintaan. Anda harus menggunakan array () agar aman dan bagi mereka yang mungkin menyalin / menempel. Juga, apakah ini mendukung produk CPT atau hanya taksonomi? Dan terakhir, apakah Anda perlu membersihkan meta_query? Melihat itu ditarik, apakah Anda menjalankan risiko keamanan dengan menerima sesuatu yang disediakan pengguna?
jgraup
1

Anda dapat melakukannya tanpa Rest API Seperti ini (Ini adalah filter posting saya)

    $ 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'); // DAN значит все условия 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',
            'bandingkan' => 'ANTARA'
        );
    };  

    if ($ area_min || $ area_max) {
        $ args ['meta_query'] [] = array (
            'key' => 'area',
            'value' => array ($ area_min, $ area_max),
            'type' => 'numeric',
            'bandingkan' => 'ANTARA'
        );
    };
Igor Fedorov
sumber
1
Terima kasih atas jawaban Anda, tetapi saya sangat ingin melakukannya dengan REST API v2.
MinhTri
Yah, saya pikir, varian saya bagus, tetapi jika Anda mau ... Fakta bahwa metode saya tidak terbatas pada parameter!
Igor Fedorov
1

Di Wordpress 4.7 filterargumen telah dihapus.

Anda dapat mengaktifkannya lagi menginstal plugin ini yang disediakan oleh tim Wordpress. Hanya setelah itu Anda dapat menggunakan salah satu solusi yang diusulkan dalam jawaban lain.

Saya belum menemukan solusi untuk melakukan hal yang sama tanpa menginstal plugin.

Michele Fortunato
sumber