2017-08-18 09:54:41 +00:00
< ? php
/**
* Cart session handling class .
*
* @ package WooCommerce / Classes
2018-03-16 17:45:28 +00:00
* @ version 3.2 . 0
2017-08-18 09:54:41 +00:00
*/
if ( ! defined ( 'ABSPATH' ) ) {
exit ;
}
/**
* WC_Cart_Session class .
*
* @ since 3.2 . 0
*/
final class WC_Cart_Session {
/**
* Reference to cart object .
*
* @ since 3.2 . 0
2017-09-27 16:12:45 +00:00
* @ var WC_Cart
2017-08-18 09:54:41 +00:00
*/
protected $cart ;
/**
* Sets up the items provided , and calculate totals .
*
* @ since 3.2 . 0
2017-09-27 16:12:45 +00:00
* @ throws Exception If missing WC_Cart object .
2017-09-27 16:16:33 +00:00
* @ param WC_Cart $cart Cart object to calculate totals for .
2017-08-18 09:54:41 +00:00
*/
2017-09-27 16:12:45 +00:00
public function __construct ( & $cart ) {
if ( ! is_a ( $cart , 'WC_Cart' ) ) {
throw new Exception ( 'A valid WC_Cart object is required' );
}
2017-08-18 09:54:41 +00:00
$this -> cart = $cart ;
2017-11-03 19:49:45 +00:00
}
2017-08-18 09:54:41 +00:00
2017-11-03 19:49:45 +00:00
/**
* Register methods for this object on the appropriate WordPress hooks .
*/
2017-11-08 15:17:52 +00:00
public function init () {
2017-08-18 09:54:41 +00:00
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' ) );
2018-06-22 12:32:45 +00:00
add_action ( 'shutdown' , array ( $this , 'maybe_set_cart_cookies' ), 0 );
2017-08-18 09:54:41 +00:00
add_action ( 'woocommerce_cart_updated' , array ( $this , 'persistent_cart_update' ) );
}
/**
* Get the cart data from the PHP session and store it in class variables .
*
* @ since 3.2 . 0
*/
public function get_cart_from_session () {
2018-06-22 12:32:45 +00:00
$this -> cart -> set_totals ( WC () -> session -> get ( 'cart_totals' , null ) );
2017-08-18 09:54:41 +00:00
$this -> cart -> set_applied_coupons ( WC () -> session -> get ( 'applied_coupons' , array () ) );
$this -> cart -> set_coupon_discount_totals ( WC () -> session -> get ( 'coupon_discount_totals' , array () ) );
$this -> cart -> set_coupon_discount_tax_totals ( WC () -> session -> get ( 'coupon_discount_tax_totals' , array () ) );
$this -> cart -> set_removed_cart_contents ( WC () -> session -> get ( 'removed_cart_contents' , array () ) );
2018-06-22 12:32:45 +00:00
$update_cart_session = false ; // Flag to indicate the stored cart should be updated.
$cart = WC () -> session -> get ( 'cart' , null );
$merge_saved_cart = ( bool ) get_user_meta ( get_current_user_id (), '_woocommerce_load_saved_cart_after_login' , true );
2018-02-19 16:36:26 +00:00
2018-06-22 12:32:45 +00:00
// Merge saved cart with current cart.
if ( is_null ( $cart ) || $merge_saved_cart ) {
$saved_cart = $this -> get_saved_cart ();
$cart = is_null ( $cart ) ? array () : $cart ;
$cart = array_merge ( $saved_cart , $cart );
2017-12-05 06:45:52 +00:00
$update_cart_session = true ;
2018-06-22 12:32:45 +00:00
delete_user_meta ( get_current_user_id (), '_woocommerce_load_saved_cart_after_login' );
}
// Populate cart from order.
if ( isset ( $_GET [ 'order_again' ], $_GET [ '_wpnonce' ] ) && is_user_logged_in () && wp_verify_nonce ( wp_unslash ( $_GET [ '_wpnonce' ] ), 'woocommerce-order_again' ) ) { // WPCS: input var ok, sanitization ok.
$cart = $this -> populate_cart_from_order ( absint ( $_GET [ 'order_again' ] ), $cart ); // WPCS: input var ok.
}
// Prime caches to reduce future queries.
if ( is_callable ( '_prime_post_caches' ) ) {
_prime_post_caches ( wp_list_pluck ( $cart , 'product_id' ) );
2017-08-18 09:54:41 +00:00
}
2018-06-22 12:32:45 +00:00
$cart_contents = array ();
foreach ( $cart as $key => $values ) {
$product = wc_get_product ( $values [ 'variation_id' ] ? $values [ 'variation_id' ] : $values [ 'product_id' ] );
2017-08-18 09:54:41 +00:00
2018-06-22 12:32:45 +00:00
if ( ! is_customize_preview () && 'customize-preview' === $key ) {
continue ;
2018-05-01 11:39:18 +00:00
}
2017-08-18 09:54:41 +00:00
2018-06-22 12:32:45 +00:00
if ( ! empty ( $product ) && $product -> exists () && $values [ 'quantity' ] > 0 ) {
2017-08-18 09:54:41 +00:00
2018-06-22 12:32:45 +00:00
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 );
} 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 <a href="%2$s">here</a>.' , 'woocommerce' ), $product -> get_name (), $product -> get_permalink () ), 'notice' );
do_action ( 'woocommerce_remove_cart_item_from_session' , $key , $values );
2018-04-11 12:19:39 +00:00
2018-06-22 12:32:45 +00:00
} 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 );
2017-08-18 09:54:41 +00:00
}
}
}
do_action ( 'woocommerce_cart_loaded_from_session' , $this -> cart );
2017-11-07 20:10:13 +00:00
if ( $update_cart_session || is_null ( WC () -> session -> get ( 'cart_totals' , null ) ) ) {
2017-08-18 09:54:41 +00:00
WC () -> session -> set ( 'cart' , $this -> get_cart_for_session () );
$this -> cart -> calculate_totals ();
}
}
/**
* Destroy cart session data .
*
* @ since 3.2 . 0
*/
public function destroy_cart_session () {
WC () -> session -> set ( 'cart' , null );
WC () -> session -> set ( 'cart_totals' , null );
WC () -> session -> set ( 'applied_coupons' , null );
WC () -> session -> set ( 'coupon_discount_totals' , null );
WC () -> session -> set ( 'coupon_discount_tax_totals' , null );
WC () -> session -> set ( 'removed_cart_contents' , null );
WC () -> session -> set ( 'order_awaiting_payment' , null );
}
/**
* Will set cart cookies if needed and when possible .
*
* @ since 3.2 . 0
*/
public function maybe_set_cart_cookies () {
if ( ! headers_sent () && did_action ( 'wp_loaded' ) ) {
if ( ! $this -> cart -> is_empty () ) {
$this -> set_cart_cookies ( true );
2018-03-16 17:45:28 +00:00
} elseif ( isset ( $_COOKIE [ 'woocommerce_items_in_cart' ] ) ) { // WPCS: input var ok.
2017-08-18 09:54:41 +00:00
$this -> set_cart_cookies ( false );
}
}
}
/**
* Sets the php session data for the cart and coupons .
*/
public function set_session () {
WC () -> session -> set ( 'cart' , $this -> get_cart_for_session () );
WC () -> session -> set ( 'cart_totals' , $this -> cart -> get_totals () );
WC () -> session -> set ( 'applied_coupons' , $this -> cart -> get_applied_coupons () );
WC () -> session -> set ( 'coupon_discount_totals' , $this -> cart -> get_coupon_discount_totals () );
WC () -> session -> set ( 'coupon_discount_tax_totals' , $this -> cart -> get_coupon_discount_tax_totals () );
WC () -> session -> set ( 'removed_cart_contents' , $this -> cart -> get_removed_cart_contents () );
do_action ( 'woocommerce_cart_updated' );
}
/**
* Returns the contents of the cart in an array without the 'data' element .
*
* @ return array contents of the cart
*/
public function get_cart_for_session () {
$cart_session = array ();
foreach ( $this -> cart -> get_cart () as $key => $values ) {
$cart_session [ $key ] = $values ;
unset ( $cart_session [ $key ][ 'data' ] ); // Unset product object.
}
return $cart_session ;
}
/**
* Save the persistent cart when the cart is updated .
*/
public function persistent_cart_update () {
2018-02-19 16:36:26 +00:00
if ( get_current_user_id () && apply_filters ( 'woocommerce_persistent_cart_enabled' , true ) ) {
2018-03-16 17:45:28 +00:00
update_user_meta (
get_current_user_id (), '_woocommerce_persistent_cart_' . get_current_blog_id (), array (
'cart' => $this -> get_cart_for_session (),
)
);
2017-08-18 09:54:41 +00:00
}
}
/**
* Delete the persistent cart permanently .
*/
public function persistent_cart_destroy () {
2018-06-22 12:32:45 +00:00
if ( get_current_user_id () ) {
2017-08-18 09:54:41 +00:00
delete_user_meta ( get_current_user_id (), '_woocommerce_persistent_cart_' . get_current_blog_id () );
}
}
/**
* Set cart hash cookie and items in cart .
*
* @ 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' , md5 ( wp_json_encode ( $this -> get_cart_for_session () ) ) );
2018-03-16 17:45:28 +00:00
} elseif ( isset ( $_COOKIE [ 'woocommerce_items_in_cart' ] ) ) { // WPCS: input var ok.
2017-08-18 09:54:41 +00:00
wc_setcookie ( 'woocommerce_items_in_cart' , 0 , time () - HOUR_IN_SECONDS );
wc_setcookie ( 'woocommerce_cart_hash' , '' , time () - HOUR_IN_SECONDS );
}
do_action ( 'woocommerce_set_cart_cookies' , $set );
}
2018-06-22 12:32:45 +00:00
/**
* Get the persistent cart from the database .
*
* @ since 3.5 . 0
* @ return array
*/
private function get_saved_cart () {
$saved_cart = array ();
if ( apply_filters ( 'woocommerce_persistent_cart_enabled' , true ) ) {
$saved_cart_meta = get_user_meta ( get_current_user_id (), '_woocommerce_persistent_cart_' . get_current_blog_id (), true );
if ( isset ( $saved_cart_meta [ 'cart' ] ) ) {
$saved_cart = array_filter ( ( array ) $saved_cart_meta [ 'cart' ] );
}
}
return $saved_cart ;
}
/**
* 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 array $cart Current cart array .
* @ return array
*/
private function populate_cart_from_order ( $order_id , $cart ) {
$order = wc_get_order ( $order_id );
if ( ! $order -> get_id () || ! $order -> has_status ( apply_filters ( 'woocommerce_valid_order_statuses_for_order_again' , array ( 'completed' ) ) ) || ! current_user_can ( 'order_again' , $order -> get_id () ) ) {
return ;
}
if ( apply_filters ( 'woocommerce_empty_cart_when_order_again' , true ) ) {
$cart = array ();
}
$inital_cart_size = count ( $cart );
$order_items = $order -> get_items ();
foreach ( $order_items as $item ) {
$product_id = ( int ) apply_filters ( 'woocommerce_add_to_cart_product_id' , $item -> get_product_id () );
$quantity = $item -> get_quantity ();
$variation_id = ( int ) $item -> get_variation_id ();
$variations = array ();
$cart_item_data = apply_filters ( 'woocommerce_order_again_cart_item_data' , array (), $item , $order );
$product = $item -> get_product ();
if ( ! $product ) {
continue ;
}
// Prevent reordering variable products if no selected variation.
if ( ! $variation_id && $product -> is_type ( 'variable' ) ) {
continue ;
}
foreach ( $item -> get_meta_data () as $meta ) {
if ( taxonomy_is_product_attribute ( $meta -> key ) ) {
$term = get_term_by ( 'slug' , $meta -> value , $meta -> key );
$variations [ $meta -> key ] = $term ? $term -> name : $meta -> value ;
} elseif ( meta_is_product_attribute ( $meta -> key , $meta -> value , $product_id ) ) {
$variations [ $meta -> key ] = $meta -> value ;
}
}
if ( ! apply_filters ( 'woocommerce_add_to_cart_validation' , true , $product_id , $quantity , $variation_id , $variations , $cart_item_data ) ) {
continue ;
}
// Add to cart directly.
$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_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
);
}
do_action ( 'woocommerce_ordered_again' , $order -> get_id () );
$num_items_in_cart = count ( $cart );
$num_items_in_original_order = count ( $order_items );
$num_items_added = $num_items_in_cart - $inital_cart_size ;
if ( $num_items_in_original_order > $num_items_added ) {
wc_add_notice (
sprintf (
2018-06-26 12:49:57 +00:00
/* translators: %d item count */
2018-06-22 12:32:45 +00:00
_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.' ,
$num_items_added ,
'woocommerce'
),
$num_items_added
),
'error'
);
}
if ( 0 < $num_items_added ) {
wc_add_notice ( __ ( 'The cart has been filled with the items from your previous order.' , 'woocommerce' ) );
}
return $cart ;
}
2017-08-18 09:54:41 +00:00
}