Discount & Coupons

The Discount & Coupons plugin (plg_solidshop_discount) extends the discount engine that ships with Solidshop. Core gives you automatic and coupon-code discounts with a minimum cart total and a percentage or fixed amount off; the plugin adds a visual AND/OR rule builder with seven more condition types, five more action types (Buy X get Y, Fixed price, Tiered, Free item, Shipping discount), a product-level scope for percentage, fixed and tiered discounts, exclusive stacking control, a per-order cap on applied discounts, and bulk coupon code generation.

Everything lives inside the existing Solidshop → Discounts screen — the plugin adds tabs and fields to the discount edit form rather than a second place to manage promotions. Read the core Discounts & Coupons page first if you have not created a discount before; this page only covers what the plugin adds. See the Discount & Coupons extension page for the high-level overview.

Requirements

  • Joomla 6.0 or later
  • PHP 8.4 or later
  • Solidshop 1.3.2 or later — the installer refuses to run against an older core, so update Solidshop first if you are behind. 1.3.2 is the core that stores the settings of the plugin’s action types and records a shipping-only discount on the order (the Shipping discount action needs it to survive checkout, show on the order and count against usage limits); on an older core the Action tab would accept the settings and silently drop them on save

Installation

Download the plugin

After purchase, plg_solidshop_discount.zip is available from the downloads area of your account on solidshop.app. Your purchase includes 12 months of updates and support.

Install via the Extension Manager

In your Joomla admin, go to System → Install → Extensions, then drag the ZIP file into the upload area. Joomla installs the plugin and creates its one database table (#__sshop_discount_advanced), which holds the rule tree and exclusive flag for each discount. The conditions and actions themselves are stored in Solidshop’s own discount tables.

Enable the plugin

Go to System → Manage → Plugins, search for discount, and enable Solidshop - Discount (Advanced). Like every Joomla plugin, it is disabled by default after install. There is no switch in the Solidshop options — the plugin is active as soon as it is enabled.

Open a discount

Go to Solidshop → Discounts and open (or create) a discount. The edit form now has an Advanced Conditions tab, the Action tab lists five more action types with their own settings, and saved coupon-code discounts gain a Bulk Generate Codes tab.

Plugin options

The plugin has two options, set on the plugin itself under System → Manage → Plugins → Solidshop - Discount (Advanced). Everything else is configured per discount.

Setting Default What it does
Maximum Discounts Per Order Blank (no limit) Caps how many discounts can apply to one order. When more qualify, the highest-priority ones are kept. See Stacking.
Show Free Item Notice Yes Tells shoppers on the cart and product pages when they have qualified for a free item but have not added it yet. See Free item.

Advanced conditions

The Advanced Conditions tab holds the rule builder. Rules here are evaluated in addition to the basic conditions on the core Conditions tab (minimum cart total and the usage limits) — a discount must pass both.

The rule builder

A rule tree starts with one group. A group has a Match switch — AND (every rule in the group must be true) or OR (any one is enough) — and contains rules and, optionally, nested groups. Click + Add Rule to add a condition to a group, + Add Group to nest a sub-group with its own AND/OR switch, and Remove to delete either. An empty tree imposes no extra condition.

Each rule is a condition type, an operator, and a value. The value box is plain text; the help line under each rule shows the expected format. Where a value is a list (SKUs, category IDs, user group IDs, country codes) separate entries with commas.

Condition Operators Value and behaviour
Customer Group in, not in Joomla user group IDs, e.g. 1,8. Guests have no groups, so in never matches a guest and not in always does.
Purchase History Pick a subtype: First order (the customer has no prior orders), Lifetime spend at least… (enter an amount), or Has purchased product… (enter a product ID). Looks at the signed-in customer’s past orders; guests never match.
Product Category contains, not contains Joomla category IDs, e.g. 3,7. True when any cart item belongs to one of the categories.
Cart Quantity >= > <= < = A number, compared against the total units across all cart items.
SKU contains, not contains SKUs, e.g. SHIRT-RED-M,SHIRT-BLUE-M. True when any cart item’s SKU is in the list.
SKU Quantity >= > <= < = A SKU list plus a quantity. Only units of the listed SKUs are counted — one matching unit plus one unrelated unit does not satisfy a threshold of 2.
Location in, not in Country codes or country-state codes, e.g. VN,US,VN-HN. Checked against the shipping address, falling back to the billing address.

Location rules are confirmed at checkout. On the cart page no address is known yet, so a coupon with a Location rule is accepted there and marked “Confirmed at checkout”. It is re-evaluated against the shopper’s real address once they reach checkout, and applies (or not) at that point.

Worked example

“10% off for VIP members ordering at least 3 items from the Accessories category, or for anyone placing their first order”:

  • Top-level group, Match OR
    • Nested group, Match AND
      • Customer Group in 8
      • Product Category contains 12
      • Cart Quantity >= 3
    • Purchase History → First order

Then on the Action tab: discount type Percentage off, value 10.

Action types

The plugin appends five types to the Discount type list on the Action tab. Choosing one reveals its own settings beneath; the core Value field is hidden for the types that do not use it.

The line-targeted types — Free item, BOGO and Fixed price per unit — apply their discount to the exact cart lines they touch: a free item’s own line is what gets cheaper, BOGO’s discounted units reduce the lines they came from, and a repriced product is taxed on its fixed price. Because tax is calculated on the discounted line amounts, a product made free by any of these carries no tax (see Discounts and tax). Tiered discounts are spread across all cart lines in proportion to their subtotals.

Buy X get Y (BOGO)

Buy quantity Units the customer pays for in each group.
Get quantity Discounted units in each group.
Discount on the free units (%) 100 makes them free; 50 gives half off.
Count units from Whole cart counts every unit in the cart towards a group; A single product counts only units of the product you pick.

The cart needs buy + get units to form one group, and each complete group discounts its cheapest get units. “Buy 2 get 1 free” on a cart of 7 units forms two groups and makes the two cheapest units free; the seventh unit is paid in full. With A single product selected and no product chosen, nothing is discounted.

Fixed price per unit

Sells the chosen items at the price entered in Value. Pick Products (individual products or variants) and/or Categories; leave both empty to sell every cart item at that price. The discount is the difference between the item’s normal price and the fixed price, per unit — an item already cheaper than the fixed price is not marked up.

Tiered by cart total

A table of Tiers, one row each with a Minimum cart total, a Type (Percentage or Fixed amount) and a Value. The highest tier whose minimum the cart reaches is applied; rows with a blank minimum are ignored. For example 100 → 5%, 250 → 10%, 500 → 15% gives a $300 cart 10% off.

Free item

Free product The product whose price is taken off the order.
Variant ID Optional. Restricts the free units to a single variant — enter that variant’s ID. 0 counts any variant of the product.
Free quantity How many units are free.

The customer must add the product to the cart themselves — the plugin does not insert it. Once it is there, the price of up to Free quantity units comes off the order; if it is not in the cart, nothing is discounted. When more units are in the cart than the offer covers, the cheapest ones are the free ones. Pair it with a minimum cart total or a rule for “free tote bag with every order over $75”.

So that the offer is not invisible, the plugin tells the shopper about it. Once they qualify, the cart page shows “Add Product to your cart — it is free with this order” with a link to the product, and the product’s own page shows “This item is free with your current order”. Both disappear as soon as the item is in the cart, because the discount is then showing on the total instead. Turn the notices off with the Show Free Item Notice plugin option if you would rather apply the discount silently.

Shipping discount

Shipping discount type Percentage of shipping or Fixed amount.
Value The percentage (100 = free shipping) or the amount taken off the shipping cost.

Reduces the shipping cost instead of the cart subtotal. The discount never exceeds the cost of the shipping rate the shopper picks, so a fixed $10 off a $6.50 rate takes $6.50 off, and an order with free shipping gets nothing off. Checkout shows the original shipping cost struck through next to the reduced one; the order, the confirmation email, the account order page and the invoice list the amount on a separate Shipping discount line, and it is deducted from the grand total alongside the regular discount.

The shipping cost is not known on the cart page (no rate has been chosen yet), so a coupon whose only effect is a shipping discount is accepted there and marked “Confirmed at checkout” — the same treatment as a location-restricted code. The cart summary and mini-cart do not show a shipping discount; it appears once a shipping rate is selected at checkout. Combine it with a minimum cart total or a rule for “free shipping over $75”; it stacks with cart discounts like any other action, subject to the usual stacking rules.

Product-level scope

For the Percentage off, Fixed amount off and Tiered types the plugin adds a Scope selector to the Action tab:

  • Cart total (default) — the discount is calculated on the full order subtotal, exactly as core does.
  • Product level — the discount base is limited to the cart items that match the SKU, SKU Quantity and Product Category rules in the Advanced Conditions tab. Items that match none of them are excluded from the calculation — if nothing in the cart matches (the discount qualified through another branch of an OR group), the discount amount is zero. If the rule tree names no SKU or category at all, there is nothing to scope by and the full subtotal is used.

“20% off all T-shirts” is therefore: a Product Category rule contains the T-shirt category, discount type Percentage off, value 20, scope Product level. With scope left at Cart total the same rule would take 20% off the whole order as soon as one T-shirt is in it.

Stacking: exclusive discounts and the per-order cap

Core resolves stacking with Priority and Combinable: combinable discounts stack, and among non-combinable ones only the highest-priority discount survives. The plugin adds two controls on top of that.

Exclusive Discount

A Yes/No switch on the Advanced Conditions tab. When a qualifying discount is exclusive, it is the only discount applied to that order — every other discount, combinable or not, is dropped. If several exclusive discounts qualify at once, the one with the highest priority (lowest Priority number) wins. Use it for promotions that must never be combined with a coupon, such as a clearance sale.

Maximum Discounts Per Order

The plugin option described above. After exclusivity has been resolved, the list of discounts still standing is cut to this many, highest priority first. Leave it blank for no cap.

Bulk coupon codes

Unique, single-use codes for an email campaign or a printed insert. Create a coupon-code discount as the template — trigger type Coupon code, with the conditions, action, dates, Total usage limit and Usage limit per customer you want each code to carry — and save it. The Bulk Generate Codes tab then appears on that discount.

Set a prefix and quantity

Code Prefix is optional (letters, digits, - and _; forced to uppercase). Quantity is how many codes to create, up to 500 per run — run it again for more.

Generate

Click Generate Codes. Each code is the prefix followed by eight random characters, e.g. SPRING3F9A1C7B, and becomes a standalone discount named after the template — Spring Sale [SPRING3F9A1C7B] — with a full copy of the template’s conditions, action, rule tree and exclusive flag.

Copy or download

The generated codes are listed on the tab with Copy All and Download CSV buttons. The CSV is a single column of codes, ready for a mail-merge.

Set the usage limit on the template before generating. Each generated code copies the template’s limits, so a Total usage limit of 1 on the template makes every code single-use. The limits are copied, not shared — redeeming one code does not count against the others. The template itself stays a working coupon, so unpublish it if you do not want its own code circulating.

Generated codes are ordinary discounts: they appear in the Discounts list, can be filtered by searching the prefix, and can be unpublished or trashed in bulk from there. Generating requires the Create permission on Solidshop.

Disabling the plugin

Disabling the plugin keeps all data in place but removes its handlers from the engine, and the engine fails closed: a discount with a rule-builder condition can no longer be evaluated, so it simply does not apply, and a discount using a plugin action type (BOGO, Fixed price, Tiered, Free item, Shipping discount) has nothing to calculate. Discounts built from core conditions and actions only keep working as before. The Exclusive flag and the per-order cap are not enforced while the plugin is off.

Opening a discount in the editor while the plugin is disabled shows the core fields only. Saving it leaves a plugin-owned action untouched rather than overwriting it with a percentage, so nothing is lost when the plugin is enabled again.

Uninstalling

Uninstalling the plugin from System → Manage → Extensions drops its own table — the rule trees and exclusive flags. The discounts themselves, with their conditions and actions, are merchant data in Solidshop’s core tables and are left in place. Every discount that uses a rule-builder condition or a plugin action type is unpublished during uninstall — without the plugin it could never apply, and a published promotion that silently does nothing is worse than an unpublished one. Reinstall the plugin and publish them again, or rebuild them with core conditions and actions.

Removing Solidshop entirely? Uninstall the add-ons first. Solidshop refuses to uninstall while add-on plugins such as this one are still installed, and names them in the error message. The order matters: an add-on’s own uninstall depends on the core tables and library still being present.