Created
December 4, 2025 07:33
-
-
Save xlplugins/0a430f43365e08a030611f172b510a0d to your computer and use it in GitHub Desktop.
Custom Quantity Increments for Specific Categories
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| if ( ! class_exists( 'Custom_WooCommerce_Quantity_Handler' ) ) { | |
| /** | |
| * Class Custom_WooCommerce_Quantity_Handler | |
| * | |
| * Handles custom quantity increments for WooCommerce products based on categories. | |
| * Compatible with standard WooCommerce cart and FunnelKit Cart (slide cart). | |
| * | |
| * @since 1.0.0 | |
| */ | |
| class Custom_WooCommerce_Quantity_Handler { | |
| /** | |
| * Categories that should use step of 1 | |
| * @var array | |
| */ | |
| private $special_categories = array( 'big-bags', 'small-bags' ); | |
| /** | |
| * Default step for products not in special categories | |
| * @var float | |
| */ | |
| private $default_step = 0.5; | |
| /** | |
| * Step for products in special categories | |
| * @var int | |
| */ | |
| private $special_step = 1; | |
| /** | |
| * Minimum quantity allowed | |
| * @var int | |
| */ | |
| private $min_quantity = 1; | |
| /** | |
| * Constructor | |
| */ | |
| public function __construct() { | |
| // Set minimum quantity value | |
| add_filter( 'woocommerce_quantity_input_min', array( $this, 'set_min_quantity' ) ); | |
| // Primary filter for FunnelKit Cart compatibility | |
| add_filter( 'woocommerce_quantity_input_step', array( $this, 'set_quantity_step' ), 10, 2 ); | |
| // Secondary filter for standard cart compatibility | |
| add_filter( 'woocommerce_quantity_input_args', array( $this, 'set_quantity_args' ), 10, 2 ); | |
| // Apply same logic in cart page | |
| add_filter( 'woocommerce_cart_item_quantity', array( $this, 'set_cart_item_quantity' ), 10, 3 ); | |
| // Enable float quantities | |
| $this->enable_float_quantities(); | |
| // Fix unit price calculation in orders | |
| add_filter( 'woocommerce_order_amount_item_total', array( $this, 'fix_unit_price' ), 10, 5 ); | |
| } | |
| /** | |
| * Set minimum quantity | |
| * | |
| * @param int $val Current minimum value | |
| * @return int Minimum quantity | |
| */ | |
| public function set_min_quantity( $val ) { | |
| return $this->min_quantity; | |
| } | |
| /** | |
| * Determine step value based on product category | |
| * | |
| * @param WC_Product|null $product Product object | |
| * @return float Step value | |
| */ | |
| private function get_quantity_step( $product ) { | |
| if ( ! $product ) { | |
| return $this->default_step; | |
| } | |
| $product_id = $product->get_id(); | |
| // For variations, get the parent product ID | |
| if ( $product->is_type( 'variation' ) ) { | |
| $product_id = $product->get_parent_id(); | |
| } | |
| // Check if product is in special categories | |
| if ( has_term( $this->special_categories, 'product_cat', $product_id ) ) { | |
| return $this->special_step; | |
| } | |
| return $this->default_step; | |
| } | |
| /** | |
| * Set quantity step (Primary filter for FunnelKit Cart) | |
| * | |
| * @param float $val Current step value | |
| * @param WC_Product $product Product object | |
| * @return float Step value | |
| */ | |
| public function set_quantity_step( $val, $product ) { | |
| return $this->get_quantity_step( $product ); | |
| } | |
| /** | |
| * Set quantity args (Secondary filter for standard cart) | |
| * | |
| * @param array $args Quantity input arguments | |
| * @param WC_Product $product Product object | |
| * @return array Modified arguments | |
| */ | |
| public function set_quantity_args( $args, $product ) { | |
| $args['step'] = $this->get_quantity_step( $product ); | |
| return $args; | |
| } | |
| /** | |
| * Set cart item quantity display | |
| * | |
| * @param string $product_quantity HTML for quantity input | |
| * @param string $cart_item_key Cart item key | |
| * @param array $cart_item Cart item data | |
| * @return string Modified HTML | |
| */ | |
| public function set_cart_item_quantity( $product_quantity, $cart_item_key, $cart_item ) { | |
| $product = $cart_item['data']; | |
| $step = $this->get_quantity_step( $product ); | |
| $product_quantity = woocommerce_quantity_input( array( | |
| 'input_name' => "cart[{$cart_item_key}][qty]", | |
| 'input_value' => $cart_item['quantity'], | |
| 'max_value' => $product->get_max_purchase_quantity(), | |
| 'min_value' => $this->min_quantity, | |
| 'step' => $step, | |
| ), $product, false ); | |
| return $product_quantity; | |
| } | |
| /** | |
| * Enable float quantities in WooCommerce | |
| */ | |
| private function enable_float_quantities() { | |
| // Remove the WooCommerce filter that validates quantity as int | |
| remove_filter( 'woocommerce_stock_amount', 'intval' ); | |
| // Add a filter that validates quantity as float | |
| add_filter( 'woocommerce_stock_amount', 'floatval' ); | |
| } | |
| /** | |
| * Fix unit price calculation when showing on processed orders | |
| * | |
| * @param float $price Current price | |
| * @param WC_Order $order Order object | |
| * @param WC_Order_Item $item Order item | |
| * @param bool $inc_tax Include tax | |
| * @param bool $round Round the price | |
| * @return float Fixed unit price | |
| */ | |
| public function fix_unit_price( $price, $order, $item, $inc_tax = false, $round = true ) { | |
| $total_price = 0; | |
| $total_qty = 0; | |
| foreach ( $order->get_items() as $order_item_id => $order_item ) { | |
| $qty = $order_item->get_quantity(); | |
| $total_qty += $qty; | |
| $total_price += $order_item->get_total(); | |
| } | |
| if ( $total_qty > 0 ) { | |
| if ( $inc_tax ) { | |
| $price = ( $total_price + $order->get_total_tax() ) / $total_qty; | |
| } else { | |
| $price = $total_price / $total_qty; | |
| } | |
| } | |
| $price = $round ? round( $price, 2 ) : $price; | |
| return $price; | |
| } | |
| } | |
| // Initialize the class | |
| new Custom_WooCommerce_Quantity_Handler(); | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment