Want personalized guidance adding this to your store?
Check out our Insiders community: https://www.skool.com/the-prompted
Members of The Prompted community receive a detailed store audit, 1-on-1 guidance for implementing new features, and access to an exclusive theme. You'll also get marketing support, the same tactics we use to spend over $100k/mo on Meta Ads.
---
In this tutorial, we’re adding a feature that lets you set minimum and maximum quantities for products on your Shopify store. Whether it’s for special promotions or limited-edition items, this customization helps you control how much customers can add to their carts. Best of all, we’ll show you how to implement it for free—no app or developer needed.
Compatible Themes: This code should work on all free Shopify themes (Dawn, Refresh, Craft, Studio, Publisher, Crave, Origin, Taste, Colorblock, Sense, Ride, Spotlight).
Create metaobject and metafields
- Create Quantity Rule metaobject with fields:
- name
- Type: single line text
- Required
- increment
- Type: integeter
- Required
- min value 1
- min
- Type: integer
- required
- min value 1
- max
- Type: integer
- Min value 1
- name
- Create Product Metafield
- Name: Quantity Rule
- Type: Metaobject (Quantity Rule)
- Create Variant Metafield
- Name: Quantity Rule
- Type: Metaobject (Quantity Rule)
- Create metaobject entries for each set of rules
- Create Product Metafield
- Name: Quantity Rule Type Override
- Type: Single Line Text
- Limit to preset choices:
- Product Rules
- Variant Rules
Edit Theme Code
Edit settings_schema.json
{
"name": "Custom Quantity Rules",
"settings": [
{
"type": "checkbox",
"id": "use_quantity_rules",
"label": "Enable custom quantity rules",
"default": false
},
{
"type": "select",
"id": "qty_rule_type",
"options": [
{
"value": "product_rule",
"label": "Product Rules"
},
{
"value": "variant_rule",
"label": "Variant Rules"
}
],
"label": "Quantity Rule Type",
"info": "Specify whether quantity rules are applied at the product level or variant level",
"default": "variant_rule"
}
]
}
Edit main-cart-items.liquid and cart-drawer.liquid
- Replace
item.variant.quantity_rule
withquantity_rule
- Add the following code:
{%- if settings.use_quantity_rules -%} {% if item.product.metafields.custom.quantity_rule_type_override == "Product Rules" %} {% assign quantity_rule_type = "product_rule" %} {% elsif item.product.metafields.custom.quantity_rule_type_override == "Variant Rules" %} {% assign quantity_rule_type = "variant_rule" %} {% elsif settings.qty_rule_type == "product_rule" %} {% assign quantity_rule_type = "product_rule" %} {% elsif settings.qty_rule_type == "variant_rule" %} {% assign quantity_rule_type = "variant_rule" %} {% endif %} {% if quantity_rule_type == "product_rule" %} {% assign quantity_rule = item.product.metafields.custom.quantity_rule.value %} {% assign total_product_quantity = 0 %} {% assign global_max = item.product.metafields.custom.quantity_rule.value.max | plus: 0 %} {% for cart_item in cart.items %} {% if cart_item.product.id == item.product.id %} {% assign total_product_quantity = total_product_quantity | plus: cart_item.quantity %} {% endif %} {% endfor %} {% assign item_remaining_qty = global_max | minus: total_product_quantity %} {% assign max_for_variant = item.quantity | plus: item_remaining_qty %} {% if max_for_variant > global_max %} {% assign max_for_variant = global_max %} {% endif %} {% elsif quantity_rule_type == "variant_rule" %} {% assign quantity_rule = item.variant.metafields.custom.quantity_rule.value %} {% endif %} {% if quantity_rule == nil %} {% assign quantity_rule = item.variant.quantity_rule %} {% endif %} {% else %} {% assign quantity_rule = item.variant.quantity_rule %} {% endif %}
- Replace the input max
max="{{ quantity_rule.max }}”
with:{% if quantity_rule_type == "product_rule"%} max="{{ max_for_variant }}" {% else %} max="{{ quantity_rule.max }}" {% endif %}
Edit main-product.liquid
- Replace
product.selected_or_first_available_variant.quantity_rule
withquantity_rule
- Add the following code:
{% if settings.use_quantity_rules %} {% if product.metafields.custom.quantity_rule_type_override == "Product Rules" %} {% assign quantity_rule_type = "product_rule" %} {% elsif product.metafields.custom.quantity_rule_type_override == "Variant Rules" %} {% assign quantity_rule_type = "variant_rule" %} {% elsif settings.qty_rule_type == "product_rule" %} {% assign quantity_rule_type = "product_rule" %} {% elsif settings.qty_rule_type == "variant_rule" %} {% assign quantity_rule_type = "variant_rule" %} {% endif %} {% if quantity_rule_type == "product_rule" %} {% assign quantity_rule = product.metafields.custom.quantity_rule.value %} {% elsif quantity_rule_type == "variant_rule" %} {% assign quantity_rule = product.selected_or_first_available_variant.metafields.custom.quantity_rule.value %} {% endif %} {% if quantity_rule == nil %} {% assign quantity_rule = product.selected_or_first_available_variant.quantity_rule %} {% endif %} {% else %} {% assign quantity_rule = product.selected_or_first_available_variant.quantity_rule %} {% endif %} {% if settings.use_quantity_rules and quantity_rule_type == "product_rule" %} {% assign cart_qty = 0 %} {% for item in cart.items %} {% if item.product.id == product.id %} {% assign cart_qty = cart_qty | plus: item.quantity %} {% endif %} {% endfor %} {% else %} ... existing cart_qty assignment... {% endif %}
Edit product-info.js
Add new method
updateQuantitySelector(html) {
const newQuantitySelectorContainer = html.querySelector('#Quantity-Form-' + this.sectionId);
const currentQuantitySelectorContainer = document.querySelector('#Quantity-Form-' + this.dataset.section);
if (newQuantitySelectorContainer && currentQuantitySelectorContainer) {
const newContent = newQuantitySelectorContainer.innerHTML.trim();
if (newContent === '') {
return;
}
currentQuantitySelectorContainer.innerHTML = newContent;
this.quantityInput = currentQuantitySelectorContainer.querySelector('.quantity__input');
this.initQuantityHandlers();
}
}
Call new method and comment out this.updateQuantityRules(this.sectionId, html);
in method handleUpdateProductInfo
this.updateQuantitySelector(html);
//this.updateQuantityRules(this.sectionId, html);
Edit quantity-popover.js
In method togglePopover
, replace this.infoButtonDesktop.classList.add
with button.classList.add
button.classList.add('quantity-popover__info-button--icon-only--animation');
In method closePopover
, reorder const button
definition so that it’s above the const isButtonChild
definition, and replace this.infoButtonDesktop.contains
with button.contains
const button = this.infoButtonDesktop && this.mql.matches ? this.infoButtonDesktop : this.infoButtonMobile;
const isButtonChild = button.contains(event.relatedTarget);
const isPopoverChild = this.popoverInfo.contains(event.relatedTarget);
In method closePopover
, replace this.infoButtonDesktop.classList.remove
with button.classList.remove
button.classList.remove('quantity-popover__info-button--icon-only--animation');