Set quantity step at product level in Woocommerce [duplicate] - woocommerce

I'm using "set minimum and maximum allowable product quantities to be added in WooCommerce Cart" to require a minimum and maximum quantity order.
Now, i need to impose for several products (not all) a mulitple quantity.
For example : 6 bottles, 12 bottles, 18 bottles (multiple of 6) or for other 12 bottles, 24 bottles (multiple of 12)
I found a solution but it's for every product with a unique value and I cant' manage it in the back office for each product individually.
I have to manage the multiple quantity in Backoffice.
Thank you if you can help me

Updated December 2020
The following revisited code will allow in addition to handle quantity steps.
I have changed quantity fields settings location to "General" settings tab.
I have added a checkbox that enables or disables those additional quantity settings at product level (showing or hiding the setting fields dynamically):
When checkbox unchecked (fields are not visible and quantity settings are disabled):
When checkbox is checked (fields are visible and quantity settings are enabled):
I have merged all settings in a unique custom field as an indexed array of values, to improve performance.
Since WooCommerce version 3, things have changed a lot, so I have made some changes enhancing and updating code to something more newer.
Also works nicely on Ajax add to cart for simple products, for product variations from variable products and also on the cart quantity input field.
All the code:
// Displaying quantity setting fields on admin product pages
add_action( 'woocommerce_product_options_pricing', 'wc_qty_add_product_field' );
function wc_qty_add_product_field() {
global $product_object;
$values = $product_object->get_meta('_qty_args');
echo '</div><div class="options_group quantity hide_if_grouped">
<style>div.qty-args.hidden { display:none; }</style>';
woocommerce_wp_checkbox( array( // Checkbox.
'id' => 'qty_args',
'label' => __( 'Quantity settings', 'woocommerce' ),
'value' => empty($values) ? 'no' : 'yes',
'description' => __( 'Enable this to show and enable the additional quantity setting fields.', 'woocommerce' ),
) );
echo '<div class="qty-args hidden">';
woocommerce_wp_text_input( array(
'id' => 'qty_min',
'type' => 'number',
'label' => __( 'Minimum Quantity', 'woocommerce-max-quantity' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Set a minimum allowed quantity limit (a number greater than 0).', 'woocommerce' ),
'custom_attributes' => array( 'step' => 'any', 'min' => '0'),
'value' => isset($values['qty_min']) && $values['qty_min'] > 0 ? (int) $values['qty_min'] : 0,
) );
woocommerce_wp_text_input( array(
'id' => 'qty_max',
'type' => 'number',
'label' => __( 'Maximum Quantity', 'woocommerce-max-quantity' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Set the maximum allowed quantity limit (a number greater than 0). Value "-1" is unlimited', 'woocommerce' ),
'custom_attributes' => array( 'step' => 'any', 'min' => '-1'),
'value' => isset($values['qty_max']) && $values['qty_max'] > 0 ? (int) $values['qty_max'] : -1,
) );
woocommerce_wp_text_input( array(
'id' => 'qty_step',
'type' => 'number',
'label' => __( 'Quantity step', 'woocommerce-quantity-step' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Optional. Set quantity step (a number greater than 0)', 'woocommerce' ),
'custom_attributes' => array( 'step' => 'any', 'min' => '1'),
'value' => isset($values['qty_step']) && $values['qty_step'] > 1 ? (int) $values['qty_step'] : 1,
) );
echo '</div>';
}
// Show/hide setting fields (admin product pages)
add_action( 'admin_footer', 'product_type_selector_filter_callback' );
function product_type_selector_filter_callback() {
global $pagenow, $post_type;
if( in_array($pagenow, array('post-new.php', 'post.php') ) && $post_type === 'product' ) :
?>
<script>
jQuery(function($){
if( $('input#qty_args').is(':checked') && $('div.qty-args').hasClass('hidden') ) {
$('div.qty-args').removeClass('hidden')
}
$('input#qty_args').click(function(){
if( $(this).is(':checked') && $('div.qty-args').hasClass('hidden')) {
$('div.qty-args').removeClass('hidden');
} else if( ! $(this).is(':checked') && ! $('div.qty-args').hasClass('hidden')) {
$('div.qty-args').addClass('hidden');
}
});
});
</script>
<?php
endif;
}
// Save quantity setting fields values
add_action( 'woocommerce_admin_process_product_object', 'wc_save_product_quantity_settings' );
function wc_save_product_quantity_settings( $product ) {
if ( isset($_POST['qty_args']) ) {
$values = $product->get_meta('_qty_args');
$product->update_meta_data( '_qty_args', array(
'qty_min' => isset($_POST['qty_min']) && $_POST['qty_min'] > 0 ? (int) wc_clean($_POST['qty_min']) : 0,
'qty_max' => isset($_POST['qty_max']) && $_POST['qty_max'] > 0 ? (int) wc_clean($_POST['qty_max']) : -1,
'qty_step' => isset($_POST['qty_step']) && $_POST['qty_step'] > 1 ? (int) wc_clean($_POST['qty_step']) : 1,
) );
} else {
$product->update_meta_data( '_qty_args', array() );
}
}
// The quantity settings in action on front end
add_filter( 'woocommerce_quantity_input_args', 'filter_wc_quantity_input_args', 99, 2 );
function filter_wc_quantity_input_args( $args, $product ) {
if ( $product->is_type('variation') ) {
$parent_product = wc_get_product( $product->get_parent_id() );
$values = $parent_product->get_meta( '_qty_args' );
} else {
$values = $product->get_meta( '_qty_args' );
}
if ( ! empty( $values ) ) {
// Min value
if ( isset( $values['qty_min'] ) && $values['qty_min'] > 1 ) {
$args['min_value'] = $values['qty_min'];
if( ! is_cart() ) {
$args['input_value'] = $values['qty_min']; // Starting value
}
}
// Max value
if ( isset( $values['qty_max'] ) && $values['qty_max'] > 0 ) {
$args['max_value'] = $values['qty_max'];
if ( $product->managing_stock() && ! $product->backorders_allowed() ) {
$args['max_value'] = min( $product->get_stock_quantity(), $args['max_value'] );
}
}
// Step value
if ( isset( $values['qty_step'] ) && $values['qty_step'] > 1 ) {
$args['step'] = $values['qty_step'];
}
}
return $args;
}
// Ajax add to cart, set "min quantity" as quantity on shop and archives pages
add_filter( 'woocommerce_loop_add_to_cart_args', 'filter_loop_add_to_cart_quantity_arg', 10, 2 );
function filter_loop_add_to_cart_quantity_arg( $args, $product ) {
$values = $product->get_meta( '_qty_args' );
if ( ! empty( $values ) ) {
// Min value
if ( isset( $values['qty_min'] ) && $values['qty_min'] > 1 ) {
$args['quantity'] = $values['qty_min'];
}
}
return $args;
}
// The quantity settings in action on front end (For variable productsand their variations)
add_filter( 'woocommerce_available_variation', 'filter_wc_available_variation_price_html', 10, 3);
function filter_wc_available_variation_price_html( $data, $product, $variation ) {
$values = $product->get_meta( '_qty_args' );
if ( ! empty( $values ) ) {
if ( isset( $values['qty_min'] ) && $values['qty_min'] > 1 ) {
$data['min_qty'] = $values['qty_min'];
}
if ( isset( $values['qty_max'] ) && $values['qty_max'] > 0 ) {
$data['max_qty'] = $values['qty_max'];
if ( $variation->managing_stock() && ! $variation->backorders_allowed() ) {
$data['max_qty'] = min( $variation->get_stock_quantity(), $data['max_qty'] );
}
}
}
return $data;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Related

Product query results are not correct

I need a custom fields on the inventory tab that will be filled in with the zipcode as the location of the agent.
Armed with the references I got here, now I have that field.
what I want to ask is how to concatenate this meta data with woocommerce shortcode?
I think like :
['products limit="12" columns="4" zipcode="12345"]
where "12345" will be changing dynamically as needed (zipcode filled based on agent location).
I have tried to do something but it is not working properly.
Here's the full code.
function action_woocommerce_product_options_inventory_product_data_zipcode() {
woocommerce_wp_text_input( array(
'id' => '_zipcode',
'label' => __( 'Zipcode', 'woocommerce' ),
'description' => __( 'Please fill your zipcode.', 'woocommerce' ),
'desc_tip' => 'true',
'placeholder' => __( '12345', 'woocommerce' )
) );
}
add_action( 'woocommerce_product_options_inventory_product_data', 'action_woocommerce_product_options_inventory_product_data_zipcode' );
// Save zipcode
function action_woocommerce_admin_process_product_object_zipcode( $product ) {
// Isset
if ( isset( $_POST['_zipcode'] ) ) {
// Update
$product->update_meta_data( '_zipcode', sanitize_text_field( $_POST['_zipcode'] ));
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object_zipcode', 10, 1 );
Try put to shortcode products :
function filter_shortcode_atts_products_zipcode ( $out, $pairs, $atts, $shortcode) {
if ( isset ( $atts['zipcode'] ) && !empty($atts['zipcode']) ) {
$out['zipcode'] = true;
} else {
$out['zipcode'] = false;
}
return $out;
}
add_filter( 'shortcode_atts_products', 'filter_shortcode_atts_products_zipcode', 10, 4);
function filter_woocommerce_shortcode_products_query_zipcode( $query_args, $atts, $type) {
if ( $type == 'products' && $atts['zipcode'] ) {
// Meta query
$query_args['meta_query'] = array(
array(
'key' => '_zipcode',
'value' => $atts['zipcode'],
'compare' => 'LIKE',
)
);
}
return $query_args;
}
add_filter( 'woocommerce_shortcode_products_query', 'filter_woocommerce_shortcode_products_query_zipcode', 10, 3 );
On testing I tried :
['products limit="12" columns="4" zipcode="12345"]
shortcode has displayed the product but does not refer to the postal code in the short code ("12345") but to all products that have a postal code.
Can somebody help me?
Thank you
Something doesn't feel right about the shortcode attribute function. I think you're setting the attribute as true and therefore it's comparing anything "truthy." Maybe just try setting the true one as the zipcode, like this:
function filter_shortcode_atts_products_zipcode ( $out, $pairs, $atts, $shortcode) {
if ( isset ( $atts['zipcode'] ) && !empty($atts['zipcode']) ) {
$out['zipcode'] = $atts['zipcode'];
} else {
$out['zipcode'] = false;
}
return $out;
}
That way it'll return the zipcode if it exists, and false if it doesn't, which the query can then use for the comparison.

Add custom field to product inventory tab and display value on single product page where meta ends

I'm using the following code in my theme functions.php file to add a additional data field to the product inventory tab:
// Add Custom Field to woocommerce inventory tab for product
add_action('woocommerce_product_options_inventory_product_data', function() {
woocommerce_wp_text_input([
'id' => '_number_in_package',
'label' => __('Number of Pages', 'txtdomain'),
'type' => 'number',
]);
});
add_action('woocommerce_process_product_meta', function($post_id) {
$product = wc_get_product($post_id);
$num_package = isset($_POST['_number_in_package']) ? $_POST['_number_in_package'] : '';
$product->update_meta_data('_number_in_package', sanitize_text_field($num_package));
$product->save();
});
add_action('woocommerce_product_meta_start', function() {
global $post;
$product = wc_get_product($post->ID);
$num_package = $product->get_meta('_number_in_package');
if (!empty($num_package)) {
printf('<div class="custom-sku">%s: %s</div>', __('Number of Pages', 'txtdomain'), $num_package);
}
});
add_filter('woocommerce_product_data_tabs', function($tabs) {
$tabs['additional_info'] = [
'label' => __('Additional info', 'txtdomain'),
'target' => 'additional_product_data',
'class' => ['hide_if_external'],
'priority' => 25
];
return $tabs;
});
However, on the single product page, the custom field is added before category and ISBN. I want to place the custom field at the end after the product ISBN. Any advice?
Some comments/suggestions regarding your code attempt
To save fields you can use the woocommerce_admin_process_product_object hook, opposite the outdated woocommerce_process_product_meta hook
WooCommerce contains by default no ISBN field, but it looks like the woocommerce_product_meta_end hook will answer your question
So you get:
// Add custom field
function action_woocommerce_product_options_inventory_product_data() {
woocommerce_wp_text_input( array(
'id' => '_number_in_package',
'label' => __( 'Number of Pages', 'woocommerce' ),
'description' => __( 'This is a custom field, you can write here anything you want.', 'woocommerce' ),
'desc_tip' => 'true',
'type' => 'number'
) );
}
add_action( 'woocommerce_product_options_inventory_product_data', 'action_woocommerce_product_options_inventory_product_data' );
// Save custom field
function action_woocommerce_admin_process_product_object( $product ) {
// Isset
if ( isset( $_POST['_number_in_package'] ) ) {
// Update
$product->update_meta_data( '_number_in_package', sanitize_text_field( $_POST['_number_in_package'] ) );
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
// Display on single product page
function action_woocommerce_product_meta_end() {
global $product;
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get meta
$number = $product->get_meta( '_number_in_package' );
// NOT empty
if ( ! empty ( $number ) ) {
echo '<p>' . $number . '</p>';
}
}
}
add_action( 'woocommerce_product_meta_end', 'action_woocommerce_product_meta_end', 10 );

Setting Min / Max and Step Quantities in Woocommerce [duplicate]

I'm using "set minimum and maximum allowable product quantities to be added in WooCommerce Cart" to require a minimum and maximum quantity order.
Now, i need to impose for several products (not all) a mulitple quantity.
For example : 6 bottles, 12 bottles, 18 bottles (multiple of 6) or for other 12 bottles, 24 bottles (multiple of 12)
I found a solution but it's for every product with a unique value and I cant' manage it in the back office for each product individually.
I have to manage the multiple quantity in Backoffice.
Thank you if you can help me
Updated December 2020
The following revisited code will allow in addition to handle quantity steps.
I have changed quantity fields settings location to "General" settings tab.
I have added a checkbox that enables or disables those additional quantity settings at product level (showing or hiding the setting fields dynamically):
When checkbox unchecked (fields are not visible and quantity settings are disabled):
When checkbox is checked (fields are visible and quantity settings are enabled):
I have merged all settings in a unique custom field as an indexed array of values, to improve performance.
Since WooCommerce version 3, things have changed a lot, so I have made some changes enhancing and updating code to something more newer.
Also works nicely on Ajax add to cart for simple products, for product variations from variable products and also on the cart quantity input field.
All the code:
// Displaying quantity setting fields on admin product pages
add_action( 'woocommerce_product_options_pricing', 'wc_qty_add_product_field' );
function wc_qty_add_product_field() {
global $product_object;
$values = $product_object->get_meta('_qty_args');
echo '</div><div class="options_group quantity hide_if_grouped">
<style>div.qty-args.hidden { display:none; }</style>';
woocommerce_wp_checkbox( array( // Checkbox.
'id' => 'qty_args',
'label' => __( 'Quantity settings', 'woocommerce' ),
'value' => empty($values) ? 'no' : 'yes',
'description' => __( 'Enable this to show and enable the additional quantity setting fields.', 'woocommerce' ),
) );
echo '<div class="qty-args hidden">';
woocommerce_wp_text_input( array(
'id' => 'qty_min',
'type' => 'number',
'label' => __( 'Minimum Quantity', 'woocommerce-max-quantity' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Set a minimum allowed quantity limit (a number greater than 0).', 'woocommerce' ),
'custom_attributes' => array( 'step' => 'any', 'min' => '0'),
'value' => isset($values['qty_min']) && $values['qty_min'] > 0 ? (int) $values['qty_min'] : 0,
) );
woocommerce_wp_text_input( array(
'id' => 'qty_max',
'type' => 'number',
'label' => __( 'Maximum Quantity', 'woocommerce-max-quantity' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Set the maximum allowed quantity limit (a number greater than 0). Value "-1" is unlimited', 'woocommerce' ),
'custom_attributes' => array( 'step' => 'any', 'min' => '-1'),
'value' => isset($values['qty_max']) && $values['qty_max'] > 0 ? (int) $values['qty_max'] : -1,
) );
woocommerce_wp_text_input( array(
'id' => 'qty_step',
'type' => 'number',
'label' => __( 'Quantity step', 'woocommerce-quantity-step' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Optional. Set quantity step (a number greater than 0)', 'woocommerce' ),
'custom_attributes' => array( 'step' => 'any', 'min' => '1'),
'value' => isset($values['qty_step']) && $values['qty_step'] > 1 ? (int) $values['qty_step'] : 1,
) );
echo '</div>';
}
// Show/hide setting fields (admin product pages)
add_action( 'admin_footer', 'product_type_selector_filter_callback' );
function product_type_selector_filter_callback() {
global $pagenow, $post_type;
if( in_array($pagenow, array('post-new.php', 'post.php') ) && $post_type === 'product' ) :
?>
<script>
jQuery(function($){
if( $('input#qty_args').is(':checked') && $('div.qty-args').hasClass('hidden') ) {
$('div.qty-args').removeClass('hidden')
}
$('input#qty_args').click(function(){
if( $(this).is(':checked') && $('div.qty-args').hasClass('hidden')) {
$('div.qty-args').removeClass('hidden');
} else if( ! $(this).is(':checked') && ! $('div.qty-args').hasClass('hidden')) {
$('div.qty-args').addClass('hidden');
}
});
});
</script>
<?php
endif;
}
// Save quantity setting fields values
add_action( 'woocommerce_admin_process_product_object', 'wc_save_product_quantity_settings' );
function wc_save_product_quantity_settings( $product ) {
if ( isset($_POST['qty_args']) ) {
$values = $product->get_meta('_qty_args');
$product->update_meta_data( '_qty_args', array(
'qty_min' => isset($_POST['qty_min']) && $_POST['qty_min'] > 0 ? (int) wc_clean($_POST['qty_min']) : 0,
'qty_max' => isset($_POST['qty_max']) && $_POST['qty_max'] > 0 ? (int) wc_clean($_POST['qty_max']) : -1,
'qty_step' => isset($_POST['qty_step']) && $_POST['qty_step'] > 1 ? (int) wc_clean($_POST['qty_step']) : 1,
) );
} else {
$product->update_meta_data( '_qty_args', array() );
}
}
// The quantity settings in action on front end
add_filter( 'woocommerce_quantity_input_args', 'filter_wc_quantity_input_args', 99, 2 );
function filter_wc_quantity_input_args( $args, $product ) {
if ( $product->is_type('variation') ) {
$parent_product = wc_get_product( $product->get_parent_id() );
$values = $parent_product->get_meta( '_qty_args' );
} else {
$values = $product->get_meta( '_qty_args' );
}
if ( ! empty( $values ) ) {
// Min value
if ( isset( $values['qty_min'] ) && $values['qty_min'] > 1 ) {
$args['min_value'] = $values['qty_min'];
if( ! is_cart() ) {
$args['input_value'] = $values['qty_min']; // Starting value
}
}
// Max value
if ( isset( $values['qty_max'] ) && $values['qty_max'] > 0 ) {
$args['max_value'] = $values['qty_max'];
if ( $product->managing_stock() && ! $product->backorders_allowed() ) {
$args['max_value'] = min( $product->get_stock_quantity(), $args['max_value'] );
}
}
// Step value
if ( isset( $values['qty_step'] ) && $values['qty_step'] > 1 ) {
$args['step'] = $values['qty_step'];
}
}
return $args;
}
// Ajax add to cart, set "min quantity" as quantity on shop and archives pages
add_filter( 'woocommerce_loop_add_to_cart_args', 'filter_loop_add_to_cart_quantity_arg', 10, 2 );
function filter_loop_add_to_cart_quantity_arg( $args, $product ) {
$values = $product->get_meta( '_qty_args' );
if ( ! empty( $values ) ) {
// Min value
if ( isset( $values['qty_min'] ) && $values['qty_min'] > 1 ) {
$args['quantity'] = $values['qty_min'];
}
}
return $args;
}
// The quantity settings in action on front end (For variable productsand their variations)
add_filter( 'woocommerce_available_variation', 'filter_wc_available_variation_price_html', 10, 3);
function filter_wc_available_variation_price_html( $data, $product, $variation ) {
$values = $product->get_meta( '_qty_args' );
if ( ! empty( $values ) ) {
if ( isset( $values['qty_min'] ) && $values['qty_min'] > 1 ) {
$data['min_qty'] = $values['qty_min'];
}
if ( isset( $values['qty_max'] ) && $values['qty_max'] > 0 ) {
$data['max_qty'] = $values['qty_max'];
if ( $variation->managing_stock() && ! $variation->backorders_allowed() ) {
$data['max_qty'] = min( $variation->get_stock_quantity(), $data['max_qty'] );
}
}
}
return $data;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Woocommerce rounding prices up

I have set prices 7,09 and in cart it shows 7,00.
How I can remove this rounding? I have custom variation price field.
My code:
woocommerce_wp_text_input(
array(
'id' => '_number_field[' . $variation->ID . ']',
'label' => __( 'Aluse hind', 'woocommerce' ),
'desc_tip' => 'true',
'description' => __( 'Sisesta aluse hind.', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, '_number_field', true ),
'custom_attributes' => array(
'step' => 'any',
'min' => '0'
)
)
);
add_filter('woocommerce_product_variation_get_price', 'custom_product_get_price', 10, 2 );
add_filter('woocommerce_show_variation_price', function() { return TRUE;});
function custom_product_get_price( $price, $product ){
if (!empty(get_post_meta( $product->get_id(), '_number_field', true))) {
return get_post_meta( $product->get_id(), '_number_field', true);
} else {
return get_post_meta( $product->get_id(), '_price', true);
}
}
As you can see here, looks like it will always be a small change in the zecimals
It is not a rounding problem. You're just passing a string as a price and the float conversion truncates the decimals.
If the value of the custom field _number_field uses a comma it must be converted to a numeric value (float), replacing the comma with the decimal point.
In your log file you will also find the notice: Notice: A non well formed numeric value encountered.
Furthermore, the woocommerce_product_variation_get_price hook already returns the meta _price of the product variation so the else declaration is not necessary.
You can optimize the custom_product_get_price function like this:
add_filter('woocommerce_product_variation_get_price', 'custom_product_get_price', 10, 2 );
function custom_product_get_price( $price, $product ) {
if ( ! empty( get_post_meta( $product->get_id(), '_number_field', true) ) ) {
$new_price = get_post_meta( $product->get_id(), '_number_field', true );
$new_price = (float) str_replace( ',', '.', $new_price );
}
if ( isset($new_price) ) {
return $new_price;
} else {
return $price;
}
}
The code has been tested and works.

WooCommerce REST API : query products by multiple attributes

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 ?
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
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!
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,
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);

Resources