Building a 'buy any 4 for a fixed price' offer in Magento 2
Magento 2 cart price rules can't set a fixed total for a mixed set of items. Here is where native actions fall short and what to build instead.
- Magento 2
- Adobe Commerce
- Operations

The marketing brief says "any 4 products from this category for 50 EGP." You open Marketing > Cart Price Rules, add a Products Subselection condition limited to the category, and set Total Quantity to 4. Then you reach the Actions tab and get stuck. Magento offers a percentage off, a fixed amount off per item, a fixed amount off the whole cart, and buy X get Y free. None of them means "make these four lines total 50."
You haven't misconfigured anything. Magento's rule engine applies a discount to each item that matches the rule. A fixed-price bundle has to work out one discount for a group of items and then split it across them. That calculation doesn't exist in core.
Each native action misses in a different way
Percent of product price discount. This only works when 50 is the same fraction of every possible set. If four items at 25 EGP each total 100, then 50% off works. Mix in a 40 EGP item and the set no longer comes to 50.
Fixed amount discount. This takes the same amount off each qualifying unit. If every product in the category costs 20, then 7.5 off each unit gives 4 × 12.5 = 50. With mixed prices it fails the same way the percentage does.
Fixed amount discount for whole cart. This spreads one fixed amount across the matching items. The amount you need is sum of the four prices − 50, and that changes with every basket. A static field can't hold it.
Buy X get Y free. This gets close only when the arithmetic lines up by luck, for example buy 3 get 1 free on items that already cost 16.67. That isn't a pricing strategy.
The native rule therefore works only when every product in the category has the same price. If the merchant can guarantee that, for example a category of identically priced socks, use the per-item fixed amount and stop there. Otherwise you need code.
The condition is wrong too
Even before the action, "Total Quantity is 4" means exactly 4. A customer who adds a fifth item loses the whole discount, which looks like a bug at checkout. Use "equals or greater than 4" in the subselection and handle the count in the action.
Also set the Actions-tab conditions (the "Apply the rule only to cart items matching the following conditions" tree) to the same category. Without it, the discount can land on items outside the category.
Decide the rules for repeat sets and leftovers first
Write these answers down before anyone writes code, because each one changes the arithmetic:
- Repeat sets. Do 8 items make two sets at 100? Do 9 items make two sets plus one item at full price? Almost always yes. Get it confirmed anyway.
- Which items form the set. With 6 qualifying items, which 4 get the bundle price? Grouping the most expensive items gives the customer the bigger saving. Grouping the cheapest protects margin. Whichever you pick, make the sort deterministic and tie-break on item ID. Otherwise the discount can shift when the cart reloads.
- Sets that are already cheap. If four items already total less than 50, the discount must be capped at zero. Never add to the price.
- Stacking. Can a coupon or another rule apply to the same lines? "Discard subsequent rules" and the rule priority need to reflect what the merchant wants.
- Tax basis. Is 50 EGP the price including tax or excluding it? Check your tax calculation settings (catalog prices including or excluding tax, discount applied before or after tax) against what the promotion promises.
Option 1: a custom discount action
This is our default recommendation. Add a new option to the rule's action dropdown, for example "Fixed price for N items," and use the existing Discount Amount field for the bundle price and Discount Qty Step for N. Register a calculator for the new action type through the classByType argument of Magento\SalesRule\Model\Rule\Action\Discount\CalculatorFactory in di.xml. The calculator implements DiscountInterface like the core actions do.
The core calculator is called once per item, but this discount depends on the whole set. In practice, the calculator gathers the qualifying items from the item's address, sorts them, builds the sets, works out each set's discount and splits it across the units in proportion to price. Put any rounding remainder on the last unit so the set totals exactly 50.00. Cache that result for the collect pass so you don't recompute it for every item.
What you get: the rule stays in the admin where marketing expects it. Coupons, customer groups, date ranges and website scoping keep working. The discount is written to each order item's discount_amount, so invoices and credit memos refund correctly per line.
The cost is a small module that touches the sales rule internals. That code needs a regression check on every Magento upgrade.
Option 2: a custom quote total collector
You can skip the rule engine and register your own total in etc/sales.xml. It sees the whole quote at once, which makes the set arithmetic easier.
The downside comes after checkout. A separate total doesn't appear in item-level discounts unless you write it there yourself. You also have to carry it through order, invoice and credit memo totals, and add it to the totals blocks in admin, email and PDF. Payment methods that send line items, PayPal being the common one, will flag a mismatch unless you add the line to their cart too. Refunding one item from a bundle then becomes a custom calculation.
Use this only if the promotion is genuinely outside the rule engine, for example a permanent price structure with no coupon, scheduling or admin control needed.
Option 3: a promotions extension
Several commercial extensions add "fixed price for N items" style actions. They can be the right call when the merchant expects more promotion types next quarter. Before buying, check:
- Does it support repeat sets, and how does it choose which items go in a set?
- Does it write the discount per item, or as a separate total? (The same refund questions as Option 2 apply.)
- Is it tested against your exact Magento or Adobe Commerce version and your checkout (Luma, Hyvä, or headless over GraphQL)?
- Does it conflict with other modules that also plug into the sales rule validator?
Read the extension's calculator code before you trust it. Many of them are well built. Some still add a fixed amount per item and call it a bundle.
What to test before launch
Whichever option you choose, test these carts with real data on staging:
- Four items at the same price, then four at different prices.
- Three items (no discount), five items (one set and one at full price), and eight items (two sets).
- Four items that already total less than 50.
- A qualifying set plus items from other categories in the same cart.
- The rule alongside a coupon and a catalog price rule.
- Qty changes and item removal on the cart page, then the totals shown at checkout.
- A partial credit memo refunding one item from a set.
- Order totals in the payment gateway's own dashboard.
If the catalog has a single price point, configure the native rule this afternoon. If it doesn't, build the custom action and agree the set-building rules with the merchant in writing first. If you'd like a second opinion on which approach fits your store, see our Magento 2 work or get in touch.
Need this done on a real stack?
Magento 2, Adobe Commerce, migrations to Medusa.js or Vendure, enterprise Next.js, WordPress, and AI automation.
Contact us