Present for Craft CMS

Bundles and slots

A bundle

A bundle is a purchasable element. It has a title, a SKU, a price, a field layout, optionally a URL — everything a product has — and no inventory of its own. That last part is the whole idea: a bundle's stock is whatever its contents can supply, and its fulfilment is whatever its contents have shipped.

A slot

A slot is one position in the box: a pool of purchasables that may go there, and how many.

SettingWhat it does
NameWhat the shopper sees above the choice
HandleHow templates address it: selection[mug]
Choices come fromA list you pick, or a query (Pro)
QuantityFixed, or a range the shopper chooses (Pro)
How manyFixed mode: units this slot always contributes
Fewest / MostRange mode: the bounds the shopper picks within
Optional (Pro)Fixed mode: let them leave this slot out
Allow repeats (Pro)Range mode: may one option be taken more than once
DiscountPercentage off everything in this slot
Show pricesWhether templates show component prices for this slot

The two shapes

Every bundle anyone builds is one of these, or a mix:

A hamper. Slots with a pool of one and a fixed quantity. "This box always contains a mug, a bag of tea and a card." Nothing is chosen; the shopper buys it or does not.

A build-your-own box. One slot with a pool of twenty and a range of 0–6, plus a bundle-wide minimum and maximum. "Pick any six."

They are the same object because they are the same question asked with different bounds, which is why there is no separate "mix and match" bundle type to choose between at the start.

Per-option settings

Within a list slot, each choice can carry:

  • Default qty — how many are pre-selected when the shopper first sees the bundle
  • Discount — overrides the slot's discount for this one option. An explicit 0 is how you say "everything in this slot is 20% off except the expensive one". Leaving it empty means "use the slot's", which is not the same thing.

Query pools (Pro)

Instead of listing choices, a slot can be filled from a query: variants of one or more product types, optionally narrowed to those related to an element, optionally only those in stock.

The pool is resolved at read time, so adding a product to the catalogue adds it to every box that queries for it — no re-saving bundles.

Bundle-wide limits (Pro)

Fewest items and Most items apply across every slot together. A box with three range slots of 0–6 and a bundle maximum of 6 lets the shopper distribute six units however they like.

Present refuses to save a bundle whose slots cannot between them reach its own minimum, because that bundle can never be configured at all and the shopper would only find out at the add-to-cart button.

What cannot go in a bundle

Another bundle. Nesting looks reasonable and is not: the stock rollup would have to recurse, the fulfilment rollup would have to nest, and Commerce would still see one flat list of line items at the end of it. Present refuses outright rather than half-supporting it.

Auditing

php craft present/bundles/check

Lists every bundle, how many boxes can be built, what is limiting it, and anything wrong — a slot with nothing available in it, a slot pointing at variants that have since been disabled, a bundle with no slots, a minimum that cannot be reached. --problems-only shows just the bad ones.