Implement Discount Pricing for Expiring Products

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInPrint this page

By woocommerce-sl, posted on February 26, 2026

Keeping licenses active is good for customers — and essential for recurring revenue. The Implement Discount Pricing for Expiring Products feature lets you automatically offer renewal discounts based on how close a license is to expiring (or how long it has been expired). This article explains how the feature works, how to configure rules programmatically, and the benefits of using expiration-aware discounts.

How it works

The feature hooks into the existing Expire functionality (see Create Expiration for License Product ) and lets you modify renewal pricing via the woo_sl/default_expire/renew_price filter. You supply a set of discount rules that map time ranges to discount percentages; when a renewal price is calculated the filter applies the correct discount based on the license’s time-to-expiry or time-since-expiry.

Discount rules format

Rules are passed as an associative array with two top-level sections: before-expire and after-expire. Keys are ranges (days) and values are discount percentages. Example structure:

    $discount_rules = [
                        'before-expire' => [
                            '30-6' => 40,  // between 6 and 30 days before expiry => 40%
                            '5-0'  => 35,   // 0 to 5 days before expiry => 35%
                        ],
                        'after-expire'  => [
                            '0-14'   => 30,  // expired 0 to 14 days => 30%
                            '15-29'  => 25,  // expired 15 to 30 days => 25%
                            '30-180' => 20,  // expired 31 to 180 days => 20%
                            '181-'   => 10,  // expired 181 days or more => 10%
                        ],
                    ];

 

  • Ranges are day intervals. 30-6 means the range between 6 and 30 days before expiration (order can be interpreted by your parser — be consistent).
  • 181- means 181 days or more.
  • Values are percentages (e.g., 40 = 40% discount).

Where to put the code

You can inject the code inside a custom file on your /wp-content/mu-plugins/ folder.

    add_filter('woo_sl/default_expire/renew_price', 'woosl_apply_renew_discount', 10, 2 );
    /**
     * Apply a renew discount based on license expire / expired timestamps and a discount rules array.
     *
     * @param float $renew_price
     * @param int   $order_item_id
     * @param array $discount_rules Optional. If not provided the default rules (from your spec) are used.
     * @return float Discounted price (rounded to 2 decimals). If no discount applies returns the original price.
     */
    function woosl_apply_renew_discount( $renew_price, $order_item_id, $discount_rules = null ) 
        {
            // default rules (PHP array syntax)
            if ( $discount_rules === null ) 
                {
                    $discount_rules = [
                                            'before-expire' => [
                                                '30-6' => 40,  // between 6 and 30 days before expiry => 40%
                                                '5-0'  => 35,   // 0 to 5 days before expiry => 35%
                                            ],
                                            'after-expire'  => [
                                                '0-14'   => 30,  // expired 0 to 14 days => 30%
                                                '15-29'  => 25,  // expired 15 to 30 days => 25%
                                                '30-180' => 20,  // expired 31 to 180 days => 20%
                                                '181-'   => 10,  // expired 181 days or more => 10%
                                            ],
                                        ];
                }

            // Fetch timestamps from order item meta (as per your original code)
            $license_expire_at  = WOO_SL_functions::get_order_item_meta( $order_item_id, '_woo_sl_licensing_expire_at',  TRUE );
            $license_expired_at = WOO_SL_functions::get_order_item_meta( $order_item_id, '_woo_sl_licensing_expired_at',  TRUE );

            $now = time();

            // normalize timestamps to integers (0 if not numeric)
            $expire_ts  = is_numeric( $license_expire_at ) ? (int) $license_expire_at : 0;
            $expired_ts = is_numeric( $license_expired_at ) ? (int) $license_expired_at : 0;

            // helper to find matching discount percent from a rules array for a given days value
            $find_discount_for_days = function( array $rules, $days ) {
                // iterate rules in array order (preserves user's ordering)
                foreach ( $rules as $range => $pct ) 
                    {
                        // parse "A-B", "A-" or "-B" formats
                        $parts = explode( '-', $range, 2 );
                        $a = isset( $parts[0] ) && $parts[0] !== '' ? (int) $parts[0] : null;
                        $b = isset( $parts[1] ) && $parts[1] !== '' ? (int) $parts[1] : null;

                        // If both are null — skip invalid rule
                        if ( $a === null && $b === null ) {
                            continue;
                        }

                        // Determine min and max for inclusive comparison
                        if ( $a === null ) {
                            $min = PHP_INT_MIN;
                            $max = $b;
                        } elseif ( $b === null ) {
                            $min = $a;
                            $max = PHP_INT_MAX;
                        } else {
                            // handle reversed ranges like "30-6" by normalizing min/max
                            $min = min( $a, $b );
                            $max = max( $a, $b );
                        }

                        if ( $days >= $min && $days <= $max ) {
                            return (float) $pct;
                        }
                    }

                return 0.0; // no match
            };

            $DAY = 86400;

            $applied_pct = 0.0;

            if ( $expire_ts > 0 ) 
                {
                    if ( $expire_ts > $now ) 
                        {
                            // license not yet expired -> days until expiry
                            // Use ceil so partial day counts as a full day remaining (you can change to floor if you prefer)
                            $days_to_expire = (int) ceil( ( $expire_ts - $now ) / $DAY );

                            // find discount in before-expire rules
                            if ( ! empty( $discount_rules['before-expire'] ) && is_array( $discount_rules['before-expire'] ) ) {
                                $applied_pct = $find_discount_for_days( $discount_rules['before-expire'], $days_to_expire );
                            }
                        } 
                    else 
                        {
                            // expired already -> days since expiry
                            // Use floor so only completed days count as "days since"
                            $days_since_expiry = (int) floor( ( $now - $expire_ts ) / $DAY );

                            if ( ! empty( $discount_rules['after-expire'] ) && is_array( $discount_rules['after-expire'] ) ) {
                                $applied_pct = $find_discount_for_days( $discount_rules['after-expire'], $days_since_expiry );
                            }
                        }
                } 
            elseif ( $expired_ts > 0 ) {
                // no expire timestamp, rely on expired timestamp (assumed in the past)
                $days_since_expiry = (int) floor( ( $now - $expired_ts ) / $DAY );

                if ( ! empty( $discount_rules['after-expire'] ) && is_array( $discount_rules['after-expire'] ) ) {
                    $applied_pct = $find_discount_for_days( $discount_rules['after-expire'], $days_since_expiry );
                }
            } else {
                // no timestamps at all -> no discount
                $applied_pct = 0.0;
            }

            // Ensure renew price numeric
            $renew_price = (float) $renew_price;

            if ( $applied_pct > 0 ) {
                $discounted_price = round( $renew_price * ( 1 - ( $applied_pct / 100.0 ) ), 2 );
            } else {
                $discounted_price = round( $renew_price, 2 );
            }


            return $discounted_price;
        }

Benefits

  • Higher renewal conversion — Timely discounts reduce friction for customers on the fence and increase the likelihood of on-time renewals.
  • Targeted reactivation — Automated post-expiry discounts (e.g., first 14 days) are a low-touch way to win back lapsed customers.
  • Flexible marketing — Define different discount intensities for “about to expire” vs. “long expired” to match business strategy.
  • Reduced churn & predictable revenue — Offering graduated discounts keeps customers on board and smooths renewal cycles.
  • Automation & consistency — Centralized rules mean every license follows the same logic — no manual price edits.
  • A/B and analytics-friendly — Because rules are data-driven, you can test different percentages and ranges and measure lift.

 

License renewals are a critical moment in the customer lifecycle. When a product is close to expiring—or has already expired—users are more likely to hesitate, delay, or abandon renewal altogether. Instead of relying solely on reminder emails or manual promotions, WP Software License allows you to turn these moments into opportunities by applying automatic, expiration-based discount pricing.

With the Implement Discount Pricing for Expiring Products feature, you can dynamically adjust renewal prices based on how many days remain before a license expires or how long it has been inactive. By leveraging the built-in expiration functionality and a simple programmatic filter, you gain full control over renewal incentives—rewarding early renewals, encouraging quick reactivation, and reducing long-term churn without ongoing manual effort.

This approach not only improves the renewal experience for customers but also creates a predictable, data-driven strategy for maximizing lifetime value. In the sections below, you’ll learn how expiration-based discounting works, how to define flexible discount rules, and why this feature is a powerful addition to any license-based business.


Category:
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments