diff --git a/classes/class-wc-cart.php b/classes/class-wc-cart.php index 4b9dc2d9a12..e93769fcf22 100644 --- a/classes/class-wc-cart.php +++ b/classes/class-wc-cart.php @@ -5,22 +5,18 @@ * The WooCommerce cart class stores cart data and active coupons as well as handling customer sessions and some cart related urls. * The cart class also has a price calculation function which calls upon other classes to calculate totals. * - * @class WC_Cart - * @package WooCommerce - * @category Class - * @author WooThemes + * @class WC_Cart + * @package WooCommerce + * @category Class + * @author WooThemes */ class WC_Cart { - - /* Public Variables */ var $cart_contents; var $applied_coupons; - var $cart_contents_total; var $cart_contents_weight; var $cart_contents_count; var $cart_contents_tax; - var $total; var $subtotal; var $subtotal_ex_tax; @@ -32,18 +28,18 @@ class WC_Cart { var $shipping_total; var $shipping_tax_total; var $shipping_label; - - /* Private variables */ var $tax; /** * Constructor + * + * Gets options from DB, loads the tax class, and queues the cart init */ function __construct() { $this->tax = new WC_Tax(); - $this->prices_include_tax = (get_option('woocommerce_prices_include_tax')=='yes') ? true : false; - $this->display_totals_ex_tax = (get_option('woocommerce_display_totals_excluding_tax')=='yes') ? true : false; - $this->display_cart_ex_tax = (get_option('woocommerce_display_cart_prices_excluding_tax')=='yes') ? true : false; + $this->prices_include_tax = ( get_option('woocommerce_prices_include_tax') == 'yes' ) ? true : false; + $this->display_totals_ex_tax = ( get_option('woocommerce_display_totals_excluding_tax') == 'yes' ) ? true : false; + $this->display_cart_ex_tax = ( get_option('woocommerce_display_cart_prices_excluding_tax') == 'yes' ) ? true : false; } /** @@ -67,69 +63,67 @@ class WC_Cart { global $woocommerce; // Load the coupons - if ( get_option( 'woocommerce_enable_coupons' ) == 'yes' ) { - $this->applied_coupons = (isset($_SESSION['coupons'])) ? array_unique(array_filter((array) $_SESSION['coupons'])) : array(); - } + if ( get_option('woocommerce_enable_coupons') == 'yes' ) + $this->applied_coupons = ( empty( $_SESSION['coupons'] ) ) ? array() : array_unique( array_filter( (array) $_SESSION['coupons'] ) ); // Load the cart - if ( isset($_SESSION['cart']) && is_array($_SESSION['cart']) ) : + if ( isset( $_SESSION['cart'] ) && is_array( $_SESSION['cart'] ) ) { $cart = $_SESSION['cart']; - foreach ($cart as $key => $values) : + foreach ( $cart as $key => $values ) { - if ($values['variation_id'] > 0) : - $_product = new WC_Product_Variation($values['variation_id']); - else : - $_product = new WC_Product($values['product_id']); - endif; + if ( $values['variation_id'] > 0 ) + $_product = new WC_Product_Variation( $values['variation_id'] ); + else + $_product = new WC_Product( $values['product_id'] ); - if ($_product->exists && $values['quantity']>0) : + if ( $_product->exists && $values['quantity'] > 0 ) { // Put session data into array. Run through filter so other plugins can load their own session data - $this->cart_contents[$key] = apply_filters('woocommerce_get_cart_item_from_session', array( + $this->cart_contents[$key] = apply_filters( 'woocommerce_get_cart_item_from_session', array( 'product_id' => $values['product_id'], 'variation_id' => $values['variation_id'], 'variation' => $values['variation'], 'quantity' => $values['quantity'], 'data' => $_product - ), $values); + ), $values ); - endif; - endforeach; + } + } - if (!is_array($this->cart_contents)) : + if ( ! is_array( $this->cart_contents ) ) $this->cart_contents = array(); - endif; - else : + } else { $this->cart_contents = array(); - endif; + } // Cookie - if (sizeof($this->cart_contents)>0) + if ( sizeof( $this->cart_contents ) > 0 ) $woocommerce->cart_has_contents_cookie( true ); else $woocommerce->cart_has_contents_cookie( false ); // Load totals - $this->cart_contents_total = isset($_SESSION['cart_contents_total']) ? $_SESSION['cart_contents_total'] : 0; - $this->cart_contents_weight = isset($_SESSION['cart_contents_weight']) ? $_SESSION['cart_contents_weight'] : 0; - $this->cart_contents_count = isset($_SESSION['cart_contents_count']) ? $_SESSION['cart_contents_count'] : 0; - $this->cart_contents_tax = isset($_SESSION['cart_contents_tax']) ? $_SESSION['cart_contents_tax'] : 0; - $this->total = isset($_SESSION['total']) ? $_SESSION['total'] : 0; - $this->subtotal = isset($_SESSION['subtotal']) ? $_SESSION['subtotal'] : 0; - $this->subtotal_ex_tax = isset($_SESSION['subtotal_ex_tax']) ? $_SESSION['subtotal_ex_tax'] : 0; - $this->tax_total = isset($_SESSION['tax_total']) ? $_SESSION['tax_total'] : 0; - $this->taxes = isset($_SESSION['taxes']) ? $_SESSION['taxes'] : array(); - $this->shipping_taxes = isset($_SESSION['shipping_taxes']) ? $_SESSION['shipping_taxes'] : array(); - $this->discount_cart = isset($_SESSION['discount_cart']) ? $_SESSION['discount_cart'] : 0; - $this->discount_total = isset($_SESSION['discount_total']) ? $_SESSION['discount_total'] : 0; - $this->shipping_total = isset($_SESSION['shipping_total']) ? $_SESSION['shipping_total'] : 0; - $this->shipping_tax_total = isset($_SESSION['shipping_tax_total']) ? $_SESSION['shipping_tax_total'] : 0; - $this->shipping_label = isset($_SESSION['shipping_label']) ? $_SESSION['shipping_label'] : ''; + $this->cart_contents_total = isset( $_SESSION['cart_contents_total'] ) ? $_SESSION['cart_contents_total'] : 0; + $this->cart_contents_weight = isset( $_SESSION['cart_contents_weight'] ) ? $_SESSION['cart_contents_weight'] : 0; + $this->cart_contents_count = isset( $_SESSION['cart_contents_count'] ) ? $_SESSION['cart_contents_count'] : 0; + $this->cart_contents_tax = isset( $_SESSION['cart_contents_tax'] ) ? $_SESSION['cart_contents_tax'] : 0; + $this->total = isset( $_SESSION['total'] ) ? $_SESSION['total'] : 0; + $this->subtotal = isset( $_SESSION['subtotal'] ) ? $_SESSION['subtotal'] : 0; + $this->subtotal_ex_tax = isset( $_SESSION['subtotal_ex_tax'] ) ? $_SESSION['subtotal_ex_tax'] : 0; + $this->tax_total = isset( $_SESSION['tax_total'] ) ? $_SESSION['tax_total'] : 0; + $this->taxes = isset( $_SESSION['taxes'] ) ? $_SESSION['taxes'] : array(); + $this->shipping_taxes = isset( $_SESSION['shipping_taxes'] ) ? $_SESSION['shipping_taxes'] : array(); + $this->discount_cart = isset( $_SESSION['discount_cart'] ) ? $_SESSION['discount_cart'] : 0; + $this->discount_total = isset( $_SESSION['discount_total'] ) ? $_SESSION['discount_total'] : 0; + $this->shipping_total = isset( $_SESSION['shipping_total'] ) ? $_SESSION['shipping_total'] : 0; + $this->shipping_tax_total = isset( $_SESSION['shipping_tax_total'] ) ? $_SESSION['shipping_tax_total'] : 0; + $this->shipping_label = isset( $_SESSION['shipping_label'] ) ? $_SESSION['shipping_label'] : ''; // Queue re-calc if subtotal is not set - if (!$this->subtotal && sizeof($this->cart_contents)>0) $this->set_session(); + if ( ! $this->subtotal && sizeof( $this->cart_contents ) > 0 ) + $this->set_session(); } /** @@ -143,12 +137,14 @@ class WC_Cart { // Set cart and coupon session data $cart_session = array(); - if ($this->cart_contents) foreach ($this->cart_contents as $key => $values) { - - $cart_session[$key] = $values; - - // Unset product object - unset($cart_session[$key]['data']); + if ( $this->cart_contents ) { + foreach ( $this->cart_contents as $key => $values ) { + + $cart_session[$key] = $values; + + // Unset product object + unset( $cart_session[$key]['data'] ); + } } $_SESSION['cart'] = $cart_session; @@ -171,13 +167,17 @@ class WC_Cart { $_SESSION['shipping_tax_total'] = $this->shipping_tax_total; $_SESSION['shipping_label'] = $this->shipping_label; - if (get_current_user_id()) $this->persistent_cart_update(); + if (get_current_user_id()) + $this->persistent_cart_update(); do_action('woocommerce_cart_updated'); } /** - * Empty the cart data and destroy the session + * Empties the cart and optionally the persistent cart too + * + * @access public + * @param bool $clear_persistent_cart (default: true) */ function empty_cart( $clear_persistent_cart = true ) { @@ -186,7 +186,8 @@ class WC_Cart { unset( $_SESSION['coupons'], $_SESSION['cart'] ); - if ($clear_persistent_cart && get_current_user_id()) $this->persistent_cart_destroy(); + if ( $clear_persistent_cart && get_current_user_id() ) + $this->persistent_cart_destroy(); do_action('woocommerce_cart_emptied'); } @@ -223,39 +224,48 @@ class WC_Cart { // Check item stock $result = $this->check_cart_item_stock(); - if (is_wp_error($result)) $woocommerce->add_error( $result->get_error_message() ); + + if (is_wp_error($result)) + $woocommerce->add_error( $result->get_error_message() ); } /** * Check for user coupons (now we have billing email) - **/ + * + * @access public + * @param array $posted + */ function check_customer_coupons( $posted ) { global $woocommerce; - if (!empty($this->applied_coupons)) foreach ($this->applied_coupons as $key => $code) { - $coupon = new WC_Coupon( $code ); - - if (is_array($coupon->customer_email) && sizeof($coupon->customer_email)>0) { - if (is_user_logged_in()) { - $current_user = wp_get_current_user(); - $check_emails[] = $current_user->user_email; - } - $check_emails[] = $posted['billing_email']; + if ( ! empty( $this->applied_coupons ) ) { + foreach ( $this->applied_coupons as $key => $code ) { + $coupon = new WC_Coupon( $code ); - if (!in_array($check_emails, $coupon->customer_email)) { - $woocommerce->add_error( sprintf(__('Sorry, it seems the coupon "%s" is not yours - it has now been removed from your order.', 'woocommerce'), $code) ); - // Remove the coupon - unset( $this->applied_coupons[$key] ); - $_SESSION['coupons'] = $this->applied_coupons; - $_SESSION['refresh_totals'] = true; + if ( is_array( $coupon->customer_email ) && sizeof( $coupon->customer_email ) > 0 ) { + if ( is_user_logged_in() ) { + $current_user = wp_get_current_user(); + $check_emails[] = $current_user->user_email; + } + $check_emails[] = $posted['billing_email']; + + if ( ! in_array($check_emails, $coupon->customer_email) ) { + $woocommerce->add_error( sprintf( __('Sorry, it seems the coupon "%s" is not yours - it has now been removed from your order.', 'woocommerce'), $code ) ); + // Remove the coupon + unset( $this->applied_coupons[$key] ); + $_SESSION['coupons'] = $this->applied_coupons; + $_SESSION['refresh_totals'] = true; + } } } - } } - - /** - * looks through the cart to check each item is in stock + + /** + * Looks through the cart to check each item is in stock + * + * @access public + * @return bool */ function check_cart_item_stock() { $error = new WP_Error(); @@ -263,19 +273,19 @@ class WC_Cart { $product_qty_in_cart = array(); // First stock check loop - foreach ($this->get_cart() as $cart_item_key => $values) { + foreach ( $this->get_cart() as $cart_item_key => $values ) { $_product = $values['data']; /** * Check stock based on inventory */ - if ($_product->managing_stock()) { + if ( $_product->managing_stock() ) { /** * Check the stock for this item individually */ - if (!$_product->is_in_stock() || !$_product->has_enough_stock( $values['quantity'] )) { + if ( ! $_product->is_in_stock() || ! $_product->has_enough_stock( $values['quantity'] ) ) { $error->add( 'out-of-stock', sprintf(__('Sorry, we do not have enough "%s" in stock to fulfill your order (%s in stock). Please edit your cart and try again. We apologise for any inconvenience caused.', 'woocommerce'), $_product->get_title(), $_product->stock ) ); return $error; } @@ -299,7 +309,7 @@ class WC_Cart { * Check stock based on stock-status */ } else { - if (!$_product->is_in_stock()) { + if ( ! $_product->is_in_stock() ) { $error->add( 'out-of-stock', sprintf(__('Sorry, we do not have enough "%s" in stock to fulfill your order. Please edit your cart and try again. We apologise for any inconvenience caused.', 'woocommerce'), $_product->get_title() ) ); return $error; } @@ -307,22 +317,22 @@ class WC_Cart { } // This time check merged rows - foreach ($this->get_cart() as $cart_item_key => $values) { + foreach ( $this->get_cart() as $cart_item_key => $values ) { $_product = $values['data']; - if ($_product->managing_stock()) { + if ( $_product->managing_stock() ) { - if ($values['variation_id'] && $_product->variation_has_stock && isset($product_qty_in_cart[$values['variation_id']])) { + if ( $values['variation_id'] && $_product->variation_has_stock && isset( $product_qty_in_cart[$values['variation_id']] ) ) { - if (!$_product->has_enough_stock( $product_qty_in_cart[$values['variation_id']] )) { + if ( ! $_product->has_enough_stock( $product_qty_in_cart[$values['variation_id']] ) ) { $error->add( 'out-of-stock', sprintf(__('Sorry, we do not have enough "%s" in stock to fulfill your order (%s in stock). Please edit your cart and try again. We apologise for any inconvenience caused.', 'woocommerce'), $_product->get_title(), $_product->stock ) ); return $error; } - } elseif (isset($product_qty_in_cart[$values['product_id']])) { + } elseif ( isset( $product_qty_in_cart[$values['product_id']] ) ) { - if (!$_product->has_enough_stock( $product_qty_in_cart[$values['product_id']] )) { + if ( ! $_product->has_enough_stock( $product_qty_in_cart[$values['product_id']] ) ) { $error->add( 'out-of-stock', sprintf(__('Sorry, we do not have enough "%s" in stock to fulfill your order (%s in stock). Please edit your cart and try again. We apologise for any inconvenience caused.', 'woocommerce'), $_product->get_title(), $_product->stock ) ); return $error; } @@ -338,128 +348,148 @@ class WC_Cart { /** * Gets and formats a list of cart item data + variations for display on the frontend + * + * @access public + * @param array $cart_item + * @param bool $flat (default: false) + * @return string */ function get_item_data( $cart_item, $flat = false ) { global $woocommerce; $has_data = false; - if (!$flat) $return = '
'; + if ( ! $flat ) $return = '
'; // Variation data - if($cart_item['data'] instanceof WC_Product_Variation && is_array($cart_item['variation'])) : + if ( $cart_item['data'] instanceof WC_Product_Variation && is_array( $cart_item['variation'] ) ) { $variation_list = array(); - foreach ($cart_item['variation'] as $name => $value) : + foreach ( $cart_item['variation'] as $name => $value ) { - if (!$value) continue; + if ( ! $value ) continue; // If this is a term slug, get the term's nice name - if (taxonomy_exists(esc_attr(str_replace('attribute_', '', $name)))) : - $term = get_term_by('slug', $value, esc_attr(str_replace('attribute_', '', $name))); - if (!is_wp_error($term) && $term->name) : + if ( taxonomy_exists( esc_attr( str_replace( 'attribute_', '', $name ) ) ) ) { + $term = get_term_by( 'slug', $value, esc_attr( str_replace( 'attribute_', '', $name ) ) ); + if ( ! is_wp_error( $term ) && $term->name ) $value = $term->name; - endif; - else : - $value = ucfirst($value); - endif; + } else { + $value = ucfirst( $value ); + } - if ($flat) : - $variation_list[] = $woocommerce->attribute_label(str_replace('attribute_', '', $name)).': '.$value; - else : - $variation_list[] = '
'.$woocommerce->attribute_label(str_replace('attribute_', '', $name)).':
'.$value.'
'; - endif; + if ($flat) + $variation_list[] = $woocommerce->attribute_label( str_replace( 'attribute_', '', $name ) ) . ': ' . $value; + else + $variation_list[] = '
'.$woocommerce->attribute_label( str_replace( 'attribute_', '', $name ) ) . ':
' . $value . '
'; - endforeach; + } - if ($flat) : - $return .= implode(', ', $variation_list); - else : - $return .= implode('', $variation_list); - endif; + if ($flat) + $return .= implode( ', ', $variation_list ); + else + $return .= implode( '', $variation_list ); $has_data = true; - endif; + } // Other data - returned as array with name/value values - $other_data = apply_filters('woocommerce_get_item_data', array(), $cart_item); + $other_data = apply_filters( 'woocommerce_get_item_data', array(), $cart_item ); - if ($other_data && is_array($other_data) && sizeof($other_data)>0) : + if ( $other_data && is_array( $other_data ) && sizeof( $other_data ) > 0 ) { $data_list = array(); - foreach ($other_data as $data) : + foreach ($other_data as $data ) { - $display_value = (isset($data['display']) && $data['display']) ? $data['display'] : $data['value']; + $display_value = !empty($data['display']) ? $data['display'] : $data['value']; - if ($flat) : + if ($flat) $data_list[] = $data['name'].': '.$display_value; - else : + else $data_list[] = '
'.$data['name'].':
'.$display_value.'
'; - endif; - endforeach; + } - if ($flat) : + if ($flat) $return .= implode(', ', $data_list); - else : + else $return .= implode('', $data_list); - endif; $has_data = true; - endif; + } - if (!$flat) $return .= '
'; + if ( ! $flat ) + $return .= '
'; - if ($has_data) return $return; - + if ( $has_data ) + return $return; } /** * Gets cross sells based on the items in the cart * - * @return array cross_sells item ids of cross sells + * @return array cross_sells (item ids) */ function get_cross_sells() { $cross_sells = array(); $in_cart = array(); - if (sizeof($this->cart_contents)>0) : foreach ($this->cart_contents as $cart_item_key => $values) : - if ($values['quantity']>0) : - $cross_sells = array_merge($values['data']->get_cross_sells(), $cross_sells); - $in_cart[] = $values['product_id']; - endif; - endforeach; endif; - $cross_sells = array_diff($cross_sells, $in_cart); + if ( sizeof( $this->cart_contents) > 0 ) { + foreach ( $this->cart_contents as $cart_item_key => $values ) { + if ( $values['quantity'] > 0 ) { + $cross_sells = array_merge( $values['data']->get_cross_sells(), $cross_sells ); + $in_cart[] = $values['product_id']; + } + } + } + $cross_sells = array_diff( $cross_sells, $in_cart ); return $cross_sells; } - /** gets the url to the cart page */ + /** + * Gets the url to the cart page + * + * @return string url to page + */ function get_cart_url() { $cart_page_id = woocommerce_get_page_id('cart'); - if ($cart_page_id) return apply_filters('woocommerce_get_cart_url', get_permalink($cart_page_id)); + if ( $cart_page_id ) return apply_filters( 'woocommerce_get_cart_url', get_permalink( $cart_page_id ) ); } - - /** gets the url to the checkout page */ + + /** + * Gets the url to the checkout page + * + * @return string url to page + */ function get_checkout_url() { $checkout_page_id = woocommerce_get_page_id('checkout'); - if ($checkout_page_id) : - if (is_ssl()) return str_replace('http:', 'https:', get_permalink($checkout_page_id)); - return apply_filters('woocommerce_get_checkout_url', get_permalink($checkout_page_id)); - endif; + if ( $checkout_page_id ) { + if ( is_ssl() ) + return str_replace( 'http:', 'https:', get_permalink($checkout_page_id) ); + else + return apply_filters( 'woocommerce_get_checkout_url', get_permalink($checkout_page_id) ); + } } - /** gets the url to remove an item from the cart */ + /** + * Gets the url to remove an item from the cart + * + * @return string url to page + */ function get_remove_url( $cart_item_key ) { global $woocommerce; $cart_page_id = woocommerce_get_page_id('cart'); - if ($cart_page_id) return apply_filters('woocommerce_get_remove_url', $woocommerce->nonce_url( 'cart', add_query_arg('remove_item', $cart_item_key, get_permalink($cart_page_id)))); + if ($cart_page_id) + return apply_filters( 'woocommerce_get_remove_url', $woocommerce->nonce_url( 'cart', add_query_arg( 'remove_item', $cart_item_key, get_permalink($cart_page_id) ) ) ); } /** * Returns the contents of the cart + * + * @return array contents of the cart */ function get_cart() { return (array) $this->cart_contents; @@ -467,13 +497,15 @@ class WC_Cart { /** * Returns the cart and shipping taxes, merged + * + * @return array merged taxes */ function get_taxes() { $merged_taxes = array(); // Merge - foreach (array_keys($this->taxes + $this->shipping_taxes) as $key) { - $merged_taxes[$key] = (isset($this->shipping_taxes[$key]) ? $this->shipping_taxes[$key] : 0) + (isset($this->taxes[$key]) ? $this->taxes[$key] : 0); + foreach ( array_keys( $this->taxes + $this->shipping_taxes ) as $key ) { + $merged_taxes[$key] = ( isset( $this->shipping_taxes[$key] ) ? $this->shipping_taxes[$key] : 0 ) + ( isset( $this->taxes[$key] ) ? $this->taxes[$key] : 0 ); } return $merged_taxes; @@ -487,125 +519,137 @@ class WC_Cart { * Check if product is in the cart and return cart item key * * Cart item key will be unique based on the item and its properties, such as variations + * + * @param mixed id of product to find in the cart + * @return string cart item key */ function find_product_in_cart( $cart_id = false ) { - if ($cart_id !== false) foreach ($this->cart_contents as $cart_item_key => $cart_item) if ($cart_item_key == $cart_id) return $cart_item_key; + if ( $cart_id !== false ) + foreach ( $this->cart_contents as $cart_item_key => $cart_item ) + if ( $cart_item_key == $cart_id ) + return $cart_item_key; } /** * Generate a unique ID for the cart item being added + * + * @param int $product_id - id of the product the key is being generated for + * @param int $variation_id of the product the key is being generated for + * @param array $variation data for the cart item + * @param array $cart_item_data other cart item data passed which affects this items uniqueness in the cart + * @return string cart item key */ function generate_cart_id( $product_id, $variation_id = '', $variation = '', $cart_item_data = '' ) { $id_parts = array( $product_id ); - if ($variation_id) $id_parts[] = $variation_id; + if ( $variation_id ) $id_parts[] = $variation_id; - if (is_array($variation)) : + if ( is_array( $variation ) ) { $variation_key = ''; - foreach ($variation as $key => $value) : - $variation_key .= trim($key) . trim($value); - endforeach; + foreach ( $variation as $key => $value ) { + $variation_key .= trim( $key ) . trim( $value ); + } $id_parts[] = $variation_key; - endif; + } - if (is_array($cart_item_data)) : + if ( is_array( $cart_item_data ) ) { $cart_item_data_key = ''; - foreach ($cart_item_data as $key => $value) : - if (is_array($value)) $value = http_build_query($value); + foreach ( $cart_item_data as $key => $value ) { + if ( is_array( $value ) ) $value = http_build_query( $value ); $cart_item_data_key .= trim($key) . trim($value); - endforeach; + } $id_parts[] = $cart_item_data_key; - endif; + } - return md5( implode('_', $id_parts) ); + return md5( implode( '_', $id_parts ) ); } /** * Add a product to the cart * - * @param string product_id contains the id of the product to add to the cart - * @param string quantity contains the quantity of the item to add - * @param int variation_id - * @param array variation attribute values + * @param string $product_id contains the id of the product to add to the cart + * @param string $quantity contains the quantity of the item to add + * @param int $variation_id + * @param array $variation attribute values + * @param array $cart_item_data extra cart item data we want to pass into the item + * @return bool */ function add_to_cart( $product_id, $quantity = 1, $variation_id = '', $variation = '', $cart_item_data = array() ) { global $woocommerce; - if ($quantity < 1) return false; + if ( $quantity < 1 ) return false; // Load cart item data - may be added by other plugins - $cart_item_data = (array) apply_filters('woocommerce_add_cart_item_data', $cart_item_data, $product_id); + $cart_item_data = (array) apply_filters( 'woocommerce_add_cart_item_data', $cart_item_data, $product_id ); // Generate a ID based on product ID, variation ID, variation data, and other cart item data $cart_id = $this->generate_cart_id( $product_id, $variation_id, $variation, $cart_item_data ); // See if this product and its options is already in the cart - $cart_item_key = $this->find_product_in_cart($cart_id); + $cart_item_key = $this->find_product_in_cart( $cart_id ); - if ($variation_id>0) : + if ( $variation_id > 0 ) $product_data = new WC_Product_Variation( $variation_id ); - else : + else $product_data = new WC_Product( $product_id ); - endif; // Type/Exists check - if ( $product_data->is_type('external') || !$product_data->exists() ) : + if ( $product_data->is_type('external') || ! $product_data->exists() ) { $woocommerce->add_error( __('This product cannot be purchased.', 'woocommerce') ); return false; - endif; + } // Price set check - if( $product_data->get_price() === '' ) : + if( $product_data->get_price() === '' ) { $woocommerce->add_error( __('This product cannot be purchased - the price is not yet set.', 'woocommerce') ); return false; - endif; + } // Stock check - only check if we're managing stock and backorders are not allowed - if ( !$product_data->has_enough_stock( $quantity ) ) : + if ( ! $product_data->has_enough_stock( $quantity ) ) { $woocommerce->add_error( sprintf(__('You cannot add that amount to the cart since there is not enough stock. We have %s in stock.', 'woocommerce'), $product_data->get_stock_quantity() )); return false; - elseif ( !$product_data->is_in_stock() ) : + } elseif ( ! $product_data->is_in_stock() ) { $woocommerce->add_error( __('You cannot add that product to the cart since the product is out of stock.', 'woocommerce') ); return false; - endif; + } // Downloadable/virtual qty check - if ( get_option('woocommerce_limit_downloadable_product_qty')=='yes' && $product_data->is_downloadable() && $product_data->is_virtual() ) : - $qty = ($cart_item_key) ? $this->cart_contents[$cart_item_key]['quantity'] + $quantity : $quantity; - if ( $qty > 1 ) : + if ( get_option('woocommerce_limit_downloadable_product_qty')=='yes' && $product_data->is_downloadable() && $product_data->is_virtual() ) { + $qty = ( $cart_item_key ) ? $this->cart_contents[$cart_item_key]['quantity'] + $quantity : $quantity; + if ( $qty > 1 ) { $woocommerce->add_error( __('You already have this item in your cart.', 'woocommerce') ); return false; - endif; - endif; - - if ($cart_item_key) : + } + } + if ($cart_item_key) { $quantity = $quantity + $this->cart_contents[$cart_item_key]['quantity']; // Stock check - this time accounting for whats already in-cart - if ( !$product_data->has_enough_stock( $quantity ) ) : + if ( ! $product_data->has_enough_stock( $quantity ) ) { $woocommerce->add_error( sprintf(__('You cannot add that amount to the cart since there is not enough stock. We have %s in stock and you already have %s in your cart.', 'woocommerce'), $product_data->get_stock_quantity(), $this->cart_contents[$cart_item_key]['quantity'] )); return false; - elseif ( !$product_data->is_in_stock() ) : + } elseif ( ! $product_data->is_in_stock() ) { $woocommerce->add_error( __('You cannot add that product to the cart since the product is out of stock.', 'woocommerce') ); return false; - endif; + } - $this->set_quantity($cart_item_key, $quantity); + $this->set_quantity( $cart_item_key, $quantity ); - else : + } else { // Add item after merging with $cart_item_data - hook to allow plugins to modify cart item - $this->cart_contents[$cart_id] = apply_filters('woocommerce_add_cart_item', array_merge( $cart_item_data, array( + $this->cart_contents[$cart_id] = apply_filters( 'woocommerce_add_cart_item', array_merge( $cart_item_data, array( 'product_id' => $product_id, 'variation_id' => $variation_id, 'variation' => $variation, 'quantity' => $quantity, 'data' => $product_data - ))); + ) ) ); - endif; + } $woocommerce->cart_has_contents_cookie( true ); @@ -622,12 +666,12 @@ class WC_Cart { */ function set_quantity( $cart_item_key, $quantity = 1 ) { - if ($quantity==0 || $quantity<0) : - unset($this->cart_contents[$cart_item_key]); - else : + if ( $quantity == 0 || $quantity < 0 ) { + unset( $this->cart_contents[$cart_item_key] ); + } else { $this->cart_contents[$cart_item_key]['quantity'] = $quantity; - do_action('woocommerce_after_cart_item_quantity_update', $this->cart_contents[$cart_item_key], $quantity); - endif; + do_action( 'woocommerce_after_cart_item_quantity_update', $this->cart_contents[$cart_item_key], $quantity ); + } $this->set_session(); } @@ -640,7 +684,6 @@ class WC_Cart { * Reset totals */ private function reset() { - $this->total = 0; $this->cart_contents_total = 0; $this->cart_contents_weight = 0; @@ -659,260 +702,276 @@ class WC_Cart { unset( $_SESSION['cart_contents_total'], $_SESSION['cart_contents_weight'], $_SESSION['cart_contents_count'], $_SESSION['cart_contents_tax'], $_SESSION['total'], $_SESSION['subtotal'], $_SESSION['subtotal_ex_tax'], $_SESSION['tax_total'], $_SESSION['taxes'], $_SESSION['shipping_taxes'], $_SESSION['discount_cart'], $_SESSION['discount_total'], $_SESSION['shipping_total'], $_SESSION['shipping_tax_total'], $_SESSION['shipping_label'] ); } - /** + /** * Function to apply discounts to a product and get the discounted price (before tax is applied) + * + * @access public + * @param mixed $values + * @param mixed $price + * @param bool $add_totals (default: false) + * @return float price */ function get_discounted_price( $values, $price, $add_totals = false ) { - if (!$price) return $price; + if ( ! $price ) return $price; - if (!empty($this->applied_coupons)) foreach ($this->applied_coupons as $code) : - $coupon = new WC_Coupon( $code ); - - if ( $coupon->apply_before_tax() && $coupon->is_valid() ) : + if ( ! empty( $this->applied_coupons ) ) { + foreach ( $this->applied_coupons as $code ) { + $coupon = new WC_Coupon( $code ); + + if ( $coupon->apply_before_tax() && $coupon->is_valid() ) { + + switch ( $coupon->type ) { + + case "fixed_product" : + case "percent_product" : + + $this_item_is_discounted = false; + + $product_cats = wp_get_post_terms( $values['product_id'], 'product_cat', array("fields" => "ids") ); - switch ($coupon->type) : - - case "fixed_product" : - case "percent_product" : + // Specific products get the discount + if ( sizeof( $coupon->product_ids ) > 0 ) { + + if ( in_array( $values['product_id'], $coupon->product_ids ) || in_array( $values['variation_id'], $coupon->product_ids ) || in_array( $values['data']->get_parent(), $coupon->product_ids ) ) + $this_item_is_discounted = true; - $this_item_is_discounted = false; - - $product_cats = wp_get_post_terms($values['product_id'], 'product_cat', array("fields" => "ids")); - - // Specific products get the discount - if (sizeof($coupon->product_ids)>0) { - - if (in_array($values['product_id'], $coupon->product_ids) || in_array($values['variation_id'], $coupon->product_ids) || in_array($values['data']->get_parent(), $coupon->product_ids)) - $this_item_is_discounted = true; - - // Category discounts - } elseif (sizeof($coupon->product_categories)>0) { - - if ( sizeof( array_intersect( $product_cats, $coupon->product_categories ) ) > 0 ) + // Category discounts + } elseif ( sizeof($coupon->product_categories ) > 0 ) { + + if ( sizeof( array_intersect( $product_cats, $coupon->product_categories ) ) > 0 ) + $this_item_is_discounted = true; + + } else { + + // No product ids - all items discounted $this_item_is_discounted = true; - } else { - - // No product ids - all items discounted - $this_item_is_discounted = true; - - } - - // Specific product ID's excluded from the discount - if (sizeof($coupon->exclude_product_ids)>0) - if (in_array($values['product_id'], $coupon->exclude_product_ids) || in_array($values['variation_id'], $coupon->exclude_product_ids) || in_array($values['data']->get_parent(), $coupon->exclude_product_ids)) - $this_item_is_discounted = false; - - // Specific categories excluded from the discount - if (sizeof($coupon->exclude_product_categories)>0) - if ( sizeof( array_intersect( $product_cats, $coupon->exclude_product_categories ) ) > 0 ) - $this_item_is_discounted = false; - - // Apply filter - $this_item_is_discounted = apply_filters( 'woocommerce_item_is_discounted', $this_item_is_discounted, $values, $before_tax = true ); - - // Apply the discount - if ($this_item_is_discounted) : - if ($coupon->type=='fixed_product') : - - if ($price < $coupon->amount) : - $discount_amount = $price; - else : - $discount_amount = $coupon->amount; - endif; - - $price = $price - $coupon->amount; - - if ($price<0) $price = 0; - - if ($add_totals) : - $this->discount_cart = $this->discount_cart + ( $discount_amount * $values['quantity'] ); - endif; - - elseif ($coupon->type=='percent_product') : - - $percent_discount = ( $values['data']->get_price_excluding_tax() / 100 ) * $coupon->amount; - - if ($add_totals) $this->discount_cart = $this->discount_cart + ( $percent_discount * $values['quantity'] ); - - $price = $price - $percent_discount; - - endif; - endif; - - break; - - case "fixed_cart" : - - /** - * This is the most complex discount - we need to divide the discount between rows based on their price in - * proportion to the subtotal. This is so rows with different tax rates get a fair discount, and so rows - * with no price (free) don't get discount too. - */ - - // Get item discount by dividing item cost by subtotal to get a % - if ($this->subtotal_ex_tax) - $discount_percent = ($values['data']->get_price_excluding_tax()*$values['quantity']) / $this->subtotal_ex_tax; - else - $discount_percent = 0; - - // Use pence to help prevent rounding errors - $coupon_amount_pence = $coupon->amount * 100; - - // Work out the discount for the row - $item_discount = $coupon_amount_pence * $discount_percent; - - // Work out discount per item - $item_discount = $item_discount / $values['quantity']; - - // Pence - $price = ( $price * 100 ); - - // Check if discount is more than price - if ($price < $item_discount) : - $discount_amount = $price; - else : - $discount_amount = $item_discount; - endif; - - // Take discount off of price (in pence) - $price = $price - $discount_amount; - - // Back to pounds - $price = $price / 100; - - // Cannot be below 0 - if ($price<0) $price = 0; - - // Add coupon to discount total (once, since this is a fixed cart discount and we don't want rounding issues) - if ($add_totals) $this->discount_cart = $this->discount_cart + (($discount_amount*$values['quantity']) / 100); - - break; - - case "percent" : - - $percent_discount = ( $values['data']->get_price( ) / 100 ) * $coupon->amount; - - if ($add_totals) $this->discount_cart = $this->discount_cart + ( $percent_discount * $values['quantity'] ); - - $price = $price - $percent_discount; - - break; - - endswitch; + } - endif; - endforeach; + // Specific product ID's excluded from the discount + if ( sizeof( $coupon->exclude_product_ids ) > 0 ) + if ( in_array( $values['product_id'], $coupon->exclude_product_ids ) || in_array( $values['variation_id'], $coupon->exclude_product_ids ) || in_array( $values['data']->get_parent(), $coupon->exclude_product_ids ) ) + $this_item_is_discounted = false; + + // Specific categories excluded from the discount + if ( sizeof( $coupon->exclude_product_categories ) > 0 ) + if ( sizeof( array_intersect( $product_cats, $coupon->exclude_product_categories ) ) > 0 ) + $this_item_is_discounted = false; + + // Apply filter + $this_item_is_discounted = apply_filters( 'woocommerce_item_is_discounted', $this_item_is_discounted, $values, $before_tax = true ); + + // Apply the discount + if ( $this_item_is_discounted ) { + if ( $coupon->type=='fixed_product' ) { + + if ( $price < $coupon->amount ) { + $discount_amount = $price; + } else { + $discount_amount = $coupon->amount; + } + + $price = $price - $coupon->amount; + + if ( $price < 0 ) $price = 0; + + if ( $add_totals ) { + $this->discount_cart = $this->discount_cart + ( $discount_amount * $values['quantity'] ); + } + + } elseif ( $coupon->type == 'percent_product' ) { + + $percent_discount = ( $values['data']->get_price_excluding_tax() / 100 ) * $coupon->amount; + + if ( $add_totals ) $this->discount_cart = $this->discount_cart + ( $percent_discount * $values['quantity'] ); + + $price = $price - $percent_discount; + + } + } + + break; + + case "fixed_cart" : + + /** + * This is the most complex discount - we need to divide the discount between rows based on their price in + * proportion to the subtotal. This is so rows with different tax rates get a fair discount, and so rows + * with no price (free) don't get discount too. + */ + + // Get item discount by dividing item cost by subtotal to get a % + if ( $this->subtotal_ex_tax ) + $discount_percent = ( $values['data']->get_price_excluding_tax()*$values['quantity'] ) / $this->subtotal_ex_tax; + else + $discount_percent = 0; + + // Use pence to help prevent rounding errors + $coupon_amount_pence = $coupon->amount * 100; + + // Work out the discount for the row + $item_discount = $coupon_amount_pence * $discount_percent; + + // Work out discount per item + $item_discount = $item_discount / $values['quantity']; + + // Pence + $price = ( $price * 100 ); + + // Check if discount is more than price + if ( $price < $item_discount ) + $discount_amount = $price; + else + $discount_amount = $item_discount; + + // Take discount off of price (in pence) + $price = $price - $discount_amount; + + // Back to pounds + $price = $price / 100; + + // Cannot be below 0 + if ( $price < 0 ) $price = 0; + + // Add coupon to discount total (once, since this is a fixed cart discount and we don't want rounding issues) + if ( $add_totals ) $this->discount_cart = $this->discount_cart + ( ( $discount_amount * $values['quantity'] ) / 100 ); + + break; + + case "percent" : + + $percent_discount = ( $values['data']->get_price( ) / 100 ) * $coupon->amount; + + if ( $add_totals ) $this->discount_cart = $this->discount_cart + ( $percent_discount * $values['quantity'] ); + + $price = $price - $percent_discount; + + break; + + } + } + } + } return apply_filters( 'woocommerce_get_discounted_price', $price, $values, $this ); } - /** + /** * Function to apply product discounts after tax + * + * @access public + * @param mixed $values + * @param mixed $price */ function apply_product_discounts_after_tax( $values, $price ) { - if (!empty($this->applied_coupons)) foreach ($this->applied_coupons as $code) : - $coupon = new WC_Coupon( $code ); - - do_action( 'woocommerce_product_discount_after_tax_' . $coupon->type, $coupon ); - - if ($coupon->type!='fixed_product' && $coupon->type!='percent_product') continue; - - if ( !$coupon->apply_before_tax() && $coupon->is_valid() ) : + if ( ! empty( $this->applied_coupons) ) { + foreach ( $this->applied_coupons as $code ) { + $coupon = new WC_Coupon( $code ); - $this_item_is_discounted = false; - - // Specific products get the discount - if (sizeof($coupon->product_ids)>0) { + do_action( 'woocommerce_product_discount_after_tax_' . $coupon->type, $coupon ); + + if ( $coupon->type != 'fixed_product' && $coupon->type != 'percent_product' ) continue; + + if ( !$coupon->apply_before_tax() && $coupon->is_valid() ) { - if (in_array($values['product_id'], $coupon->product_ids) || in_array($values['variation_id'], $coupon->product_ids) || in_array($values['data']->get_parent(), $coupon->product_ids)) - $this_item_is_discounted = true; - - // Category discounts - } elseif (sizeof($coupon->product_categories)>0) { - - if ( sizeof( array_intersect( $product_cats, $coupon->product_categories ) ) > 0 ) - $this_item_is_discounted = true; - - } else { - - // No product ids - all items discounted - $this_item_is_discounted = true; - - } - - // Specific product ID's excluded from the discount - if (sizeof($coupon->exclude_product_ids)>0) - if (in_array($values['product_id'], $coupon->exclude_product_ids) || in_array($values['variation_id'], $coupon->exclude_product_ids) || in_array($values['data']->get_parent(), $coupon->exclude_product_ids)) - $this_item_is_discounted = false; - - // Specific categories excluded from the discount - if (sizeof($coupon->exclude_product_categories)>0) - if ( sizeof( array_intersect( $product_cats, $coupon->exclude_product_categories ) ) > 0 ) - $this_item_is_discounted = false; - - // Apply filter - $this_item_is_discounted = apply_filters( 'woocommerce_item_is_discounted', $this_item_is_discounted, $values, $before_tax = false ); - - // Apply the discount - if ($this_item_is_discounted) : - if ($coupon->type=='fixed_product') : - - if ($price < $coupon->amount) : - $discount_amount = $price; - else : - $discount_amount = $coupon->amount; - endif; - - $this->discount_total = $this->discount_total + ( $discount_amount * $values['quantity'] ); + $this_item_is_discounted = false; + + // Specific products get the discount + if ( sizeof( $coupon->product_ids ) > 0 ) { - elseif ($coupon->type=='percent_product') : - $this->discount_total = $this->discount_total + ( $price / 100 ) * $coupon->amount; - endif; - endif; - - endif; - endforeach; + if (in_array($values['product_id'], $coupon->product_ids) || in_array($values['variation_id'], $coupon->product_ids) || in_array($values['data']->get_parent(), $coupon->product_ids)) + $this_item_is_discounted = true; + + // Category discounts + } elseif ( sizeof( $coupon->product_categories ) > 0 ) { + + if ( sizeof( array_intersect( $product_cats, $coupon->product_categories ) ) > 0 ) + $this_item_is_discounted = true; + + } else { + + // No product ids - all items discounted + $this_item_is_discounted = true; + + } + + // Specific product ID's excluded from the discount + if ( sizeof( $coupon->exclude_product_ids ) > 0 ) + if ( in_array( $values['product_id'], $coupon->exclude_product_ids ) || in_array( $values['variation_id'], $coupon->exclude_product_ids ) || in_array( $values['data']->get_parent(), $coupon->exclude_product_ids ) ) + $this_item_is_discounted = false; + + // Specific categories excluded from the discount + if ( sizeof( $coupon->exclude_product_categories ) > 0 ) + if ( sizeof( array_intersect( $product_cats, $coupon->exclude_product_categories ) ) > 0 ) + $this_item_is_discounted = false; + + // Apply filter + $this_item_is_discounted = apply_filters( 'woocommerce_item_is_discounted', $this_item_is_discounted, $values, $before_tax = false ); + + // Apply the discount + if ( $this_item_is_discounted ) { + if ( $coupon->type == 'fixed_product' ) { + + if ( $price < $coupon->amount ) + $discount_amount = $price; + else + $discount_amount = $coupon->amount; + + $this->discount_total = $this->discount_total + ( $discount_amount * $values['quantity'] ); + + } elseif ( $coupon->type == 'percent_product' ) { + $this->discount_total = $this->discount_total + ( $price / 100 ) * $coupon->amount; + } + } + } + } + } } - /** + /** * Function to apply cart discounts after tax + * + * @access public */ function apply_cart_discounts_after_tax() { - if ($this->applied_coupons) foreach ($this->applied_coupons as $code) : - $coupon = new WC_Coupon( $code ); - - do_action( 'woocommerce_cart_discount_after_tax_' . $coupon->type, $coupon ); - - if ( !$coupon->apply_before_tax() && $coupon->is_valid() ) : + if ( $this->applied_coupons ) { + foreach ( $this->applied_coupons as $code ) { + $coupon = new WC_Coupon( $code ); - switch ($coupon->type) : + do_action( 'woocommerce_cart_discount_after_tax_' . $coupon->type, $coupon ); - case "fixed_cart" : - - $this->discount_total = $this->discount_total + $coupon->amount; - - break; + if ( !$coupon->apply_before_tax() && $coupon->is_valid() ) { - case "percent" : - - $percent_discount = (round( $this->cart_contents_total + $this->tax_total , 2) / 100 ) * $coupon->amount; - - $this->discount_total = $this->discount_total + $percent_discount; - - break; + switch ( $coupon->type ) { - endswitch; - - endif; - endforeach; + case "fixed_cart" : + + $this->discount_total = $this->discount_total + $coupon->amount; + + break; + + case "percent" : + + $percent_discount = ( round( $this->cart_contents_total + $this->tax_total , 2 ) / 100 ) * $coupon->amount; + + $this->discount_total = $this->discount_total + $percent_discount; + + break; + + } + + } + } + } } - /** + /** * calculate totals for the items in the cart + * + * @access public */ function calculate_totals() { global $woocommerce; @@ -922,282 +981,292 @@ class WC_Cart { do_action('woocommerce_before_calculate_totals', $this); // Get count of all items + weights + subtotal (we may need this for discounts) - if (sizeof($this->cart_contents)>0) foreach ($this->cart_contents as $cart_item_key => $values) : - - $_product = $values['data']; - - $this->cart_contents_weight = $this->cart_contents_weight + ($_product->get_weight() * $values['quantity']); - $this->cart_contents_count = $this->cart_contents_count + $values['quantity']; - - // Base Price (inlusive of tax for now) - $row_base_price = $_product->get_price() * $values['quantity']; - $base_tax_rates = $this->tax->get_shop_base_rate( $_product->tax_class ); - $tax_amount = 0; - - if ($this->prices_include_tax) : + if ( sizeof( $this->cart_contents ) > 0 ) { + foreach ( $this->cart_contents as $cart_item_key => $values ) { - if ( $_product->is_taxable() ) : - - $tax_rates = $this->tax->get_rates( $_product->get_tax_class() ); - - // ADJUST BASE if tax rate is different (different region or modified tax class) - if ( $tax_rates !== $base_tax_rates ) : - $base_taxes = $this->tax->calc_tax( $row_base_price, $base_tax_rates, true ); - $modded_taxes = $this->tax->calc_tax( $row_base_price - array_sum($base_taxes), $tax_rates, false ); - $row_base_price = ($row_base_price - array_sum($base_taxes)) + array_sum($modded_taxes); - endif; - - $taxes = $this->tax->calc_tax( $row_base_price, $tax_rates, true ); - $tax_amount = $this->tax->get_tax_total($taxes); - - endif; - - // Sub total is based on base prices (without discounts) - $this->subtotal = $this->subtotal + $row_base_price; + $_product = $values['data']; - $this->subtotal_ex_tax = $this->subtotal_ex_tax + ( $row_base_price - $tax_amount); - - else : + $this->cart_contents_weight = $this->cart_contents_weight + ($_product->get_weight() * $values['quantity']); + $this->cart_contents_count = $this->cart_contents_count + $values['quantity']; - if ( $_product->is_taxable() ) : + // Base Price (inlusive of tax for now) + $row_base_price = $_product->get_price() * $values['quantity']; + $base_tax_rates = $this->tax->get_shop_base_rate( $_product->tax_class ); + $tax_amount = 0; - $tax_rates = $this->tax->get_rates( $_product->get_tax_class() ); - $taxes = $this->tax->calc_tax( $row_base_price, $tax_rates, false ); - $tax_amount = $this->tax->get_tax_total($taxes); + if ($this->prices_include_tax) { - endif; + if ( $_product->is_taxable() ) { + + $tax_rates = $this->tax->get_rates( $_product->get_tax_class() ); + + // ADJUST BASE if tax rate is different (different region or modified tax class) + if ( $tax_rates !== $base_tax_rates ) { + + $base_taxes = $this->tax->calc_tax( $row_base_price, $base_tax_rates, true ); + $modded_taxes = $this->tax->calc_tax( $row_base_price - array_sum($base_taxes), $tax_rates, false ); + $row_base_price = ( $row_base_price - array_sum( $base_taxes ) ) + array_sum( $modded_taxes ); + + } + + $taxes = $this->tax->calc_tax( $row_base_price, $tax_rates, true ); + $tax_amount = $this->tax->get_tax_total( $taxes ); + + } + + // Sub total is based on base prices (without discounts) + $this->subtotal = $this->subtotal + $row_base_price; + + $this->subtotal_ex_tax = $this->subtotal_ex_tax + ( $row_base_price - $tax_amount); + + } else { + + if ( $_product->is_taxable() ) { + + $tax_rates = $this->tax->get_rates( $_product->get_tax_class() ); + $taxes = $this->tax->calc_tax( $row_base_price, $tax_rates, false ); + $tax_amount = $this->tax->get_tax_total( $taxes ); + + } + + // Sub total is based on base prices (without discounts) + $this->subtotal = $this->subtotal + $row_base_price + $tax_amount; + $this->subtotal_ex_tax = $this->subtotal_ex_tax + $row_base_price; - // Sub total is based on base prices (without discounts) - $this->subtotal = $this->subtotal + $row_base_price + $tax_amount; - $this->subtotal_ex_tax = $this->subtotal_ex_tax + $row_base_price; - - endif; - - endforeach; + } + + } + } // Now calc the main totals, including discounts - if ($this->prices_include_tax) : + if ( $this->prices_include_tax ) { /** * Calculate totals for items */ - if (sizeof($this->cart_contents)>0) : foreach ($this->cart_contents as $cart_item_key => $values) : - - /** - * Prices include tax - * - * To prevent rounding issues we need to work with the inclusive price where possible - * otherwise we'll see errors such as when working with a 9.99 inc price, 20% VAT which would - * be 8.325 leading to totals being 1p off - * - * Pre tax coupons come off the price the customer thinks they are paying - tax is calculated - * afterwards. - * - * e.g. $100 bike with $10 coupon = customer pays $90 and tax worked backwards from that - * - * Used this excellent article for reference: - * http://developer.practicalecommerce.com/articles/1473-Coding-for-Tax-Calculations-Everything-You-Never-Wanted-to-Know-Part-2 - */ - $_product = $values['data']; + if ( sizeof($this->cart_contents) > 0 ) { + foreach ($this->cart_contents as $cart_item_key => $values ) { - // Base Price (inlusive of tax for now) - $base_price = $_product->get_price(); - - // Base Price Adjustment - if ( $_product->is_taxable() ) : + /** + * Prices include tax + * + * To prevent rounding issues we need to work with the inclusive price where possible + * otherwise we'll see errors such as when working with a 9.99 inc price, 20% VAT which would + * be 8.325 leading to totals being 1p off + * + * Pre tax coupons come off the price the customer thinks they are paying - tax is calculated + * afterwards. + * + * e.g. $100 bike with $10 coupon = customer pays $90 and tax worked backwards from that + * + * Used this excellent article for reference: + * http://developer.practicalecommerce.com/articles/1473-Coding-for-Tax-Calculations-Everything-You-Never-Wanted-to-Know-Part-2 + */ + $_product = $values['data']; + + // Base Price (inlusive of tax for now) + $base_price = $_product->get_price(); - // Get rates - $tax_rates = $this->tax->get_rates( $_product->get_tax_class() ); + // Base Price Adjustment + if ( $_product->is_taxable() ) { + + // Get rates + $tax_rates = $this->tax->get_rates( $_product->get_tax_class() ); + + /** + * ADJUST TAX - Checkout calculations when customer is OUTSIDE the shop base country and prices INCLUDE tax + * OR + * ADJUST TAX - Checkout calculations when a tax class is modified + */ + if ( ( $woocommerce->customer->is_customer_outside_base() && defined('WOOCOMMERCE_CHECKOUT') ) || ( $_product->get_tax_class() !== $_product->tax_class ) ) { + + // Get tax rate for the store base, ensuring we use the unmodified tax_class for the product + $base_tax_rates = $this->tax->get_shop_base_rate( $_product->tax_class ); + + // Work out new price based on region + $row_base_price = $base_price * $values['quantity']; + $base_taxes = $this->tax->calc_tax( $row_base_price, $base_tax_rates, true ); + $taxes = $this->tax->calc_tax( $row_base_price - array_sum($base_taxes), $tax_rates, false ); + + // Tax amount + $tax_amount = array_sum( $taxes ); + + // Line subtotal + tax + $line_subtotal_tax = ( get_option('woocommerce_tax_round_at_subtotal')=='no' ) ? round( $tax_amount, 2 ) : $tax_amount; + $line_subtotal = $row_base_price - $this->tax->get_tax_total($base_taxes); + + // Adjusted price + $adjusted_price = ( $row_base_price - array_sum($base_taxes) + array_sum($taxes) ) / $values['quantity']; - /** - * ADJUST TAX - Checkout calculations when customer is OUTSIDE the shop base country and prices INCLUDE tax - * OR - * ADJUST TAX - Checkout calculations when a tax class is modified + // Apply discounts + $discounted_price = $this->get_discounted_price( $values, $adjusted_price, true ); + + $discounted_taxes = $this->tax->calc_tax( $discounted_price * $values['quantity'], $tax_rates, true ); + $discounted_tax_amount = array_sum( $discounted_taxes ); // Sum taxes + + /** + * Regular tax calculation (customer inside base and the tax class is unmodified + */ + } else { + + // Base tax for line before discount - we will store this in the order data + $tax_amount = array_sum( $this->tax->calc_tax( $base_price * $values['quantity'], $tax_rates, true ) ); + + // Line subtotal + tax + $line_subtotal_tax = ( get_option('woocommerce_tax_round_at_subtotal')=='no' ) ? round($tax_amount, 2) : $tax_amount; + $line_subtotal = ( $base_price * $values['quantity'] ) - round( $line_subtotal_tax, 2 ); + + // Calc prices and tax (discounted) + $discounted_price = $this->get_discounted_price( $values, $base_price, true ); + $discounted_taxes = $this->tax->calc_tax( $discounted_price * $values['quantity'], $tax_rates, true ); + $discounted_tax_amount = array_sum( $discounted_taxes ); // Sum taxes + + } + + // Tax rows - merge the totals we just got + foreach ( array_keys( $this->taxes + $discounted_taxes ) as $key ) { + $this->taxes[$key] = ( isset( $discounted_taxes[$key] ) ? $discounted_taxes[$key] : 0 ) + ( isset( $this->taxes[$key] ) ? $this->taxes[$key] : 0 ); + } + + } else { + + // Discounted Price (price with any pre-tax discounts applied) + $discounted_price = $this->get_discounted_price( $values, $base_price, true ); + $discounted_tax_amount = 0; + $tax_amount = 0; + $line_subtotal_tax = 0; + $line_subtotal = ( $base_price * $values['quantity'] ); + + } + + // Line prices + $line_tax = ( get_option('woocommerce_tax_round_at_subtotal') == 'no' ) ? round( $discounted_tax_amount, 2 ) : $discounted_tax_amount; + $line_total = ( $discounted_price * $values['quantity'] ) - round( $line_tax, 2 ); + + // Add any product discounts (after tax) + $this->apply_product_discounts_after_tax( $values, $line_total + $discounted_tax_amount ); + + // Cart contents total is based on discounted prices and is used for the final total calculation + $this->cart_contents_total = $this->cart_contents_total + $line_total; + + // Store costs + taxes for lines + $this->cart_contents[$cart_item_key]['line_total'] = $line_total; + $this->cart_contents[$cart_item_key]['line_tax'] = $line_tax; + $this->cart_contents[$cart_item_key]['line_subtotal'] = $line_subtotal; + $this->cart_contents[$cart_item_key]['line_subtotal_tax'] = $line_subtotal_tax; + + } + } + + } else { + + if ( sizeof( $this->cart_contents ) > 0 ) { + foreach ( $this->cart_contents as $cart_item_key => $values ) { + + /** + * Prices exclude tax + * + * This calculation is simpler - work with the base, untaxed price. */ - if ( ( $woocommerce->customer->is_customer_outside_base() && defined('WOOCOMMERCE_CHECKOUT')) || ($_product->get_tax_class() !== $_product->tax_class) ) : - - // Get tax rate for the store base, ensuring we use the unmodified tax_class for the product - $base_tax_rates = $this->tax->get_shop_base_rate( $_product->tax_class ); - - // Work out new price based on region - $row_base_price = $base_price * $values['quantity']; - $base_taxes = $this->tax->calc_tax( $row_base_price, $base_tax_rates, true ); - $taxes = $this->tax->calc_tax( $row_base_price - array_sum($base_taxes), $tax_rates, false ); - - // Tax amount - $tax_amount = array_sum($taxes); - - // Line subtotal + tax - $line_subtotal_tax = ( get_option('woocommerce_tax_round_at_subtotal')=='no' ) ? round($tax_amount, 2) : $tax_amount; - $line_subtotal = $row_base_price - $this->tax->get_tax_total($base_taxes); - - // Adjusted price - $adjusted_price = ($row_base_price - array_sum($base_taxes) + array_sum($taxes)) / $values['quantity']; - - // Apply discounts - $discounted_price = $this->get_discounted_price( $values, $adjusted_price, true ); - - $discounted_taxes = $this->tax->calc_tax( $discounted_price * $values['quantity'], $tax_rates, true ); - $discounted_tax_amount = array_sum($discounted_taxes); // Sum taxes - - /** - * Regular tax calculation (customer inside base and the tax class is unmodified - */ - else : + $_product = $values['data']; + + // Base Price (i.e. no tax, regardless of region) + $base_price = $_product->get_price(); + + // Discounted Price (base price with any pre-tax discounts applied + $discounted_price = $this->get_discounted_price( $values, $base_price, true ); + + // Tax Amount (For the line, based on discounted, ex.tax price) + if ( $_product->is_taxable() ) { + + // Get tax rates + $tax_rates = $this->tax->get_rates( $_product->get_tax_class() ); // Base tax for line before discount - we will store this in the order data - $tax_amount = array_sum($this->tax->calc_tax( $base_price * $values['quantity'], $tax_rates, true )); + $tax_amount = array_sum( $this->tax->calc_tax( $base_price * $values['quantity'], $tax_rates, false ) ); - // Line subtotal + tax - $line_subtotal_tax = ( get_option('woocommerce_tax_round_at_subtotal')=='no' ) ? round($tax_amount, 2) : $tax_amount; - $line_subtotal = ($base_price * $values['quantity']) - round($line_subtotal_tax, 2); - - // Calc prices and tax (discounted) - $discounted_price = $this->get_discounted_price( $values, $base_price, true ); - $discounted_taxes = $this->tax->calc_tax( $discounted_price * $values['quantity'], $tax_rates, true ); - $discounted_tax_amount = array_sum($discounted_taxes); // Sum taxes - - endif; - - // Tax rows - merge the totals we just got - foreach (array_keys($this->taxes + $discounted_taxes) as $key) { - $this->taxes[$key] = (isset($discounted_taxes[$key]) ? $discounted_taxes[$key] : 0) + (isset($this->taxes[$key]) ? $this->taxes[$key] : 0); + // Now calc product rates + $discounted_taxes = $this->tax->calc_tax( $discounted_price * $values['quantity'], $tax_rates, false ); + $discounted_tax_amount = array_sum( $discounted_taxes ); + + // Tax rows - merge the totals we just got + foreach ( array_keys( $this->taxes + $discounted_taxes ) as $key ) { + $this->taxes[$key] = ( isset( $discounted_taxes[$key] ) ? $discounted_taxes[$key] : 0 ) + ( isset( $this->taxes[$key] ) ? $this->taxes[$key] : 0 ); + } + + } else { + $discounted_tax_amount = 0; + $tax_amount = 0; } - else : - - // Discounted Price (price with any pre-tax discounts applied) - $discounted_price = $this->get_discounted_price( $values, $base_price, true ); - $discounted_tax_amount = 0; - $tax_amount = 0; - $line_subtotal_tax = 0; - $line_subtotal = ($base_price * $values['quantity']); - - endif; - - // Line prices - $line_tax = ( get_option('woocommerce_tax_round_at_subtotal')=='no' ) ? round($discounted_tax_amount, 2) : $discounted_tax_amount; - $line_total = ($discounted_price * $values['quantity']) - round($line_tax, 2); - - // Add any product discounts (after tax) - $this->apply_product_discounts_after_tax( $values, $line_total + $discounted_tax_amount ); + // Line prices + $line_subtotal_tax = $tax_amount; + $line_tax = $discounted_tax_amount; + $line_subtotal = $base_price * $values['quantity']; + $line_total = $discounted_price * $values['quantity']; + + // Add any product discounts (after tax) + $this->apply_product_discounts_after_tax( $values, $line_total + $line_tax ); + + // Cart contents total is based on discounted prices and is used for the final total calculation + $this->cart_contents_total = $this->cart_contents_total + $line_total; - // Cart contents total is based on discounted prices and is used for the final total calculation - $this->cart_contents_total = $this->cart_contents_total + $line_total; + // Store costs + taxes for lines + $this->cart_contents[$cart_item_key]['line_total'] = $line_total; + $this->cart_contents[$cart_item_key]['line_tax'] = $line_tax; + $this->cart_contents[$cart_item_key]['line_subtotal'] = $line_subtotal; + $this->cart_contents[$cart_item_key]['line_subtotal_tax'] = $line_subtotal_tax; - // Store costs + taxes for lines - $this->cart_contents[$cart_item_key]['line_total'] = $line_total; - $this->cart_contents[$cart_item_key]['line_tax'] = $line_tax; - $this->cart_contents[$cart_item_key]['line_subtotal'] = $line_subtotal; - $this->cart_contents[$cart_item_key]['line_subtotal_tax'] = $line_subtotal_tax; - - endforeach; endif; + } + } - else : - - if (sizeof($this->cart_contents)>0) : foreach ($this->cart_contents as $cart_item_key => $values) : - - /** - * Prices exclude tax - * - * This calculation is simpler - work with the base, untaxed price. - */ - $_product = $values['data']; - - // Base Price (i.e. no tax, regardless of region) - $base_price = $_product->get_price(); - - // Discounted Price (base price with any pre-tax discounts applied - $discounted_price = $this->get_discounted_price( $values, $base_price, true ); - - // Tax Amount (For the line, based on discounted, ex.tax price) - if ( $_product->is_taxable() ) : - - // Get tax rates - $tax_rates = $this->tax->get_rates( $_product->get_tax_class() ); - - // Base tax for line before discount - we will store this in the order data - $tax_amount = array_sum($this->tax->calc_tax( $base_price * $values['quantity'], $tax_rates, false )); - - // Now calc product rates - $discounted_taxes = $this->tax->calc_tax( $discounted_price * $values['quantity'], $tax_rates, false ); - $discounted_tax_amount = array_sum( $discounted_taxes ); - - // Tax rows - merge the totals we just got - foreach (array_keys($this->taxes + $discounted_taxes) as $key) { - $this->taxes[$key] = (isset($discounted_taxes[$key]) ? $discounted_taxes[$key] : 0) + (isset($this->taxes[$key]) ? $this->taxes[$key] : 0); - } - - else : - $discounted_tax_amount = 0; - $tax_amount = 0; - endif; - - // Line prices - $line_subtotal_tax = $tax_amount; - $line_tax = $discounted_tax_amount; - $line_subtotal = $base_price * $values['quantity']; - $line_total = $discounted_price * $values['quantity']; - - // Add any product discounts (after tax) - $this->apply_product_discounts_after_tax( $values, $line_total + $line_tax ); - - // Cart contents total is based on discounted prices and is used for the final total calculation - $this->cart_contents_total = $this->cart_contents_total + $line_total; - - // Store costs + taxes for lines - $this->cart_contents[$cart_item_key]['line_total'] = $line_total; - $this->cart_contents[$cart_item_key]['line_tax'] = $line_tax; - $this->cart_contents[$cart_item_key]['line_subtotal'] = $line_subtotal; - $this->cart_contents[$cart_item_key]['line_subtotal_tax'] = $line_subtotal_tax; - - endforeach; endif; - - endif; + } // Set tax total to sum of all tax rows - $this->tax_total = $this->tax->get_tax_total( $this->taxes ); + $this->tax_total = $this->tax->get_tax_total( $this->taxes ); // VAT exemption done at this point - so all totals are correct before exemption - if ($woocommerce->customer->is_vat_exempt() || (is_cart() && get_option('woocommerce_display_cart_taxes')=='no')) : + if ( $woocommerce->customer->is_vat_exempt() || ( is_cart() && get_option('woocommerce_display_cart_taxes') == 'no' ) ) { $this->shipping_tax_total = $this->tax_total = 0; $this->taxes = $this->shipping_taxes = array(); - endif; + } // Cart Discounts (after tax) $this->apply_cart_discounts_after_tax(); // Only go beyond this point if on the cart/checkout - if (!is_checkout() && !is_cart() && !defined('WOOCOMMERCE_CHECKOUT') && !defined('WOOCOMMERCE_CART')) return; + if ( ! is_checkout() && ! is_cart() && ! defined('WOOCOMMERCE_CHECKOUT') && ! defined('WOOCOMMERCE_CART') ) return; // Cart Shipping $this->calculate_shipping(); // VAT exemption for shipping - if ($woocommerce->customer->is_vat_exempt()) : + if ( $woocommerce->customer->is_vat_exempt() ) { $this->shipping_tax_total = 0; $this->shipping_taxes = array(); - endif; + } // Round cart/shipping tax rows - $this->taxes = array_map(array(&$this->tax, 'round'), $this->taxes); - $this->shipping_taxes = array_map(array(&$this->tax, 'round'), $this->shipping_taxes); + $this->taxes = array_map( array( &$this->tax, 'round' ), $this->taxes ); + $this->shipping_taxes = array_map( array( &$this->tax, 'round' ), $this->shipping_taxes ); // Allow plugins to hook and alter totals before final total is calculated - do_action('woocommerce_calculate_totals', $this); + do_action( 'woocommerce_calculate_totals', $this ); /** * Grand Total * * Based on discounted product prices, discounted tax, shipping cost + tax, and any discounts to be added after tax (e.g. store credit) */ - $this->total = apply_filters('woocommerce_calculated_total', number_format( $this->cart_contents_total + $this->tax_total + $this->shipping_tax_total + $this->shipping_total - $this->discount_total, 2, '.', ''), $this); + $this->total = apply_filters( 'woocommerce_calculated_total', number_format( $this->cart_contents_total + $this->tax_total + $this->shipping_tax_total + $this->shipping_total - $this->discount_total, 2, '.', '' ), $this ); if ($this->total < 0) $this->total = 0; } /** * looks at the totals to see if payment is actually required + * + * @return bool */ function needs_payment() { if ( $this->total > 0 ) return true; else return false; @@ -1213,11 +1282,11 @@ class WC_Cart { function calculate_shipping() { global $woocommerce; - if ($this->needs_shipping()) : + if ( $this->needs_shipping() ) { $woocommerce->shipping->calculate_shipping(); - else : + } else { $woocommerce->shipping->reset_shipping(); - endif; + } $this->shipping_total = $woocommerce->shipping->shipping_total; // Shipping Total $this->shipping_label = $woocommerce->shipping->shipping_label; // Shipping Label @@ -1227,71 +1296,79 @@ class WC_Cart { /** * looks through the cart to see if shipping is actually required + * + * @return bool whether or not the cart needs shipping */ function needs_shipping() { - if (get_option('woocommerce_calc_shipping')=='no') return false; - if (!is_array($this->cart_contents)) return false; + if ( get_option('woocommerce_calc_shipping')=='no' ) return false; + if ( ! is_array( $this->cart_contents ) ) return false; $needs_shipping = false; - foreach ($this->cart_contents as $cart_item_key => $values) : + foreach ( $this->cart_contents as $cart_item_key => $values ) { $_product = $values['data']; - if ( $_product->needs_shipping() ) : + if ( $_product->needs_shipping() ) { $needs_shipping = true; - endif; - endforeach; + } + } return apply_filters( 'woocomerce_cart_needs_shipping', $needs_shipping ); } /** * Sees if we need a shipping address + * + * @return bool */ function ship_to_billing_address_only() { - if (get_option('woocommerce_ship_to_billing_address_only')=='yes') return true; else return false; + if ( get_option('woocommerce_ship_to_billing_address_only') == 'yes' ) return true; else return false; } /** * gets the shipping total (after calculation) + * + * @return mixed price or string for the shipping total */ function get_cart_shipping_total() { global $woocommerce; - if (isset($this->shipping_label)) : - if ($this->shipping_total>0) : + if ( isset( $this->shipping_label ) ) { + if ( $this->shipping_total > 0 ) { // Display ex tax if the option is set, or prices exclude tax - if ($this->display_totals_ex_tax || !$this->prices_include_tax) : + if ( $this->display_totals_ex_tax || !$this->prices_include_tax ) { - $return = woocommerce_price($this->shipping_total); - if ($this->shipping_tax_total>0 && $this->prices_include_tax) : - $return .= ' '.$woocommerce->countries->ex_tax_or_vat().''; - endif; + $return = woocommerce_price( $this->shipping_total ); + if ( $this->shipping_tax_total > 0 && $this->prices_include_tax ) { + $return .= ' ' . $woocommerce->countries->ex_tax_or_vat() . ''; + } return $return; - else : + } else { - $return = woocommerce_price($this->shipping_total + $this->shipping_tax_total); - if ($this->shipping_tax_total>0 && !$this->prices_include_tax) : - $return .= ' '.$woocommerce->countries->inc_tax_or_vat().''; - endif; + $return = woocommerce_price( $this->shipping_total + $this->shipping_tax_total ); + if ( $this->shipping_tax_total > 0 && ! $this->prices_include_tax ) { + $return .= ' ' . $woocommerce->countries->inc_tax_or_vat() . ''; + } return $return; - endif; + } - else : + } else { return __('Free!', 'woocommerce'); - endif; - endif; + } + } } /** * gets title of the chosen shipping method + * + * @return string shipping method title */ function get_cart_shipping_title() { - if (isset($this->shipping_label)) : + if ( isset( $this->shipping_label ) ) { return __('via', 'woocommerce') . ' ' . $this->shipping_label; - endif; + } return false; } @@ -1300,52 +1377,54 @@ class WC_Cart { /*-----------------------------------------------------------------------------------*/ /** - *returns whether or not a discount has been applied + * returns whether or not a discount has been applied + * + * @return bool */ function has_discount( $code ) { - if (in_array($code, $this->applied_coupons)) return true; + if ( in_array($code, $this->applied_coupons) ) return true; return false; } /** * Applies a coupon code * - * @param string code The code to apply - * @return bool True if the coupon is applied, false if it does not exist or cannot be applied + * @param string $coupon_code - The code to apply + * @return bool True if the coupon is applied, false if it does not exist or cannot be applied */ function add_discount( $coupon_code ) { global $woocommerce; // Coupons are globally disabled - if ( get_option( 'woocommerce_enable_coupons' ) == 'no' ) return false; + if ( get_option('woocommerce_enable_coupons') == 'no' ) return false; $the_coupon = new WC_Coupon($coupon_code); - if ($the_coupon->id) : + if ( $the_coupon->id ) { // Check it can be used with cart - if (!$the_coupon->is_valid()) : + if ( ! $the_coupon->is_valid() ) { $woocommerce->add_error( __('Invalid coupon.', 'woocommerce') ); return false; - endif; + } // Check if applied - if ($woocommerce->cart->has_discount($coupon_code)) : + if ( $woocommerce->cart->has_discount( $coupon_code ) ) { $woocommerce->add_error( __('Discount code already applied!', 'woocommerce') ); return false; - endif; + } // If its individual use then remove other coupons - if ($the_coupon->individual_use=='yes') : + if ( $the_coupon->individual_use == 'yes' ) { $this->applied_coupons = array(); - endif; + } - foreach ($this->applied_coupons as $code) : + foreach ( $this->applied_coupons as $code ) { $coupon = new WC_Coupon($code); - if ($coupon->individual_use=='yes') : + if ( $coupon->individual_use == 'yes' ) { $this->applied_coupons = array(); - endif; - endforeach; + } + } $this->applied_coupons[] = $coupon_code; @@ -1354,41 +1433,49 @@ class WC_Cart { $woocommerce->add_message( __('Discount code applied successfully.', 'woocommerce') ); return true; - else : + } else { $woocommerce->add_error( __('Coupon does not exist!', 'woocommerce') ); return false; - endif; + } return false; } /** * gets the array of applied coupon codes + * + * @return array of applied coupons */ function get_applied_coupons() { return (array) $this->applied_coupons; } /** - * gets the array of applied coupon codes + * Remove coupons from the cart + * + * @params int type - 0 for all, 1 for before tax, 2 for after tax */ function remove_coupons( $type = 0 ) { - if ($type == 1) : - if ($this->applied_coupons) foreach ($this->applied_coupons as $index => $code) : - $coupon = new WC_Coupon( $code ); - if ( $coupon->apply_before_tax() ) unset($this->applied_coupons[$index]); - endforeach; + if ( $type == 1 ) { + if ($this->applied_coupons) { + foreach ( $this->applied_coupons as $index => $code ) { + $coupon = new WC_Coupon( $code ); + if ( $coupon->apply_before_tax() ) unset($this->applied_coupons[$index]); + } + } $_SESSION['coupons'] = $this->applied_coupons; - elseif ($type == 2) : - if ($this->applied_coupons) foreach ($this->applied_coupons as $index => $code) : - $coupon = new WC_Coupon( $code ); - if ( !$coupon->apply_before_tax() ) unset($this->applied_coupons[$index]); - endforeach; + } elseif ( $type == 2 ) { + if ( $this->applied_coupons ) { + foreach ( $this->applied_coupons as $index => $code ) { + $coupon = new WC_Coupon( $code ); + if ( !$coupon->apply_before_tax() ) unset($this->applied_coupons[$index]); + } + } $_SESSION['coupons'] = $this->applied_coupons; - else : + } else { unset($_SESSION['coupons']); $this->applied_coupons = array(); - endif; + } } /*-----------------------------------------------------------------------------------*/ @@ -1397,6 +1484,8 @@ class WC_Cart { /** * Get the total of all order discounts (after tax discounts) + * + * @return float */ function get_order_discount_total() { return $this->discount_total; @@ -1404,6 +1493,8 @@ class WC_Cart { /** * Get the total of all cart discounts (before tax discounts) + * + * @return float */ function get_cart_discount_total() { return $this->discount_cart; @@ -1411,67 +1502,76 @@ class WC_Cart { /** * gets the total (after calculation) + * + * @return string formatted price */ function get_total() { - return woocommerce_price($this->total); + return woocommerce_price( $this->total ); } /** * gets the total excluding taxes + * + * @return string formatted price */ function get_total_ex_tax() { $total = $this->total - $this->tax_total - $this->shipping_tax_total; - if ($total<0) $total = 0; + if ( $total < 0 ) $total = 0; return woocommerce_price( $total ); } /** * gets the cart contents total (after calculation) + * + * @return string formatted price */ function get_cart_total() { - if (!$this->prices_include_tax) : - return woocommerce_price($this->cart_contents_total); - else : - return woocommerce_price($this->cart_contents_total + $this->tax_total); - endif; + if ( ! $this->prices_include_tax ) { + return woocommerce_price( $this->cart_contents_total ); + } else { + return woocommerce_price( $this->cart_contents_total + $this->tax_total ); + } } /** * gets the sub total (after calculation) + * + * @params bool whether to include compound taxes + * @return string formatted price */ function get_cart_subtotal( $compound = false ) { global $woocommerce; // If the cart has compound tax, we want to show the subtotal as // cart + shipping + non-compound taxes (after discount) - if ($compound) : + if ( $compound ) { return woocommerce_price( $this->cart_contents_total + $this->shipping_total + $this->get_taxes_total( false ) ); // Otherwise we show cart items totals only (before discount) - else : + } else { // Display ex tax if the option is set, or prices exclude tax - if ($this->display_totals_ex_tax || !$this->prices_include_tax) : + if ($this->display_totals_ex_tax || !$this->prices_include_tax ) { $return = woocommerce_price( $this->subtotal_ex_tax ); - if ($this->tax_total>0 && $this->prices_include_tax) : + if ( $this->tax_total>0 && $this->prices_include_tax ) { $return .= ' '.$woocommerce->countries->ex_tax_or_vat().''; - endif; + } return $return; - else : + } else { $return = woocommerce_price( $this->subtotal ); - if ($this->tax_total>0 && !$this->prices_include_tax) : + if ( $this->tax_total>0 && !$this->prices_include_tax ) { $return .= ' '.$woocommerce->countries->inc_tax_or_vat().''; - endif; + } return $return; - endif; - endif; + } + } } /** @@ -1480,6 +1580,10 @@ class WC_Cart { * Gets the tax etc to avoid rounding issues. * * When on the checkout (review order), this will get the subtotal based on the customer's tax rate rather than the base rate + * + * @params object product + * @params int quantity + * @return string formatted price */ function get_product_subtotal( $_product, $quantity ) { global $woocommerce; @@ -1490,9 +1594,9 @@ class WC_Cart { $tax_rates = $this->tax->get_rates( $_product->get_tax_class() ); // This will get the base rate unless we're on the checkout page // Taxable - if ( $taxable ) : + if ( $taxable ) { - if ( $this->display_cart_ex_tax && $this->prices_include_tax ) : + if ( $this->display_cart_ex_tax && $this->prices_include_tax ) { $base_taxes = $this->tax->calc_tax( $price * $quantity, $base_tax_rates, true ); $base_tax_amount = array_sum( $base_taxes ); @@ -1500,33 +1604,33 @@ class WC_Cart { $row_price = ( $price * $quantity ) - $base_tax_amount; $return = woocommerce_price( $row_price ); - $return .= ' '.$woocommerce->countries->ex_tax_or_vat().''; + $return .= ' ' . $woocommerce->countries->ex_tax_or_vat() . ''; - elseif ( !$this->display_cart_ex_tax && $tax_rates !== $base_tax_rates && $this->prices_include_tax ) : + } elseif ( ! $this->display_cart_ex_tax && $tax_rates !== $base_tax_rates && $this->prices_include_tax ) { $base_taxes = $this->tax->calc_tax( $price * $quantity, $base_tax_rates, true ); $modded_taxes = $this->tax->calc_tax( ( $price * $quantity ) - array_sum( $base_taxes ), $tax_rates, false ); $row_price = (( $price * $quantity ) - array_sum( $base_taxes )) + array_sum( $modded_taxes ); $return = woocommerce_price( $row_price ); - if (!$this->prices_include_tax) : - $return .= ' '.$woocommerce->countries->inc_tax_or_vat().''; - endif; + if ( ! $this->prices_include_tax ) { + $return .= ' ' . $woocommerce->countries->inc_tax_or_vat() . ''; + } - else : + } else { - $row_price = $price * $quantity; + $row_price = $price * $quantity; $return = woocommerce_price( $row_price ); - endif; + } // Non taxable - else : + } else { - $row_price = $price * $quantity; + $row_price = $price * $quantity; $return = woocommerce_price( $row_price ); - endif; + } return $return; @@ -1534,62 +1638,77 @@ class WC_Cart { /** * gets the cart tax (after calculation) + * + * @return string formatted price */ function get_cart_tax() { $return = false; $cart_total_tax = $this->tax_total + $this->shipping_tax_total; - if ($cart_total_tax > 0) $return = woocommerce_price( $cart_total_tax ); - return apply_filters('woocommerce_get_cart_tax', $return); + if ( $cart_total_tax > 0 ) $return = woocommerce_price( $cart_total_tax ); + return apply_filters( 'woocommerce_get_cart_tax', $return ); } /** * Get tax row amounts with or without compound taxes includes + * + * @return float price */ function get_taxes_total( $compound = true ) { $total = 0; - foreach ($this->taxes as $key => $tax) : - if (!$compound && $this->tax->is_compound( $key )) continue; + foreach ( $this->taxes as $key => $tax ) { + if ( ! $compound && $this->tax->is_compound( $key ) ) continue; $total += $tax; - endforeach; - foreach ($this->shipping_taxes as $key => $tax) : - if (!$compound && $this->tax->is_compound( $key )) continue; + } + foreach ( $this->shipping_taxes as $key => $tax ) { + if ( ! $compound && $this->tax->is_compound( $key ) ) continue; $total += $tax; - endforeach; + } return $total; } /** * gets the total (product) discount amount - these are applied before tax + * + * @return mixed formatted price or false if there are none */ function get_discounts_before_tax() { - if ($this->discount_cart) : - return woocommerce_price($this->discount_cart); - endif; + if ( $this->discount_cart ) { + return woocommerce_price( $this->discount_cart ); + } return false; } /** * gets the order discount amount - these are applied after tax + * + * @return mixed formatted price or false if there are none */ function get_discounts_after_tax() { - if ($this->discount_total) : - return woocommerce_price($this->discount_total); - endif; + if ( $this->discount_total ) { + return woocommerce_price( $this->discount_total ); + } return false; } /** * gets the total discount amount - both kinds + * + * @return mixed formatted price or false if there are none */ function get_total_discount() { - if ($this->discount_total || $this->discount_cart) : - return woocommerce_price($this->discount_total + $this->discount_cart); - endif; + if ( $this->discount_total || $this->discount_cart ) { + return woocommerce_price( $this->discount_total + $this->discount_cart ); + } return false; } } -/** Depreciated */ +/** + * woocommerce_cart class. + * + * @extends WC_Cart + * @deprecated 1.4 + */ class woocommerce_cart extends WC_Cart { public function __construct() { _deprecated_function( 'woocommerce_cart', '1.4', 'WC_Cart()' ); diff --git a/classes/class-wc-checkout.php b/classes/class-wc-checkout.php index ff8e7405423..4211f59f6f8 100644 --- a/classes/class-wc-checkout.php +++ b/classes/class-wc-checkout.php @@ -163,6 +163,7 @@ class WC_Checkout { if (!$validation->is_phone( $this->posted[$key] )) : $woocommerce->add_error( '' . $field['label'] . ' ' . __('is not a valid number.', 'woocommerce') ); endif; break; case "billing_email" : + $this->posted[$key] = strtolower( $this->posted[$key] ); if (!$validation->is_email( $this->posted[$key] )) : $woocommerce->add_error( '' . $field['label'] . ' ' . __('is not a valid email address.', 'woocommerce') ); endif; break; endswitch; diff --git a/classes/class-wc-tax.php b/classes/class-wc-tax.php index 270de49c15e..9263e0922be 100644 --- a/classes/class-wc-tax.php +++ b/classes/class-wc-tax.php @@ -29,10 +29,10 @@ class WC_Tax { if (!empty($tax_rates)) foreach( $tax_rates as $rate ) : // Standard Rate? - if (!$rate['class']) $rate['class'] = '*'; + if ( isset( $rate['class'] ) && !$rate['class']) $rate['class'] = '*'; // Add entry for each country/state - each will hold all matching rates - if ($rate['countries']) foreach ($rate['countries'] as $country => $states) : + if ( isset( $rate['countries'] ) && $rate['countries']) foreach ($rate['countries'] as $country => $states) : if ($states) : @@ -65,13 +65,13 @@ class WC_Tax { endforeach; endforeach; - - if (!empty($local_tax_rates)) foreach( $local_tax_rates as $rate ) : + + if ( isset( $rate['countries'] ) && !empty($local_tax_rates)) foreach( $local_tax_rates as $rate ) : // Standard Rate? if (!$rate['class']) $rate['class'] = '*'; - if (!$rate['label']) : + if ( isset( $rate['label'] ) && !$rate['label']) : $rate['label'] = $woocommerce->countries->tax_or_vat(); // Add % to label @@ -537,4 +537,4 @@ class woocommerce_tax extends WC_Tax { public function __construct() { _deprecated_function( 'woocommerce_tax', '1.4', 'WC_Tax()' ); } -} \ No newline at end of file +} diff --git a/readme.txt b/readme.txt index 2af974e3b7d..37db1728670 100644 --- a/readme.txt +++ b/readme.txt @@ -147,10 +147,12 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc * Feature - Control default catalog sort order from Catalog Settings * Tweak - Order items table (for emails) moved to template file * Tweak - Queries on report pages to replace get_posts to resolve issues on stores with a shed load of orders +* Tweak - Remove case sensitively from order tracking and force email lowercase on checkout * Fix - Put chosen frontend script back * Fix - Make download links use billing email, not user email -* Localization - Spanish update by Héctor Carranza * Fix - ' in prices (thousand separator) +* Fix - Admin menu highlighting when adding orders +* Localization - Spanish update by Héctor Carranza = 1.5.2.1 - 16/03/2012 = * Fix - Redirect when no payment is required diff --git a/shortcodes/shortcode-order_tracking.php b/shortcodes/shortcode-order_tracking.php index 3e4ccc62e4d..a1ccbc9af7c 100644 --- a/shortcodes/shortcode-order_tracking.php +++ b/shortcodes/shortcode-order_tracking.php @@ -34,7 +34,7 @@ function woocommerce_order_tracking( $atts ) { if ($order->id && $order_email) : - if ($order->billing_email == $order_email) : + if (strtolower($order->billing_email) == strtolower($order_email)) : woocommerce_get_template( 'order/tracking.php', array( 'order' => $order diff --git a/templates/shop/breadcrumb.php b/templates/shop/breadcrumb.php index d13f8d48dc9..ac4acec4652 100644 --- a/templates/shop/breadcrumb.php +++ b/templates/shop/breadcrumb.php @@ -186,5 +186,4 @@ if ( (!is_home() && !is_front_page() && !(is_post_type_archive() && get_option(' echo $wrap_after; -endif; - \ No newline at end of file +endif; \ No newline at end of file diff --git a/woocommerce.php b/woocommerce.php index 2b9ab799dd6..4b5dc2187b0 100644 --- a/woocommerce.php +++ b/woocommerce.php @@ -1,22 +1,25 @@ version ); @@ -86,7 +89,7 @@ class Woocommerce { $this->includes(); // Installation - if (is_admin() && !defined('DOING_AJAX')) $this->install(); + if ( is_admin() && !defined('DOING_AJAX') ) $this->install(); // Actions add_action( 'init', array(&$this, 'init'), 0); @@ -97,12 +100,12 @@ class Woocommerce { * Include required core files **/ function includes() { - if (is_admin()) $this->admin_includes(); - if (defined('DOING_AJAX')) $this->ajax_includes(); - if (!is_admin() || defined('DOING_AJAX')) $this->frontend_includes(); + if ( is_admin() ) $this->admin_includes(); + if ( defined('DOING_AJAX') ) $this->ajax_includes(); + if ( ! is_admin() || defined('DOING_AJAX') ) $this->frontend_includes(); - include( 'woocommerce-core-functions.php' ); // Contains core functions for the front/back end - include( 'widgets/widget-init.php' ); // Widget classes + include( 'woocommerce-core-functions.php' ); // Contains core functions for the front/back end + include( 'widgets/widget-init.php' ); // Widget classes include( 'classes/class-wc-countries.php' ); // Defines countries and states include( 'classes/class-wc-order.php' ); // Single order class include( 'classes/class-wc-product.php' ); // Product class @@ -115,7 +118,6 @@ class Woocommerce { include( 'classes/gateways/class-wc-payment-gateway.php' ); include( 'classes/shipping/class-wc-shipping.php' ); include( 'classes/shipping/class-wc-shipping-method.php' ); - include( 'classes/shipping/class-wc-flat-rate.php' ); include( 'classes/shipping/class-wc-international-delivery.php' ); include( 'classes/shipping/class-wc-free-shipping.php' ); @@ -147,11 +149,11 @@ class Woocommerce { function frontend_includes() { include( 'woocommerce-hooks.php' ); // Template hooks used on the front-end include( 'woocommerce-functions.php' ); // Contains functions for various front-end events - include( 'shortcodes/shortcode-init.php' ); // Init the shortcodes - include( 'classes/class-wc-query.php' ); // The main store queries - include( 'classes/class-wc-cart.php' ); // The main cart class - include( 'classes/class-wc-coupon.php' ); // Coupon class - include( 'classes/class-wc-customer.php' ); // Customer class + include( 'shortcodes/shortcode-init.php' ); // Init the shortcodes + include( 'classes/class-wc-query.php' ); // The main store queries + include( 'classes/class-wc-cart.php' ); // The main cart class + include( 'classes/class-wc-coupon.php' ); // Coupon class + include( 'classes/class-wc-customer.php' ); // Customer class } /** @@ -188,7 +190,7 @@ class Woocommerce { $term = get_queried_object(); - $file = 'taxonomy-' . $term->taxonomy . '.php'; + $file = 'taxonomy-' . $term->taxonomy . '.php'; $find[] = 'taxonomy-' . $term->taxonomy . '-' . $term->slug . '.php'; $find[] = $this->template_url . 'taxonomy-' . $term->taxonomy . '-' . $term->slug . '.php'; $find[] = $file; @@ -202,7 +204,7 @@ class Woocommerce { } - if ($file) { + if ( $file ) { $template = locate_template( $find ); if ( ! $template ) $template = $this->plugin_path() . '/templates/' . $file; } @@ -211,7 +213,7 @@ class Woocommerce { } function comments_template_loader( $template ) { - if(get_post_type() !== 'product') return $template; + if( get_post_type() !== 'product' ) return $template; if (file_exists( STYLESHEETPATH . '/' . $this->template_url . 'single-product-reviews.php' )) return STYLESHEETPATH . '/' . $this->template_url . 'single-product-reviews.php'; @@ -225,7 +227,8 @@ class Woocommerce { function install() { register_activation_hook( __FILE__, 'activate_woocommerce' ); register_activation_hook( __FILE__, 'flush_rewrite_rules' ); - if ( get_option('woocommerce_db_version') != $this->version ) : add_action('init', 'install_woocommerce', 0); endif; + if ( get_option('woocommerce_db_version') != $this->version ) + add_action('init', 'install_woocommerce', 0); } /** @@ -246,48 +249,48 @@ class Woocommerce { $this->payment_gateways->init(); // Classes/actions loaded for the frontend and for ajax requests - if ( !is_admin() || defined('DOING_AJAX') ) : - + if ( ! is_admin() || defined('DOING_AJAX') ) { + // Class instances $this->cart = new WC_Cart(); // Cart class, stores the cart contents $this->customer = new WC_Customer(); // Customer class, sorts out session data such as location $this->query = new WC_Query(); // Query class, handles front-end queries and loops $this->cart->init(); - + // Load messages $this->load_messages(); - + + // Load functions + $this->include_template_functions(); + // Hooks add_filter( 'template_include', array(&$this, 'template_loader') ); add_filter( 'comments_template', array(&$this, 'comments_template_loader') ); - // add_action( 'init', array(&$this, 'include_template_functions'), 25 ); - $this->include_template_functions(); add_filter( 'wp_redirect', array(&$this, 'redirect'), 1, 2 ); add_action( 'wp', array(&$this, 'buffer_checkout') ); add_action( 'wp_enqueue_scripts', array(&$this, 'frontend_scripts') ); add_action( 'wp_head', array(&$this, 'generator') ); add_action( 'wp_head', array(&$this, 'wp_head') ); add_filter( 'body_class', array(&$this, 'output_body_class') ); - add_action( 'wp_footer', array(&$this, 'output_inline_js'), 25); - - endif; + add_action( 'wp_footer', array(&$this, 'output_inline_js'), 25 ); + } // Actions - add_action( 'the_post', array(&$this, 'setup_product_data') ); - add_action( 'admin_footer', array(&$this, 'output_inline_js'), 25); + add_action( 'the_post', array( &$this, 'setup_product_data' ) ); + add_action( 'admin_footer', array( &$this, 'output_inline_js' ), 25 ); // Email Actions $email_actions = array( 'woocommerce_low_stock', 'woocommerce_no_stock', 'woocommerce_product_on_backorder', 'woocommerce_order_status_pending_to_processing', 'woocommerce_order_status_pending_to_completed', 'woocommerce_order_status_pending_to_on-hold', 'woocommerce_order_status_failed_to_processing', 'woocommerce_order_status_failed_to_completed', 'woocommerce_order_status_pending_to_processing', 'woocommerce_order_status_pending_to_on-hold', 'woocommerce_order_status_completed', 'woocommerce_new_customer_note' ); - foreach ($email_actions as $action) add_action($action, array( &$this, 'send_transactional_email')); - + foreach ( $email_actions as $action ) add_action( $action, array( &$this, 'send_transactional_email') ); + // Actions for SSL - if (!is_admin() || defined('DOING_AJAX')) : - add_action( 'wp', array( &$this, 'ssl_redirect')); - + if ( ! is_admin() || defined('DOING_AJAX') ) { + add_action( 'wp', array( &$this, 'ssl_redirect' ) ); + $filters = array( 'post_thumbnail_html', 'widget_text', 'wp_get_attachment_url', 'wp_get_attachment_image_attributes', 'wp_get_attachment_url', 'option_siteurl', 'option_homeurl', 'option_home', 'option_url', 'option_wpurl', 'option_stylesheet_url', 'option_template_url', 'script_loader_src', 'style_loader_src', 'template_directory_uri', 'stylesheet_directory_uri', 'site_url' ); - foreach ($filters as $filter) add_filter($filter, array( &$this, 'force_ssl')); - endif; + foreach ( $filters as $filter ) add_filter( $filter, array( &$this, 'force_ssl') ); + } // Register globals for WC environment $this->register_globals(); @@ -302,7 +305,7 @@ class Woocommerce { $this->init_image_sizes(); // Init styles - if (!is_admin()) $this->init_styles(); + if ( ! is_admin() ) $this->init_styles(); // Trigger API requests $this->api_requests(); @@ -315,8 +318,8 @@ class Woocommerce { * API request - Trigger any API requests (handy for third party plugins/gateways) **/ function api_requests() { - if (isset($_GET['wc-api'])) { - $api = strtolower(esc_attr( $_GET['wc-api'] )); + if ( isset( $_GET['wc-api'] ) ) { + $api = strtolower( esc_attr( $_GET['wc-api'] ) ); do_action( 'woocommerce_api_' . $api ); } } @@ -336,7 +339,7 @@ class Woocommerce { * Output buffering on the checkout allows gateways to do header redirects **/ function buffer_checkout() { - if (is_checkout()) ob_start(); + if ( is_checkout() ) ob_start(); } /** @@ -350,8 +353,8 @@ class Woocommerce { * When the_post is called, get product data too **/ function setup_product_data( $post ) { - if ($post->post_type!=='product') return; - unset($GLOBALS['product']); + if ( $post->post_type !== 'product' ) return; + unset( $GLOBALS['product'] ); $GLOBALS['product'] = new WC_Product( $post->ID ); return $GLOBALS['product']; } @@ -361,18 +364,19 @@ class Woocommerce { **/ function compatibility() { // Post thumbnail support - if ( !current_theme_supports( 'post-thumbnails' ) ) : + if ( ! current_theme_supports( 'post-thumbnails' ) ) { add_theme_support( 'post-thumbnails' ); remove_post_type_support( 'post', 'thumbnail' ); remove_post_type_support( 'page', 'thumbnail' ); - else : + } else { add_post_type_support( 'product', 'thumbnail' ); - endif; + } // IIS - if (!isset($_SERVER['REQUEST_URI'])) { - $_SERVER['REQUEST_URI'] = substr($_SERVER['PHP_SELF'],1 ); - if (isset($_SERVER['QUERY_STRING'])) { $_SERVER['REQUEST_URI'].='?'.$_SERVER['QUERY_STRING']; } + if ( ! isset($_SERVER['REQUEST_URI'] ) ) { + $_SERVER['REQUEST_URI'] = substr( $_SERVER['PHP_SELF'], 1 ); + if ( isset( $_SERVER['QUERY_STRING'] ) ) + $_SERVER['REQUEST_URI'].='?'.$_SERVER['QUERY_STRING']; } } @@ -380,30 +384,30 @@ class Woocommerce { * Redirect to https if Force SSL is enabled **/ function ssl_redirect() { - if (get_option('woocommerce_force_ssl_checkout')=='no') return; + if ( get_option('woocommerce_force_ssl_checkout') == 'no' ) return; - if (!is_ssl()) { - if (is_checkout()) { + if ( ! is_ssl() ) { + if ( is_checkout() ) { wp_redirect( str_replace('http:', 'https:', get_permalink(woocommerce_get_page_id('checkout'))), 301 ); exit; - } elseif (is_account_page()) { + } elseif ( is_account_page() ) { if ( 0 === strpos($_SERVER['REQUEST_URI'], 'http') ) { - wp_redirect(preg_replace('|^http://|', 'https://', $_SERVER['REQUEST_URI'])); + wp_redirect( preg_replace( '|^http://|', 'https://', $_SERVER['REQUEST_URI'] ) ); exit; } else { - wp_redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); + wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); exit; } exit; } } else { // Break out of SSL if we leave the checkout/my accounts (anywhere but thanks) - if (get_option('woocommerce_unforce_ssl_checkout')=='yes' && $_SERVER['REQUEST_URI'] && !is_checkout() && !is_page(woocommerce_get_page_id('thanks')) && !is_ajax() && !is_account_page()) { + if ( get_option('woocommerce_unforce_ssl_checkout') == 'yes' && $_SERVER['REQUEST_URI'] && ! is_checkout() && ! is_page( woocommerce_get_page_id('thanks') ) && ! is_ajax() && ! is_account_page() ) { if ( 0 === strpos($_SERVER['REQUEST_URI'], 'http') ) { - wp_redirect(preg_replace('|^https://|', 'http://', $_SERVER['REQUEST_URI'])); + wp_redirect( preg_replace( '|^https://|', 'http://', $_SERVER['REQUEST_URI'] ) ); exit; } else { - wp_redirect('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); + wp_redirect( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); exit; } } @@ -423,15 +427,15 @@ class Woocommerce { function wp_head() { $this->add_body_class('theme-' . strtolower( get_current_theme() )); - if (is_woocommerce()) $this->add_body_class('woocommerce'); + if ( is_woocommerce() ) $this->add_body_class('woocommerce'); - if (is_checkout()) $this->add_body_class('woocommerce-checkout'); + if ( is_checkout() ) $this->add_body_class('woocommerce-checkout'); - if (is_cart()) $this->add_body_class('woocommerce-cart'); + if ( is_cart() ) $this->add_body_class('woocommerce-cart'); - if (is_account_page()) $this->add_body_class('woocommerce-account'); + if ( is_account_page() ) $this->add_body_class('woocommerce-account'); - if (is_woocommerce() || is_checkout() || is_cart() || is_account_page() || is_page(woocommerce_get_page_id('order_tracking')) || is_page(woocommerce_get_page_id('thanks'))) $this->add_body_class('woocommerce-page'); + if ( is_woocommerce() || is_checkout() || is_cart() || is_account_page() || is_page( woocommerce_get_page_id('order_tracking') ) || is_page( woocommerce_get_page_id('thanks') ) ) $this->add_body_class('woocommerce-page'); } /** @@ -440,19 +444,19 @@ class Woocommerce { function init_user_roles() { global $wp_roles; - if (class_exists('WP_Roles')) if ( ! isset( $wp_roles ) ) $wp_roles = new WP_Roles(); + if ( class_exists('WP_Roles') ) if ( ! isset( $wp_roles ) ) $wp_roles = new WP_Roles(); - if (is_object($wp_roles)) : + if ( is_object($wp_roles) ) { // Customer role - add_role('customer', __('Customer', 'woocommerce'), array( + add_role( 'customer', __('Customer', 'woocommerce'), array( 'read' => true, 'edit_posts' => false, 'delete_posts' => false - )); + ) ); // Shop manager role - add_role('shop_manager', __('Shop Manager', 'woocommerce'), array( + add_role( 'shop_manager', __('Shop Manager', 'woocommerce'), array( 'read' => true, 'read_private_pages' => true, 'read_private_posts' => true, @@ -486,7 +490,7 @@ class Woocommerce { 'manage_woocommerce_coupons' => true, 'manage_woocommerce_products' => true, 'view_woocommerce_reports' => true - )); + ) ); // Main Shop capabilities for admin $wp_roles->add_cap( 'administrator', 'manage_woocommerce' ); @@ -494,7 +498,7 @@ class Woocommerce { $wp_roles->add_cap( 'administrator', 'manage_woocommerce_coupons' ); $wp_roles->add_cap( 'administrator', 'manage_woocommerce_products' ); $wp_roles->add_cap( 'administrator', 'view_woocommerce_reports' ); - endif; + } } /** @@ -502,33 +506,33 @@ class Woocommerce { **/ function init_taxonomy() { - if (post_type_exists('product')) return; + if ( post_type_exists('product') ) return; /** * Slugs **/ $shop_page_id = woocommerce_get_page_id('shop'); - $base_slug = ($shop_page_id > 0 && get_page( $shop_page_id )) ? get_page_uri( $shop_page_id ) : 'shop'; + $base_slug = ( $shop_page_id > 0 && get_page( $shop_page_id ) ) ? get_page_uri( $shop_page_id ) : 'shop'; - $category_base = (get_option('woocommerce_prepend_shop_page_to_urls')=="yes") ? trailingslashit($base_slug) : ''; + $category_base = ( get_option('woocommerce_prepend_shop_page_to_urls') == "yes" ) ? trailingslashit($base_slug) : ''; - $category_slug = (get_option('woocommerce_product_category_slug')) ? get_option('woocommerce_product_category_slug') : _x('product-category', 'slug', 'woocommerce'); + $category_slug = ( get_option('woocommerce_product_category_slug') ) ? get_option('woocommerce_product_category_slug') : _x('product-category', 'slug', 'woocommerce'); - $tag_slug = (get_option('woocommerce_product_tag_slug')) ? get_option('woocommerce_product_tag_slug') : _x('product-tag', 'slug', 'woocommerce'); + $tag_slug = ( get_option('woocommerce_product_tag_slug') ) ? get_option('woocommerce_product_tag_slug') : _x('product-tag', 'slug', 'woocommerce'); - $product_base = (get_option('woocommerce_prepend_shop_page_to_products')=='yes') ? trailingslashit($base_slug) : trailingslashit(_x('product', 'slug', 'woocommerce')); + $product_base = ( get_option('woocommerce_prepend_shop_page_to_products') == 'yes' ) ? trailingslashit($base_slug) : trailingslashit(_x('product', 'slug', 'woocommerce')); - if (get_option('woocommerce_prepend_category_to_products')=='yes') $product_base .= trailingslashit('%product_cat%'); + if ( get_option('woocommerce_prepend_category_to_products') == 'yes' ) $product_base .= trailingslashit('%product_cat%'); $product_base = untrailingslashit($product_base); - if (current_user_can('manage_woocommerce')) $show_in_menu = 'woocommerce'; else $show_in_menu = true; + if ( current_user_can('manage_woocommerce') ) $show_in_menu = 'woocommerce'; else $show_in_menu = true; /** * Taxonomies **/ - $admin_only_query_var = (is_admin()) ? true : false; + $admin_only_query_var = ( is_admin() ) ? true : false; register_taxonomy( 'product_type', array('product'), @@ -655,12 +659,12 @@ class Woocommerce { ); $attribute_taxonomies = $this->get_attribute_taxonomies(); - if ( $attribute_taxonomies ) : - foreach ($attribute_taxonomies as $tax) : + if ( $attribute_taxonomies ) { + foreach ($attribute_taxonomies as $tax) { $name = $this->attribute_taxonomy_name($tax->attribute_name); $hierarchical = true; - if ($name) : + if ($name) { $label = ( isset( $tax->attribute_label ) && $tax->attribute_label ) ? $tax->attribute_label : $tax->attribute_name; @@ -689,9 +693,9 @@ class Woocommerce { ) ); - endif; - endforeach; - endif; + } + } + } /** * Post Types @@ -887,15 +891,15 @@ class Woocommerce { */ function init_styles() { $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min'; - $chosen_en = (get_option('woocommerce_enable_chosen')=='yes') ? true : false; - $lightbox_en = (get_option('woocommerce_enable_lightbox')=='yes') ? true : false; + $chosen_en = ( get_option('woocommerce_enable_chosen') == 'yes' ) ? true : false; + $lightbox_en = ( get_option('woocommerce_enable_lightbox') == 'yes' ) ? true : false; // Optional front end css - if ((defined('WOOCOMMERCE_USE_CSS') && WOOCOMMERCE_USE_CSS) || (!defined('WOOCOMMERCE_USE_CSS') && get_option('woocommerce_frontend_css')=='yes')) : - $css = file_exists(get_stylesheet_directory() . '/woocommerce/style.css') ? get_stylesheet_directory_uri() . '/woocommerce/style.css' : $this->plugin_url() . '/assets/css/woocommerce.css'; - wp_register_style('woocommerce_frontend_styles', $css ); + if ( ( defined('WOOCOMMERCE_USE_CSS') && WOOCOMMERCE_USE_CSS ) || ( ! defined('WOOCOMMERCE_USE_CSS') && get_option('woocommerce_frontend_css') == 'yes') ) { + $css = file_exists( get_stylesheet_directory() . '/woocommerce/style.css' ) ? get_stylesheet_directory_uri() . '/woocommerce/style.css' : $this->plugin_url() . '/assets/css/woocommerce.css'; + wp_register_style( 'woocommerce_frontend_styles', $css ); wp_enqueue_style( 'woocommerce_frontend_styles' ); - endif; + } if ($lightbox_en) wp_enqueue_style( 'woocommerce_fancybox_styles', $this->plugin_url() . '/assets/css/fancybox'.$suffix.'.css' ); if ($chosen_en) wp_enqueue_style( 'woocommerce_chosen_styles', $this->plugin_url() . '/assets/css/chosen'.$suffix.'.css' ); @@ -906,23 +910,22 @@ class Woocommerce { */ function frontend_scripts() { $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min'; - $lightbox_en = (get_option('woocommerce_enable_lightbox')=='yes') ? true : false; - $chosen_en = (get_option('woocommerce_enable_chosen')=='yes') ? true : false; - $jquery_ui_en = (get_option('woocommerce_enable_jquery_ui')=='yes') ? true : false; - $scripts_position = (get_option('woocommerce_scripts_position') == 'yes') ? true : false; + $lightbox_en = ( get_option('woocommerce_enable_lightbox') == 'yes' ) ? true : false; + $chosen_en = ( get_option('woocommerce_enable_chosen') == 'yes' ) ? true : false; + $jquery_ui_en = ( get_option('woocommerce_enable_jquery_ui') == 'yes' ) ? true : false; + $scripts_position = ( get_option('woocommerce_scripts_position') == 'yes' ) ? true : false; // Woocommerce.min.js is minified and contains woocommerce_plugins wp_enqueue_script( 'woocommerce', $this->plugin_url() . '/assets/js/woocommerce'.$suffix.'.js', array('jquery'), '1.0', $scripts_position ); - if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) { + if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) wp_enqueue_script( 'woocommerce_plugins', $this->plugin_url() . '/assets/js/woocommerce_plugins.js', array('jquery'), '1.0', $scripts_position ); - } if ($lightbox_en) wp_enqueue_script( 'fancybox', $this->plugin_url() . '/assets/js/fancybox'.$suffix.'.js', array('jquery'), '1.0', $scripts_position ); // Chosen.jquery.min.js is minified and contains the frontend code for chosen selects - if ($chosen_en && is_checkout()) { + if ( $chosen_en && is_checkout() ) { wp_enqueue_script( 'chosen', $this->plugin_url() . '/assets/js/chosen.jquery'.$suffix.'.js', array('jquery'), '1.0' ); if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) { @@ -930,7 +933,7 @@ class Woocommerce { } } - if ($jquery_ui_en) : + if ($jquery_ui_en) { wp_enqueue_script( 'jqueryui', $this->plugin_url() . '/assets/js/jquery-ui'.$suffix.'.js', array('jquery'), '1.0', $scripts_position ); wp_enqueue_script( 'wc_price_slider', $this->plugin_url() . '/assets/js/price_slider'.$suffix.'.js', array('jqueryui'), '1.0', $scripts_position ); @@ -942,7 +945,7 @@ class Woocommerce { ); wp_localize_script( 'wc_price_slider', 'woocommerce_price_slider_params', $woocommerce_price_slider_params ); - endif; + } /* Script variables */ $states = json_encode( $this->countries->states ); @@ -967,7 +970,7 @@ class Woocommerce { 'is_cart' => ( is_cart() ) ? 1 : 0 ); - if (is_checkout() || is_cart()) + if ( is_checkout() || is_cart() ) $woocommerce_params['locale'] = json_encode( $this->countries->get_country_locale() ); wp_localize_script( 'woocommerce', 'woocommerce_params', apply_filters('woocommerce_params', $woocommerce_params) ); @@ -979,10 +982,10 @@ class Woocommerce { * Get Checkout Class */ function checkout() { - if ( !class_exists('WC_Checkout') ) : + if ( ! class_exists('WC_Checkout') ) { include( 'classes/class-wc-checkout.php' ); $this->checkout = new WC_Checkout(); - endif; + } return $this->checkout; } @@ -991,7 +994,7 @@ class Woocommerce { * Get Logging Class */ function logger() { - if ( !class_exists('WC_Logger') ) include( 'classes/class-wc-logger.php' ); + if ( ! class_exists('WC_Logger') ) include( 'classes/class-wc-logger.php' ); return new WC_Logger(); } @@ -999,7 +1002,7 @@ class Woocommerce { * Get Validation Class */ function validation() { - if ( !class_exists('WC_Validation') ) include( 'classes/class-wc-validation.php' ); + if ( ! class_exists('WC_Validation') ) include( 'classes/class-wc-validation.php' ); return new WC_Validation(); } @@ -1013,10 +1016,10 @@ class Woocommerce { function mailer() { // Init mail class - if ( !class_exists('WC_Email') ) : + if ( ! class_exists('WC_Email') ) { include( 'classes/class-wc-email.php' ); $this->woocommerce_email = new WC_Email(); - endif; + } return $this->woocommerce_email; } @@ -1026,7 +1029,7 @@ class Woocommerce { * Get the plugin url */ function plugin_url() { - if($this->plugin_url) return $this->plugin_url; + if ( $this->plugin_url ) return $this->plugin_url; return $this->plugin_url = plugins_url( basename( plugin_dir_path(__FILE__) ), basename( __FILE__ ) ); } @@ -1034,7 +1037,7 @@ class Woocommerce { * Get the plugin path */ function plugin_path() { - if($this->plugin_path) return $this->plugin_path; + if ( $this->plugin_path ) return $this->plugin_path; return $this->plugin_path = plugin_dir_path( __FILE__ ); } @@ -1043,13 +1046,12 @@ class Woocommerce { * Return the URL with https if SSL is on */ function force_ssl( $content ) { - if (is_ssl()) : - if (is_array($content)) : - $content = array_map( array(&$this, 'force_ssl') , $content); - else : - $content = str_replace('http:', 'https:', $content); - endif; - endif; + if ( is_ssl() ) { + if ( is_array($content) ) + $content = array_map( array( &$this, 'force_ssl' ) , $content ); + else + $content = str_replace( 'http:', 'https:', $content ); + } return $content; } @@ -1060,14 +1062,14 @@ class Woocommerce { */ function get_image_size( $image_size ) { $return = ''; - switch ($image_size) : + switch ( $image_size ) { case "shop_thumbnail_image_width" : $return = get_option('woocommerce_thumbnail_image_width'); break; case "shop_thumbnail_image_height" : $return = get_option('woocommerce_thumbnail_image_height'); break; case "shop_catalog_image_width" : $return = get_option('woocommerce_catalog_image_width'); break; case "shop_catalog_image_height" : $return = get_option('woocommerce_catalog_image_height'); break; case "shop_single_image_width" : $return = get_option('woocommerce_single_image_width'); break; case "shop_single_image_height" : $return = get_option('woocommerce_single_image_height'); break; - endswitch; + } return apply_filters( 'woocommerce_get_image_size_'.$image_size, $return ); } @@ -1077,14 +1079,14 @@ class Woocommerce { * Load Messages */ function load_messages() { - if (isset($_SESSION['errors'])) $this->errors = $_SESSION['errors']; - if (isset($_SESSION['messages'])) $this->messages = $_SESSION['messages']; + if ( isset( $_SESSION['errors'] ) ) $this->errors = $_SESSION['errors']; + if ( isset( $_SESSION['messages'] ) ) $this->messages = $_SESSION['messages']; - unset($_SESSION['messages']); - unset($_SESSION['errors']); + unset( $_SESSION['messages'] ); + unset( $_SESSION['errors'] ); // Load errors from querystring - if (isset($_GET['wc_error'])) { + if ( isset( $_GET['wc_error'] ) ) { $this->add_error( esc_attr( $_GET['wc_error'] ) ); } } @@ -1102,8 +1104,7 @@ class Woocommerce { /** Clear messages and errors from the session data */ function clear_messages() { $this->errors = $this->messages = array(); - unset($_SESSION['messages']); - unset($_SESSION['errors']); + unset( $_SESSION['messages'], $_SESSION['errors'] ); } /** @@ -1148,9 +1149,9 @@ class Woocommerce { $this->set_messages(); // IIS fix - if ($is_IIS) session_write_close(); + if ( $is_IIS ) session_write_close(); - return apply_filters('woocommerce_redirect', $location); + return apply_filters( 'woocommerce_redirect', $location ); } /** Attribute Helpers ****************************************************************/ @@ -1160,9 +1161,8 @@ class Woocommerce { */ function get_attribute_taxonomies() { global $wpdb; - if (!$this->attribute_taxonomies) : + if ( ! $this->attribute_taxonomies ) $this->attribute_taxonomies = $wpdb->get_results("SELECT * FROM ".$wpdb->prefix."woocommerce_attribute_taxonomies;"); - endif; return $this->attribute_taxonomies; } @@ -1179,15 +1179,15 @@ class Woocommerce { function attribute_label( $name ) { global $wpdb; - if (strstr( $name, 'pa_' )) : + if ( strstr( $name, 'pa_' ) ) { $name = str_replace( 'pa_', '', sanitize_title( $name ) ); $label = $wpdb->get_var( $wpdb->prepare( "SELECT attribute_label FROM ".$wpdb->prefix."woocommerce_attribute_taxonomies WHERE attribute_name = %s;", $name ) ); if ($label) return $label; else return ucfirst($name); - else : + } else { return $name; - endif; + } } /** @@ -1197,8 +1197,8 @@ class Woocommerce { $taxonomy_names = array(); $attribute_taxonomies = $this->get_attribute_taxonomies(); if ( $attribute_taxonomies ) { - foreach ($attribute_taxonomies as $tax) { - $taxonomy_names[] = $this->attribute_taxonomy_name( strtolower(sanitize_title($tax->attribute_name)) ); + foreach ( $attribute_taxonomies as $tax ) { + $taxonomy_names[] = $this->attribute_taxonomy_name( strtolower( sanitize_title( $tax->attribute_name ) ) ); } } return $taxonomy_names; @@ -1210,14 +1210,14 @@ class Woocommerce { * Get coupon types */ function get_coupon_discount_types() { - if (!isset($this->coupon_discount_types)) : - $this->coupon_discount_types = apply_filters('woocommerce_coupon_discount_types', array( + if ( ! isset($this->coupon_discount_types ) ) { + $this->coupon_discount_types = apply_filters( 'woocommerce_coupon_discount_types', array( 'fixed_cart' => __('Cart Discount', 'woocommerce'), 'percent' => __('Cart % Discount', 'woocommerce'), 'fixed_product' => __('Product Discount', 'woocommerce'), 'percent_product' => __('Product % Discount', 'woocommerce') - )); - endif; + ) ); + } return $this->coupon_discount_types; } @@ -1226,7 +1226,7 @@ class Woocommerce { */ function get_coupon_discount_type( $type = '' ) { $types = (array) $this->get_coupon_discount_types(); - if (isset($types[$type])) return $types[$type]; + if ( isset( $types[$type] ) ) return $types[$type]; } /** Nonces ****************************************************************/ @@ -1234,12 +1234,12 @@ class Woocommerce { /** * Return a nonce field */ - function nonce_field ($action, $referer = true , $echo = true) { return wp_nonce_field('woocommerce-' . $action, '_n', $referer, $echo); } + function nonce_field ( $action, $referer = true , $echo = true ) { return wp_nonce_field('woocommerce-' . $action, '_n', $referer, $echo ); } /** * Return a url with a nonce appended */ - function nonce_url ($action, $url = '') { return add_query_arg( '_n', wp_create_nonce( 'woocommerce-' . $action ), $url); } + function nonce_url ( $action, $url = '' ) { return add_query_arg( '_n', wp_create_nonce( 'woocommerce-' . $action ), $url ); } /** * Check a nonce and sets woocommerce error in case it is invalid @@ -1252,18 +1252,18 @@ class Woocommerce { * * @return bool */ - function verify_nonce($action, $method='_POST', $error_message = false) { + function verify_nonce( $action, $method='_POST', $error_message = false ) { $name = '_n'; $action = 'woocommerce-' . $action; - if( $error_message === false ) $error_message = __('Action failed. Please refresh the page and retry.', 'woocommerce'); + if ( $error_message === false ) $error_message = __('Action failed. Please refresh the page and retry.', 'woocommerce'); - if(!in_array($method, array('_GET', '_POST', '_REQUEST'))) $method = '_POST'; + if ( ! in_array( $method, array( '_GET', '_POST', '_REQUEST' ) ) ) $method = '_POST'; - if ( isset($_REQUEST[$name]) && wp_verify_nonce($_REQUEST[$name], $action) ) return true; + if ( isset($_REQUEST[$name] ) && wp_verify_nonce( $_REQUEST[$name], $action ) ) return true; - if( $error_message ) $this->add_error( $error_message ); + if ( $error_message ) $this->add_error( $error_message ); return false; } @@ -1275,9 +1275,9 @@ class Woocommerce { */ function cache( $id, $data, $args=array() ) { - if( ! isset($this->_cache[ $id ]) ) $this->_cache[ $id ] = array(); + if ( ! isset( $this->_cache[ $id ] ) ) $this->_cache[ $id ] = array(); - if( empty($args) ) $this->_cache[ $id ][0] = $data; + if ( empty( $args ) ) $this->_cache[ $id ][0] = $data; else $this->_cache[ $id ][ serialize($args) ] = $data; return $data; @@ -1285,20 +1285,20 @@ class Woocommerce { } function cache_get( $id, $args=array() ) { - if( ! isset($this->_cache[ $id ]) ) return null; + if ( ! isset( $this->_cache[ $id ] ) ) return null; - if( empty($args) && isset($this->_cache[ $id ][0]) ) return $this->_cache[ $id ][0]; - elseif ( isset($this->_cache[ $id ][ serialize($args) ] ) ) return $this->_cache[ $id ][ serialize($args) ]; + if ( empty( $args ) && isset( $this->_cache[ $id ][0] ) ) return $this->_cache[ $id ][0]; + elseif ( isset( $this->_cache[ $id ][ serialize($args) ] ) ) return $this->_cache[ $id ][ serialize($args) ]; } /** * Shortcode cache */ function shortcode_wrapper($function, $atts=array()) { - if( $content = $this->cache_get( $function . '-shortcode', $atts ) ) return $content; + if ( $content = $this->cache_get( $function . '-shortcode', $atts ) ) return $content; ob_start(); - call_user_func($function, $atts); + call_user_func( $function, $atts ); return $this->cache( $function . '-shortcode', ob_get_clean(), $atts); } @@ -1308,7 +1308,7 @@ class Woocommerce { * Sets a constant preventing some caching plugins from caching a page. Used on dynamic pages */ function nocache() { - if(!defined('DONOTCACHEPAGE')) define("DONOTCACHEPAGE", "true"); // WP Super Cache constant + if ( ! defined('DONOTCACHEPAGE') ) define("DONOTCACHEPAGE", "true"); // WP Super Cache constant } /** @@ -1317,11 +1317,11 @@ class Woocommerce { * Sets a cookie when the cart has something in it. Can be used by hosts to prevent caching if set. */ function cart_has_contents_cookie( $set ) { - if (!headers_sent()) { + if ( ! headers_sent() ) { if ($set) - setcookie("woocommerce_items_in_cart", "1", 0, COOKIEPATH, COOKIE_DOMAIN, false); + setcookie( "woocommerce_items_in_cart", "1", 0, COOKIEPATH, COOKIE_DOMAIN, false ); else - setcookie("woocommerce_items_in_cart", "0", time() - 3600, COOKIEPATH, COOKIE_DOMAIN, false); + setcookie( "woocommerce_items_in_cart", "0", time() - 3600, COOKIEPATH, COOKIE_DOMAIN, false ); } } @@ -1341,7 +1341,7 @@ class Woocommerce { $wpdb->query("DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_uf_pid_%')"); $wpdb->query("DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_ln_count_%')"); - if ($post_id>0) : + if ($post_id>0) { $post_id = (int) $post_id; delete_transient('wc_product_total_stock_'.$post_id); delete_transient('wc_product_children_ids_'.$post_id); @@ -1352,11 +1352,11 @@ class Woocommerce { '_transient_wc_product_total_stock_$post_id', '_transient_wc_average_rating_$post_id' )"); - else : + } else { $wpdb->query("DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_product_children_ids_%')"); $wpdb->query("DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_product_total_stock_%')"); $wpdb->query("DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_average_rating_%')"); - endif; + } } /** Body Classes **********************************************************/ @@ -1366,12 +1366,12 @@ class Woocommerce { } function output_body_class( $classes ) { - if (sizeof($this->_body_classes)>0) $classes = array_merge($classes, $this->_body_classes); + if ( sizeof( $this->_body_classes ) > 0 ) $classes = array_merge( $classes, $this->_body_classes ); - if( is_singular('product') ) : - $key = array_search('singular', $classes); - if ( $key !== false ) unset($classes[$key]); - endif; + if ( is_singular('product') ) { + $key = array_search( 'singular', $classes ); + if ( $key !== false ) unset( $classes[$key] ); + } return $classes; } @@ -1383,7 +1383,7 @@ class Woocommerce { } function output_inline_js() { - if ($this->_inline_js) : + if ($this->_inline_js) { echo "\n