Шаг количества товара или кратность в некоторых сферах интернет торговли является важной составляющей. Рассмотрим варианты создания данного функционала.
Quantities and Units for WooCommerce
Плагин Quantities and Units for WooCommerce (3,000+) дает возможность создавать как массовые правила для различных групп товаров (категорий, меток, ролей пользователей), так и индивидуальные игнорируя массовые. Можно назначить шаг количества (в т.ч. десятичные значения), минимальное (должно быть не меньше количества шага) и максимальное количество, минимальное и максимальное количество чтобы считать товар не в наличии (если на сайте учитываются остатки), а также приоритет правила.
Просто надо обновить скрипты:
$(document).ready(function(){ $('.quantity').on('click', '.plus', function() { $input = $(this).prev('input.qty'); var val = parseFloat($input.val()); var step = parseFloat($input.attr('step')); $input.val( val+step ).change(); }); $('.quantity').on('click', '.minus', function() { $input = $(this).next('input.qty'); var val = parseFloat($input.val()); var step = parseFloat($input.attr('step')); var min = parseFloat($input.attr('min')); if (val > min) { $input.val( val-step ).change(); } }); });
// Скрипт для кнопок + и - в шаблоне Корзина $(document).ready(function(){ $('body').on('click', '.plus', function(e) { $input = $(this).prev('input.qty'); var val = parseFloat($input.val()); var step = parseFloat($input.attr('step')); $input.val( val+step ).change(); }); $('body').on('click', '.minus', function(e) { $input = $(this).next('input.qty'); var val = parseFloat($input.val()); var step = parseFloat($input.attr('step')); var min = parseFloat($input.attr('min')); if (val > min) { $input.val( val-step ).change(); } }); }); //Кнопка Обновить в Корзине изначально активна $(document).bind('ready ajaxComplete', function(){ $('[name="update_cart"]').attr("disabled",false); });
Плагин Quantities and Units for WooCommerce и доработка кнопок quantity вместе работают отлично. Больше ничего и не нужно. Ниже уже вариации на тему.
Используя десятичные значения количества можно немного переработать миникорзину под вывод количества наименований.
Нашелся еще один недочет этого плагина, помимо того что в коде много устаревших вызовов WC (более 4-х лет не обновлялся), но это можно поправить вручную, кратность некорректно работает при добавлении товаров из категории ajax. Происходит переход в карточку с предупреждением
Есть еще один плагин дающий тот же функционал — WooCommerce Advanced Quantity, но он платный — 27$ (19.06). Протестировав могу сказать, что он включает в себя весь функционал предыдущего плагина, и исправно работает с добавлением товара ajax’ом.
Глобальное изменение шага
add_filter( 'woocommerce_quantity_input_args', 'jk_woocommerce_quantity_input_args', 10, 2 ); // Simple products function jk_woocommerce_quantity_input_args( $args, $product ) { if ( is_singular( 'product' ) ) { $args['input_value'] = 2; // Starting value (we only want to affect product pages, not cart) } $args['max_value'] = 80; // Maximum value $args['min_value'] = 2; // Minimum value $args['step'] = 2; // Quantity steps return $args; } add_filter( 'woocommerce_available_variation', 'jk_woocommerce_available_variation' ); // Variations function jk_woocommerce_available_variation( $args ) { $args['max_qty'] = 80; // Maximum value (variations) $args['min_qty'] = 2; // Minimum value (variations) return $args; }
Шаг товара из метаполя
Дорабатываем предыдущий скрипт и привязываем к нему метаполе с шагом количества.
// Simple products add_filter( 'woocommerce_quantity_input_args', 'jk_woocommerce_quantity_input_args', 10, 2 ); function jk_woocommerce_quantity_input_args( $args, $product ) { $pcs_pack = get_post_meta($product->post->ID, "step_text_field", true); //$args['max_value'] = 80; // Maximum value $args['min_value'] = $pcs_pack; // Minimum value if ( !empty($pcs_pack) ) { $args['step'] = $pcs_pack; } else { $args['step'] = 1; } return $args; } // Variations add_filter( 'woocommerce_available_variation', 'jk_woocommerce_available_variation' ); function jk_woocommerce_available_variation( $args ) { //$args['max_qty'] = 80; // Maximum value (variations) $args['min_qty'] = $pcs_pack; // Minimum value (variations) return $args; }
Создаем метаполе
add_action( 'woocommerce_product_options_general_product_data', 'woo_add_step_field' ); function woo_add_step_field() { global $woocommerce, $post; echo '<div class="options_group">'; // Add Text field in woocommerce woocommerce_wp_text_input( array( 'id' => 'step_text_field', 'label' => __( 'Шаг количества', 'woocommerce' ), 'placeholder' => 'шаг количества', 'desc_tip' => 'true', 'description' => __( 'Введите шаг количества.', 'woocommerce' ), 'type' => 'number' ) ); echo '</div>';} add_action( 'woocommerce_process_product_meta', 'woo_add_custom_step_field_save' ); function woo_add_custom_step_field_save( $post_id ){ // Text Field $woocommerce_text_field = $_POST['step_text_field']; if( !empty( $woocommerce_text_field ) ) update_post_meta( $post_id, 'step_text_field', esc_attr( $woocommerce_text_field ) ); }
Если используется решение по изменению кнопок (+ и -) необходимо доработать скрипты для товаров:
$(document).ready(function(){ $('.quantity').on('click', '.plus', function() { $input = $(this).prev('input.qty'); var val = parseInt($input.val()); var step = parseInt($input.attr('step')); $input.val( val+step ).change(); }); $('.quantity').on('click', '.minus', function() { $input = $(this).next('input.qty'); var val = parseInt($input.val()); var step = parseInt($input.attr('step')); if (val > step) { $input.val( val-step ).change(); } }); });
и корзины:
$(document).ready(function(){ $('body').on('click', '.plus', function(e) { $input = $(this).prev('input.qty'); var val = parseInt($input.val()); var step = parseInt($input.attr('step')); $input.val( val+step ).change(); }); $('body').on('click', '.minus', function(e) { $input = $(this).next('input.qty'); var val = parseInt($input.val()); var step = parseInt($input.attr('step')); if (val > step) { $input.val( val-step ).change(); } }); });
А шаблон quantity-input.php должен выглядеть примерно так:
<input class="minus" type="button" value="-"> <input type="number" id="<?php echo esc_attr( $input_id ); ?>" class="input-text qty text" step="<?php echo esc_attr( $step ); ?>" min="<?php echo esc_attr( $min_value ); ?>" max="<?php echo esc_attr( 0 < $max_value ? $max_value : '' ); ?>" name="<?php echo esc_attr( $input_name ); ?>" value="<?php echo esc_attr( $input_value ); ?>" title="<?php echo esc_attr_x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ); ?>" size="4" pattern="<?php echo esc_attr( $pattern ); ?>" inputmode="<?php echo esc_attr( $inputmode ); ?>" aria-labelledby="<?php echo esc_attr( $labelledby ); ?>" /> <input class="plus" type="button" value="+">
Минимальное количество товара из метаполя
Добавляем еще одно метаполе — как это сделать см. выше. Немного меняем функцию формирования количества:
function jk_woocommerce_quantity_input_args( $args, $product ) { $pcs_step = get_post_meta($product->post->ID, "step_text_field", true); $pcs_min = get_post_meta($product->post->ID, "min_text_field", true); //$args['max_value'] = 80; // Maximum value if ( !empty($pcs_step) ) { $args['min_value'] = $pcs_min; } else { $args['min_value'] = 1; } if ( !empty($pcs_step) ) { $args['step'] = $pcs_step; } else { $args['step'] = 1; } return $args; }
И снова нужно доработать скрипты кнопок — и + (если используются), добавив в части минуса захват значения min
var min = parseInt($input.attr('min')); if (val > min) { $input.val( val-step ).change(); }
Вводим десятичность
Глобально уменьшить шаг до десятичных чисел можно таким образом:
// Add min value to the quantity field (default = 1) add_filter('woocommerce_quantity_input_min', 'min_decimal'); function min_decimal($val) { return 0.5; } // Add step value to the quantity field (default = 1) add_filter('woocommerce_quantity_input_step', 'nsk_allow_decimal'); function nsk_allow_decimal($val) { return 0.5; } // Removes the WooCommerce filter, that is validating the quantity to be an int remove_filter('woocommerce_stock_amount', 'intval'); // Add a filter, that validates the quantity to be a float add_filter('woocommerce_stock_amount', 'floatval'); // Add unit price fix when showing the unit price on processed orders add_filter('woocommerce_order_amount_item_total', 'unit_price_fix', 10, 5); function unit_price_fix($price, $order, $item, $inc_tax = false, $round = true) { $qty = (!empty($item['qty']) && $item['qty'] != 0) ? $item['qty'] : 1; if($inc_tax) { $price = ($item['line_total'] + $item['line_tax']) / $qty; } else { $price = $item['line_total'] / $qty; } $price = $round ? round( $price, 2 ) : $price; return $price; }
Но данные функции не работают с предыдущими решениями (функции из предыдущих решений их перекрывают).
Корректно работают с кнопками + и — только нужно изменить преобразование до целого числа на преобразование на число с плавающей точкой, заменив parseInt на parseFloat.
Вывод данных в шаблоне товара
С данными (кратность, минимальное количество) далее можно экспериментировать и выводить данные где угодно. Пример (сайт по продаже ламината):
// Вывод данных по количеству function wc_get_step_size() { global $product; $step_size = get_post_meta($product->post->ID, "_wpbo_step", true); $step_min = get_post_meta($product->post->ID, "_wpbo_minimum", true); $step_unit = get_post_meta($product->post->ID, "unit_text_field", true); $price_pack = $product->get_price() * $step_size; if ( !empty($step_size) ) { echo '
В упаковке ‘.$step_size.’ ‘.$step_unit.’ (‘.$price_pack.’ руб.)
'; } if ( !empty($step_min) ) { echo '
Мин. количество заказа — ‘.$step_min.’ ‘.$step_unit.’
'; } } add_filter( 'woocommerce_single_product_summary', 'wc_get_step_size', 16 );
unit_text_field — это поле из моей функции по созданию единиц измерения товара.
А какие именно скрипты нужно поправить, что бы кнопка минус заработала?
Вот в этой статье есть решение Изменить вид quantity. К нему есть скрипт. Так вот для корректной работы с плагином Quantities and Units for WooCommerce нужно обновить скрипт на тот который я прописал выше.