Controller
The Controller is your store’s rulebook for what codes and gift cards are allowed to do at checkout. It applies to everything — codes you created in PromoLock, codes made in the Shopify admin, and codes generated by other apps. If a code is typed into your checkout, the Controller has a say.
It has three layers, top to bottom on the page: Quick controls for the common cases, Rule variables (the tags and collections your rules can reference), and Custom rules for everything else.
Nothing takes effect while you’re editing — a save bar appears as soon as you change something, and your changes go live the moment you hit Save.
Quick controls
Section titled “Quick controls”Quick controls are one-switch locks. Each one is a card with a switch — turn it on, adjust its options, save. They’re split into two tabs: Discount Code and Gift Card.
Discount Code tab
Section titled “Discount Code tab”Discount Lock
Section titled “Discount Lock”Blocks discount codes at checkout. The Mode select decides how strict:
| Mode | What it does | Use it when |
|---|---|---|
| Block all codes | No discount code works at all. | Sale events where codes shouldn’t apply, or an emergency shut-off. |
| Block all codes except | Only the codes you list under Allowed codes still work. | You run a tight ship — a few official codes, nothing else. |
| Block only these codes | Everything works except the codes you list under Blocked codes. | A code leaked to a coupon site and needs to die today. |
The code lists accept patterns, so “block everything that starts with SUMMER” is one entry, not fifty.
Discount Stacking Lock
Section titled “Discount Stacking Lock”Stops customers from combining multiple discount codes on one order. When two or more codes land in a checkout, the first one is kept and the extras are rejected with your message.
Stacking exceptions is a list of codes that live outside the limit: an exception code always applies, and it doesn’t count toward the limit — so a customer can use your free-shipping code alongside a regular discount if that’s the combination you actually want.
Lock Discount Usage On Sale Items
Section titled “Lock Discount Usage On Sale Items”Stops discount codes from being used on carts that contain marked-down products — the classic double-dip. A product counts as “on sale” when its current price is below its compare-at price.
The Trigger select has two modes:
| Trigger | What it does |
|---|---|
| Block if cart has any sale item | One sale item anywhere in the cart blocks all codes. The strictest option. |
| Block when sale items exceed % of cart total | Codes are blocked only once sale items make up more than your Threshold (%) of the cart’s value. |
The threshold is measured in money, not item count: with a threshold of 50, a customer whose cart is $60 regular-priced and $40 sale items can still use a code (40% of cart value is on sale); tip the balance past half and codes stop working. This mode lets bundled carts through while still blocking pure sale-hauls.
Gift Card tab
Section titled “Gift Card tab”| Lock | What it does |
|---|---|
| Gift Card Lock | Blocks gift cards as a payment method entirely. |
| Gift Card Stacking Lock (Shopify Plus) | Only one gift card can be applied per order. |
| Gift Card & Discount Stacking Lock | A discount code and a gift card can’t be used on the same order — closes the “discounted purchase paid with a discounted-purchase gift card” loop. |
Code patterns
Section titled “Code patterns”Every code list in PromoLock — allowed, blocked, exceptions, rule triggers — accepts patterns, not just exact codes. The # symbol is the wildcard:
| You type | It matches |
|---|---|
WELCOME10 |
Exactly WELCOME10, nothing else. |
VIP# |
Any code starting with VIP — VIP2026 ✓, VIPGOLD ✓, MYVIP ✗ |
#2026 |
Any code ending with 2026 — SALE2026 ✓, 2026SALE ✗ |
#SAVE# |
Any code containing SAVE — BIGSAVE50 ✓, WEEKLYSAVE ✓ |
Matching ignores upper/lowercase. Inside any code field, the expand button opens a bigger editor that labels each entry (“Starts with:”, “Contains:”) so you can see how it will be read.
Error messages
Section titled “Error messages”Every lock and every block rule can carry its own error message (up to 75 characters) — this is what the customer sees on the discount field when their code is rejected. Leave it blank and a sensible default is used, like “This code is not valid at this time.”
If your store sells in multiple languages, the translate button next to the field opens a Localization editor — one message per language, with your default language used as the fallback.
Rule variables
Section titled “Rule variables”Before custom rules can reference your tags or collections, you register them here — three tiles: Customer tags, Product tags, and Collections, each holding up to 10 values. Rules then pick from these lists rather than free-typing, which keeps typos from silently breaking a rule.
If a condition like “Customer tag” shows no options, this is why — add the tag as a variable first.
Custom rules
Section titled “Custom rules”When a quick lock is too blunt, write a rule. Rules live in a list — each with an on/off switch, a Block/Allow badge, and a one-line summary — and you can keep a rule in the list but disabled while you think it over.
A rule has four parts, in the order the editor shows them:
Name. Optional, for your own sanity in the list.
Action. Block (with your custom error message) or Allow. Allow rules are exceptions — they punch holes through your other rules (see which rule wins).
Trigger — which codes the rule watches.
- All codes — optionally minus an Except list.
- Specific codes — only the codes/patterns you list.
Conditions — when the rule applies. Add as many as you need; all of them must be true for the rule to fire. A rule with no conditions always applies to its triggered codes.
| Condition | Checks | Operators |
|---|---|---|
| Cart subtotal | The cart’s subtotal | Greater than / Less than / Equals |
| Product in cart | Specific products (picked from your catalog) | Has any of / Has all of / Has none of |
| Product from collection | Products from a Collections variable | Has any of / Has all of / Has none of |
| Product with tag | Products carrying a Product tags variable | Has any of / Has all of / Has none of |
| Cart has sale item | Whether any cart item is marked down | Is true / Is false |
| Customer is logged in | Guest vs. signed-in checkout | Is true / Is false |
| Customer is new | The signed-in customer has zero past orders | Is true / Is false |
| Customer tag | Tags on the customer (from a Customer tags variable) | Has any of / Has all of / Has none of |
| Discount code count | How many codes are on the order, with an optional “don’t count these” list | Greater than / Equals / Less than |
Which rule wins
Section titled “Which rule wins”Three things to remember about ordering:
- Rules run top to bottom, and a later rule wins. If rule 1 blocks
VIP#and rule 3 allowsVIPGOLD,VIPGOLDgets through. Put your exceptions below the broad rules they carve out of. - Quick controls always have the last word. They run after all custom rules — an Allow rule can’t override Discount Lock, the stacking lock, or the sale-items lock. Exceptions to a quick control go in that control’s own exception/allowed list.
- A disabled rule does nothing — it’s saved, but skipped.
