diff --git a/includes/class-wc-cart-session.php b/includes/class-wc-cart-session.php index a2c2e405d36..960d023d200 100644 --- a/includes/class-wc-cart-session.php +++ b/includes/class-wc-cart-session.php @@ -47,13 +47,19 @@ final class WC_Cart_Session { public function init() { add_action( 'wp_loaded', array( $this, 'get_cart_from_session' ) ); add_action( 'woocommerce_cart_emptied', array( $this, 'destroy_cart_session' ) ); - add_action( 'wp', array( $this, 'maybe_set_cart_cookies' ), 99 ); - add_action( 'woocommerce_add_to_cart', array( $this, 'maybe_set_cart_cookies' ) ); add_action( 'woocommerce_after_calculate_totals', array( $this, 'set_session' ) ); add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'set_session' ) ); add_action( 'woocommerce_removed_coupon', array( $this, 'set_session' ) ); - add_action( 'shutdown', array( $this, 'maybe_set_cart_cookies' ), 0 ); add_action( 'woocommerce_cart_updated', array( $this, 'persistent_cart_update' ) ); + + // Cookie events - cart cookies need to be set before headers are sent. + if ( function_exists( 'header_register_callback' ) ) { + header_register_callback( array( $this, 'maybe_set_cart_cookies' ) ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.header_register_callbackFound + } else { + add_action( 'woocommerce_add_to_cart', array( $this, 'maybe_set_cart_cookies' ) ); + add_action( 'wp', array( $this, 'maybe_set_cart_cookies' ), 99 ); + add_action( 'shutdown', array( $this, 'maybe_set_cart_cookies' ), 0 ); + } } /** @@ -253,18 +259,34 @@ final class WC_Cart_Session { } /** - * Set cart hash cookie and items in cart. + * Set cart hash cookie and items in cart if not already set. * * @param bool $set Should cookies be set (true) or unset. */ private function set_cart_cookies( $set = true ) { if ( $set ) { - wc_setcookie( 'woocommerce_items_in_cart', 1 ); - wc_setcookie( 'woocommerce_cart_hash', WC()->cart->get_cart_hash() ); - } elseif ( isset( $_COOKIE['woocommerce_items_in_cart'] ) ) { // WPCS: input var ok. - wc_setcookie( 'woocommerce_items_in_cart', 0, time() - HOUR_IN_SECONDS ); - wc_setcookie( 'woocommerce_cart_hash', '', time() - HOUR_IN_SECONDS ); + $setcookies = array( + 'woocommerce_items_in_cart' => '1', + 'woocommerce_cart_hash' => WC()->cart->get_cart_hash(), + ); + foreach ( $setcookies as $name => $value ) { + if ( ! isset( $_COOKIE[ $name ] ) || $_COOKIE[ $name ] !== $value ) { + wc_setcookie( $name, $value ); + } + } + } else { + $unsetcookies = array( + 'woocommerce_items_in_cart', + 'woocommerce_cart_hash', + ); + foreach ( $unsetcookies as $name ) { + if ( isset( $_COOKIE[ $name ] ) ) { + wc_setcookie( $name, 0, time() - HOUR_IN_SECONDS ); + unset( $_COOKIE[ $name ] ); + } + } } + do_action( 'woocommerce_set_cart_cookies', $set ); } diff --git a/includes/class-wc-session-handler.php b/includes/class-wc-session-handler.php index 5a4907b1a97..6e18f6774f9 100644 --- a/includes/class-wc-session-handler.php +++ b/includes/class-wc-session-handler.php @@ -111,7 +111,9 @@ class WC_Session_Handler extends WC_Session { $cookie_value = $this->_customer_id . '||' . $this->_session_expiration . '||' . $this->_session_expiring . '||' . $cookie_hash; $this->_has_cookie = true; - wc_setcookie( $this->_cookie, $cookie_value, $this->_session_expiration, apply_filters( 'wc_session_use_secure_cookie', false ) ); + if ( ! isset( $_COOKIE[ $this->_cookie ] ) || $_COOKIE[ $this->_cookie ] !== $cookie_value ) { + wc_setcookie( $this->_cookie, $cookie_value, $this->_session_expiration, apply_filters( 'wc_session_use_secure_cookie', false ) ); + } } }