Filtrage de plusieurs champs personnalisés avec WP REST API 2

14

Je souhaite filtrer les publications en fonction de plusieurs champs personnalisés acf avec la relation AND. Quelque chose comme ça:

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

Je pourrais même avoir plus de filtres. Comment puis-je les convertir en filtres REST API 2?

Sohrab Taee
la source
Jetez un œil à cet article et essayez de créer votre fonction wordpress.stackexchange.com/questions/169408/…
emilushi

Réponses:

3

Cette solution fonctionne avec get_items()in /lib/endpoints/class-wp-rest-posts-controller.phpdu v2 WP Rest API.


Tout d'abord, vous voudrez construire les GETarguments comme vous le feriez pour a new WP_Query(). La façon la plus simple de le faire est d'utiliser 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 );

Cela produira quelque chose comme:

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

Si vous le souhaitez, vous pouvez également utiliser les outils Chrome et decodeURIComponent('your-query-here')le rendre plus facile à lire lorsque vous le jetez dans l' URL de votre API JSON Rest :

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

Remarque: Pour utiliser votre type de publication personnalisé, vous devez le mettre productavant?

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


Vous avez donc votre requête, mais nous devons indiquer à WP comment gérer certaines choses:

  1. Ajout de la prise en charge REST pour le type de publication personnalisé product
  2. Autoriser les arguments de requête meta_query
  3. Analyse 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
la source
2

Voici un test que j'ai fait sur Localhost:

Pour des raisons de sécurité, la méta-requête n'est pas autorisée sur WP Api, tout d'abord, vous devez ajouter la méta-requête à la rest_query autorisée en ajoutant cette fonction sur votre thème 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' );

après cela, vous devrez créer la requête html en utilisant cette fonction sur l'autre site Web qui obtiendra les données du site Web 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);

Je change le tableau des champs pour que l'apparence ressemble maintenant à vos arguments de requête. La chaîne de requête codée ressemblera à ceci:

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

En utilisant urldecode(), qui dans ce cas sera: urldecode('http://yourwordpreswebssite.com/wp-json/wp/v2/posts?' . $field_string);vous aurez une URL comme celle-ci:

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

Si vous pouvez nous fournir l'URL de votre site Web en direct afin que nous puissions le tester à l'aide de postman directement sur votre site Web, car pour le tester sur localhost ou sur tout site WordPress existant, vous devrez créer un type de publication personnalisé et ajouter des champs méta, etc.

emilushi
la source
Merci pour votre réponse mais j'ai testé avec la requête comme dans la question sur Postman et cela n'a pas fonctionné.
MinhTri
@Dan i fait quelques améliorations sur la solution, les valeurs de filtre sont les mêmes que vos arguments de requête, y compris le type de message personnalisé qui n'était pas spécifié dans la solution précédente.
emilushi
Nous n'avons pas de producttaxonomie. Ça marche super! Je n'ai pas pensé à envelopper à l' meta_queryintérieur filter:)
MinhTri
@ Dan, je suis content de l'entendre. J'ai écrit un article à ce sujet hier, vous pouvez envisager de le partager :) API REST WordPress avec des champs méta .
emilushi
1
Quelques choses, sur certains serveurs AWS, en utilisant [] comme un tableau tuera la demande. Vous devez simplement utiliser array () pour être sûr et pour ceux qui pourraient copier / coller. En outre, cela prend-il en charge le produit CPT ou uniquement la taxonomie? Et enfin, avez-vous besoin de désinfecter meta_query? Voyant qu'il a été retiré, courez-vous un risque de sécurité en acceptant tout ce qu'un utilisateur fournit?
jgraup
1

Vous pouvez le faire sans API Rest comme ça (c'est mon filtre de messages)

    $ paged = (get_query_var ('paged'))? get_query_var ('paged'): 1;
$ args = tableau (
        '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'); // ET значит все условия 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' => 'prix',
            'value' => tableau ($ price_min, $ price_max),
            'type' => 'numérique',
            'compare' => 'ENTRE'
        );
    };  

    if ($ area_min || $ area_max) {
        $ args ['meta_query'] [] = array (
            'key' => 'zone',
            'value' => tableau ($ area_min, $ area_max),
            'type' => 'numérique',
            'compare' => 'ENTRE'
        );
    };
Igor Fedorov
la source
1
Merci pour votre réponse, mais je suis vraiment curieux de le faire avec REST API v2.
MinhTri
Bon, je pense que ma variante est bonne, mais si tu veux ... Le fait que ma méthode ne se limite pas aux paramètres!
Igor Fedorov
1

Dans Wordpress 4.7, l' filterargument a été supprimé.

Vous pouvez le réactiver en installant ce plugin fourni par l'équipe Wordpress. Ce n'est qu'après cela que vous pouvez utiliser l'une des solutions proposées dans les autres réponses.

Je n'ai pas encore trouvé de solution pour faire de même sans installer le plugin.

Michele Fortunato
la source