Hooks for Discount Calculation
Filters for modifying discount calculation and price rounding.
Calculation Base Mode
Section titled “Calculation Base Mode”Each rule can have a calculation_base_mode setting that determines which price the discount is calculated from:
| Value | Constant | Description |
|---|---|---|
current_price | CalculationBaseModes::CURRENT_PRICE | Discount from current price (after previous discounts) - default |
original_price | CalculationBaseModes::ORIGINAL_PRICE | Discount always from regular price (regular_price) |
Behavior Example — multiple Auto Price rules
Section titled “Behavior Example — multiple Auto Price rules”Product: regular_price = $100Rule 1 (Product): -20% → $80Rule 2 (Bulk): -5%
With calculation_base_mode = 'current_price' on Rule 2: → 5% of $80 = $4 → final $76 (stacks on Rule 1)
With calculation_base_mode = 'original_price' on Rule 2: → 5% of $100 = $5 → final $95 (overrides Rule 1, recalculated from regular_price)When multiple Auto Price rules match the same product, they are applied in priority order (lower menu_order first). Each rule’s calculation_base_mode decides whether it stacks on the running price or restarts from regular_price. The stop_processing flag halts iteration over lower-priority rules.
Behavior Example — Auto Price + BOGO
Section titled “Behavior Example — Auto Price + BOGO”Product: regular_price = $100Rule 1 (Product): -20% → price = $80Rule 2 (BOGO): -50%
With calculation_base_mode = 'current_price': → 50% of 80 = $40 (discounts stack)
With calculation_base_mode = 'original_price': → 50% of 100 = $50 (discount from original price)Accessing the Setting in Code
Section titled “Accessing the Setting in Code”use WpifyWooDiscountRule\Services\Rules;use WpifyWooDiscountRule\Enums\CalculationBaseModes;
// Within a rule$calc_base_mode = $rule[ Rules::CALCULATION_BASE_MODE ] ?? CalculationBaseModes::CURRENT_PRICE;
if ( CalculationBaseModes::ORIGINAL_PRICE === $calc_base_mode ) { // Use regular_price $base = $product->get_regular_price();} else { // Use current price (may include other discounts) $base = $product->get_price();}Modifying Data Before Discount Calculation
Section titled “Modifying Data Before Discount Calculation”This filter allows you to modify data before the actual discount calculation.
apply_filters( 'wpify_woo_discounts_calculate_data', $data, $product, $rule, $range );Filter Parameters
Section titled “Filter Parameters”| Parameter | Type | Description |
|---|---|---|
$data | array | Data for discount calculation (original_price, calculation_base, discount_type, discount_value) |
$product | WC_Product | Product the discount is applied to |
$rule | array | Rule settings (including calculation_base_mode) |
$range | array | Current discount range/tier |
Usage Examples
Section titled “Usage Examples”Adjusting Discount for a Specific Category
Section titled “Adjusting Discount for a Specific Category”/** * Increase discount for products in the "sale" category * * @param array $data Calculation data * @param WC_Product $product Product * @param array $rule Rule * @param array $range Discount range * * @return array */function boost_discount_for_sale_category( $data, $product, $rule, $range ): array { if ( has_term( 'akce', 'product_cat', $product->get_id() ) ) { // Increase percentage discount by 5% if ( $data['discount_type'] === 'percentage' && isset( $data['discount_value'] ) ) { $data['discount_value'] += 5; } } return $data;}add_filter( 'wpify_woo_discounts_calculate_data', 'boost_discount_for_sale_category', 10, 4 );Setting a Minimum Discount
Section titled “Setting a Minimum Discount”/** * Ensure a minimum discount of 10% * * @param array $data Calculation data * @param WC_Product $product Product * @param array $rule Rule * @param array $range Discount range * * @return array */function ensure_minimum_discount( $data, $product, $rule, $range ): array { if ( $data['discount_type'] === 'percentage' ) { $data['discount_value'] = max( 10, $data['discount_value'] ?? 0 ); } return $data;}add_filter( 'wpify_woo_discounts_calculate_data', 'ensure_minimum_discount', 10, 4 );Modifying the Discount Calculation Result
Section titled “Modifying the Discount Calculation Result”This filter allows you to modify the result after the discount has been calculated.
apply_filters( 'wpify_woo_discounts_calculate_product_discount', $result, $product, $rule, $range );Filter Parameters
Section titled “Filter Parameters”| Parameter | Type | Description |
|---|---|---|
$result | array | Calculation result (discounted_price, discount_amount, discount_percentage) |
$product | WC_Product | Product |
$rule | array | Rule settings |
$range | array | Discount range |
Usage Examples
Section titled “Usage Examples”Logging Discount Calculations
Section titled “Logging Discount Calculations”/** * Log all discount calculations * * @param array $result Calculation result * @param WC_Product $product Product * @param array $rule Rule * @param array $range Discount range * * @return array */function log_discount_calculation( $result, $product, $rule, $range ): array { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( sprintf( 'Discount calculated: Product #%d, Original: %s, Discounted: %s', $product->get_id(), $result['original_price'] ?? 'N/A', $result['discounted_price'] ?? 'N/A' ) ); } return $result;}add_filter( 'wpify_woo_discounts_calculate_product_discount', 'log_discount_calculation', 10, 4 );Modifying Price Rounding
Section titled “Modifying Price Rounding”This filter allows you to modify the rounding logic of the final discounted price.
apply_filters( 'wpify_woo_discounts_round_price', $rounded_price, $original_price, $rounding_mode, $rule );Filter Parameters
Section titled “Filter Parameters”| Parameter | Type | Description |
|---|---|---|
$rounded_price | float | Price after rounding (according to the configured mode) |
$original_price | float | Price before rounding (after discount) |
$rounding_mode | string | Mode: whole, ending_99, ending_90, ending_9 |
$rule | array | Complete rule data |
Usage Examples
Section titled “Usage Examples”Custom Rounding for VIP Customers
Section titled “Custom Rounding for VIP Customers”/** * Always round down for VIP customers * * @param float $rounded_price Rounded price * @param float $original_price Price before rounding * @param string $rounding_mode Rounding mode * @param array $rule Rule * * @return float */function vip_rounding( $rounded_price, $original_price, $rounding_mode, $rule ): float { if ( current_user_can( 'vip_member' ) ) { return floor( $original_price ); } return $rounded_price;}add_filter( 'wpify_woo_discounts_round_price', 'vip_rounding', 10, 4 );Rounding to Multiples of 10
Section titled “Rounding to Multiples of 10”/** * Round price to multiples of 10 * * @param float $rounded_price Rounded price * @param float $original_price Price before rounding * @param string $rounding_mode Rounding mode * @param array $rule Rule * * @return float */function round_to_tens( $rounded_price, $original_price, $rounding_mode, $rule ): float { return round( $original_price / 10 ) * 10;}add_filter( 'wpify_woo_discounts_round_price', 'round_to_tens', 10, 4 );Controlling Discount Application (Subscriptions)
Section titled “Controlling Discount Application (Subscriptions)”Filter to control whether a discount should be applied. Primarily used for WooCommerce Subscriptions.
apply_filters( 'wpify_woo_discounts_should_apply_discount', $should_apply, $rule );Filter Parameters
Section titled “Filter Parameters”| Parameter | Type | Description |
|---|---|---|
$should_apply | bool | Default value (true) |
$rule | array | Rule data including renewal_behavior |
Usage Examples
Section titled “Usage Examples”Disabling Bulk Discounts on Renewals
Section titled “Disabling Bulk Discounts on Renewals”/** * Never apply bulk discounts on renewal orders * * @param bool $should_apply Default value * @param array $rule Rule * * @return bool */function no_bulk_on_renewals( $should_apply, $rule ): bool { if ( function_exists( 'wcs_cart_contains_renewal' ) && wcs_cart_contains_renewal() ) { if ( ( $rule['rule_type'] ?? '' ) === 'bulk' ) { return false; } } return $should_apply;}add_filter( 'wpify_woo_discounts_should_apply_discount', 'no_bulk_on_renewals', 10, 2 );Available renewal behavior values:
first_order_only- Discount only on the first orderrenewals_only- Discount only on renewal ordersboth- Discount on both (default)
Modifying Target Products
Section titled “Modifying Target Products”This filter allows you to modify the list of target products after they have been prepared.
apply_filters( 'wpify_woo_discounts_targets_prepared', $targets, $rule );Filter Parameters
Section titled “Filter Parameters”| Parameter | Type | Description |
|---|---|---|
$targets | array | Array of target products |
$rule | array | Rule settings |
Usage Example
Section titled “Usage Example”/** * Exclude low-margin products from discount targets * * @param array $targets Target products * @param array $rule Rule * * @return array */function exclude_low_margin_products( $targets, $rule ): array { return array_filter( $targets, function( $target ) { $product_id = $target['product_id'] ?? 0; $margin = get_post_meta( $product_id, '_profit_margin', true ); return $margin > 10; // Exclude products with margin below 10% } );}add_filter( 'wpify_woo_discounts_targets_prepared', 'exclude_low_margin_products', 10, 2 );Modifying Subrule Metadata
Section titled “Modifying Subrule Metadata”This filter allows you to add custom metadata to subrules (discount tiers).
apply_filters( 'wpify_woo_discounts_subrule_metadata', $metadata, $subrule, $rule );Filter Parameters
Section titled “Filter Parameters”| Parameter | Type | Description |
|---|---|---|
$metadata | array | Subrule metadata |
$subrule | array | Subrule data |
$rule | array | Rule settings |
Usage Example
Section titled “Usage Example”/** * Add custom metadata for tracking * * @param array $metadata Metadata * @param array $subrule Subrule * @param array $rule Rule * * @return array */function add_tracking_metadata( $metadata, $subrule, $rule ): array { $metadata['campaign_id'] = $rule['campaign_id'] ?? ''; $metadata['applied_at'] = current_time( 'mysql' ); return $metadata;}add_filter( 'wpify_woo_discounts_subrule_metadata', 'add_tracking_metadata', 10, 3 );Modifying the Quantity Limit
Section titled “Modifying the Quantity Limit”This filter allows you to modify the maximum quantity for a discount.
apply_filters( 'wpify_woo_discounts_quantity_limit', $limit, $product, $rule );Filter Parameters
Section titled “Filter Parameters”| Parameter | Type | Description |
|---|---|---|
$limit | int | Quantity limit |
$product | WC_Product | Product |
$rule | array | Rule settings |
Usage Example
Section titled “Usage Example”/** * Limit quantity for wholesale customers * * @param int $limit Limit * @param WC_Product $product Product * @param array $rule Rule * * @return int */function limit_wholesale_quantity( $limit, $product, $rule ): int { if ( current_user_can( 'wholesale_customer' ) ) { return min( $limit, 100 ); // Max 100 pcs for wholesale } return $limit;}add_filter( 'wpify_woo_discounts_quantity_limit', 'limit_wholesale_quantity', 10, 3 );Fee Application Type
Section titled “Fee Application Type”This filter allows you to modify the fee/discount application type in the cart.
apply_filters( 'wpify_woo_discounts_fee_application_type', $type, $rule );Filter Parameters
Section titled “Filter Parameters”| Parameter | Type | Description |
|---|---|---|
$type | string | Application type (fixed, percent) |
$rule | array | Rule settings |
Usage Example
Section titled “Usage Example”/** * Change application type for specific rules * * @param string $type Application type * @param array $rule Rule * * @return string */function change_fee_application_type( $type, $rule ): string { // Use percentage for rules with the high_value tag if ( in_array( 'high_value', $rule['tags'] ?? [], true ) ) { return 'percent'; } return $type;}add_filter( 'wpify_woo_discounts_fee_application_type', 'change_fee_application_type', 10, 2 );Bundle Set Price
Section titled “Bundle Set Price”This filter returns the price of a concrete bundle product selection — useful for custom selectors, blocks or templates that need to display the bundle price before the products are added to the cart. The filter matches the provided products against active Bundle rules and returns the discounted total of the first matching variant.
apply_filters( 'wpify_woo_discounts_bundle_set_price', $result, $products, $context );Filter Parameters
Section titled “Filter Parameters”| Parameter | Type | Description |
|---|---|---|
$result | array|null | Previously computed payload (pass null as the initial value) |
$products | WC_Product[] | One product per Bundle slot; slot quantities are read from the rule |
$context | array | Optional. 'application_mode' => string|string[] limits matching to rules containing that mode (default: no filtering) |
Return Value
Section titled “Return Value”null when no Bundle variant matches the supplied products; otherwise an array with:
| Key | Type | Description |
|---|---|---|
rule_id | string | Matching rule identifier |
variant_id | string | Matching variant (filter group) identifier |
regular_total | float | Sum of unit_price × slot_qty across all slots |
discounted_total | float | Sum of discounted_unit_price × slot_qty across all slots |
slots | array | Per-slot breakdown: slot_id, product_id, product, slot_qty, unit_price, discounted_unit_price |
html | string | Pre-rendered strikethrough HTML (wc_format_sale_price when discounted, wc_price otherwise) |
Usage Example
Section titled “Usage Example”/** * Render bundle price in a custom selector template. * * @param WC_Product[] $selected_products Products the customer picked. */function render_bundle_set_price( array $selected_products ): void { $price = apply_filters( 'wpify_woo_discounts_bundle_set_price', null, $selected_products );
if ( null === $price ) { return; // no bundle matched }
echo $price['html']; // or build your own markup from $price['regular_total'] / $price['discounted_total']}To limit matching to a specific application mode (e.g. only Auto Price bundles):
$price = apply_filters( 'wpify_woo_discounts_bundle_set_price', null, $selected_products, [ 'application_mode' => 'auto_price' ]);Where to Place the Code
Section titled “Where to Place the Code”You can add custom functions either in your child theme’s functions.php or using the Code Snippets plugin.