From a4c5a34e99d2b9d144f3971a69fb43aefe6e697c Mon Sep 17 00:00:00 2001 From: Alessandro Morelli Date: Sat, 22 Dec 2018 10:25:37 +0100 Subject: [PATCH 1/4] Add a new integration hook to allow removal of cart items when the cart is loaded from the session without triggering preset notices. --- includes/class-wc-cart-session.php | 44 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/includes/class-wc-cart-session.php b/includes/class-wc-cart-session.php index 01eade27190..903aa8743bd 100644 --- a/includes/class-wc-cart-session.php +++ b/includes/class-wc-cart-session.php @@ -106,30 +106,36 @@ final class WC_Cart_Session { if ( ! empty( $product ) && $product->exists() && $values['quantity'] > 0 ) { - if ( ! $product->is_purchasable() ) { + if(apply_filter('woocommerce_pre_remove_cart_item_from_session', false, $key, $values)) { $update_cart_session = true; - /* translators: %s: product name */ - wc_add_notice( sprintf( __( '%s has been removed from your cart because it can no longer be purchased. Please contact us if you need assistance.', 'woocommerce' ), $product->get_name() ), 'error' ); - do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); - - } elseif ( ! empty( $values['data_hash'] ) && ! hash_equals( $values['data_hash'], wc_get_cart_item_data_hash( $product ) ) ) { // phpcs:ignore PHPCompatibility.PHP.NewFunctions.hash_equalsFound - $update_cart_session = true; - /* translators: %1$s: product name. %2$s product permalink */ - wc_add_notice( sprintf( __( '%1$s has been removed from your cart because it has since been modified. You can add it back to your cart here.', 'woocommerce' ), $product->get_name(), $product->get_permalink() ), 'notice' ); - do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); + do_action('woocommerce_remove_cart_item_from_session', $key, $values); } else { - // Put session data into array. Run through filter so other plugins can load their own session data. - $session_data = array_merge( - $values, array( - 'data' => $product, - ) - ); + if (!$product->is_purchasable()) { + $update_cart_session = true; + /* translators: %s: product name */ + wc_add_notice(sprintf(__('%s has been removed from your cart because it can no longer be purchased. Please contact us if you need assistance.', 'woocommerce'), $product->get_name()), 'error'); + do_action('woocommerce_remove_cart_item_from_session', $key, $values); - $cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key ); + } elseif (!empty($values['data_hash']) && !hash_equals($values['data_hash'], wc_get_cart_item_data_hash($product))) { // phpcs:ignore PHPCompatibility.PHP.NewFunctions.hash_equalsFound + $update_cart_session = true; + /* translators: %1$s: product name. %2$s product permalink */ + wc_add_notice(sprintf(__('%1$s has been removed from your cart because it has since been modified. You can add it back to your cart here.', 'woocommerce'), $product->get_name(), $product->get_permalink()), 'notice'); + do_action('woocommerce_remove_cart_item_from_session', $key, $values); - // Add to cart right away so the product is visible in woocommerce_get_cart_item_from_session hook. - $this->cart->set_cart_contents( $cart_contents ); + } else { + // Put session data into array. Run through filter so other plugins can load their own session data. + $session_data = array_merge( + $values, array( + 'data' => $product, + ) + ); + + $cart_contents[$key] = apply_filters('woocommerce_get_cart_item_from_session', $session_data, $values, $key); + + // Add to cart right away so the product is visible in woocommerce_get_cart_item_from_session hook. + $this->cart->set_cart_contents($cart_contents); + } } } } From be0f4b45e3798b0badba1616638491d656fe97df Mon Sep 17 00:00:00 2001 From: Alessandro Morelli Date: Mon, 21 Jan 2019 16:54:49 +0100 Subject: [PATCH 2/4] Fix coding standard violations --- includes/class-wc-cart-session.php | 54 ++++++++++++++++-------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/includes/class-wc-cart-session.php b/includes/class-wc-cart-session.php index 903aa8743bd..9895cb280a0 100644 --- a/includes/class-wc-cart-session.php +++ b/includes/class-wc-cart-session.php @@ -30,6 +30,7 @@ final class WC_Cart_Session { * * @since 3.2.0 * @throws Exception If missing WC_Cart object. + * * @param WC_Cart $cart Cart object to calculate totals for. */ public function __construct( &$cart ) { @@ -71,8 +72,8 @@ final class WC_Cart_Session { $update_cart_session = false; // Flag to indicate the stored cart should be updated. $order_again = false; // Flag to indicate whether this is a re-order. - $cart = WC()->session->get( 'cart', null ); - $merge_saved_cart = (bool) get_user_meta( get_current_user_id(), '_woocommerce_load_saved_cart_after_login', true ); + $cart = WC()->session->get( 'cart', null ); + $merge_saved_cart = (bool) get_user_meta( get_current_user_id(), '_woocommerce_load_saved_cart_after_login', true ); // Merge saved cart with current cart. if ( is_null( $cart ) || $merge_saved_cart ) { @@ -106,35 +107,36 @@ final class WC_Cart_Session { if ( ! empty( $product ) && $product->exists() && $values['quantity'] > 0 ) { - if(apply_filter('woocommerce_pre_remove_cart_item_from_session', false, $key, $values)) { + if ( apply_filter( 'woocommerce_pre_remove_cart_item_from_session', false, $key, $values ) ) { $update_cart_session = true; - do_action('woocommerce_remove_cart_item_from_session', $key, $values); + do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); } else { - if (!$product->is_purchasable()) { + if ( ! $product->is_purchasable() ) { $update_cart_session = true; /* translators: %s: product name */ - wc_add_notice(sprintf(__('%s has been removed from your cart because it can no longer be purchased. Please contact us if you need assistance.', 'woocommerce'), $product->get_name()), 'error'); - do_action('woocommerce_remove_cart_item_from_session', $key, $values); + wc_add_notice( sprintf( __( '%s has been removed from your cart because it can no longer be purchased. Please contact us if you need assistance.', 'woocommerce' ), $product->get_name() ), 'error' ); + do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); - } elseif (!empty($values['data_hash']) && !hash_equals($values['data_hash'], wc_get_cart_item_data_hash($product))) { // phpcs:ignore PHPCompatibility.PHP.NewFunctions.hash_equalsFound + } elseif ( ! empty( $values['data_hash'] ) && ! hash_equals( $values['data_hash'], wc_get_cart_item_data_hash( $product ) ) ) { // phpcs:ignore PHPCompatibility.PHP.NewFunctions.hash_equalsFound $update_cart_session = true; /* translators: %1$s: product name. %2$s product permalink */ - wc_add_notice(sprintf(__('%1$s has been removed from your cart because it has since been modified. You can add it back to your cart here.', 'woocommerce'), $product->get_name(), $product->get_permalink()), 'notice'); - do_action('woocommerce_remove_cart_item_from_session', $key, $values); + wc_add_notice( sprintf( __( '%1$s has been removed from your cart because it has since been modified. You can add it back to your cart here.', 'woocommerce' ), $product->get_name(), $product->get_permalink() ), 'notice' ); + do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); } else { // Put session data into array. Run through filter so other plugins can load their own session data. $session_data = array_merge( - $values, array( + $values, + array( 'data' => $product, ) ); - $cart_contents[$key] = apply_filters('woocommerce_get_cart_item_from_session', $session_data, $values, $key); + $cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key ); // Add to cart right away so the product is visible in woocommerce_get_cart_item_from_session hook. - $this->cart->set_cart_contents($cart_contents); + $this->cart->set_cart_contents( $cart_contents ); } } } @@ -281,8 +283,10 @@ final class WC_Cart_Session { * Get a cart from an order, if user has permission. * * @since 3.5.0 - * @param int $order_id Order ID to try to load. + * + * @param int $order_id Order ID to try to load. * @param array $cart Current cart array. + * * @return array */ private function populate_cart_from_order( $order_id, $cart ) { @@ -334,16 +338,16 @@ final class WC_Cart_Session { $product_data = wc_get_product( $variation_id ? $variation_id : $product_id ); $cart[ $cart_id ] = apply_filters( 'woocommerce_add_order_again_cart_item', array_merge( - $cart_item_data, array( - 'key' => $cart_id, - 'product_id' => $product_id, - 'variation_id' => $variation_id, - 'variation' => $variations, - 'quantity' => $quantity, - 'data' => $product_data, - 'data_hash' => wc_get_cart_item_data_hash( $product_data ), - ) - ), $cart_id + $cart_item_data, array( + 'key' => $cart_id, + 'product_id' => $product_id, + 'variation_id' => $variation_id, + 'variation' => $variations, + 'quantity' => $quantity, + 'data' => $product_data, + 'data_hash' => wc_get_cart_item_data_hash( $product_data ), + ) + ), $cart_id ); } @@ -356,7 +360,7 @@ final class WC_Cart_Session { if ( $num_items_in_original_order > $num_items_added ) { wc_add_notice( sprintf( - /* translators: %d item count */ + /* translators: %d item count */ _n( '%d item from your previous order is currently unavailable and could not be added to your cart.', '%d items from your previous order are currently unavailable and could not be added to your cart.', From 9b6694341f89d17d4d64e369135d1c3326b46572 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Tue, 22 Jan 2019 16:01:17 +0000 Subject: [PATCH 3/4] Fix code and improve indenting --- includes/class-wc-cart-session.php | 68 +++++++++++++++++------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/includes/class-wc-cart-session.php b/includes/class-wc-cart-session.php index 9895cb280a0..2d374213bb6 100644 --- a/includes/class-wc-cart-session.php +++ b/includes/class-wc-cart-session.php @@ -99,46 +99,54 @@ final class WC_Cart_Session { $cart_contents = array(); foreach ( $cart as $key => $values ) { - $product = wc_get_product( $values['variation_id'] ? $values['variation_id'] : $values['product_id'] ); - if ( ! is_customize_preview() && 'customize-preview' === $key ) { continue; } - if ( ! empty( $product ) && $product->exists() && $values['quantity'] > 0 ) { + $product = wc_get_product( $values['variation_id'] ? $values['variation_id'] : $values['product_id'] ); - if ( apply_filter( 'woocommerce_pre_remove_cart_item_from_session', false, $key, $values ) ) { - $update_cart_session = true; - do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); + if ( empty( $product ) || ! $product->exists() || 0 >= $values['quantity'] ) { + continue; + } - } else { - if ( ! $product->is_purchasable() ) { - $update_cart_session = true; - /* translators: %s: product name */ - wc_add_notice( sprintf( __( '%s has been removed from your cart because it can no longer be purchased. Please contact us if you need assistance.', 'woocommerce' ), $product->get_name() ), 'error' ); - do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); + /** + * Allow 3rd parties to validate this item before it's added to cart and add their own notices. + * + * @since 3.6.0 + * + * @param bool $remove_cart_item_from_session If true, the item will not be added to the cart. Default: false. + * @param string $key Cart item key. + * @param array $values Cart item values e.g. quantity and product_id. + */ + if ( apply_filters( 'woocommerce_pre_remove_cart_item_from_session', false, $key, $values ) ) { + $update_cart_session = true; + do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); - } elseif ( ! empty( $values['data_hash'] ) && ! hash_equals( $values['data_hash'], wc_get_cart_item_data_hash( $product ) ) ) { // phpcs:ignore PHPCompatibility.PHP.NewFunctions.hash_equalsFound - $update_cart_session = true; - /* translators: %1$s: product name. %2$s product permalink */ - wc_add_notice( sprintf( __( '%1$s has been removed from your cart because it has since been modified. You can add it back to your cart here.', 'woocommerce' ), $product->get_name(), $product->get_permalink() ), 'notice' ); - do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); + } elseif ( ! $product->is_purchasable() ) { + $update_cart_session = true; + /* translators: %s: product name */ + wc_add_notice( sprintf( __( '%s has been removed from your cart because it can no longer be purchased. Please contact us if you need assistance.', 'woocommerce' ), $product->get_name() ), 'error' ); + do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); - } else { - // Put session data into array. Run through filter so other plugins can load their own session data. - $session_data = array_merge( - $values, - array( - 'data' => $product, - ) - ); + } elseif ( ! empty( $values['data_hash'] ) && ! hash_equals( $values['data_hash'], wc_get_cart_item_data_hash( $product ) ) ) { // phpcs:ignore PHPCompatibility.PHP.NewFunctions.hash_equalsFound + $update_cart_session = true; + /* translators: %1$s: product name. %2$s product permalink */ + wc_add_notice( sprintf( __( '%1$s has been removed from your cart because it has since been modified. You can add it back to your cart here.', 'woocommerce' ), $product->get_name(), $product->get_permalink() ), 'notice' ); + do_action( 'woocommerce_remove_cart_item_from_session', $key, $values ); - $cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key ); + } else { + // Put session data into array. Run through filter so other plugins can load their own session data. + $session_data = array_merge( + $values, + array( + 'data' => $product, + ) + ); - // Add to cart right away so the product is visible in woocommerce_get_cart_item_from_session hook. - $this->cart->set_cart_contents( $cart_contents ); - } - } + $cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key ); + + // Add to cart right away so the product is visible in woocommerce_get_cart_item_from_session hook. + $this->cart->set_cart_contents( $cart_contents ); } } From 11b172d583be96a9aed383badfbb48d7b0dd9073 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Tue, 22 Jan 2019 16:04:16 +0000 Subject: [PATCH 4/4] phpcs --- includes/class-wc-cart-session.php | 35 +++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/includes/class-wc-cart-session.php b/includes/class-wc-cart-session.php index 2d374213bb6..d845e7e9a93 100644 --- a/includes/class-wc-cart-session.php +++ b/includes/class-wc-cart-session.php @@ -164,7 +164,7 @@ final class WC_Cart_Session { // If this is a re-order, redirect to the cart page to get rid of the `order_again` query string. if ( $order_again ) { - wp_redirect( wc_get_page_permalink( 'cart' ) ); + wp_safe_redirect( wc_get_page_permalink( 'cart' ) ); exit; } } @@ -235,7 +235,9 @@ final class WC_Cart_Session { public function persistent_cart_update() { if ( get_current_user_id() && apply_filters( 'woocommerce_persistent_cart_enabled', true ) ) { update_user_meta( - get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), array( + get_current_user_id(), + '_woocommerce_persistent_cart_' . get_current_blog_id(), + array( 'cart' => $this->get_cart_for_session(), ) ); @@ -292,7 +294,7 @@ final class WC_Cart_Session { * * @since 3.5.0 * - * @param int $order_id Order ID to try to load. + * @param int $order_id Order ID to try to load. * @param array $cart Current cart array. * * @return array @@ -345,17 +347,20 @@ final class WC_Cart_Session { $cart_id = WC()->cart->generate_cart_id( $product_id, $variation_id, $variations, $cart_item_data ); $product_data = wc_get_product( $variation_id ? $variation_id : $product_id ); $cart[ $cart_id ] = apply_filters( - 'woocommerce_add_order_again_cart_item', array_merge( - $cart_item_data, array( - 'key' => $cart_id, - 'product_id' => $product_id, - 'variation_id' => $variation_id, - 'variation' => $variations, - 'quantity' => $quantity, - 'data' => $product_data, - 'data_hash' => wc_get_cart_item_data_hash( $product_data ), - ) - ), $cart_id + 'woocommerce_add_order_again_cart_item', + array_merge( + $cart_item_data, + array( + 'key' => $cart_id, + 'product_id' => $product_id, + 'variation_id' => $variation_id, + 'variation' => $variations, + 'quantity' => $quantity, + 'data' => $product_data, + 'data_hash' => wc_get_cart_item_data_hash( $product_data ), + ) + ), + $cart_id ); } @@ -368,7 +373,7 @@ final class WC_Cart_Session { if ( $num_items_in_original_order > $num_items_added ) { wc_add_notice( sprintf( - /* translators: %d item count */ + /* translators: %d item count */ _n( '%d item from your previous order is currently unavailable and could not be added to your cart.', '%d items from your previous order are currently unavailable and could not be added to your cart.',