Skip to content

Discount Schemes

Discount schemes use a strategy pattern. Each scheme implements the DiscountScheme interface and extends BaseDiscountScheme.

Built-in schemes

Scheme class Enum constant Description
FixedAmountDiscountScheme FIXED_AMOUNT_DISCOUNT Deducts a fixed currency amount; requires amount meta
PercentageOrderDiscountScheme PERCENTAGE_ORDER_DISCOUNT Deducts a percentage of the order total; requires amount meta
OffboardingDiscountScheme OFFBOARDING_ORDER_DISCOUNT Extends PercentageOrderDiscountScheme; can only be granted once per subscription; auto-deleted on cancellation

Scheme interface

interface DiscountScheme {
    public static function enum(): string;
    public static function get_name(): string;
    public static function get_description(): string;
    public static function get_helper_text(): string;
    public function create(WC_Subscription $subscription, string $created_via, array $meta_data = []): DataDiscount;
    public function apply(DataDiscount $discount, WC_Order $order): void;
}

Adding a custom scheme

  1. Create a class extending BaseDiscountScheme:
namespace MyPlugin\DiscountSchemes;

use RenewalDiscounts\DiscountScheme\BaseDiscountScheme;
use RenewalDiscounts\Data\Models\DataDiscount;
use WC_Order;
use WC_Subscription;

class FreeShippingDiscountScheme extends BaseDiscountScheme {
    public const enum = 'FREE_SHIPPING_DISCOUNT';

    public static function enum(): string { return self::enum; }
    public static function get_name(): string { return 'Free Shipping'; }
    public static function get_description(): string { return 'Waives shipping on the next renewal.'; }
    public static function get_helper_text(): string { return ''; }

    protected function can_create(WC_Subscription $subscription, array $meta_data = []): bool {
        return true; // add your guard conditions
    }

    public function apply(DataDiscount $discount, WC_Order $order): void {
        if (!$this->can_apply($discount, $order)) {
            return;
        }
        // apply discount logic here
        $discount->set_order_id($order->get_id());
        $discount->save();
        $this->log_discount_usage($discount, $order);
    }
}
  1. Register the scheme via the filter:
add_filter('renewal-discounts/schemes', function (array $schemes): array {
    $schemes[FreeShippingDiscountScheme::enum()] = FreeShippingDiscountScheme::class;
    return $schemes;
});
  1. Seed the new type in the database (e.g. in a migration):
DataDiscountType::from_scheme(new FreeShippingDiscountScheme())->save();

can_apply guard

BaseDiscountScheme::can_apply() blocks the discount if the renewal order has the _winback_renewal meta set to a non-zero value. Override this method in your scheme to add additional guards.