Filtrado de múltiples campos personalizados con WP REST API 2

14

Quiero filtrar publicaciones basadas en múltiples campos personalizados de acf con relación AND. Algo como esto:

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

Incluso podría tener más filtros. ¿Cómo puedo convertirlos en filtros REST API 2?

Sohrab Taee
fuente
Eche un vistazo a esta publicación e intente crear su función wordpress.stackexchange.com/questions/169408/…
emilushi

Respuestas:

3

Esta solución funciona con get_items()en /lib/endpoints/class-wp-rest-posts-controller.phpdel v2 WP Rest API.


Primero, querrás construir los GETargumentos como lo harías para a new WP_Query(). La forma más fácil de hacer esto es con 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 );

Producirá algo como:

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

Lo cual, si desea que se pueda leer, también puede usar las herramientas de Chrome y decodeURIComponent('your-query-here')hacer que sea más fácil de leer cuando lo arroje a su URL de 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]==

Nota: Para usar su tipo de publicación personalizada, debe poner productantes?

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


Entonces tiene su consulta pero necesitamos instruir a WP sobre cómo manejar algunas cosas:

  1. Agregar soporte REST para el tipo de publicación personalizada product
  2. Permitir los argumentos de consulta meta_query
  3. Analizando 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
fuente
2

Aquí hay una prueba que hice en Localhost:

Por razones de seguridad, la metaconsulta no está permitida en WP Api, primero lo que tiene que hacer es agregar meta_query a rest_query permitido agregando esta función en su tema de 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' );

después de eso, necesitará construir la consulta html usando esta función en el otro sitio web que obtendrá los datos del sitio web de 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);

Cambio la matriz de campos para que se vea ahora como los argumentos de su consulta. La cadena de consulta codificada se verá así:

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

Al usar urldecode(), que en este caso será: urldecode('http://yourwordpreswebssite.com/wp-json/wp/v2/posts?' . $field_string);tendrá una URL como esta:

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 puede proporcionarnos la URL de su sitio web en vivo para que podamos probarlo utilizando el cartero directamente en su sitio web, porque para probarlo en localhost o en cualquier sitio existente de WordPress será necesario crear un tipo de publicación personalizada del producto y agregar metacampos, etc. ¡Saludos!

emilushi
fuente
Gracias por su respuesta, pero he probado con la consulta como en la pregunta sobre Cartero y no funcionó.
MinhTri
@Dané algunas mejoras en la solución, los valores de filtro son los mismos que los argumentos de su consulta, incluido el tipo de publicación personalizada que no se especificó en la solución anterior.
emilushi
No tenemos producttaxonomía. ¡Funciona muy bien! No pensé en envolverme meta_querydentro filter:)
MinhTri
@ Dan, me alegra escucharlo. Ayer escribí una publicación al respecto, puede considerar compartirla :) API REST de WordPress con metacampos .
emilushi
1
Un par de cosas, en algunos servidores de AWS, usando [] como una matriz matará la solicitud. Solo debe usar array () para estar seguro y para aquellos cómo copiar / pegar. Además, ¿esto es compatible con el producto CPT o solo con la taxonomía? Y por último, ¿necesitas desinfectar meta_query? Al ver que fue retirado, ¿corre un riesgo de seguridad al aceptar cualquier cosa que el usuario proporcione?
jgraup
1

Puedes hacerlo sin Rest API como este (es mi filtro de publicaciones)

    $ paged = (get_query_var ('paged'))? get_query_var ('paginado'): 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 ('relación' => 'Y'); // Y значит все условия meta_query должны выполняться


    if ($ tipo) {
        $ 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' => 'precio',
            'value' => array ($ price_min, $ price_max),
            'type' => 'numérico',
            'compare' => 'ENTRE'
        );
    };  

    if ($ area_min || $ area_max) {
        $ args ['meta_query'] [] = array (
            'key' => 'area',
            'value' => array ($ area_min, $ area_max),
            'type' => 'numérico',
            'compare' => 'ENTRE'
        );
    };
Igor Fedorov
fuente
1
Gracias por su respuesta, pero tengo mucha curiosidad por hacerlo con REST API v2.
MinhTri
Bueno, creo que mi variante es buena, pero si quieres ... ¡El hecho de que mi método no se limita a los parámetros!
Igor Fedorov
1

En Wordpress 4.7 el filterargumento ha sido eliminado.

Puede reactivarlo instalando este complemento proporcionado por el equipo de Wordpress. Solo después de eso puede usar una de las soluciones propuestas en las otras respuestas.

Todavía no he encontrado una solución para hacer lo mismo sin instalar el complemento.

Michele Fortunato
fuente