Minimum Quantity Enforcement
The PromoSync Pricing Engine embed block is shared with Volume Pricing. If you already enabled it for tier pricing, minimum quantity enforcement is included. Just verify the checkbox is on.
PromoSync stores a per-product minimum order quantity in the psrestful.minimum_quantity metafield (populated during supplier import) and enforces it in three places, with zero theme code changes:
| Where | How | Works on |
|---|---|---|
| Product page | Pricing Engine embed keeps the quantity input at or above the minimum | Dawn-compatible themes |
| Cart page and cart drawer | Pricing Engine embed raises a lowered quantity back to what the product needs | Dawn-compatible themes |
| Checkout | Minimum Order Quantity checkout rule blocks checkout below the minimum | Any theme, including express checkouts (Shop Pay, PayPal, Apple Pay, Google Pay) |
The product page and cart run in the shopper’s browser and give immediate feedback. The checkout rule runs on Shopify’s servers, so it can’t be bypassed by a theme that our scripts don’t recognize, a custom cart, or direct Storefront API calls.
How It Works
1. Product page (Embed Block)
The PromoSync Pricing Engine embed block (target: "body") injects a <script type="application/json" data-promo-min-quantity> tag on product pages with the minimum quantity and product ID. MinQuantityHandler in promo-pricing.js then:
- Sets the HTML5
minattribute anddata-minon quantity inputs - Sets the initial value to the minimum if it’s currently below
- Adds
changeandblurlisteners that snap typed values back to the minimum (0 is allowed for themes that use 0 as a reset) - Calls
validateQtyRules()on Dawn’s<quantity-input>custom element if available (updates +/- button states) - Uses a
MutationObserverto re-apply after Section Rendering API re-renders (e.g., variant changes)
2. Cart page and cart drawer (Embed Block)
On every page, the embed also outputs <script type="application/json" data-promo-cart-min-quantities>: the minimum and product ID for each item already in the cart, keyed by variant ID. CartMinQuantityHandler listens for quantity changes in the capture phase, so it adjusts the value before the theme’s own handler sends the cart update:
- The minimum applies to the product’s total across its variants, so a line is only raised as far as the product still needs (60 red + 40 blue meets a minimum of 100)
- Setting a line to 0 removes it, as usual
- Items added to the cart without a page reload (for example through an AJAX add-to-cart) are picked up after the next page load; the checkout rule covers them in the meantime
3. Checkout rule (Shopify Function)
The Minimum Order Quantity checkout rule is a Cart and Checkout Validation function shipped with PromoSync. When the buyer is in checkout, it totals each product’s quantity across its variants and, for any product below its psrestful.minimum_quantity, blocks checkout with a message such as:
Kelly Bottle has a minimum order of 100 units. Your cart has 40.
It only blocks during checkout, not while the cart is being edited, so a buyer can build a mixed-color order one variant at a time.
4. Minimum Quantity Notice (App Block)
The Min Quantity Notice app block (target: "section") renders a styled notice: “Minimum order: N units”. Merchants drag it into any product page section via Theme Customizer.
Samples and single units. The checkout rule only knows psrestful.minimum_quantity. If your store sells samples or single units of products that have a minimum (for example through a custom theme flow), the rule will block those orders too. Leave the checkout rule off in that case and contact us.
Setup Instructions
Step 1: Enable the Embed Block
- Go to Online Store > Themes > Customize
- Click App embeds (left sidebar, puzzle piece icon)
- Toggle PromoSync Pricing Engine to ON (if not already enabled for tier pricing)
- The “Enforce minimum order quantity” checkbox is ON by default
Quantity inputs on product pages, the cart page, and the cart drawer now respect the minimum.
Step 2: Turn On the Checkout Rule
- In your Shopify admin, go to Settings > Checkout
- Find the Checkout rules section and add Minimum Order Quantity (PromoSync)
- Turn the rule on and save
The checkout rule is what guarantees the minimum on every theme. Steps 1 and 3 improve the shopping experience, but only this step stops an under-minimum order from being placed.
Step 3 (Optional): Add the Notice Block
To show a visible “Minimum order: N units” message on product pages:
- In Theme Customizer, navigate to a product page template
- Click Add block in the product section
- Select Min Quantity Notice (under the PromoSync app)
- Drag it to your preferred position (e.g., below the quantity selector)
- Save
The notice only renders on products that have a psrestful.minimum_quantity metafield with a value greater than 0.
Settings Reference
PromoSync Pricing Engine (Embed Block)
| Setting | Default | Description |
|---|---|---|
| Enforce minimum order quantity | ON | Keep quantities at or above psrestful.minimum_quantity on product pages, the cart page and the cart drawer |
Minimum Order Quantity (Checkout Rule)
No settings. Turn it on or off under Settings > Checkout > Checkout rules. It reads psrestful.minimum_quantity from each product in the cart.
Min Quantity Notice (App Block)
No additional settings. The block reads psrestful.minimum_quantity directly and uses the promo.min_quantity.notice translation key.
Behavior Details
Product page
| Scenario | Behavior |
|---|---|
| Page load (min=5) | Quantity input starts at 5, min attribute set to 5 |
| User types “2”, tabs away | Value snaps back to 5 |
| User clicks minus button | Stops at 5 (Dawn’s built-in stepDown() respects min) |
| User types “0” | Allowed (some themes use 0 as remove/reset) |
| User types “10” | Allowed (above minimum) |
| Variant changes re-render form | MutationObserver re-applies enforcement |
| Product has no minimum metafield | No enforcement, quantity input behaves normally |
| Minimum is 0 or 1 | No enforcement (minimum of 1 is the default) |
Cart page and cart drawer
| Scenario (min=100) | Behavior |
|---|---|
| One line, changed from 100 to 40 | Raised back to 100 before the cart updates |
| Red 60 + Blue 40, red changed to 50 | Red raised to 60 (blue already covers 40) |
| Red 60 + Blue 40, red changed to 70 | Allowed |
| Line set to 0 | Line is removed |
| Product has no minimum metafield | No change |
Checkout
| Scenario (min=100) | Behavior |
|---|---|
| 40 units of one variant | Checkout blocked: ”… has a minimum order of 100 units. Your cart has 40.” |
| 60 + 40 units of two variants of the same product | Allowed |
| Two products below their minimums | One message per product |
| Product has no minimum, or a minimum of 0 or 1 | Allowed |
| Buyer is editing the cart (not in checkout yet) | Not blocked |
Supported quantity input selectors
The browser-side handlers find inputs via these selectors, covering Dawn and compatible themes. On themes with different markup, the checkout rule still enforces the minimum.
/* Product page */
product-info quantity-input input.quantity__input
.product-form quantity-input input.quantity__input
form[action*="/cart/add"] input[name="quantity"]
/* Cart page and cart drawer (variant read from data-quantity-variant-id or the line's data-promo-variant-id) */
input[name="updates[]"]
cart-items input.quantity__input
cart-drawer-items input.quantity__inputMetafield Reference
| Metafield | Namespace | Key | Type | Set By |
|---|---|---|---|---|
| Minimum quantity | psrestful | minimum_quantity | number_integer | PromoSync product import |
The metafield is populated automatically when products are imported from PromoStandards suppliers. No manual setup is required.
Files Involved
| File | Type | Purpose |
|---|---|---|
blocks/promo-pricing-engine.liquid | Embed block | Serializes min quantity JSON on product pages and cart minimums on every page |
assets/promo-pricing.js | JavaScript | MinQuantityHandler (product page) and CartMinQuantityHandler (cart page and drawer) |
blocks/min-quantity-notice.liquid | App block | Drag-and-drop “Minimum order: N units” notice |
assets/promo-pricing.css | Stylesheet | .promo-min-quantity styles |
snippets/min-quantity.liquid | Snippet | Legacy snippet, kept for backward compatibility |
locales/en.default.json | Translations | promo.min_quantity.notice key |
extensions/minimum-quantity-validation | Shopify Function | The Minimum Order Quantity checkout rule (cart.validations.generate.run) |
Customization
CSS
Override the notice styles using CSS custom properties:
:root {
--promo-bg-alt: #f0f0f0; /* Notice background */
--promo-primary: #2c6ecb; /* Left border color */
--promo-text: #1a1a1a; /* Text color */
--promo-font-size-sm: 0.8125rem; /* Font size */
--promo-spacing-sm: 0.5rem; /* Padding */
--promo-radius-sm: 0.25rem; /* Border radius */
}Translations
Edit locales/en.default.json to customize the notice text:
{
"promo": {
"min_quantity": {
"notice": "Minimum order: {{ quantity }} units",
"notice_short": "Min: {{ quantity }}"
}
}
}Verification Checklist
- Open a product page with
psrestful.minimum_quantityset (e.g., min=5) - Quantity input starts at 5, not 1, and
min/data-minare set to 5 - Type “2” in the input, tab away: it snaps back to 5
- Click minus button: it stops at 5
- Change variant: enforcement is still active after re-render
- Add “Min Quantity Notice” block via Theme Customizer: it renders correctly
- Open a product with no minimum quantity metafield: no enforcement, no notice
- Add a product with a minimum to the cart, open the cart page, change the quantity below the minimum: it goes back up to the minimum
- With the checkout rule on, open
/cart/<variant_id>:<below minimum>and continue to checkout: checkout is blocked with the minimum order message - Add two variants of the same product that together meet the minimum: checkout is allowed
Migrating from Theme-Level Enforcement
If you previously added minimum quantity enforcement directly in your theme code, you can safely remove:
enforceMinimum()fromglobal.jsorQuantityInputclass overridessetQuantityBoundries()/data-minlogic fromproduct-info.js- Metafield reads and
min/data-min/valueattributes frommain-product.liquid data-minplumbing from cart drawer/page templates
The app extension handles all of this automatically.