How to Setup Minimum Order Quantity in WooCommerce (Without Plugins)

Adding a Minimum Order Quantity (MOQ) is a great way to control how much of a product your customers must buy. For example, if you’re running a wholesale store or want to offer bulk discounts, MOQ is a must-have feature.
In this tutorial, we’ll show you how to set up Minimum and Maximum Order Quantities in WooCommerce without installing any plugins. We’ll use a bit of custom code to achieve this. It’s beginner-friendly and easy to follow.
Why Use Minimum Order Quantity?
Here are some common reasons to add an MOQ:
- Avoid selling low-quantity products that aren’t profitable
- Encourage bulk purchases
- Control inventory better
- Set minimum order rules for wholesale buyers
Setup WooCommerce Minimum Order Quantity
In this step, we add two custom fields in the product settings: one for minimum quantity and one for maximum quantity.
- These fields appear under the Inventory tab of the WooCommerce product editor.
- Store owners can define how many units a customer must buy (minimum) or cannot exceed (maximum).
// Add custom fields in the Product Data panel add_action('woocommerce_product_options_inventory_product_data', 'add_custom_qty_limits_fields'); function add_custom_qty_limits_fields() { woocommerce_wp_text_input([ 'id' => '_min_qty', 'label' => __('Minimum Quantity', 'woocommerce'), 'type' => 'number', 'desc_tip' => true, 'description' => __('Set the minimum quantity allowed for this product'), 'custom_attributes' => ['min' => '1'] ]); woocommerce_wp_text_input([ 'id' => '_max_qty', 'label' => __('Maximum Quantity', 'woocommerce'), 'type' => 'number', 'desc_tip' => true, 'description' => __('Set the maximum quantity allowed for this product'), 'custom_attributes' => ['min' => '1'] ]); } // Save the custom fields when product is saved add_action('woocommerce_process_product_meta', 'save_custom_qty_limits_fields'); function save_custom_qty_limits_fields($post_id) { if (isset($_POST['_min_qty'])) { update_post_meta($post_id, '_min_qty', sanitize_text_field($_POST['_min_qty'])); } if (isset($_POST['_max_qty'])) { update_post_meta($post_id, '_max_qty', sanitize_text_field($_POST['_max_qty'])); } } // Validate min/max quantity limits in cart add_action('woocommerce_check_cart_items', 'validate_custom_qty_limits_in_cart'); function validate_custom_qty_limits_in_cart() { foreach (WC()->cart->get_cart() as $cart_item) { $product = $cart_item['data']; $product_id = $cart_item['product_id']; $quantity = $cart_item['quantity']; $product_name = $product->get_name(); $min = get_post_meta($product_id, '_min_qty', true); $max = get_post_meta($product_id, '_max_qty', true); if ($min && $quantity < $min) { wc_add_notice(sprintf(__('You must order at least %s of "%s".', 'woocommerce'), $min, $product_name), 'error'); } if ($max && $quantity > $max) { wc_add_notice(sprintf(__('You cannot order more than %s of "%s".', 'woocommerce'), $max, $product_name), 'error'); } } } add_action('woocommerce_before_add_to_cart_button', 'add_qty_validation_script_with_message'); function add_qty_validation_script_with_message() { global $product; $min_qty = get_post_meta($product->get_id(), '_min_qty', true); $max_qty = get_post_meta($product->get_id(), '_max_qty', true); if (!$min_qty && !$max_qty) return; ?> <style> .custom-qty-warning { color: #d9534f; font-size: 14px; margin-top: 10px; margin-bottom: 20px; display: none; border: 1px solid #f5c6cb; background-color: #f8d7da; padding: 10px; border-radius: 5px; } </style> <div class="custom-qty-warning" id="custom-qty-warning"></div> <script> document.addEventListener('DOMContentLoaded', function () { const form = document.querySelector('form.cart'); const qtyInput = form.querySelector('input.qty'); const warningBox = document.getElementById('custom-qty-warning'); form.addEventListener('submit', function (e) { const quantity = parseInt(qtyInput.value); let error = ''; <?php if ($min_qty): ?> if (quantity < <?php echo esc_js($min_qty); ?>) { error = "Minimum quantity for this product is <?php echo esc_js($min_qty); ?>."; } <?php endif; ?> <?php if ($max_qty): ?> if (quantity > <?php echo esc_js($max_qty); ?>) { error = "Maximum quantity for this product is <?php echo esc_js($max_qty); ?>."; } <?php endif; ?> if (error) { e.preventDefault(); warningBox.textContent = error; warningBox.style.display = 'block'; } else { warningBox.style.display = 'none'; } }); // Hide warning when quantity input changes qtyInput.addEventListener('input', function () { warningBox.style.display = 'none'; }); }); </script> <?php }
💡 Why it’s useful: You get full flexibility to set quantity limits per product without installing a plugin.
Show “Minimum Order Quantity” Label on the Product Page
After setting a minimum quantity, it’s a good idea to show this info to the customer directly on the product page.
This helps reduce confusion and lets shoppers know how many items they need to add before clicking “Add to Cart.”
A small label is displayed like: 🛒 Minimum Order: 3
add_action('woocommerce_single_product_summary', 'show_min_qty_label_on_product_page', 25); function show_min_qty_label_on_product_page() { global $product; $min_qty = get_post_meta($product->get_id(), '_min_qty', true); if (!empty($min_qty)) { echo '<p class="min-qty-label" style="font-size: 14px; color: #555; margin-top: 10px;">🛒 Minimum Order: <strong>' . esc_html($min_qty) . '</strong></p>'; } }
Show “Minimum Order Quantity” Label on Archive Pages (Shop, Category)
Want to show the same info on your shop, category, or tag pages?
This step displays the minimum quantity label on all product cards in archive views. Helps shoppers get the info even before clicking on the product.
add_action('woocommerce_after_shop_loop_item_title', 'show_min_qty_label_on_archive_page', 15); function show_min_qty_label_on_archive_page() { global $product; $min_qty = get_post_meta($product->get_id(), '_min_qty', true); if (!empty($min_qty)) { echo '<p class="min-qty-label" style="font-size: 13px; color: #777; margin-top: 5px; display: flex; gap: 5px;">Minimum Order: <strong>' . esc_html($min_qty) . '</strong></p>'; } }
Optional: Set HTML Min/Max Attributes on Quantity Field
This step adds the min and max HTML attributes to the quantity input box.
This means the + and – buttons in the quantity field will stop at the right limits. User won’t be able to select quantity below the set limit or above the max limit.
add_filter('woocommerce_quantity_input_args', 'set_html_min_max_qty_input', 10, 2); function set_html_min_max_qty_input($args, $product) { $min = get_post_meta($product->get_id(), '_min_qty', true); $max = get_post_meta($product->get_id(), '_max_qty', true); if ($min) $args['min_value'] = (int) $min; if ($max) $args['max_value'] = (int) $max; return $args; }
Set Minimum Order Quantity in Cart
It ensures users must buy at least X total items across all products to place an order (Default value is 2 ). Great for wholesale stores or B2B sites.
add_action('woocommerce_check_cart_items', 'custom_minimum_order_quantity'); function custom_minimum_order_quantity() { $min_qty = 2; // Set your minimum quantity $total_qty = 0; foreach (WC()->cart->get_cart() as $cart_item) { $total_qty += $cart_item['quantity']; } if ($total_qty < $min_qty) { wc_add_notice( sprintf('You must order at least %d items to proceed to checkout. You currently have %d.', $min_qty, $total_qty), 'error' ); } }
Video Tutorial
Conclusion
Setting up a Minimum Order Quantity in WooCommerce without using plugins is a smart way to control your product sales and ensure better profit margins — all while keeping your site lightweight and fast.
This solution gives you full control without bloating your site with unnecessary plugins. Try implementing it today and enhance your WooCommerce store’s functionality like a pro!
If you found this tutorial helpful, feel free to share it or leave a comment below 👇