XaniaCode · WooCommerce extension
XC Tiered Pricing
A complete rule engine for quantity discounts, B2B pricing tiers, and scheduled promotions in WooCommerce. This guide covers everything from server requirements through to developer hooks.
01 — SetupServer requirements
XC Tiered Pricing is a standard WordPress plugin and runs anywhere modern WooCommerce runs. The list below reflects the minimum tested versions. Newer versions are always recommended.
| Component | Minimum | Recommended |
|---|---|---|
| WordPress | 6.0 | Latest stable |
| PHP | 8.1 | 8.2 or newer |
| WooCommerce | 8.0 | Latest stable |
| MySQL / MariaDB | MySQL 5.7 / MariaDB 10.4 | MySQL 8 / MariaDB 10.6+ |
| HTTPS | Required for license activation | Required for license activation |
| PHP memory_limit | 128 MB | 256 MB |
Browser support
The admin interface targets evergreen browsers from mid-2023 onwards: Chrome 111+, Edge 111+, Firefox 113+, Safari 16.2+. Older browsers will still load the plugin but some visual refinements (such as color-mix() tinting on the frontend) fall back to neutral defaults.
Theme & builder compatibility
The plugin uses standard WordPress and WooCommerce hooks, so it is theme-independent and works alongside the major page builders.
- Gutenberg block editor
- Elementor (free & Pro)
- Divi
- Beaver Builder
- Bricks
WooCommerce features
- HPOS (High-Performance Order Storage) — declared compatible
- Cart & Checkout Blocks — declared compatible
- Variable products & variations — fully supported
- Sale prices — excluded from tiered discounts by default; per-rule override available
- Multi-currency — works with any extension that filters
woocommerce_product_get_price
WordPress Multisite is supported. Each network site needs its own license activation, since rules and settings are site-scoped.
02 — SetupInstallation
Install XC Tiered Pricing the same way you install any premium WordPress plugin. The whole process — including license activation — takes about three minutes.
Upload & activate
- Download the plugin ZIP After purchase, you receive an email with a download link. The same link is always available under My Account → Downloads on xaniacode.com. Keep the ZIP — you can re-download a fresh copy at any time.
-
Upload via WordPress admin
In WordPress, go to Plugins → Add New → Upload Plugin. Select the ZIP file (do not unzip it locally) and click Install Now. WordPress accepts ZIPs up to the value of
upload_max_filesize, so a default 2 MB host is more than enough. -
Activate the plugin
When the upload finishes, click Activate Plugin. The plugin creates two database tables (
wp_xc_tp_rulesandwp_xc_tp_logs) and adds a top-level Tiered Pricing menu in the WordPress admin sidebar. - Confirm activation You should see a green admin notice and the Tiered Pricing menu on the left. The dashboard opens with empty stat cards — that is expected on a fresh install.
If you maintain multiple staging sites, install the same ZIP on each one. Staging and development sites that share a root domain are covered by a single license.
License activation
Until activated, the plugin runs in a limited mode and displays an admin notice asking for your key. Activation unlocks plugin updates and full functionality.
- Open the License screen Go to Tiered Pricing → License. The submenu appears under the main plugin menu.
- Paste your license key The key is a 32-character alphanumeric string sent to you by email after purchase. You can also find it under My Account → Licenses on xaniacode.com.
- Click Activate The plugin contacts the XaniaCode license server over HTTPS, validates the key, and binds it to your site URL. On success, the screen shows the activation date and remaining support window.
If the activation request fails, your server probably blocks outbound HTTPS to xaniacode.com. See License will not activate in Troubleshooting.
03 — Quick startBuild your first rule
This walkthrough creates a "buy 10, save 10%" rule on every product in the store. Total time: about ninety seconds.
- Open the rule editor Go to Tiered Pricing → Rules and click Add New. The rule editor opens with a blank form and an empty tier table.
- Name the rule and pick a discount type Type a name like Volume retail — 10%. Leave Discount type on Percentage off. Set Apply to to All products. Leave Quantity scope on Per product.
-
Add the tier
In the Tiers table, click + Add tier. Set Min qty to
10, leave Max qty at0(which means unbounded), and set Value to10. With the discount type set to percentage, the value10is interpreted as 10%. -
Test in the live preview
In the Live preview card, type a base price (for example
50) and a quantity (10). The preview shows the per-unit price, total savings, and percentage discount applied. - Save the rule In the right sidebar, leave Status on Active and click Create rule. You return to the rules list with the new rule visible at the top.
- Verify on the storefront Open any product page on the frontend. A pricing table titled Volume discounts appears below the product summary, showing the discount applied at qty 10 and above. Add 10 of the product to the cart to see the savings notice.
That is the entire workflow. Every rule you create — from simple percentage tiers to role-restricted B2B pricing scheduled for a specific window — follows the same pattern.
04 — ReferenceSettings reference
Settings are grouped into four tabs, found under Tiered Pricing → Settings. Every option below is documented with its default value and effect.
Display tab
Controls where and how pricing tables and notices appear on the storefront.
| Setting | Default | Effect |
|---|---|---|
| Show pricing table | Enabled | Renders the tiered pricing table on every product page where at least one rule applies. |
| Position | After product summary | Choose where the table appears: before summary, after summary, after add-to-cart button, or after the product tabs. |
| Style | Modern | One of four presets: Modern, Minimal, Bordered, Striped. All four inherit the theme's typography. |
| Show savings column | Enabled | Shows the per-unit saving and percentage in a third column. Disable for a compact two-column table. |
| Highlight active tier | Enabled | Highlights the row matching the current quantity input on the product page. Updates live as the customer changes quantity. |
| Show shop badge | Disabled | Adds a small Bulk discount badge next to the price on shop archive listings. |
| Show cart notice | Enabled | Displays a success notice in the cart when a customer's purchase qualifies for a tiered discount. |
| Show next-tier notice | Enabled | Encourages customers to add a few more units to unlock a bigger discount. |
| Primary color | Empty (inherit theme) | Optional brand colour used for the active tier highlight and the next-tier notice. Leave empty to inherit the theme's text colour. |
| Accent color | Empty (inherit theme) | Optional accent used for the savings figure and the cart success notice. Leave empty to inherit. |
Labels tab
Customise every customer-facing string. All fields support the placeholders listed below.
| Field | Default |
|---|---|
| Pricing table title | Volume discounts |
| Quantity column | Quantity |
| Price column | Price |
| Savings column | You save |
| Cart notice template | You saved {amount} thanks to your bulk discount! |
| Next-tier notice template | Add {extra} more of {product} to unlock a bigger discount. |
| Discount label format | -{value} |
Available placeholders
{amount}— total savings for the order, formatted with the store currency{extra}— number of extra units needed to reach the next tier{product}— product name (next-tier notice only){value}— the raw discount value, used in the discount label
Behaviour tab
Controls how the engine evaluates rules at runtime.
| Setting | Default | Effect |
|---|---|---|
| Apply to sale items | Disabled | By default, products with an active sale price are excluded from tiered discounts to prevent stacking. Enable to allow tiers to discount sale prices further. |
| Enable logging | Enabled | Records every rule application in wp_xc_tp_logs. Used by the dashboard for usage statistics. Older entries are trimmed automatically. |
Advanced tab
Lifecycle and clean-up options.
| Setting | Default | Effect |
|---|---|---|
| Remove data on uninstall | Disabled | When enabled and the plugin is deleted via Plugins → Delete, all rules, logs, and settings are wiped. Disabled by default for safety. |
The Remove data on uninstall option is irreversible. Once activated and the plugin is deleted, there is no way to recover rules without a database backup.
05 — ReferenceBuilding rules
A rule is the unit of pricing logic. Every rule has a name, a discount type, a list of tiers, a target, optional restrictions, and a status. The sections below break down each piece.
Rule anatomy
- Name
- Internal label shown in the admin. Customers never see it.
- Internal description
- Notes for your team, shown only in the admin.
- Discount type
- How the discount is calculated — see Discount types.
- Tiers
- Quantity thresholds and the value applied at each — see Tiers.
- Apply to
- Which products the rule targets — see Targeting.
- User roles
- Optional list of WordPress roles that can use the rule. Empty means everyone.
- Date range
- Optional start and end timestamps for scheduled promotions.
- Min subtotal
- Optional cart subtotal threshold.
- Combine with others
- Whether this rule stacks with other matching rules or wins outright.
- Priority
- Lower number = higher priority. Used to break ties between competing rules.
- Status
- Active or inactive. Inactive rules are skipped by the pricing engine.
Discount types
Five discount types cover the common pricing models:
| Type | Tier value means | Effect |
|---|---|---|
Percentage offpercentage |
Percentage | Subtracts the percentage from the per-unit price. 10 = 10% off. |
Fixed amount offfixed_discount |
Currency amount | Subtracts a fixed amount from each unit. 5 on a €50 item = €45 per unit. |
Fixed price per unitfixed_price |
Currency amount | Sets the unit price to this exact value. 40 = every unit costs €40. |
Cart discount – percentagecart_percentage |
Percentage | Applies a percentage discount to the matching items at the cart-total level. Useful for "10% off when you buy 50+ across the store" promotions. |
Cart discount – fixed amountcart_fixed |
Currency amount | Applies a fixed currency discount at the cart level once the tier qty is reached. |
Worked example
Base price €100, customer buys 10 units:
- Percentage 10% → €90 per unit, line total €900, savings €100
- Fixed amount off €5 → €95 per unit, line total €950, savings €50
- Fixed price €80 → €80 per unit, line total €800, savings €200
- Cart percentage 10% → €100 per unit, line total €900 after cart discount
- Cart fixed €100 → €100 per unit, line total €900 after €100 off the cart
Targeting
Each rule targets one of four product scopes:
| Apply to | What you select | When to use |
|---|---|---|
| All products | — | Storewide volume promotions (Black Friday, B2B blanket pricing) |
| Specific products | One or more products via the searchable picker | Bestseller incentives, individual SKU promotions |
| Product categories | One or more WooCommerce categories | Section-wide pricing (Apparel −10%, Hardware −15%) |
| Product tags | One or more product tags | Cross-cutting groupings (everything tagged clearance) |
Variable products can be targeted as a whole or by individual variation. Selecting the parent product in the picker covers all its variations.
Restrictions
Three optional restrictions let you scope a rule down further. All three combine with AND logic — every restriction must pass for the rule to apply.
User roles
Pick one or more WordPress roles. Logged-out customers do not match a rule that has any role restriction. Leave empty to apply the rule to everyone, including guests.
Date range
Set an optional start timestamp, end timestamp, or both. Times use the WordPress timezone configured under Settings → General → Timezone. Internally they are stored in UTC, so daylight savings transitions are handled automatically.
Min subtotal
The cart subtotal must reach this threshold before the rule applies. Useful for "free volume discount on orders over €500" mechanics.
For B2B pricing, restrict by user role (Wholesale, Retailer, etc.) and turn off Combine with others so the wholesale tier is the only price these customers see.
Tiers & quantity scope
A tier is a row in the rule's tier table with three values: Min qty, Max qty, and Value.
- Min qty — the smallest quantity that qualifies for this tier.
- Max qty — the largest qualifying quantity. Use
0for unbounded (always recommended on the highest tier). - Value — the discount amount (interpretation depends on the rule's discount type).
Tiers within one rule must not overlap. The plugin sorts tiers by Min qty on save and applies the matching tier to each line item or cart total, depending on quantity scope.
Quantity scope
| Scope | Quantity counted from | Typical use |
|---|---|---|
| Per product (line item) | The quantity of the matching line item in the cart | Per-SKU bulk pricing — buy 10 of THIS shirt to get 10% off |
| Total cart quantity | Sum of all matching line items in the cart | Cross-product mix-and-match — buy any 10 shirts to get 10% off all of them |
Combine vs exclusive rules
Two rules can target the same product. The Combine with others flag and the Priority field decide what happens.
- Combine = on
- The rule's discount stacks with other combinable rules. Each rule's discount is applied independently to the line item.
- Combine = off
- The rule is exclusive. If multiple exclusive rules match, the one with the lowest priority number wins. All others are skipped for that line item.
- Combinable + exclusive together
- The exclusive rule wins on its own; combinable rules still stack on top of the winning exclusive rule.
Lower priority number = higher priority. A rule with priority 1 beats a rule with priority 10.
Live preview
The rule editor includes a Live preview card that calculates the discount in real time as you edit the tiers. It is the fastest way to validate a complicated tier table before saving.
The preview accepts two inputs:
- Base unit price — any positive number representing the product's regular unit price.
- Quantity — the quantity to test against the tier table.
It outputs:
- After discount — the per-unit price after the rule applies.
- You save — total savings for the line.
- Discount — the percentage off, computed from base × quantity.
- Status line — confirms which tier matched, or warns if no tier matches.
06 — FrontendCustomer experience
Customers interact with three frontend elements. All three inherit your theme's font, colours, and spacing by default.
Pricing table on product pages
When a product matches at least one active rule, a small table appears on its product page. Position is controlled by the Position setting under Display.
The table shows three columns by default — Quantity, Price, You save — with one row per tier. As the customer types into the quantity input, the matching tier highlights in real time. This works for the standard WooCommerce quantity field as well as themed +/− button widgets that update the underlying input.
Cart success notice
When a customer's cart contains items that qualify for one or more tiered discounts, the cart page shows a success notice with the total savings. The wording is set by the Cart notice template under Labels and supports the {amount} placeholder.
Next-tier upsell notice
If a customer is one or more units short of unlocking a bigger tier, the cart page shows an encouragement notice. Wording is set by Next-tier notice template and supports {qty}, {extra}, and {product}.
Example:
Add 3 more of "Premium T-Shirt" to unlock a bigger discount.
Shop archive badge (optional)
Enable Show shop badge in Display settings to add a small Bulk discount badge next to the price on shop archive listings. The badge is purely informational — clicking through to the product reveals the full tier table.
07 — MaintenanceTools
The Tools page (Tiered Pricing → Tools) groups four utilities for moving rules between sites and inspecting plugin health.
JSON export
Click Export rules to download a JSON file containing every rule on this site, with tiers, targets, and restrictions intact. Logs and usage counts are not included — exports are about pricing logic, not history.
JSON import
Use Import rules to upload a previously exported JSON file. Rules are added to the existing rule set; nothing is overwritten. The import handler enforces a 2 MB upload cap and validates the structure before inserting anything.
Pair this with a staging-to-production workflow: build and test rules on staging, export them, import on production. No copy-paste, no human error.
System status
A read-only table that confirms versions and configuration: plugin version, database schema version, total rule count, and active rule count. Useful when a support ticket asks "what version are you running?".
Uninstall behaviour
The Tools page also displays the current state of the Remove data on uninstall setting. Toggling it requires a trip to Advanced settings.
08 — DevelopersDeveloper reference
XC Tiered Pricing is autoloader-driven and exposes a small public API for extension. Every public class is namespaced under the XC_TP_ prefix; helper functions use xc_tp_.
Hooks
The plugin fires WordPress actions at the key lifecycle moments and exposes a single capability filter.
| Hook | Type | Arguments | Fires when |
|---|---|---|---|
xc_tp_rule_saved |
Action | (int $rule_id) |
A rule is created, updated, or duplicated. |
xc_tp_rule_deleted |
Action | (int $rule_id) |
A rule is permanently deleted. |
xc_tp_admin_capability |
Filter | (string $capability) |
Used to gate every plugin admin page and AJAX endpoint. Defaults to manage_woocommerce. |
xc_tp_daily_maintenance |
Cron action | — | Daily WordPress cron task that trims logs older than one year. |
Example: log every rule change to a file
add_action( 'xc_tp_rule_saved', function ( $rule_id ) {
error_log( "XC TP rule {$rule_id} was saved at " . current_time( 'mysql' ) );
} );
Example: open the admin to shop managers
add_filter( 'xc_tp_admin_capability', function ( $cap ) {
return 'edit_others_shop_orders';
} );
Helper functions
A handful of helper functions are available for theme and plugin developers:
| Function | Returns | Purpose |
|---|---|---|
xc_tp_rules() | XC_TP_Rules_Manager | Singleton rules manager for queries and CRUD. |
xc_tp_get_rule( $id ) | XC_TP_Rule|null | Load a single rule by ID. |
xc_tp_get_option( $key, $default ) | mixed | Read a plugin setting with a fallback. |
xc_tp_get_discount_types() | array<string,string> | Map of discount-type keys to translated labels. |
xc_tp_get_target_types() | array<string,string> | Map of targeting modes to translated labels. |
xc_tp_format_price( $amount ) | string (HTML) | Format a number using WooCommerce currency settings. |
Database tables
Two tables are created on activation:
{$wpdb->prefix}xc_tp_rules— one row per rule, including a JSON-encodedtierscolumn.{$wpdb->prefix}xc_tp_logs— one row per discount application; trimmed daily.
Both tables follow WordPress naming conventions and respect the wp_ prefix configured in wp-config.php.
09 — SupportTroubleshooting
The most common issues, with proven fixes. If yours is not listed, open a ticket and include the System status output from the Tools page.
Pricing table does not show on product pages
Check the following in order:
- Is the rule Active? Inactive rules are skipped entirely.
- Does the rule's targeting include the product? An Apply to: Specific products rule needs the product explicitly selected.
- Is Show pricing table enabled under Display settings?
- Is the user logged in if the rule has a role restriction? Logged-out customers will not match.
- Is the product on sale? By default, sale-priced products are excluded — toggle Apply to sale items if needed.
Discounts not applied at checkout
If the pricing table is visible but the cart total is wrong:
- Empty the cart and re-add the product. Cart totals are computed at add-to-cart and on quantity change — a stale cart from before the rule existed will not retroactively update.
- Check whether another extension is overriding
woocommerce_product_get_price. XC Tiered Pricing hooks into the standard pricing pipeline, so any extension that runs at a higher priority will win. - Confirm the customer's user role matches the rule's role restriction (if any).
Wholesale prices show to logged-out users
This means the rule has no role restriction. Edit the rule, expand User roles, and pick the role(s) that should see the discount. Logged-out customers never satisfy any role restriction.
Date scheduling doesn't activate the rule at the expected time
Two timezone realities collide here:
- The plugin stores start and end timestamps in UTC.
- The admin date input uses the WordPress timezone configured under Settings → General → Timezone.
If your site timezone is wrong, every rule schedule will be wrong. Verify the WordPress timezone first; the plugin reads it correctly afterwards.
License will not activate
Activation requires outbound HTTPS to xaniacode.com. Common blockers:
- Strict server firewall blocking outbound traffic — ask the host to whitelist
xaniacode.comon port 443. - WordPress
WP_HTTP_BLOCK_EXTERNALis true with no whitelist — addxaniacode.comtoWP_ACCESSIBLE_HOSTS. - Server clock is off by more than 5 minutes — fix NTP.
- License already activated on a different domain. One license = one production domain. Open a support ticket if you legitimately moved the site.
Settings not saving
Almost always a server-side write or nonce problem:
- Browser session expired. Reload the page and try again.
- An aggressive caching plugin is caching admin pages — exclude
/wp-admin/from the cache. - A web application firewall is rejecting the POST. Check the WAF logs for blocked requests.
Import file rejected
The import handler validates three things, in order: file size (max 2 MB), JSON parseability, and structural shape. The most common rejection is invalid JSON — open the file in any editor and verify it parses. Files exported from the plugin always pass.
Pricing table looks broken on my theme
The frontend inherits your theme's typography by default. If the table looks broken (collapsed columns, misaligned text), the most likely cause is an aggressive !important rule in the theme's stylesheet on table selectors. Override it by setting a primary and accent colour under Display settings, or contact support with the theme name.
Conflict with another tiered pricing plugin
Run only one quantity-discount plugin at a time. They all hook the same WooCommerce filters and the result of running two simultaneously is undefined — sometimes one wins, sometimes the discounts compound, sometimes they cancel. Disable the other plugin first.
10 — ReferenceTechnical FAQ
How are prices applied internally?
The pricing engine hooks into woocommerce_product_get_price and related variation pricing filters. For cart-level discount types, it also hooks woocommerce_cart_calculate_fees to register a discount fee. This is the WooCommerce-recommended pricing pipeline; nothing in the database is mutated to show a discounted price.
Does the plugin affect site performance?
Rules are loaded once per request and cached in memory for the duration of that request. The pricing engine evaluates each line item against in-memory rules — no extra database queries per item. On a store with 500 active rules, the typical overhead is under 5 ms per page load.
Which database tables are created?
Two: wp_xc_tp_rules (one row per rule) and wp_xc_tp_logs (one row per discount application). The prefix wp_ follows your wp-config.php.
Is there multi-currency support?
Yes, indirectly. The plugin uses WooCommerce's pricing pipeline, so any multi-currency extension that filters woocommerce_product_get_price sees the discounted value and can convert it. Tested with WooCommerce Multilingual / Multi-Currency and CURCY-style plugins.
Does it work with WordPress Multisite?
Yes. Each site in the network needs its own license activation. Rules and settings are stored per site.
Custom user roles?
Fully supported. The role picker lists every role registered with WordPress, including roles added by Members, User Role Editor, custom code, or other extensions.
WPML / Polylang compatibility?
Both work. Translations are picked up automatically because every customer-facing string runs through WordPress's gettext functions. Targeting by product applies to all language variants of the same product.
Subscription products?
Compatible with WooCommerce Subscriptions for the per-product discount types (percentage, fixed amount, fixed price). Cart-level discount types apply to the initial order; recurring renewals use the post-discount price as a baseline.
Variable products?
Fully supported. Selecting a variable product as a target applies the rule to every variation. Individual variations can also be selected directly.
Can I apply tiered pricing to bundles, composites, or grouped products?
The plugin works with WooCommerce Product Bundles and Composite Products at the line-item level — bundled children are discounted individually if they match a rule. Bundle-level pricing requires a small custom integration; contact support for guidance.
Are the assets loaded on every page?
No. Frontend CSS and JS load only on product, cart, and checkout pages. The admin assets load only on the plugin's own admin screens.
Does the plugin store any personal data?
The logs table stores the user ID (if logged in) and the cart line item that received a discount. No names, emails, or addresses. The data follows the same lifecycle as the rest of your WooCommerce data and respects WordPress data export and erasure requests.
11 — HelpSupport & updates
Direct developer support
Every license includes 6 months of direct support from the developer who built the plugin. Open a ticket from My Account → Support on xaniacode.com. Expect a response within one business day; most tickets are resolved on the first reply.
When opening a ticket, include:
- The plugin version (visible on the dashboard)
- The WordPress and WooCommerce versions
- The output of the System status table
- A clear description of expected vs actual behaviour
- Screenshots, browser console output, or PHP error log entries when relevant
Support renewal
After 6 months, support can be renewed for a small fee. Updates remain free for the life of the plugin regardless of support status — your installation never stops receiving fixes and new features.
How updates are delivered
Updates appear inside WordPress admin under Plugins → Installed Plugins, just like any plugin from the WordPress.org repository. The license key activated on the site authorises the update channel; nothing else is required from you.
Privacy & data
The plugin contacts the XaniaCode server only for two purposes: license validation on activation, and update checks (twice daily, the WordPress default). No customer data, order data, or analytics are ever transmitted.
License terms recap
- Pricing model
- One-time payment, no subscription
- Updates
- Lifetime, delivered through WordPress admin
- Support
- 6 months included, renewable thereafter
- Domain scope
- Single production domain; staging on the same root domain is included
- Refund policy
- Reviewed individually for products that do not function on a clean WordPress install — see the Refund Policy page on xaniacode.com