From 4e87591245d81c825d84ad6e5642739d85db2909 Mon Sep 17 00:00:00 2001 From: Tofandel Date: Mon, 17 Jul 2023 12:35:39 +0200 Subject: [PATCH 1/4] fix: cloning cart reference in session --- .../includes/class-wc-cart-fees.php | 24 ++++++-------- .../includes/class-wc-cart-session.php | 12 ++++++- .../woocommerce/includes/class-wc-cart.php | 18 ++++++----- .../legacy/unit-tests/cart/cart-fees.php | 2 +- .../tests/php/includes/class-wc-cart-test.php | 31 +++++++++++++++++++ 5 files changed, 62 insertions(+), 25 deletions(-) diff --git a/plugins/woocommerce/includes/class-wc-cart-fees.php b/plugins/woocommerce/includes/class-wc-cart-fees.php index f80376f996a..58c51369881 100644 --- a/plugins/woocommerce/includes/class-wc-cart-fees.php +++ b/plugins/woocommerce/includes/class-wc-cart-fees.php @@ -26,14 +26,6 @@ final class WC_Cart_Fees { */ private $fees = array(); - /** - * Reference to cart object. - * - * @since 3.2.0 - * @var WC_Cart - */ - private $cart; - /** * New fees are made out of these props. * @@ -51,16 +43,18 @@ final class WC_Cart_Fees { /** * Constructor. Reference to the cart. * + * @param null $deprecated Deprecated since WooCommerce 7.9.1. + * * @since 3.2.0 - * @throws Exception If missing WC_Cart object. - * @param WC_Cart $cart Cart object. */ - public function __construct( &$cart ) { - if ( ! is_a( $cart, 'WC_Cart' ) ) { - throw new Exception( 'A valid WC_Cart object is required' ); + public function __construct( $deprecated = null ) { + if ( isset( $deprecated ) ) { + wc_doing_it_wrong( + 'new WC_Cart_Fees', + 'You don\'t need to pass a cart parameter to the WC_Cart_Fees constructor anymore', + '7.9.1' + ); } - - $this->cart = $cart; } /** diff --git a/plugins/woocommerce/includes/class-wc-cart-session.php b/plugins/woocommerce/includes/class-wc-cart-session.php index cfc6bc24284..478e9fdabfa 100644 --- a/plugins/woocommerce/includes/class-wc-cart-session.php +++ b/plugins/woocommerce/includes/class-wc-cart-session.php @@ -33,14 +33,24 @@ final class WC_Cart_Session { * * @param WC_Cart $cart Cart object to calculate totals for. */ - public function __construct( &$cart ) { + public function __construct( $cart ) { if ( ! is_a( $cart, 'WC_Cart' ) ) { throw new Exception( 'A valid WC_Cart object is required' ); } + $this->set_cart( $cart ); + } + + /** + * Sets the cart instance. + * + * @param WC_Cart $cart Cart object. + */ + public function set_cart( WC_Cart $cart ) { $this->cart = $cart; } + /** * Register methods for this object on the appropriate WordPress hooks. */ diff --git a/plugins/woocommerce/includes/class-wc-cart.php b/plugins/woocommerce/includes/class-wc-cart.php index 085f9cfbcb5..84410f9c505 100644 --- a/plugins/woocommerce/includes/class-wc-cart.php +++ b/plugins/woocommerce/includes/class-wc-cart.php @@ -98,7 +98,7 @@ class WC_Cart extends WC_Legacy_Cart { */ public function __construct() { $this->session = new WC_Cart_Session( $this ); - $this->fees_api = new WC_Cart_Fees( $this ); + $this->fees_api = new WC_Cart_Fees(); // Register hooks for the objects. $this->session->init(); @@ -120,6 +120,8 @@ class WC_Cart extends WC_Legacy_Cart { public function __clone() { $this->session = clone $this->session; $this->fees_api = clone $this->fees_api; + + $this->session->set_cart( $this ); } /* @@ -667,7 +669,7 @@ class WC_Cart extends WC_Legacy_Cart { public function get_cart_contents_weight() { $weight = 0.0; - foreach ( $this->get_cart() as $cart_item_key => $values ) { + foreach ( $this->get_cart() as $values ) { if ( $values['data']->has_weight() ) { $weight += (float) $values['data']->get_weight() * $values['quantity']; } @@ -684,7 +686,7 @@ class WC_Cart extends WC_Legacy_Cart { public function get_cart_item_quantities() { $quantities = array(); - foreach ( $this->get_cart() as $cart_item_key => $values ) { + foreach ( $this->get_cart() as $values ) { $product = $values['data']; $quantities[ $product->get_stock_managed_by_id() ] = isset( $quantities[ $product->get_stock_managed_by_id() ] ) ? $quantities[ $product->get_stock_managed_by_id() ] + $values['quantity'] : $values['quantity']; } @@ -759,7 +761,7 @@ class WC_Cart extends WC_Legacy_Cart { $product_qty_in_cart = $this->get_cart_item_quantities(); $current_session_order_id = isset( WC()->session->order_awaiting_payment ) ? absint( WC()->session->order_awaiting_payment ) : 0; - foreach ( $this->get_cart() as $cart_item_key => $values ) { + foreach ( $this->get_cart() as $values ) { $product = $values['data']; // Check stock based on stock-status. @@ -818,7 +820,7 @@ class WC_Cart extends WC_Legacy_Cart { $cross_sells = array(); $in_cart = array(); if ( ! $this->is_empty() ) { - foreach ( $this->get_cart() as $cart_item_key => $values ) { + foreach ( $this->get_cart() as $values ) { if ( $values['quantity'] > 0 ) { $cross_sells = array_merge( $values['data']->get_cross_sell_ids(), $cross_sells ); $in_cart[] = $values['product_id']; @@ -908,7 +910,7 @@ class WC_Cart extends WC_Legacy_Cart { public function get_cart_item_tax_classes() { $found_tax_classes = array(); - foreach ( WC()->cart->get_cart() as $item ) { + foreach ( $this->get_cart() as $item ) { if ( $item['data'] && ( $item['data']->is_taxable() || $item['data']->is_shipping_taxable() ) ) { $found_tax_classes[] = $item['data']->get_tax_class(); } @@ -925,7 +927,7 @@ class WC_Cart extends WC_Legacy_Cart { public function get_cart_item_tax_classes_for_shipping() { $found_tax_classes = array(); - foreach ( WC()->cart->get_cart() as $item ) { + foreach ( $this->get_cart() as $item ) { if ( $item['data'] && ( $item['data']->is_shipping_taxable() ) ) { $found_tax_classes[] = $item['data']->get_tax_class(); } @@ -1536,7 +1538,7 @@ class WC_Cart extends WC_Legacy_Cart { } $needs_shipping = false; - foreach ( $this->get_cart_contents() as $cart_item_key => $values ) { + foreach ( $this->get_cart_contents() as $values ) { if ( $values['data']->needs_shipping() ) { $needs_shipping = true; break; diff --git a/plugins/woocommerce/tests/legacy/unit-tests/cart/cart-fees.php b/plugins/woocommerce/tests/legacy/unit-tests/cart/cart-fees.php index 20721913ccc..1b59e03808e 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/cart/cart-fees.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/cart/cart-fees.php @@ -14,7 +14,7 @@ class WC_Tests_WC_Cart_Fees extends WC_Unit_Test_Case { */ public function test_set_get_remove_fees() { - $cart_fees = new WC_Cart_Fees( wc()->cart ); + $cart_fees = new WC_Cart_Fees(); // Test add_fee. $args = array( diff --git a/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php b/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php index bf6a85bbd9c..57835fc52d3 100644 --- a/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php +++ b/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php @@ -96,6 +96,37 @@ class WC_Cart_Test extends \WC_Unit_Test_Case { $variable_product->delete( true ); } + /** + * Test cloning cart holds no references in session + */ + public function test_cloning_cart_session() { + $product = WC_Helper_Product::create_simple_product(); + + // Initialize $cart1 and $cart2 as empty carts. + $cart1 = WC()->cart; + $cart1->empty_cart(); + $cart2 = clone $cart1; + + // Create a cart in session. + $cart1->add_to_cart( $product->get_id(), 1 ); + $cart1->set_session(); + + // Empty the cart without clearing the session. + $cart1->set_cart_contents( array() ); + + // Both carts are empty at that point. + $this->assertTrue( $cart2->is_empty() ); + $this->assertTrue( $cart1->is_empty() ); + + $cart2->get_cart_from_session(); + + // We retrieved $cart2 from the previously set session so it should not be empty. + $this->assertFalse( $cart2->is_empty() ); + + // We didn't touch $cart1 so it should still be empty. + $this->assertTrue( $cart1->is_empty() ); + } + /** * Test show shipping. */ From 300790271d1e77233d1d6f818a3211a16f54f019 Mon Sep 17 00:00:00 2001 From: Tofandel Date: Wed, 6 Sep 2023 11:20:46 +0200 Subject: [PATCH 2/4] Change deprecated version --- plugins/woocommerce/includes/class-wc-cart-fees.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/includes/class-wc-cart-fees.php b/plugins/woocommerce/includes/class-wc-cart-fees.php index 58c51369881..bc8d6633f4b 100644 --- a/plugins/woocommerce/includes/class-wc-cart-fees.php +++ b/plugins/woocommerce/includes/class-wc-cart-fees.php @@ -43,7 +43,7 @@ final class WC_Cart_Fees { /** * Constructor. Reference to the cart. * - * @param null $deprecated Deprecated since WooCommerce 7.9.1. + * @param null $deprecated Deprecated since WooCommerce 8.0.4. * * @since 3.2.0 */ @@ -52,7 +52,7 @@ final class WC_Cart_Fees { wc_doing_it_wrong( 'new WC_Cart_Fees', 'You don\'t need to pass a cart parameter to the WC_Cart_Fees constructor anymore', - '7.9.1' + '8.0.4' ); } } From dbc2fed88a4e17ed2a31572bcbf1aa7503124ae7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 6 Sep 2023 09:24:24 +0000 Subject: [PATCH 3/4] Add changefile(s) from automation for the following project(s): woocommerce --- plugins/woocommerce/changelog/trunk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/changelog/trunk b/plugins/woocommerce/changelog/trunk index 96319e14d80..2e7f0ab896e 100644 --- a/plugins/woocommerce/changelog/trunk +++ b/plugins/woocommerce/changelog/trunk @@ -1,4 +1,4 @@ Significance: patch Type: fix -Fixes PHP error when WooCommerce menus are created without a position and when users view the WordPress admin dashboard without having WooCommerce admin permissions. +Use correct object reference when cloning a cart From 93aae26b1b0c850de73ab15264c922ed9ead896a Mon Sep 17 00:00:00 2001 From: Tofandel Date: Wed, 6 Sep 2023 20:28:40 +0200 Subject: [PATCH 4/4] Change deprecated version --- plugins/woocommerce/includes/class-wc-cart-fees.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/includes/class-wc-cart-fees.php b/plugins/woocommerce/includes/class-wc-cart-fees.php index bc8d6633f4b..ed1b98cacfc 100644 --- a/plugins/woocommerce/includes/class-wc-cart-fees.php +++ b/plugins/woocommerce/includes/class-wc-cart-fees.php @@ -43,7 +43,7 @@ final class WC_Cart_Fees { /** * Constructor. Reference to the cart. * - * @param null $deprecated Deprecated since WooCommerce 8.0.4. + * @param null $deprecated Deprecated since WooCommerce 8.2.0. * * @since 3.2.0 */ @@ -52,7 +52,7 @@ final class WC_Cart_Fees { wc_doing_it_wrong( 'new WC_Cart_Fees', 'You don\'t need to pass a cart parameter to the WC_Cart_Fees constructor anymore', - '8.0.4' + '8.2.0' ); } }