Skip to main content

Dynamic Pricing Rules

Overview​

Dynamic Pricing Rules is the premium pricing engine, aimed at quantity-based pricing: buy more, pay less. A rule carries tiers, a discount type and a target — particular products, categories or customer roles, each in its own table — and the calculated price is cached so a catalogue page does not re-evaluate every rule for every product on every request.

Where the free Dynamic Pricing module spans product prices, cart discounts and free gifts, this one concentrates on the product price and does more with it: a discount badge with configurable text, the original price shown struck through, an explicit stacking choice, and a cache with a configurable lifetime.

It is for stores selling at volume, where price depends on quantity and on who is buying.

Availability​

ItemValue
Module keydynamic-pricing-rules
TierPremium
Entitlement keydynamic-pricing-rules
Admin tabpricing-rules
Enabled optionaiowc_module_enabled_dynamic-pricing-rules (off until turned on)
REST namespaceaiowc/v1

Enabling the module creates the six tables below, seeds the defaults and schedules both jobs.

registerHooks() returns early twice: once when the licence does not grant dynamic-pricing-rules, and again when enable_dynamic_pricing is off — so switching that setting off takes the REST routes and every price filter out of the request entirely.

Settings​

Stored in the bundled option row aiowc_dpr_settings.

Stored keyDefaultMeaning
enable_dynamic_pricingtrueMaster switch. Off means no hooks, no routes and no price changes.
show_discount_badgetrueWhether a badge is shown on a discounted product.
badge_textSave {amount}!The badge's text. {amount} is replaced with the saving.
show_original_pricetrueWhether the undiscounted price is shown alongside the new one.
apply_to_sale_productsfalseWhether products already on sale are discounted further. Off by default.
stack_rulesfalseWhether several matching rules combine, or only the best one applies. Off by default.
cache_duration3600How long a calculated price is cached, in seconds — one hour.

The last three are passed into the price service when the module starts, so changing them changes how prices are calculated rather than only how they are displayed.

Rules​

FieldMeaning
rule_typeThe kind of rule. Defaults to bulk.
discount_typepercentage or fixed. Defaults to percentage.
discount_valueThe amount, stored to four decimal places.
tiersThe quantity bands and what each one charges.
priorityWhich rule is preferred when several match.
stack_rulesA per-rule override of the module-wide stacking setting.
apply_to_sale_productsA per-rule override of the module-wide sale-item setting.
date_from, date_toThe window the rule is live in.
statusDefaults to active — unlike the free module, a new rule here is live immediately.

Targeting is relational rather than JSON: a rule's products, categories and roles each live in their own table, so a rule can name many of each and the match is a join rather than a decoded blob.

How a price is chosen​

Candidate rules are collected for the product, sorted by priority, and then either the best one applies or all of them stack, according to the stacking setting. The result is cached under a key derived from the product, the variation, the base price and the request context, so two customers in different roles do not share a cached price.

The cache is refreshed by a background job and can be invalidated directly. It is a time-based cache rather than an event-based one — see the limits below.

Admin screen​

The Pricing Rules tab lists the rules, creates and edits them with their tiers and targeting, and shows each rule's usage. The module's seven settings are edited from the same screen.

REST API endpoints​

All routes are on aiowc/v1 and answer with the { success, data, message } envelope.

MethodPathPurposePermissionRequired args
GET/pricing-rulesEvery rule.manage_woocommerce–
POST/pricing-rulesCreate a rule.manage_woocommerce–
PUT/pricing-rules/{id}Update a rule.manage_woocommerceid
DELETE/pricing-rules/{id}Delete a rule.manage_woocommerceid
GET/pricing-rules/{id}/usageHow often the rule has applied.manage_woocommerceid
POST/pricing-rules/calculatePrice a product under the current rules.Public, rate-limitedproduct_id

/calculate is public and rate-limited so the product page can show a live tier price as the customer changes the quantity.

Unlike most modules here, the update route registers only PUT — not PATCH or POST — so a client that assumes PATCH will get a 404.

WooCommerce integration​

HookWhat the module does
woocommerce_product_get_priceReturns the rule-adjusted price for a product.
woocommerce_product_variation_get_priceThe same for a variation.
woocommerce_before_calculate_totalsApplies the adjusted price to the cart lines.
woocommerce_get_price_htmlRenders the badge and the original price beside the new one.

A deliberately narrow surface compared with the free module: this one changes the price and how it reads, and leaves the cart and order display alone.

Database schema​

TableHolds
{prefix}aiowc_dpr_pricing_rulesThe rule: name, type, discount type and value, tiers, priority, its two overrides, date window, status.
{prefix}aiowc_pricing_rule_conditionsConditions on a rule: type, operator and value.
{prefix}aiowc_pricing_rule_productsThe products a rule targets.
{prefix}aiowc_pricing_rule_categoriesThe categories a rule targets.
{prefix}aiowc_pricing_rule_rolesThe customer roles a rule targets.
{prefix}aiowc_pricing_rule_usageOne row per application: the rule, customer, order and amount discounted.

The rules table carries a dpr_ prefix because the plainer aiowc_pricing_rules belongs to the free Dynamic Pricing module. The two modules never share a row.

Background jobs​

HookIntervalWork
aiowc_pricing_cache_refreshhourlyRebuilds the calculated-price cache.
aiowc_pricing_rules_cleanupdailyPrunes expired rules and old usage rows.

Both run on WP-Cron, first scheduled an hour after the module is enabled.

Action hooks for integrators​

HookFired when
aiowc_track_eventThe module is enabled or disabled.

Unlike the free module, this one exposes no filter for adding a condition type or overriding stacking — those are settings rather than extension points.

Entitlement limits​

dynamic-pricing-rules is an on/off grant with no cap on the number of rules, tiers or targets.

Health check​

The module reports a warning when its tables are missing or WooCommerce is inactive, and otherwise reports that it is functioning normally. A disabled module reports that it is disabled.

Known gaps​

  • Two modules filter woocommerce_product_get_price — this one and the free Dynamic Pricing. With both enabled, both adjust the same price and neither knows about the other, so the result depends on filter order. A store should run one or the other.
  • There is no preview or test tool; the effect of a rule is confirmed by looking at a product.
  • badge_text supports only the {amount} placeholder, so a badge cannot quote the quantity or the tier that produced the saving.

Changed on 2026-09-13​

  • 🔴 Editing a rule now takes effect immediately. The price cache was time-based only, so a change could take up to cache_duration — an hour by default — to appear. Creating, updating or deleting a rule now invalidates the cache, with the TTL kept as a backstop. There was a second layer to this: the invalidation method itself was a no-op on any object cache without group flushing, because it deleted a key nothing ever wrote. It now bumps a generation folded into the cache key, which works on every cache backend.
  • The update route accepts PATCH and POST as well as PUT, matching comparable modules. A client written against those now works here unchanged.