WooCommerce: "one per order" vs "one per customer"
These two phrases get used interchangeably, and that confusion costs store owners real money on launch day. They are not the same rule, and WooCommerce only enforces one of them out of the box. This post draws the line clearly, then shows how to enforce whichever one you actually need.
The one-sentence difference
One per order limits a single transaction. One per customer limits a person, forever, no matter how many transactions they spread it across.
If your goal is "nobody hoards my limited drop," you want one per customer. Sold individually will not get you there — a buyer simply checks out, then opens a new cart and checks out again.
Side by side
| One per order | One per customer | |
|---|---|---|
| Scope | A single cart / checkout | Every order the customer ever places |
| Stops a second order? | No | Yes |
| In WooCommerce core? | Yes — "Sold individually" | No |
| Covers guests? | N/A (per cart) | Only if matched by billing email at checkout |
| Good for | Stopping accidental bulk-add | Fair limited drops, one-per-person products, memberships |
How to enforce "one per order" (the easy one)
This is built in. Edit the product, open the Inventory tab, and tick Sold individually. The customer can now only have one of that item in their cart at a time. Done — no plugin needed.
If you need "max 3 per order" rather than exactly one, that's the official Min/Max Quantities extension. Still per-order scope.
How to enforce "one per customer" (the one people actually want)
Because core has no concept of a lifetime limit, you have to look at the customer's history. The logic is always the same three steps:
- Identify the customer. Logged in → user ID. Guest → the billing email they enter at checkout.
- Count what they've already bought of this product across past orders in the statuses you count (typically
completed,processing,on-hold). - Block before the order is created if prior purchases + what's in the cart would exceed the limit.
The detail that trips people up: you must validate at checkout, not just add-to-cart. Guests are anonymous until they type their email, so an add-to-cart-only check can't see them. And the block has to land before the order and payment go through — blocking after you've charged the card is worse than not blocking at all.
DropLock does the "one per customer" part for you
One toggle per product enforces a true lifetime limit — at add-to-cart, cart update, and checkout. Guests matched by billing email, variations rolled up to the parent, HPOS and Block Checkout supported, admin bypass built in. 14-day refund.
See pricing — from $49"One per customer" has its own sub-flavors
Once you're enforcing per-customer limits, you'll hit a few finer questions. Quick guide:
- One per customer, all variations count as the same product — buying "Red" uses up the allowance for "Blue" too. This is the default and what most drops want. DropLock rolls variations up to the parent automatically.
- One per customer, per variation — each color/size gets its own quota. That's a per-variation limit (a DropLock Pro feature).
- One per customer across a whole category — e.g. "one item from the Drops category, period." That's a category-level rule (DropLock Pro).
- Limit only while on sale — unlimited normally, capped during a discount so a flash sale isn't drained by one buyer (DropLock Pro).
Which one do you need?
- "Stop people putting 10 in the cart" → one per order (Sold individually, free, built in).
- "Everyone gets exactly one, no matter how many times they come back" → one per customer (lifetime limit — plugin or code).
- "It's a guest-heavy store and people re-order with the same email" → one per customer with email matching at checkout.
If it's the first one, you're already done with core. If it's the second or third, that's exactly the gap DropLock was built to close.
Enforce a real one-per-customer limit on your next drop
Lifetime per-customer limits with guest matching, in minutes. HPOS and Block Checkout ready. 14-day refund, no questions asked.
Get DropLock — from $49