1
votes

According to the API : http://woocommerce.github.io/woocommerce-rest-api-docs/#list-all-products we can filter products by a single attribute. But Is it impossible to search by multiple attributes through API ?

Example : "I want red shirts". Here attribute is color and attribute term is red. To accomplish the search, the query string goes like this : products?category=17&attribute=pa_color&attribute_term=22&

And we get the red shirts only.

But for "I want red medium shirts" , here an additional size attribute with value medium is encountered. And according to the API there is no way to associate both the color and the size attributes in the query string. So the query -

products?category=17&attribute=pa_color&attribute_term=22&attribute=pa_size&attribute_term=24& 

returns all products from the store

Is there any workaround ?

4

4 Answers

3
votes

I have written custom query that does it all :D This is a callback function. All you need to do is create new endpoint with this callback:

Here is a documentation:

category - string (category slug) - filter by products category.
per_page - int (default - from admin) - show items on one page.
offset - int (default - 1) - show page number.
order - string (ASC/DESC, default: desc) - order products ascending or descending.
orderby - string (name, price, default: name) - order products by key.
filter - array
[pa_attribute_name (string) ]  = array of ID's.
[min_price (string) ] = int.
[max_price (string) ] = int.

Example:

/wp-json/go/v1/products/?category=smartphones&filter[pa_brand]=87,88&filter[pa_colour]=17&filter[min_price]=1&filter[max_price]=50&per_page=10&offset=1&order=DESC&orderby=price

Here is a function:

public function get_products_list_callback( \WP_REST_Request $request ) {
    $params = $request->get_params();

    $category = General_Helper::get_array_value( 'category', $params );
    $filters  = General_Helper::get_array_value( 'filter', $params );
    $per_page = General_Helper::get_array_value( 'per_page', $params );
    $offset   = General_Helper::get_array_value( 'offset', $params );
    $order    = General_Helper::get_array_value( 'order', $params );
    $orderby  = General_Helper::get_array_value( 'orderby', $params );

    $output = [];

    // Use default arguments.
    $args = [
      'post_type'      => Config::POST_TYPE_SLUG_PRODUCT,
      'posts_per_page' => get_option( 'posts_per_page' ),
      'post_status'    => 'publish',
      'paged'          => 1,
    ];

    // Posts per page.
    if ( ! empty( $per_page ) ) {
      $args['posts_per_page'] = $per_page;
    }

    // Pagination, starts from 1.
    if ( ! empty( $offset ) ) {
      $args['paged'] = $offset;
    }

    // Order condition. ASC/DESC.
    if ( ! empty( $order ) ) {
      $args['order'] = $order;
    }

    // Orderby condition. Name/Price.
    if ( ! empty( $orderby ) ) {
      if ( $orderby === 'price' ) {
        $args['orderby'] = 'meta_value_num';
      } else {
        $args['orderby'] = $orderby;
      }
    }

    // If filter buy category or attributes.
    if ( ! empty( $category ) || ! empty( $filters ) ) {
      $args['tax_query']['relation'] = 'AND';

      // Category filter.
      if ( ! empty( $category ) ) {
        $args['tax_query'][] = [
          'taxonomy' => Config::TAXONOMY_SLUG_PRODUCT,
          'field'    => 'slug',
          'terms'    => [ $category ],
        ];
      }

      // Attributes filter.
      if ( ! empty( $filters ) ) {
        foreach ( $filters as $filter_key => $filter_value ) {
          if ( $filter_key === 'min_price' || $filter_key === 'max_price' ) {
            continue;
          }

          $args['tax_query'][] = [
            'taxonomy' => $filter_key,
            'field'    => 'term_id',
            'terms'    => \explode( ',', $filter_value ),
          ];
        }
      }

      // Min / Max price filter.
      if ( isset( $filters['min_price'] ) || isset( $filters['max_price'] ) ) {
        $price_request = [];

        if ( isset( $filters['min_price'] ) ) {
          $price_request['min_price'] = $filters['min_price'];
        }

        if ( isset( $filters['max_price'] ) ) {
          $price_request['max_price'] = $filters['max_price'];
        }

        $args['meta_query'][] = \wc_get_min_max_price_meta_query( $price_request );
      }
    }

    $the_query = new \WP_Query( $args );

    if ( ! $the_query->have_posts() ) {
      return $output;
    }

    while ( $the_query->have_posts() ) {
      $the_query->the_post();

      $output[] = get_the_title();
    }
    wp_reset_postdata();

    return $output;
  }

Hope it helps

2
votes

Try to request like this:

products?attribute=pa_color&attribute_term=51,50&per_page=100

Its worked for me. Latest woocommerce-api wc/v2!

1
votes

I just looked into the woocommerce rest api implementation at

plugins/woocommerce/includes/api/class-wc-rest-products-controller.php

file but unfortunately their codes doesn't support multiple attributes. But you can write your own query to achieve your goal.

$args = array(
'post_type' => 'product',
'tax_query' => array(
    array(
        'relation' => 'AND',
        array(
            'taxonomy' => 'pa_color',
            'field'    => 'term_id',
            'terms'    => array( 'red' ),
        ),
        array(
            'taxonomy' => 'pa_size',
            'field'    => 'term_id',
            'terms'    => array( 'Long' ),
        ),
    ),
),
);
$products = new WP_Query( $args );
print_r($products);
0
votes

after test on WooRest API v3, you can pass multiple term taxonomy IDs. You have to pass a string with ids separated by comma, this will be parsed as an array by WooRest API v3.

Like this :

/wp-json/wc/v3/products/?category=1,2,3,4

Don't forget to encode query parameter or use Automattic\WooCommerce package Enjoy,