diff --git a/plugins/woocommerce/changelog/fix-27077-order-editor-coupons-deleted-products b/plugins/woocommerce/changelog/fix-27077-order-editor-coupons-deleted-products new file mode 100644 index 00000000000..980bc32a838 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-27077-order-editor-coupons-deleted-products @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Addresses a fatal error that can occur when applying a coupon within the order editor (where one of the products has been deleted). diff --git a/plugins/woocommerce/includes/class-wc-coupon.php b/plugins/woocommerce/includes/class-wc-coupon.php index 15eb38739ee..46b690447a7 100644 --- a/plugins/woocommerce/includes/class-wc-coupon.php +++ b/plugins/woocommerce/includes/class-wc-coupon.php @@ -906,7 +906,7 @@ class WC_Coupon extends WC_Legacy_Coupon { * @return bool */ public function is_valid_for_product( $product, $values = array() ) { - if ( ! $this->is_type( wc_get_product_coupon_types() ) ) { + if ( ! $this->is_type( wc_get_product_coupon_types() ) || ! is_a( $product, WC_Product::class ) ) { return apply_filters( 'woocommerce_coupon_is_valid_for_product', false, $product, $this, $values ); } diff --git a/plugins/woocommerce/tests/php/includes/class-wc-coupon-test.php b/plugins/woocommerce/tests/php/includes/class-wc-coupon-test.php new file mode 100644 index 00000000000..f7a781843ef --- /dev/null +++ b/plugins/woocommerce/tests/php/includes/class-wc-coupon-test.php @@ -0,0 +1,52 @@ + 'percent', + 'coupon_amount' => 10, + ) + ); + + // Add our further product to the order, but then delete the product itself. + $order->add_product( $extra_product ); + $order->save(); + wp_delete_post( $extra_product->get_id(), true ); + + $this->assertTrue( + $order->apply_coupon( $coupon ), + 'The coupon was successfully applied to an order containing a deleted product, without triggering an error.' + ); + + // Both products have a cost of $10. The first item has a quantity of 4 units ($40). So, the 10% discount + // should give an actual discount total of $4 (the second line item is excluded from the calculation, because + // its product was deleted). + $this->assertEquals( + 4, + $order->get_discount_total(), + 'Line items associated with deleted products are not included in the discount calculation.' + ); + } +}