使用WP REST API 2过滤多个自定义字段


14

我想基于具有AND关系的多个acf自定义字段来过滤帖子。像这样:

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

我什至可以拥有更多过滤器。如何将它们转换为REST API 2过滤器?


看看这篇文章,尝试创建您的功能wordpress.stackexchange.com/questions/169408/…–
emilushi

Answers:


3

此解决方案适用get_items()/lib/endpoints/class-wp-rest-posts-controller.php中的v2 WP Rest API


首先,您将希望GET像构造一样构造参数new WP_Query()。最简单的方法是使用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 );

它将产生类似:

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

如果您希望阅读,也可以使用Chrome工具,并将decodeURIComponent('your-query-here')其放入JSON Rest API URL时,使其更易于阅读:

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

注意:要使用自定义帖子类型,您需要product?

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


所以您有您的查询,但是我们需要指导WP如何处理一些事情:

  1. 为自定义帖子类型添加REST支持 product
  2. 允许查询参数 meta_query
  3. 解析中 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 );

2

这是我在Localhost上进行的测试:

出于安全原因,不允许在WP Api上使用元查询,首先,您需要在wordpress主题上添加此功能,以将meta_query添加到允许的rest_query中 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' );

之后,您将需要在另一个网站上使用此功能来构建html查询,该网站将从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);

我更改了fields数组,使外观现在看起来像您的查询参数。编码的查询字符串将如下所示:

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

通过使用urldecode(),在这种情况下将是:urldecode('http://yourwordpreswebssite.com/wp-json/wp/v2/posts?' . $field_string);您将拥有一个类似于以下的URL:

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

如果您可以向我们提供您的实时网站URL,那么我们可以直接在您的网站上使用postman对其进行测试,因为要在localhost或任何现有的WordPress网站上对其进行测试,都需要创建产品自定义帖子类型并添加元字段等。


感谢您的回答,但我已经按照Postman的问题对查询进行了测试,但无法正常工作。
MinhTri

@Dan我对该解决方案进行了一些改进,筛选器值与您的查询参数相同,包括自定义帖子类型,该类型在上一个解决方案中未指定。
emilushi '16

我们没有product分类法。效果很好!没想到要包裹meta_query在里面filter:)
MinhTri '16

@丹我很高兴听到它。昨天我写了一篇关于它的文章,您可以考虑分享它:) 带有元字段的WordPress REST API
emilushi's

1
在某些AWS服务器上,使用[]作为数组的几件事会终止该请求。您应该只使用array()是安全的,对于那些可能会复制/粘贴的人而言。此外,这是否支持CPT产品或仅支持分类法?最后,您是否需要清理meta_query?看到它被拉了,您是否接受用户提供的任何东西会带来安全风险?
jgraup

1

您可以像这样不使用Rest API来完成此操作(这是我的帖子过滤器)

    $ paged =(get_query_var('paged'))?get_query_var('paged'):1;
$ args =数组(
        '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'); // ANDзначитвсеусловияmeta_queryдолжнывыполняться


    if($ type){
        $ args ['meta_query'] [] = array(
            'key'=>'type',
            '值'=> $ type,
        );
    };

    if($ plan){
        $ args ['meta_query'] [] = array(
            'key'=>'plan',
            '值'=> $计划,
        );
    };

    if($ room_num){
        $ args ['meta_query'] [] = array(
            'key'=>'room_num',
            '值'=> $ room_num,
        );
    };

    if($ etage){
        $ args ['meta_query'] [] = array(
            'key'=>'etage',
            '值'=> $ etage,
        );
    };  

    if($ price_min || $ price_max){
        $ args ['meta_query'] [] = array(
            '键'=>'价格',
            '值'=>数组($ price_min,$ price_max),
            '类型'=>'数字',
            '比较'=>'BETWEEN'
        );
    };  

    if($ area_min || $ area_max){
        $ args ['meta_query'] [] = array(
            'key'=>'area',
            '值'=>数组($ area_min,$ area_max),
            '类型'=>'数字',
            '比较'=>'BETWEEN'
        );
    };

1
感谢您的回答,但我真的很想使用REST API v2做到这一点。
MinhTri '16

好吧,我认为我的变量不错,但是如果您想...我的方法不限于参数的事实!
伊戈尔·费多罗夫

1

在Wordpress 4.7中,该filter参数已被删除。

您可以安装Wordpress团队提供的插件来重新激活它。只有这样,您才能使用其他答案中提出的解决方案之一。

我还没有找到一种无需安装插件即可执行相同操作的解决方案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.