Filtern mehrerer benutzerdefinierter Felder mit WP REST API 2

14

Ich möchte Posts basierend auf mehreren benutzerdefinierten ACF-Feldern mit UND-Verknüpfung filtern. Etwas wie das:

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

Ich könnte sogar mehr Filter haben. Wie kann ich diese in REST API 2-Filter konvertieren?

Sohrab Taee
quelle
Schauen Sie sich diesen Beitrag an und versuchen Sie, Ihre Funktion wordpress.stackexchange.com/questions/169408/…
emilushi

Antworten:

3

Diese Lösung funktioniert mit get_items()in /lib/endpoints/class-wp-rest-posts-controller.phpder v2 WP Rest API.


Zunächst möchten Sie die GETArgumente so konstruieren , wie Sie es für a tun würden new WP_Query(). Am einfachsten geht das mit 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 );

Es wird so etwas produzieren wie:

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

Wenn Sie lesbar sein möchten, können Sie auch Chrome-Tools verwenden und decodeURIComponent('your-query-here')das Lesen vereinfachen, wenn Sie es in Ihre JSON Rest API-URL einfügen :

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

Hinweis: Um Ihren benutzerdefinierten Beitragstyp zu verwenden, den Sie productzuvor eingegeben haben?

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


Sie haben also Ihre Frage, aber wir müssen WP anweisen, wie ein paar Dinge zu erledigen sind:

  1. Hinzufügen von REST-Unterstützung für den benutzerdefinierten Beitragstyp product
  2. Zulassen der Abfrageargs 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
quelle
2

Hier ist ein Test, den ich auf Localhost gemacht habe:

Aus Sicherheitsgründen ist eine Meta-Abfrage in WP Api nicht zulässig. Zuerst müssen Sie meta_query zu allowed rest_query hinzufügen, indem Sie diese Funktion in Ihrem WordPress-Design hinzufügen 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' );

Danach müssen Sie die HTML-Abfrage mithilfe dieser Funktion auf der anderen Website erstellen, die die Daten von der WordPress-Website abruft

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

Ich ändere das Feldarray so, dass es jetzt wie Ihre Abfrageargumente aussieht. Die codierte Abfragezeichenfolge sieht folgendermaßen aus:

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

Mit urldecode(), was in diesem Fall ist: haben urldecode('http://yourwordpreswebssite.com/wp-json/wp/v2/posts?' . $field_string);Sie eine URL wie diese:

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

Wenn Sie uns Ihre Live-Website-URL zur Verfügung stellen können, damit wir sie mit postman direkt auf Ihrer Website testen können, da Sie zum Testen auf localhost oder einer vorhandenen WordPress-Site einen benutzerdefinierten Produktposttyp erstellen und Metafelder usw. usw. hinzufügen müssen.

emilushi
quelle
Vielen Dank für Ihre Antwort, aber ich habe mit der Abfrage wie in der Frage auf Postman getestet und es hat nicht funktioniert.
MinhTri
@Dann habe ich einige Verbesserungen an der Lösung vorgenommen. Die Filterwerte stimmen mit Ihren Abfrageargumenten überein, einschließlich des benutzerdefinierten Beitragstyps, der in der vorherigen Lösung nicht angegeben wurde.
Emilushi
Wir haben keine productTaxonomie. Es funktioniert super Ich habe nicht daran gedacht, nach meta_queryinnen zu wickeln filter:)
MinhTri
@Dan Ich bin froh, das zu hören. Ich habe gestern einen Post darüber geschrieben, Sie können ihn vielleicht teilen :) WordPress REST API mit Metafeldern .
Emilushi
1
Bei einigen AWS-Servern führt die Verwendung von [] als Array zum Abbruch der Anforderung. Sie sollten einfach array () verwenden, um sicher zu gehen und um festzustellen, wie Sie kopieren / einfügen können. Unterstützt dies auch das CPT-Produkt oder nur die Taxonomie? Und schließlich müssen Sie meta_query bereinigen? Gehen Sie ein Sicherheitsrisiko ein, indem Sie alles akzeptieren, was ein Benutzer zur Verfügung stellt?
JGRAUP
1

Du kannst es auch ohne Rest API machen.

    $ 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'); // UND значит все условия 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'
        );
    };
Igor Fedorov
quelle
1
Vielen Dank für Ihre Antwort, aber ich bin sehr gespannt darauf, dies mit REST API v2 zu tun.
MinhTri
Nun, ich denke, meine Variante ist gut, aber wenn Sie wollen ... Die Tatsache, dass meine Methode nicht auf die Parameter beschränkt ist!
Igor Fedorov
1

In Wordpress 4.7 wurde das filterArgument entfernt.

Sie können es reaktivieren, indem Sie das vom Wordpress-Team bereitgestellte Plugin installieren . Erst danach können Sie eine der in den anderen Antworten vorgeschlagenen Lösungen verwenden.

Ich habe noch keine Lösung gefunden, um dasselbe zu tun, ohne das Plugin zu installieren.

Michele Fortunato
quelle