WooCommerce coupon stacking

Promotion conflicts should have a plan, not an accident.

When several eligible coupons want the same cart, PerkRule resolves explicit priority and stacking rules before it starts changing the live WooCommerce cart.

PRIORITY

Stable ordering with deterministic ties.

Higher explicit priority wins. Equal priority resolves predictably using stable coupon identity rather than whatever traversal order happened to occur.

EXPLICIT PRIORITY

Higher configured priority wins, and equal priority still has a deterministic answer.

PerkRule bounds priority to a known integer range and treats missing priority as zero. When two eligible candidates have the same effective rank, stable coupon identity becomes the tie-breaker instead of database traversal order or timing. That sounds like a small implementation detail, but deterministic ties are what make a promotion setup reproducible: the same cart and configuration should not alternate winners between requests simply because candidates arrived in a different order.

PRIORITY IS NOT EXCLUSIVITY

A higher-priority coupon does not automatically delete every lower-priority coupon.

Priority answers ordering and conflict preference; stacking policy answers compatibility. Ordinary stackable promotions can remain together even when their priorities differ. This separation avoids turning priority into an accidental global 'winner takes all' mechanism. Only actual constraints — native individual-use, PerkRule exclusive mode, a conflict relationship or a Best Deal group — determine when otherwise eligible promotions cannot coexist.

STACKING MODES

Stack, exclusive, conflict group or Best Deal.

Stacking configuration describes the relationship between eligible promotions without weakening native WooCommerce individual-use behavior.

STACK

Compatible promotions can coexist instead of competing merely because PerkRule manages both.

Stack is the default relationship when no stricter configuration exists. It does not override native WooCommerce restrictions; it simply says PerkRule itself is not adding a mutual-exclusion rule between those promotions. This makes the policy layer additive: WooCommerce can still reject a combination for native reasons, while PerkRule can introduce stricter relationships when the store explicitly asks for them.

EXCLUSIVE / GROUPED

Exclusive and conflict-group modes describe different kinds of incompatibility and are resolved before mutation.

Exclusive is a hard PerkRule constraint around a promotion. Conflict groups model a known set of promotions that should not all survive together. Best Deal adds comparison within a mutually exclusive group rather than relying on priority alone. All of these relationships are normalized into policy data before the resolver runs, so malformed explicit configuration makes an automatic candidate ineligible instead of being guessed into a permissive default.

BEST DEAL

Bounded selection, not an exponential promotion search.

Best Deal groups choose within explicit bounded groups. The engine avoids unbounded subset permutations and scores through native WooCommerce totals behavior.

NO POWERSET SEARCH

PerkRule does not try every possible subset of every eligible promotion to find a theoretical global optimum.

That approach grows exponentially and would be a terrible checkout dependency. Best Deal instead operates only inside explicit bounded groups where one winner is required. Candidates outside a contested Best Deal group are not scored just for the sake of scoring them. This gives the feature a clear meaning and a tractable cost instead of turning 'best deal' into an open-ended optimization problem whose runtime depends on how many coupons a store happens to have.

NATIVE SCORE

A contested candidate is compared using WooCommerce's own totals behavior on isolated cloned state.

The scorer starts from the same protected-coupon baseline, adds one candidate and constructs native cart totals on a clone. The comparison value is the candidate's native discount including discount tax in WooCommerce precision units. The live cart, session and notice queue remain untouched. Free-shipping Best Deal is not currently treated as solved; that limitation stays explicit rather than inventing a monetary score that the implementation cannot justify yet.

PLAN FIRST

Decide before touching the live cart.

The resolver produces a minimal application plan first. Obsolete automatic coupons are removed and selected coupons are applied only after conflict resolution is complete.

DESIRED STATE FIRST

Conflict resolution produces the desired managed set before any apply or remove call occurs.

This makes mutation a small synchronization step rather than part of the decision algorithm. The reconciler can compare current owned automatic coupons with the selected set, remove only obsolete owned codes in stable order and apply selected missing codes in policy order. Already-correct state becomes a no-op. Keeping planning pure also makes the resolver testable without WordPress or WooCommerce and makes partial failures easier to reason about because the intended result already exists before mutation begins.

FAIL BEFORE TOUCHING CART

If required scoring or policy evaluation cannot be completed safely, reconciliation stops before the live cart is changed.

The dangerous alternative is to remove some coupons, discover an error halfway through selection and then attempt to reconstruct what the shopper had before. PerkRule pushes uncertainty earlier: validate definitions, capture protected state, obtain the scores that are required and resolve the full plan first. Only then does it perform the minimal mutation diff. That does not make every external WooCommerce mutation infallible, but it dramatically reduces how much decision-making happens after state has already changed.

Read the engineering receipt.

See why deterministic planning is part of the PerkRule product standard.

Open Engineering

PerkRule support room

Real support works better when people can talk.

The PerkRule Discord will be the direct place for setup questions, bug reports, compatibility notes and release discussion. Useful answers should not disappear into private tickets — recurring problems can become documentation and Engineering Notes.

Discord opens around Product 001 release