Automattic / woocommerce-subscriptions-core

Subscriptions core package for WooCommerce
Other
80 stars 29 forks source link

Fatal Error on Adding Coupon with Recurring Product to Cart #630

Open felipepitol opened 1 month ago

felipepitol commented 1 month ago

Describe the bug

I encountered a fatal error after activating the Smart Coupons plugin and generating a coupon that offers a discount on a recurring product, limited to 3 payments. The error occurred when attempting to add the product and apply the coupon directly to the cart using the following URL structure:

/checkout/?add-to-cart=26470&quantity=1&coupon_code=DISCOUNT24

Fatal error: Uncaught Error: Call to a member function supports() on string in .../wp-content/plugins/woocommerce-subscriptions/includes/class-wcs-limited-recurring-coupon-manager.php on line 166

To Reproduce

  1. Activate the Smart Coupons plugin.
  2. Create a coupon with a discount on a recurring product, limited to 3 payments.
  3. Use the URL to add the product and coupon directly to the cart (e.g., /checkout/?add-to-cart=26470&quantity=1&coupon_code=DISCOUNT24). // you need to change to your product id

Detailed Error Explanation:

The error is caused by the function limit_gateways_subscription_amount_changes() in the class-wcs-limited-recurring-coupon-manager.php file. This function attempts to call the supports() method on $gateway objects. However, under certain conditions, $gateway may be a string instead of an object, leading to a fatal error.

Solution:

To fix this issue, I added a check to ensure that $gateway is an object before calling the supports() method. Here is the updated code for the limit_gateways_subscription_amount_changes() function:

 * Limits payment gateways to those that support changing subscription amounts.
 *
 * @since 4.0.0
 * @param WC_Payment_Gateway[] $gateways The current available gateways.
 * @return WC_Payment_Gateway[]
 */
private static function limit_gateways_subscription_amount_changes( $gateways ) {
    foreach ( $gateways as $index => $gateway ) {
        if ( is_object( $gateway ) && $gateway->supports( 'subscriptions' ) && ! $gateway->supports( 'subscription_amount_changes' ) ) {
            unset( $gateways[ $index ] );
        }
    }

    return $gateways;
}

Summary:

This fix ensures that the supports() method is only called on valid objects, preventing the fatal error from occurring. Please consider incorporating this fix into the plugin to avoid similar issues for other users.