How to apply a custom coupon to a WooCommerce Subscription recurring amount?

I ned to create a custom coupon for use with WooCommerce Subscriptions because for some reason you can either have one on the sign up fee OR you have one on the recurring amount, but I need a coupon to be applied to both, but there is no option.

I have created a custom coupon using the filter woocommerce_coupon_discount_types, but the filter to then implement this coupon in the cart, woocommerce_coupon_get_discount_amount, does not add it to the recurring amounts, only adds it to the sign up fee.

How does one apply a coupon to the recurring fee?

function dhti_coupon_get_discount_amount($discount, $discounting_amount, $cart_item, $single, $coupon)
{
    if ($coupon-discount_type == 'sign_up_and_recurring_percent')
    {
        $discount = $discounting_amount * $coupon-amount / 100;
        return $discount;
    }
    else
    {
        return $discount;
    }
}
add_filter('woocommerce_coupon_get_discount_amount', 'dhti_coupon_get_discount_amount', 10, 5);

Topic woocommerce-offtopic subscription Wordpress

Category Web


I have managed to find a way, but welcome a better one.

As mentioned in the OP comments, the function remove_coupons() in class WC_Subscriptions_Coupon in file woocommerce-subscriptions/includes/class-wc-subscriptions-coupon.php is removing coupons that are not 'recurring_fee' or 'recurring_percent'. There is no filter added we can tap into to assign our own custom coupon types, so there does not seem to be any chance of getting past this.

So to get around this, we can create our own filter using the same code as the remove_coupons() method, in this case called remove_coupons_custom() and then add this filter in the same way as it is in the original class.

But the original method still runs and will remove our coupon, so we need to then remove the original filter from running by adding remove_action( 'woocommerce_before_calculate_totals', 'WC_Subscriptions_Coupon::remove_coupons', 10 ); in the top of our new function.

I do not like this approach in case the original code is changed to a degree that breaks or stops ours working, but is the only way I can see to do it at the moment, unless the original code is modified to add a filter we can tap into to add our own custom types.

function remove_coupons_custom( $cart )
{
    // Remove original action added by WC_Subscriptions_Coupon class
    remove_action( 'woocommerce_before_calculate_totals', 'WC_Subscriptions_Coupon::remove_coupons', 10 );

    // Create WC_Subscriptions_Coupon instance so we can replace self reference below in original method
    $WC_Subscriptions_Coupon = new WC_Subscriptions_Coupon;

    $calculation_type = WC_Subscriptions_Cart::get_calculation_type();

    // Only hook when totals are being calculated completely (on cart & checkout pages)
    if ( 'none' == $calculation_type || ! WC_Subscriptions_Cart::cart_contains_subscription() || ( ! is_checkout() && ! is_cart() && ! defined( 'WOOCOMMERCE_CHECKOUT' ) && ! defined( 'WOOCOMMERCE_CART' ) ) ) {
        return;
    }

    $applied_coupons = $cart->get_applied_coupons();

    // If we're calculating a sign-up fee or recurring fee only amount, remove irrelevant coupons
    if ( ! empty( $applied_coupons ) ) {

        // Keep track of which coupons, if any, need to be reapplied immediately
        $coupons_to_reapply = array();

        foreach ( $applied_coupons as $coupon_code ) {

            $coupon      = new WC_Coupon( $coupon_code );
            $coupon_type = wcs_get_coupon_property( $coupon, 'discount_type' );

            if ( in_array( $coupon_type, array( 'recurring_fee', 'recurring_percent', 'sign_up_and_recurring_percent' ) ) ) {  // always apply coupons to their specific calculation case
                if ( 'recurring_total' == $calculation_type ) {
                    $coupons_to_reapply[] = $coupon_code;
                } elseif ( 'none' == $calculation_type && ! WC_Subscriptions_Cart::all_cart_items_have_free_trial() ) { // sometimes apply recurring coupons to initial total
                    $coupons_to_reapply[] = $coupon_code;
                } else {
                    $WC_Subscriptions_Coupon::$removed_coupons[] = $coupon_code;
                }
            } elseif ( ( 'none' == $calculation_type ) && ! in_array( $coupon_type, array( 'recurring_fee', 'recurring_percent' ) ) ) { // apply all coupons to the first payment
                $coupons_to_reapply[] = $coupon_code;
            } else {
                $WC_Subscriptions_Coupon::$removed_coupons[] = $coupon_code;
            }
        }
        // Now remove all coupons (WC only provides a function to remove all coupons)
        $cart->remove_coupons();

        // And re-apply those which relate to this calculation
        $cart->applied_coupons = $coupons_to_reapply;

        if ( isset( $cart->coupons ) ) { // WC 2.3+
            $cart->coupons = $cart->get_coupons();
        }
    }
}
add_action( 'woocommerce_before_calculate_totals', 'remove_coupons_custom', 10 );

enter image description here

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.