diff --git a/includes/abstracts/abstract-wc-product.php b/includes/abstracts/abstract-wc-product.php index c1097b4a61a..a1c3d6fe193 100644 --- a/includes/abstracts/abstract-wc-product.php +++ b/includes/abstracts/abstract-wc-product.php @@ -874,7 +874,7 @@ class WC_Product { $tax_rates = WC_Tax::get_rates( $this->get_tax_class() ); $base_tax_rates = WC_Tax::get_base_tax_rates( $this->tax_class ); - if ( ! empty( WC()->customer ) && WC()->customer->is_vat_exempt() ) { + if ( ! empty( WC()->customer ) && WC()->customer->get_is_vat_exempt() ) { $base_taxes = WC_Tax::calc_tax( $price * $qty, $base_tax_rates, true ); $base_tax_amount = array_sum( $base_taxes ); diff --git a/includes/abstracts/abstract-wc-shipping-method.php b/includes/abstracts/abstract-wc-shipping-method.php index 783bb56ce10..3f1e0bff8a0 100644 --- a/includes/abstracts/abstract-wc-shipping-method.php +++ b/includes/abstracts/abstract-wc-shipping-method.php @@ -144,7 +144,7 @@ abstract class WC_Shipping_Method extends WC_Settings_API { * @return boolean */ public function is_taxable() { - return wc_tax_enabled() && 'taxable' === $this->tax_status && ! WC()->customer->is_vat_exempt(); + return wc_tax_enabled() && 'taxable' === $this->tax_status && ! WC()->customer->get_is_vat_exempt(); } /** diff --git a/includes/class-wc-ajax.php b/includes/class-wc-ajax.php index 53ab91b99f6..a5f14821b99 100644 --- a/includes/class-wc-ajax.php +++ b/includes/class-wc-ajax.php @@ -336,7 +336,7 @@ class WC_AJAX { if ( isset( $_POST['country'] ) ) { WC()->customer->set_shipping_country( $_POST['country'] ); - WC()->customer->calculated_shipping( true ); + WC()->customer->set_calculated_shipping( true ); } if ( isset( $_POST['state'] ) ) { @@ -362,7 +362,7 @@ class WC_AJAX { if ( isset( $_POST['s_country'] ) ) { WC()->customer->set_shipping_country( $_POST['s_country'] ); - WC()->customer->calculated_shipping( true ); + WC()->customer->set_calculated_shipping( true ); } if ( isset( $_POST['s_state'] ) ) { @@ -386,6 +386,7 @@ class WC_AJAX { } } + WC()->customer->save(); WC()->cart->calculate_totals(); // Get order review fragment diff --git a/includes/class-wc-cache-helper.php b/includes/class-wc-cache-helper.php index d67f9b24e9e..7ed7c15de73 100644 --- a/includes/class-wc-cache-helper.php +++ b/includes/class-wc-cache-helper.php @@ -56,11 +56,12 @@ class WC_Cache_Helper { */ public static function geolocation_ajax_get_location_hash() { $customer = new WC_Customer(); + $customer->load_session(); $location = array(); - $location['country'] = $customer->get_country(); - $location['state'] = $customer->get_state(); - $location['postcode'] = $customer->get_postcode(); - $location['city'] = $customer->get_city(); + $location['country'] = $customer->get_billing_country(); + $location['state'] = $customer->get_billing_state(); + $location['postcode'] = $customer->get_billing_postcode(); + $location['city'] = $customer->get_billing_city(); return substr( md5( implode( '', $location ) ), 0, 12 ); } diff --git a/includes/class-wc-cart.php b/includes/class-wc-cart.php index c2c586d4072..7c8062871f2 100644 --- a/includes/class-wc-cart.php +++ b/includes/class-wc-cart.php @@ -1353,7 +1353,7 @@ class WC_Cart { } // VAT exemption done at this point - so all totals are correct before exemption - if ( WC()->customer->is_vat_exempt() ) { + if ( WC()->customer->get_is_vat_exempt() ) { $this->remove_taxes(); } @@ -1369,7 +1369,7 @@ class WC_Cart { $this->tax_total = WC_Tax::get_tax_total( $this->taxes ); // VAT exemption done at this point - so all totals are correct before exemption - if ( WC()->customer->is_vat_exempt() ) { + if ( WC()->customer->get_is_vat_exempt() ) { $this->remove_taxes(); } } @@ -1516,7 +1516,7 @@ class WC_Cart { return false; if ( 'yes' === get_option( 'woocommerce_shipping_cost_requires_address' ) ) { - if ( ! WC()->customer->has_calculated_shipping() ) { + if ( ! WC()->customer->get_calculated_shipping() ) { if ( ! WC()->customer->get_shipping_country() || ( ! WC()->customer->get_shipping_state() && ! WC()->customer->get_shipping_postcode() ) ) { return false; } diff --git a/includes/class-wc-checkout.php b/includes/class-wc-checkout.php index 3610ca2e118..39b4170cfb8 100644 --- a/includes/class-wc-checkout.php +++ b/includes/class-wc-checkout.php @@ -316,18 +316,26 @@ class WC_Checkout { $order->set_total( WC()->cart->shipping_tax_total, 'shipping_tax' ); $order->set_total( WC()->cart->total ); + $customer = new WC_Customer( $this->customer_id ); + // Update user meta if ( $this->customer_id ) { if ( apply_filters( 'woocommerce_checkout_update_customer_data', true, $this ) ) { foreach ( $billing_address as $key => $value ) { - update_user_meta( $this->customer_id, 'billing_' . $key, $value ); + if ( is_callable( array( $customer, "set_billing_{$key}" ) ) ) { + $customer->{"set_billing_{$key}"}( $value ); + } } if ( WC()->cart->needs_shipping() ) { foreach ( $shipping_address as $key => $value ) { - update_user_meta( $this->customer_id, 'shipping_' . $key, $value ); + if ( is_callable( array( $customer, "set_shipping_{$key}" ) ) ) { + $customer->{"set_shipping_{$key}"}( $value ); + } } } } + + $customer->save(); do_action( 'woocommerce_checkout_update_user_meta', $this->customer_id, $this->posted ); } @@ -554,6 +562,8 @@ class WC_Checkout { } + WC()->customer->save(); + // Update cart totals now we have customer address WC()->cart->calculate_totals(); @@ -796,15 +806,15 @@ class WC_Checkout { switch ( $input ) { case 'billing_country' : - return apply_filters( 'default_checkout_country', WC()->customer->get_country() ? WC()->customer->get_country() : WC()->countries->get_base_country(), 'billing' ); + return apply_filters( 'default_checkout_country', WC()->customer->get_billing_country() ? WC()->customer->get_billing_country() : WC()->countries->get_base_country(), 'billing' ); case 'billing_state' : - return apply_filters( 'default_checkout_state', WC()->customer->has_calculated_shipping() ? WC()->customer->get_state() : '', 'billing' ); + return apply_filters( 'default_checkout_state', WC()->customer->get_calculated_shipping() ? WC()->customer->get_billing_state() : '', 'billing' ); case 'billing_postcode' : - return apply_filters( 'default_checkout_postcode', WC()->customer->get_postcode() ? WC()->customer->get_postcode() : '', 'billing' ); + return apply_filters( 'default_checkout_postcode', WC()->customer->get_billing_postcode() ? WC()->customer->get_billing_postcode() : '', 'billing' ); case 'shipping_country' : return apply_filters( 'default_checkout_country', WC()->customer->get_shipping_country() ? WC()->customer->get_shipping_country() : WC()->countries->get_base_country(), 'shipping' ); case 'shipping_state' : - return apply_filters( 'default_checkout_state', WC()->customer->has_calculated_shipping() ? WC()->customer->get_shipping_state() : '', 'shipping' ); + return apply_filters( 'default_checkout_state', WC()->customer->get_calculated_shipping() ? WC()->customer->get_shipping_state() : '', 'shipping' ); case 'shipping_postcode' : return apply_filters( 'default_checkout_postcode', WC()->customer->get_shipping_postcode() ? WC()->customer->get_shipping_postcode() : '', 'shipping' ); default : diff --git a/includes/class-wc-customer.php b/includes/class-wc-customer.php index 0bc6a871806..40c3b0a1eaf 100644 --- a/includes/class-wc-customer.php +++ b/includes/class-wc-customer.php @@ -1,352 +1,434 @@ 0, + 'email' => '', + 'first_name' => '', + 'last_name' => '', + 'role' => 'customer', + 'last_order_id' => null, // read only + 'last_order_date' => null, // read only + 'orders_count' => 0, // read only + 'total_spent' => 0, // read only + 'username' => '', // read only on existing users + 'password' => '', // write only + 'date_created' => '', // read only + 'date_modified' => '', // read only + 'billing_postcode' => '', + 'billing_city' => '', + 'billing_address_1' => '', + 'billing_address_2' => '', + 'billing_state' => '', + 'billing_country' => '', + 'shipping_postcode' => '', + 'shipping_city' => '', + 'shipping_address_1' => '', + 'shipping_address_2' => '', + 'shipping_state' => '', + 'shipping_country' => '', + 'is_paying_customer' => false, + 'is_vat_exempt' => false, // session only. + 'calculated_shipping' => false, // session only + ); /** - * Stores bool when data is changed. - * - * @var bool + * Keys which are also stored in a session (so we can make sure they get updated...) + * @var array */ - private $_changed = false; + protected $_session_keys = array( + 'billing_postcode', 'billing_city', 'billing_address_1', 'billing_address', 'billing_address_2', + 'billing_state', 'billing_country', 'shipping_postcode', 'shipping_city', 'shipping_address_1', 'shipping_address', + 'shipping_address_2', 'shipping_state', 'shipping_country', 'is_vat_exempt', 'calculated_shipping', + ); /** - * Constructor for the customer class loads the customer data. - * + * Data stored in meta keys, but not considered "meta" for a coupon. + * @since 2.7.0 + * @var array */ - public function __construct() { - $this->_data = (array) WC()->session->get( 'customer' ); + protected $_internal_meta_keys = array( + 'billing_postcode', 'billing_city', 'billing_address_1', 'billing_address_2', 'billing_state', + 'billing_country', 'shipping_postcode', 'shipping_city', 'shipping_address_1', + 'shipping_address_2', 'shipping_state', 'shipping_country', 'paying_customer', + 'last_update', 'first_name', 'last_name' + ); - // No data - set defaults - if ( empty( $this->_data ) ) { - $this->set_default_data(); + /** + * Internal meta type used to store user data. + * @var string + */ + protected $_meta_type = 'user'; + + /** + * Was data changed in the database for this class? + * @var boolean + */ + protected $_changed = false; + + /** + * If some of the customer information is loaded by session (instead of just from the DB). + * @var boolean + */ + protected $_from_session = false; + + /** + * WC_Customer can also return an object for a logged out user (session). + * $_is_user will be false in this case. It will be true for all other cases + * (logged in users or getting a WC_Customer for another object) + * @var boolean + */ + protected $_is_user = false; + + /** + * Load customer data based on how WC_Customer is called. + * @param mixed $customer WC_Customer object or customer ID is accepted. + * if $customer is 'new', you can build a new WC_Customer object. If it's empty, some + * data will be pulled from the session for the current user/customer. + */ + public function __construct( $customer = '' ) { + if ( $customer instanceof WC_Customer ) { + $this->_is_user = true; + $this->read( absint( $customer->get_id() ) ); + } else if ( is_numeric( $customer ) ) { + $this->_is_user = true; + $this->read( $customer ); + } else if ( empty( $customer ) ) { + $this->_is_user = true; // unless load_session gets called after. } - // When leaving or ending page load, store data - add_action( 'shutdown', array( $this, 'save_data' ), 10 ); + if ( $this->_from_session ) { + add_action( 'shutdown', array( $this, 'save_session_if_changed' ), 10 ); + } } /** - * Save data function. + * Saves customer information to the current session if any data changed. + * @since 2.7.0 */ - public function save_data() { + public function save_session_if_changed() { if ( $this->_changed ) { - WC()->session->set( 'customer', $this->_data ); + $this->save_to_session(); } } /** - * __set function. - * - * @param mixed $property - * @return bool + * Loads a WC session into the customer class. */ - public function __isset( $property ) { - if ( 'address' === $property ) { - $property = 'address_1'; + public function load_session() { + $this->_from_session = true; + if ( is_user_logged_in() ) { + $this->_is_user = true; + $this->read( get_current_user_id() ); + } else { + $this->_is_user = false; + $this->read( WC()->session->get_customer_id() ); } - if ( 'shipping_address' === $property ) { - $property = 'shipping_address_1'; - } - return isset( $this->_data[ $property ] ); + } + + /* + |-------------------------------------------------------------------------- + | Getters + |-------------------------------------------------------------------------- + | Methods for getting data from the customer object. + */ + + /** + * Return a customer's user ID. If the current customer is logged out, this will be a session key. + * @since 2.7.0 + * @return mixed + */ + public function get_id() { + return $this->_data['id']; } /** - * __get function. - * - * @param string $property + * Return the customer's username. + * @since 2.7.0 * @return string */ - public function __get( $property ) { - if ( 'address' === $property ) { - $property = 'address_1'; - } - if ( 'shipping_address' === $property ) { - $property = 'shipping_address_1'; - } - return isset( $this->_data[ $property ] ) ? $this->_data[ $property ] : ''; + public function get_username() { + return $this->_data['username']; } /** - * __set function. - * - * @param mixed $property - * @param mixed $value - */ - public function __set( $property, $value ) { - if ( 'address' === $property ) { - $property = 'address_1'; - } - if ( 'shipping_address' === $property ) { - $property = 'shipping_address_1'; - } - $this->_data[ $property ] = $value; - $this->_changed = true; - } - - /** - * Get default country for a customer. - * + * Return the customer's email. + * @since 2.7.0 * @return string */ - public function get_default_country() { - $default = wc_get_customer_default_location(); - return $default['country']; + public function get_email() { + return sanitize_email( $this->_data['email'] ); } /** - * Get default state for a customer. - * + * Return customer's first name. + * @since 2.7.0 * @return string */ - public function get_default_state() { - $default = wc_get_customer_default_location(); - return $default['state']; + public function get_first_name() { + return $this->_data['first_name']; } /** - * Has calculated shipping? - * - * @return bool + * Return customer's last name. + * @since 2.7.0 + * @return string */ - public function has_calculated_shipping() { - return ! empty( $this->calculated_shipping ); + public function get_last_name() { + return $this->_data['last_name']; } /** - * Set customer address to match shop base address. + * Return customer's user role. + * @since 2.7.0 + * @return string */ - public function set_to_base() { - $this->country = $this->get_default_country(); - $this->state = $this->get_default_state(); - $this->postcode = ''; - $this->city = ''; + public function get_role() { + return $this->_data['role']; } /** - * Set customer shipping address to base address. + * Return customer's last order ID. + * @since 2.7.0 + * @return integer|null */ - public function set_shipping_to_base() { - $this->shipping_country = $this->get_default_country(); - $this->shipping_state = $this->get_default_state(); - $this->shipping_postcode = ''; - $this->shipping_city = ''; + public function get_last_order_id() { + return ( is_null( $this->_data['last_order_id'] ) ? null : intval( $this->_data['last_order_id'] ) ); } /** - * Is customer outside base country (for tax purposes)? - * - * @return bool + * Return the date of the customer's last order. + * @since 2.7.0 + * @return integer|null */ - public function is_customer_outside_base() { - list( $country, $state ) = $this->get_taxable_address(); + public function get_last_order_date() { + return ( is_null( $this->_data['last_order_date'] ) ? null : intval( $this->_data['last_order_date'] ) ); + } - if ( $country ) { + /** + * Return the number of orders this customer has. + * @since 2.7.0 + * @return integer + */ + public function get_orders_count() { + return intval( $this->_data['orders_count'] ); + } - $default = wc_get_base_location(); + /** + * Return how much money this customer has spent. + * @since 2.7.0 + * @return float + */ + public function get_total_spent() { + return wc_format_decimal( $this->_data['total_spent'] ); + } - if ( $default['country'] !== $country ) { - return true; - } + /** + * Return this customer's avatar. + * @since 2.7.0 + * @return string + */ + public function get_avatar_url() { + $avatar_html = get_avatar( $this->get_email() ); - if ( $default['state'] && $default['state'] !== $state ) { - return true; - } + // Get the URL of the avatar from the provided HTML + preg_match( '/src=["|\'](.+)[\&|"|\']/U', $avatar_html, $matches ); + if ( isset( $matches[1] ) && ! empty( $matches[1] ) ) { + return esc_url( $matches[1] ); } - return false; + return ''; } /** - * Is the user a paying customer? - * - * @return bool + * Return the date this customer was created. + * @since 2.7.0 + * @return integer */ - function is_paying_customer( $user_id ) { - return '1' === get_user_meta( $user_id, 'paying_customer', true ); + public function get_date_created() { + return absint( $this->_data['date_created'] ); } /** - * Is customer VAT exempt? - * - * @return bool + * Return the date this customer was last updated. + * @since 2.7.0 + * @return integer */ - public function is_vat_exempt() { - return ( ! empty( $this->is_vat_exempt ) ) ? true : false; + public function get_date_modified() { + return absint( $this->_data['date_modified'] ); } /** - * Gets the state from the current session. - * + * Gets customer postcode. * @return string */ - public function get_state() { - return $this->state; + public function get_billing_postcode() { + return wc_format_postcode( $this->_data['billing_postcode'], $this->get_billing_country() ); } /** - * Gets the country from the current session. - * + * Get customer city. * @return string */ - public function get_country() { - return $this->country; + public function get_billing_city() { + return $this->_data['billing_city']; } /** - * Gets the postcode from the current session. - * + * Get customer address. * @return string */ - public function get_postcode() { - return empty( $this->postcode ) ? '' : wc_format_postcode( $this->postcode, $this->get_country() ); + public function get_billing_address() { + return $this->_data['billing_address_1']; } /** - * Get the city from the current session. - * + * Get customer address. * @return string */ - public function get_city() { - return $this->city; + public function get_billing_address_1() { + return $this->get_billing_address(); } /** - * Gets the address from the current session. - * + * Get customer's second address. * @return string */ - public function get_address() { - return $this->address_1; + public function get_billing_address_2() { + return $this->_data['billing_address_2']; } /** - * Gets the address_2 from the current session. - * + * Get customer state. * @return string */ - public function get_address_2() { - return $this->address_2; + public function get_billing_state() { + return $this->_data['billing_state']; } /** - * Gets the state from the current session. - * + * Get customer country. + * @return string + */ + public function get_billing_country() { + return $this->_data['billing_country']; + } + + /** + * Get customer's shipping state. * @return string */ public function get_shipping_state() { - return $this->shipping_state; + return $this->_data['shipping_state']; } /** - * Gets the country from the current session. - * + * Get customer's shipping country. * @return string */ public function get_shipping_country() { - return $this->shipping_country; + return $this->_data['shipping_country']; } /** - * Gets the postcode from the current session. - * + * Get customer's shipping postcode. * @return string */ public function get_shipping_postcode() { - return empty( $this->shipping_postcode ) ? '' : wc_format_postcode( $this->shipping_postcode, $this->get_shipping_country() ); + return wc_format_postcode( $this->_data['shipping_postcode'], $this->get_shipping_country() ); } /** - * Gets the city from the current session. - * + * Get customer's shipping city. * @return string */ public function get_shipping_city() { - return $this->shipping_city; + return $this->_data['shipping_city']; } /** - * Gets the address from the current session. - * + * Get customer's shipping address. * @return string */ public function get_shipping_address() { - return $this->shipping_address_1; + return $this->_data['shipping_address_1']; } /** - * Gets the address_2 from the current session. - * + * Get customer address. + * @return string + */ + public function get_shipping_address_1() { + return $this->get_shipping_address(); + } + + /** + * Get customer's second shipping address. * @return string */ public function get_shipping_address_2() { - return $this->shipping_address_2; + return $this->_data['shipping_address_2']; + } + + /** + * Get if customer is VAT exempt? + * @since 2.7.0 + * @return bool + */ + public function get_is_vat_exempt() { + return ( ! empty( $this->_data['is_vat_exempt'] ) ) ? true : false; + } + + /** + * Has customer calculated shipping? + * @return bool + */ + public function get_calculated_shipping() { + return ! empty( $this->_data['calculated_shipping'] ); } /** * Get taxable address. - * * @return array */ public function get_taxable_address() { $tax_based_on = get_option( 'woocommerce_tax_based_on' ); // Check shipping method at this point to see if we need special handling - if ( true == apply_filters( 'woocommerce_apply_base_tax_for_local_pickup', true ) && WC()->cart->needs_shipping() && sizeof( array_intersect( WC()->session->get( 'chosen_shipping_methods', array() ), apply_filters( 'woocommerce_local_pickup_methods', array( 'legacy_local_pickup', 'local_pickup' ) ) ) ) > 0 ) { + if ( true === (bool) apply_filters( 'woocommerce_apply_base_tax_for_local_pickup', true ) && WC()->cart->needs_shipping() && sizeof( array_intersect( WC()->session->get( 'chosen_shipping_methods', array() ), apply_filters( 'woocommerce_local_pickup_methods', array( 'legacy_local_pickup', 'local_pickup' ) ) ) ) > 0 ) { $tax_based_on = 'base'; } if ( 'base' === $tax_based_on ) { - $country = WC()->countries->get_base_country(); $state = WC()->countries->get_base_state(); $postcode = WC()->countries->get_base_postcode(); $city = WC()->countries->get_base_city(); - } elseif ( 'billing' === $tax_based_on ) { - $country = $this->get_country(); - $state = $this->get_state(); - $postcode = $this->get_postcode(); - $city = $this->get_city(); - + $country = $this->get_billing_country(); + $state = $this->get_billing_state(); + $postcode = $this->get_billing_postcode(); + $city = $this->get_billing_city(); } else { $country = $this->get_shipping_country(); $state = $this->get_shipping_state(); @@ -358,218 +440,610 @@ class WC_Customer { } /** - * Set default data for a customer. - */ - public function set_default_data( $get_user_profile_data = true ) { - $this->_data = array( - 'postcode' => '', - 'city' => '', - 'address_1' => '', - 'address_2' => '', - 'state' => '', - 'country' => '', - 'shipping_postcode' => '', - 'shipping_city' => '', - 'shipping_address_1' => '', - 'shipping_address_2' => '', - 'shipping_state' => '', - 'shipping_country' => '', - 'is_vat_exempt' => false, - 'calculated_shipping' => false - ); - - if ( is_user_logged_in() && $get_user_profile_data ) { - foreach ( $this->_data as $key => $value ) { - $meta_value = get_user_meta( get_current_user_id(), ( false === strstr( $key, 'shipping_' ) ? 'billing_' : '' ) . $key, true ); - $this->_data[ $key ] = $meta_value ? $meta_value : $this->_data[ $key ]; - } - } - - if ( empty( $this->_data['country'] ) ) { - $this->_data['country'] = $this->get_default_country(); - } - - if ( empty( $this->_data['shipping_country'] ) ) { - $this->_data['shipping_country'] = $this->_data['country']; - } - - if ( empty( $this->_data['state'] ) ) { - $this->_data['state'] = $this->get_default_state(); - } - - if ( empty( $this->_data['shipping_state'] ) ) { - $this->_data['shipping_state'] = $this->_data['state']; - } - } - - /** - * Sets session data for the location. - * - * @param string $country - * @param string $state - * @param string $postcode (default: '') - * @param string $city (default: '') - */ - public function set_location( $country, $state, $postcode = '', $city = '' ) { - $this->country = $country; - $this->state = $state; - $this->postcode = $postcode; - $this->city = $city; - } - - /** - * Sets session data for the country. - * - * @param mixed $country - */ - public function set_country( $country ) { - $this->country = $country; - } - - /** - * Sets session data for the state. - * - * @param mixed $state - */ - public function set_state( $state ) { - $this->state = $state; - } - - /** - * Sets session data for the postcode. - * - * @param mixed $postcode - */ - public function set_postcode( $postcode ) { - $this->postcode = $postcode; - } - - /** - * Sets session data for the city. - * - * @param mixed $city - */ - public function set_city( $city ) { - $this->city = $city; - } - - /** - * Sets session data for the address. - * - * @param mixed $address - */ - public function set_address( $address ) { - $this->address_1 = $address; - } - - /** - * Sets session data for the $address. - * - * @param mixed $address - */ - public function set_address_2( $address ) { - $this->address_2 = $address; - } - - /** - * Sets session data for the location. - * - * @param string $country - * @param string $state (default: '') - * @param string $postcode (default: '') - * @param string $city (default: '') - */ - public function set_shipping_location( $country, $state = '', $postcode = '', $city = '' ) { - $this->shipping_country = $country; - $this->shipping_state = $state; - $this->shipping_postcode = $postcode; - $this->shipping_city = $city; - } - - /** - * Sets session data for the country. - * - * @param string $country - */ - public function set_shipping_country( $country ) { - $this->shipping_country = $country; - } - - /** - * Sets session data for the state. - * - * @param string $state - */ - public function set_shipping_state( $state ) { - $this->shipping_state = $state; - } - - /** - * Sets session data for the postcode. - * - * @param string $postcode - */ - public function set_shipping_postcode( $postcode ) { - $this->shipping_postcode = $postcode; - } - - /** - * Sets session data for the city. - * - * @param string $city - */ - public function set_shipping_city( $city ) { - $this->shipping_city = $city; - } - - /** - * Sets session data for the address. - * - * @param string $address - */ - public function set_shipping_address( $address ) { - $this->shipping_address_1 = $address; - } - - /** - * Sets session data for the address_2. - * - * @param string $address - */ - public function set_shipping_address_2( $address ) { - $this->shipping_address_2 = $address; - } - - /** - * Sets session data for the tax exemption. - * - * @param bool $is_vat_exempt - */ - public function set_is_vat_exempt( $is_vat_exempt ) { - $this->is_vat_exempt = $is_vat_exempt; - } - - /** - * Calculated shipping. - * - * @param boolean $calculated - */ - public function calculated_shipping( $calculated = true ) { - $this->calculated_shipping = $calculated; - } - - /** - * Gets a user's downloadable products if they are logged in. - * + * Gets a customer's downloadable products. * @return array Array of downloadable products */ public function get_downloadable_products() { $downloads = array(); - - if ( is_user_logged_in() ) { - $downloads = wc_get_customer_available_downloads( get_current_user_id() ); + if ( $this->_is_user ) { + $downloads = wc_get_customer_available_downloads( $this->get_id() ); } - return apply_filters( 'woocommerce_customer_get_downloadable_products', $downloads ); } + + /** + * Is the user a paying customer? + * @since 2.7.0 + * @return bool + */ + function get_is_paying_customer() { + return (bool) $this->_data['is_paying_customer']; + } + + /* + |-------------------------------------------------------------------------- + | Setters + |-------------------------------------------------------------------------- + | Functions for setting customer data. These should not update anything in the + | database itself and should only change what is stored in the class + | object. + */ + + /** + * Set customer's username. + * @since 2.7.0 + * @param string $username + */ + public function set_username( $username ) { + $this->_data['username'] = $username; + } + + /** + * Set customer's email. + * @since 2.7.0 + * @param string $email + */ + public function set_email( $email ) { + $this->_data['email'] = sanitize_email( $email ); + } + + /** + * Set customer's first name. + * @since 2.7.0 + * @param string $first_name + */ + public function set_first_name( $first_name ) { + $this->_data['first_name'] = $first_name; + } + + /** + * Set customer's last name. + * @since 2.7.0 + * @param string $last_name + */ + public function set_last_name( $last_name ) { + $this->_data['last_name'] = $last_name; + } + + /** + * Set customer's user role(s). + * @since 2.7.0 + * @param mixed $role + */ + public function set_role( $role ) { + $this->_data['role'] = $role; + } + + /** + * Set customer's last order ID. + * @since 2.7.0 + * @param integer|null $last_order_id + */ + public function set_last_order_id( $last_order_id ) { + $this->_data['last_order_id'] = $last_order_id; + } + + /** + * Set the date of the customer's last order. + * @since 2.7.0 + * @param string|null $last_order_date + */ + public function set_last_order_date( $last_order_date ) { + $this->_data['last_order_date'] = $last_order_date; + } + + /** + * Set the number of orders this customer has. + * @since 2.7.0 + * @param integer $order_count + */ + public function set_orders_count( $orders_count ) { + $this->_data['orders_count'] = $orders_count; + } + + /** + * Return how much money this customer has spent. + * @since 2.7.0 + * @param float $total_spent + */ + public function set_total_spent( $total_spent ) { + $this->_data['total_spent'] = $total_spent; + } + + /** + * Set customer's password. + * @since 2.7.0 + * @param string $password + */ + public function set_password( $password ) { + $this->_data['password'] = wc_clean( $password ); + } + + /** + * Set the date this customer was last updated. + * @since 2.7.0 + * @param integer $timestamp + */ + public function set_date_modified( $timestamp ) { + $this->_data['date_modified'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp ); + } + + /** + * Set the date this customer was last updated. + * @since 2.7.0 + * @param integer $timestamp + */ + public function set_date_created( $timestamp ) { + $this->_data['date_created'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp ); + } + + /** + * Set customer address to match shop base address. + * @since 2.7.0 + */ + public function set_billing_address_to_base() { + $base = wc_get_customer_default_location(); + $this->_data['billing_country'] = $base['country']; + $this->_data['billing_state'] = $base['state']; + $this->_data['billing_postcode'] = ''; + $this->_data['billing_city'] = ''; + } + + /** + * Set customer shipping address to base address. + * @since 2.7.0 + */ + public function set_shipping_address_to_base() { + $base = wc_get_customer_default_location(); + $this->_data['shipping_country'] = $base['country']; + $this->_data['shipping_state'] = $base['state']; + $this->_data['shipping_postcode'] = ''; + $this->_data['shipping_city'] = ''; + } + + /** + * Sets all shipping info at once. + * @param string $country + * @param string $state + * @param string $postcode + * @param string $city + */ + public function set_shipping_location( $country, $state = '', $postcode = '', $city = '' ) { + $this->_data['shipping_country'] = $country; + $this->_data['shipping_state'] = $state; + $this->_data['shipping_postcode'] = $postcode; + $this->_data['shipping_city'] = $city; + } + + /** + * Sets all address info at once. + * @param string $country + * @param string $state + * @param string $postcode + * @param string $city + */ + public function set_billing_location( $country, $state, $postcode = '', $city = '' ) { + $this->_data['billing_country'] = $country; + $this->_data['billing_state'] = $state; + $this->_data['billing_postcode'] = $postcode; + $this->_data['billing_city'] = $city; + } + + /** + * Set customer country. + * @param mixed $country + */ + public function set_billing_country( $country ) { + $this->_data['billing_country'] = $country; + } + + /** + * Set customer state. + * @param mixed $state + */ + public function set_billing_state( $state ) { + $this->_data['billing_state'] = $state; + } + + /** + * Sets customer postcode. + * @param mixed $postcode + */ + public function set_billing_postcode( $postcode ) { + $this->_data['billing_postcode'] = $postcode; + } + + /** + * Sets customer city. + * @param mixed $city + */ + public function set_billing_city( $city ) { + $this->_data['billing_city'] = $city; + } + + /** + * Set customer address. + * @param mixed $address + */ + public function set_billing_address( $address ) { + $this->_data['billing_address_1'] = $address; + } + + /** + * Set customer address. + * @param mixed $address + */ + public function set_billing_address_1( $address ) { + $this->set_billing_address( $address ); + } + + /** + * Set customer's second address. + * @param mixed $address + */ + public function set_billing_address_2( $address ) { + $this->_data['billing_address_2'] = $address; + } + + /** + * Set shipping country. + * @param string $country + */ + public function set_shipping_country( $country ) { + $this->_data['shipping_country'] = $country; + } + + /** + * Set shipping state. + * @param string $state + */ + public function set_shipping_state( $state ) { + $this->_data['shipping_state'] = $state; + } + + /** + * Set shipping postcode. + * @param string $postcode + */ + public function set_shipping_postcode( $postcode ) { + $this->_data['shipping_postcode'] = $postcode; + } + + /** + * Sets shipping city. + * @param string $city + */ + public function set_shipping_city( $city ) { + $this->_data['shipping_city'] = $city; + } + + /** + * Set shipping address. + * @param string $address + */ + public function set_shipping_address( $address ) { + $this->_data['shipping_address_1'] = $address; + } + + /** + * Set customer shipping address. + * @param mixed $address + */ + public function set_shipping_address_1( $address ) { + $this->set_shipping_address( $address ); + } + + /** + * Set second shipping address. + * @param string $address + */ + public function set_shipping_address_2( $address ) { + $this->_data['shipping_address_2'] = $address; + } + + /** + * Set if customer has tax exemption. + * @param bool $is_vat_exempt + */ + public function set_is_vat_exempt( $is_vat_exempt ) { + $this->_data['is_vat_exempt'] = $is_vat_exempt; + } + + /** + * Calculated shipping? + * @param boolean $calculated + */ + public function set_calculated_shipping( $calculated = true ) { + $this->_data['calculated_shipping'] = $calculated; + } + + /** + * Set if the user a paying customer. + * @since 2.7.0 + * @param boolean $is_paying_customer + */ + function set_is_paying_customer( $is_paying_customer ) { + $this->_data['is_paying_customer'] = (bool) $is_paying_customer; + } + + /* + |-------------------------------------------------------------------------- + | Other methods + |-------------------------------------------------------------------------- + | Other functions for interacting with customers. + */ + + /** + * Is customer outside base country (for tax purposes)? + * @return bool + */ + public function is_customer_outside_base() { + list( $country, $state ) = $this->get_taxable_address(); + if ( $country ) { + $default = wc_get_base_location(); + if ( $default['country'] !== $country ) { + return true; + } + if ( $default['state'] && $default['state'] !== $state ) { + return true; + } + } + return false; + } + + /* + |-------------------------------------------------------------------------- + | CRUD methods + |-------------------------------------------------------------------------- + | Methods which create, read, update and delete from the database. + | + | A save method is included for convenience (chooses update or create based + | on if the order exists yet). + */ + + /** + * Create a customer. + * @since 2.7.0. + */ + public function create() { + $customer_id = wc_create_new_customer( $this->get_email(), $this->get_username(), $this->_data['password'] ); + unset( $this->_data['password'] ); + if ( $customer_id ) { + $this->_data['id'] = $customer_id; + update_user_meta( $this->get_id(), 'billing_postcode', $this->get_billing_postcode() ); + update_user_meta( $this->get_id(), 'billing_city', $this->get_billing_city() ); + update_user_meta( $this->get_id(), 'billing_address_1', $this->get_billing_address() ); + update_user_meta( $this->get_id(), 'billing_address_2', $this->get_billing_address_2() ); + update_user_meta( $this->get_id(), 'billing_state', $this->get_billing_state() ); + update_user_meta( $this->get_id(), 'billing_country', $this->get_billing_country() ); + update_user_meta( $this->get_id(), 'shipping_postcode', $this->get_shipping_postcode() ); + update_user_meta( $this->get_id(), 'shipping_city', $this->get_shipping_city() ); + update_user_meta( $this->get_id(), 'shipping_address_1', $this->get_shipping_address() ); + update_user_meta( $this->get_id(), 'shipping_address_2', $this->get_shipping_address_2() ); + update_user_meta( $this->get_id(), 'shipping_state', $this->get_shipping_state() ); + update_user_meta( $this->get_id(), 'shipping_country', $this->get_shipping_country() ); + update_user_meta( $this->get_id(), 'paying_customer', $this->get_is_paying_customer() ); + $this->set_date_modified( time() ); + update_user_meta( $this->get_id(), 'last_update', $this->get_date_modified() ); + update_user_meta( $this->get_id(), 'first_name', $this->get_first_name() ); + update_user_meta( $this->get_id(), 'last_name', $this->get_last_name() ); + wp_update_user( array( 'ID' => $this->get_id(), 'role' => $this->get_role() ) ); + $wp_user = new WP_User( $this->get_id() ); + $this->set_date_created( strtotime( $wp_user->user_registered ) ); + $this->save_meta_data(); + } + } + + /** + * Read a customer from the database. + * @since 2.7.0 + * @param integer $id + */ + public function read( $id ) { + global $wpdb; + $pull_from_db = true; + $data = array(); + if ( $this->_from_session ) { + $data = (array) WC()->session->get( 'customer' ); + if ( ! empty( $data ) ) { + $pull_from_db = false; + foreach ( $this->_session_keys as $session_key ) { + $function_key = $session_key; + if ( 'billing_' === substr( $session_key, 0, 8 ) ) { + $session_key = str_replace( 'billing_', '', $session_key ); + } + if ( ! empty( $data[ $session_key ] ) && is_callable( array( $this, "set_{$function_key}" ) ) ) { + $this->{"set_{$function_key}"}( $data[ $session_key ] ); + } + } + } + } + + if ( $this->_is_user ) { + + // Only continue reading if the customer exists. + $user_object = get_userdata( $id ); + if ( empty( $user_object ) || empty ( $user_object->ID ) ) { + $this->_data['id'] = 0; + return; + } + + foreach ( array_keys( $this->_data ) as $key ) { + if ( 'billing_' === substr( $key, 0, 8 ) ) { + $session_key = str_replace( 'billing_', '', $key ); + } + if ( ! $pull_from_db && ! empty( $data[ $session_key ] ) ) { + continue; + } + + $meta_value = get_user_meta( $id, $key, true ); + if ( $meta_value && is_callable( array( $this, "set_{$key}" ) ) ) { + $this->{"set_{$key}"}( $meta_value ); + } + } + } + + if ( $this->_is_user ) { + $this->set_is_paying_customer( get_user_meta( $id, 'paying_customer', true ) ); + $wp_user = new WP_User( $id ); + $this->set_email( $wp_user->user_email ); + $this->set_username( $wp_user->user_login ); + $this->set_date_created( strtotime( $wp_user->user_registered ) ); + $this->set_date_modified( get_user_meta( $id, 'last_update', true ) ); + $this->set_role( ( ! empty ( $wp_user->roles[0] ) ? $wp_user->roles[0] : 'customer' ) ); + + // Get info about user's last order + $last_order = $wpdb->get_row( "SELECT id, post_date_gmt + FROM $wpdb->posts AS posts + LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id + WHERE meta.meta_key = '_customer_user' + AND meta.meta_value = {$id} + AND posts.post_type = 'shop_order' + AND posts.post_status IN ( '" . implode( "','", array_keys( wc_get_order_statuses() ) ) . "' ) + ORDER BY posts.ID DESC + " ); + + $this->set_last_order_id( is_object( $last_order ) ? $last_order->id : null ); + $this->set_last_order_date( is_object( $last_order ) ? strtotime( $last_order->post_date_gmt ) : null ); + + // WC_Customer can't use wc_get_customer_order_count because get_order_types might not be loaded by the time a customer/session is + + $count = $wpdb->get_var( "SELECT COUNT(*) + FROM $wpdb->posts as posts + + LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id + + WHERE meta.meta_key = '_customer_user' + AND posts.post_type = 'shop_order' + AND posts.post_status IN ('" . implode( "','", array_keys( wc_get_order_statuses() ) ) . "') + AND meta_value = $id + " ); + + $spent = $wpdb->get_var( "SELECT SUM(meta2.meta_value) + FROM $wpdb->posts as posts + + LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id + LEFT JOIN {$wpdb->postmeta} AS meta2 ON posts.ID = meta2.post_id + + WHERE meta.meta_key = '_customer_user' + AND meta.meta_value = $id + AND posts.post_type = 'shop_order' + AND posts.post_status IN ( 'wc-completed', 'wc-processing' ) + AND meta2.meta_key = '_order_total' + " ); + if ( ! $spent ) { + $spent = 0; + } + + $this->set_orders_count( $count ); + $this->set_total_spent( $spent ); + + $this->read_meta_data(); + } + + $this->_data['id'] = $id; + + $default = wc_get_customer_default_location(); + + // Set some defaults if some of our values are still not set. + if ( empty( $this->get_billing_country() ) ) { + $this->set_billing_country( $default['country'] ); + } + + if ( empty( $this->get_shipping_country() ) ) { + $this->set_shipping_country( $this->get_billing_country() ); + } + + if ( empty( $this->get_billing_state() ) ) { + $this->set_billing_state( $default['state'] ); + } + + if ( empty( $this->get_shipping_state() ) ) { + $this->set_shipping_state( $this->get_billing_state() ); + } + + unset( $this->_data['password'] ); // password is write only, never ever read it + } + + /** + * Update a customer. + * @since 2.7.0 + */ + public function update() { + $customer_ID = $this->get_id(); + + wp_update_user( array( 'ID' => $customer_ID, 'user_email' => $this->get_email() ) ); + // Only update password if a new one was set with set_password + if ( isset( $this->_data['password'] ) ) { + wp_update_user( array( 'ID' => $customer_ID, 'user_pass' => $this->_data['password'] ) ); + unset( $this->_data['password'] ); + } + + update_user_meta( $this->get_id(), 'billing_postcode', $this->get_billing_postcode() ); + update_user_meta( $this->get_id(), 'billing_city', $this->get_billing_city() ); + update_user_meta( $this->get_id(), 'billing_address_1', $this->get_billing_address() ); + update_user_meta( $this->get_id(), 'billing_address_2', $this->get_billing_address_2() ); + update_user_meta( $this->get_id(), 'billing_state', $this->get_billing_state() ); + update_user_meta( $this->get_id(), 'billing_country', $this->get_billing_country() ); + update_user_meta( $this->get_id(), 'shipping_postcode', $this->get_shipping_postcode() ); + update_user_meta( $this->get_id(), 'shipping_city', $this->get_shipping_city() ); + update_user_meta( $this->get_id(), 'shipping_address_1', $this->get_shipping_address() ); + update_user_meta( $this->get_id(), 'shipping_address_2', $this->get_shipping_address_2() ); + update_user_meta( $this->get_id(), 'shipping_state', $this->get_shipping_state() ); + update_user_meta( $this->get_id(), 'shipping_country', $this->get_shipping_country() ); + update_user_meta( $this->get_id(), 'paying_customer', $this->get_is_paying_customer() ); + $this->set_date_modified( time() ); + update_user_meta( $this->get_id(), 'last_update', $this->get_date_modified() ); + update_user_meta( $this->get_id(), 'first_name', $this->get_first_name() ); + update_user_meta( $this->get_id(), 'last_name', $this->get_last_name() ); + wp_update_user( array( 'ID' => $this->get_id(), 'role' => $this->get_role() ) ); + $this->save_meta_data(); + } + + /** + * Delete a customer. + * @since 2.7.0 + */ + public function delete() { + if ( ! $this->get_id() ) { + return; + } + wp_delete_user( $this->get_id() ); + } + + /** + * Save data (either create or update depending on if we are working on an existing customer). + * @since 2.7.0 + */ + public function save() { + if ( ! $this->_is_user ) { + $this->create(); + } else { + if ( ! $this->get_id() ) { + $this->create(); + } else { + $this->update(); + } + } + } + + /** + * Saves data to the session only (does not overwrite DB values). + * @since 2.7.0 + */ + public function save_to_session() { + if ( ! $this->_from_session ) { + return; + } + $data = array(); + foreach ( $this->_session_keys as $session_key ) { + $function_key = $session_key; + if ( 'billing_' === substr( $session_key, 0, 8 ) ) { + $session_key = str_replace( 'billing_', '', $session_key ); + } + $data[ $session_key ] = $this->{"get_$function_key"}(); + } + WC()->session->set( 'customer', $data ); + } + } diff --git a/includes/class-wc-form-handler.php b/includes/class-wc-form-handler.php index a2d75c5a129..02afd645dc5 100644 --- a/includes/class-wc-form-handler.php +++ b/includes/class-wc-form-handler.php @@ -292,6 +292,8 @@ class WC_Form_Handler { WC()->customer->set_city( $order->billing_city ); } + WC()->customer->save(); + // Terms if ( ! empty( $_POST['terms-field'] ) && empty( $_POST['terms'] ) ) { wc_add_notice( __( 'You must accept our Terms & Conditions.', 'woocommerce' ), 'error' ); diff --git a/includes/class-wc-shipping-rate.php b/includes/class-wc-shipping-rate.php index ceacc3525d1..bc4f6330969 100644 --- a/includes/class-wc-shipping-rate.php +++ b/includes/class-wc-shipping-rate.php @@ -62,7 +62,7 @@ class WC_Shipping_Rate { * @return array */ public function get_shipping_tax() { - return apply_filters( 'woocommerce_get_shipping_tax', sizeof( $this->taxes ) > 0 && ! WC()->customer->is_vat_exempt() ? array_sum( $this->taxes ) : 0, $this ); + return apply_filters( 'woocommerce_get_shipping_tax', sizeof( $this->taxes ) > 0 && ! WC()->customer->get_is_vat_exempt() ? array_sum( $this->taxes ) : 0, $this ); } /** diff --git a/includes/legacy/class-wc-legacy-customer.php b/includes/legacy/class-wc-legacy-customer.php new file mode 100644 index 00000000000..1ed08eb6890 --- /dev/null +++ b/includes/legacy/class-wc-legacy-customer.php @@ -0,0 +1,224 @@ +filter_legacy_key( $key ); + return in_array( $key, $legacy_keys ); + } + + /** + * __get function. + * @todo use get_* methods + * @param string $key + * @return string + */ + public function __get( $key ) { + _doing_it_wrong( $key, 'Customer properties should not be accessed directly.', '2.7' ); + $key = $this->filter_legacy_key( $key ); + if ( in_array( $key, array( 'country', 'state', 'postcode' ,'city', 'address_1', 'address', 'address_2' ) ) ) { + $key = 'billing_' . $key; + } + return isset( $this->_data[ $key ] ) ? $this->_data[ $key ] : ''; + } + + /** + * __set function. + * @todo use set_* methods + * @param mixed $property + * @param mixed $key + */ + public function __set( $key, $value ) { + _doing_it_wrong( $key, 'Customer properties should not be set directly.', '2.7' ); + $key = $this->filter_legacy_key( $key ); + $this->_data[ $key ] = $value; + $this->_changed = true; + } + + /** + * Address and shipping_address are aliased, so we want to get the 'real' key name. + * For all other keys, we can just return it. + * @since 2.7.0 + * @param string $key + * @return string + */ + private function filter_legacy_key( $key ) { + if ( 'address' === $key ) { + $key = 'address_1'; + } + if ( 'shipping_address' === $key ) { + $key = 'shipping_address_1'; + } + + + return $key; + } + + /** + * Is customer VAT exempt? + * @return bool + */ + public function is_vat_exempt() { + _deprecated_function( 'WC_Customer::is_vat_exempt', '2.7', 'WC_Customer::get_is_vat_exempt' ); + return $this->get_is_vat_exempt(); + } + + /** + * Has calculated shipping? + * @return bool + */ + public function has_calculated_shipping() { + _deprecated_function( 'WC_Customer::has_calculated_shipping', '2.7', 'WC_Customer::get_calculated_shipping' ); + return $this->get_calculated_shipping(); + } + + /** + * Get default country for a customer. + * @return string + */ + public function get_default_country() { + _deprecated_function( 'WC_Customer::get_default_country', '2.7', 'wc_get_customer_default_location' ); + $default = wc_get_customer_default_location(); + return $default['country']; + } + + /** + * Get default state for a customer. + * @return string + */ + public function get_default_state() { + _deprecated_function( 'WC_Customer::get_default_state', '2.7', 'wc_get_customer_default_location' ); + $default = wc_get_customer_default_location(); + return $default['state']; + } + + /** + * Set customer address to match shop base address. + */ + public function set_to_base() { + _deprecated_function( 'WC_Customer::set_to_base', '2.7', 'WC_Customer::set_billing_address_to_base' ); + $this->set_billing_address_to_base(); + } + + /** + * Set customer shipping address to base address. + */ + public function set_shipping_to_base() { + _deprecated_function( 'WC_Customer::set_shipping_to_base', '2.7', 'WC_Customer::set_shipping_address_to_base' ); + $this->set_shipping_address_to_base(); + } + + /** + * Calculated shipping. + * @param boolean $calculated + */ + public function calculated_shipping( $calculated = true ) { + _deprecated_function( 'WC_Customer::calculated_shipping', '2.7', 'WC_Customer::set_calculated_shipping' ); + $this->set_calculated_shipping( $calculated ); + } + + /** + * Set default data for a customer. + */ + public function set_default_data() { + _deprecated_function( 'WC_Customer::set_default_data', '2.7', '' ); + } + + /** + * Is the user a paying customer? + * @todo should this be moved to a get_ readonly? + * @return bool + */ + function is_paying_customer( $user_id = '' ) { + _deprecated_function( 'WC_Customer::is_paying_customer', '2.7', 'WC_Customer::get_is_paying_customer' ); + if ( ! empty( $user_id ) ) { + $user_id = get_current_user_id(); + } + return '1' === get_user_meta( $user_id, 'paying_customer', true ); + } + + /** + * Legacy get country. + */ + function get_country() { + _deprecated_function( 'WC_Customer::get_country', '2.7', 'WC_Customer::get_billing_country' ); + return $this->get_billing_country(); + } + + /** + * Legacy get state. + */ + function get_state() { + _deprecated_function( 'WC_Customer::get_state', '2.7', 'WC_Customer::get_billing_state' ); + return $this->get_billing_state(); + } + + /** + * Legacy get postcode. + */ + function get_postcode() { + _deprecated_function( 'WC_Customer::get_postcode', '2.7', 'WC_Customer::get_billing_postcode' ); + return $this->get_billing_postcode(); + } + + /** + * Legacy get city. + */ + function get_city() { + _deprecated_function( 'WC_Customer::get_city', '2.7', 'WC_Customer::get_billing_city' ); + return $this->get_billing_city(); + } + + /** + * Legacy set country. + */ + function set_country( $country ) { + _deprecated_function( 'WC_Customer::set_country', '2.7', 'WC_Customer::set_billing_country' ); + $this->set_billing_country( $country ); + } + + /** + * Legacy set state. + */ + function set_state( $state ) { + _deprecated_function( 'WC_Customer::set_state', '2.7', 'WC_Customer::set_billing_state' ); + $this->set_billing_state( $state ); + } + + /** + * Legacy set postcode. + */ + function set_postcode( $postcode ) { + _deprecated_function( 'WC_Customer::set_postcode', '2.7', 'WC_Customer::set_billing_postcode' ); + $this->set_billing_postcode( $postcode ); + } + + /** + * Legacy set city. + */ + function set_city( $city ) { + _deprecated_function( 'WC_Customer::set_city', '2.7', 'WC_Customer::set_billing_city' ); + $this->set_billing_city( $city ); + } + +} diff --git a/includes/shortcodes/class-wc-shortcode-cart.php b/includes/shortcodes/class-wc-shortcode-cart.php index c64213c6c74..26ba6d32e90 100644 --- a/includes/shortcodes/class-wc-shortcode-cart.php +++ b/includes/shortcodes/class-wc-shortcode-cart.php @@ -37,7 +37,9 @@ class WC_Shortcode_Cart { WC()->customer->set_shipping_to_base(); } - WC()->customer->calculated_shipping( true ); + WC()->customer->set_calculated_shipping( true ); + + WC()->customer->save_to_session(); wc_add_notice( __( 'Shipping costs updated.', 'woocommerce' ), 'notice' ); diff --git a/includes/shortcodes/class-wc-shortcode-checkout.php b/includes/shortcodes/class-wc-shortcode-checkout.php index ac59a99ee20..fcc289b5a6b 100644 --- a/includes/shortcodes/class-wc-shortcode-checkout.php +++ b/includes/shortcodes/class-wc-shortcode-checkout.php @@ -105,6 +105,8 @@ class WC_Shortcode_Checkout { WC()->customer->set_postcode( $order->billing_postcode ); } + WC()->customer->save(); + $available_gateways = WC()->payment_gateways->get_available_payment_gateways(); if ( sizeof( $available_gateways ) ) { diff --git a/includes/wc-cart-functions.php b/includes/wc-cart-functions.php index bd085cd2384..bd9ef14e4a3 100644 --- a/includes/wc-cart-functions.php +++ b/includes/wc-cart-functions.php @@ -275,7 +275,7 @@ function wc_cart_totals_order_total_html() { if ( ! empty( $tax_string_array ) ) { $taxable_address = WC()->customer->get_taxable_address(); - $estimated_text = WC()->customer->is_customer_outside_base() && ! WC()->customer->has_calculated_shipping() + $estimated_text = WC()->customer->is_customer_outside_base() && ! WC()->customer->get_calculated_shipping() ? sprintf( ' ' . __( 'estimated for %s', 'woocommerce' ), WC()->countries->estimated_for_prefix( $taxable_address[0] ) . WC()->countries->countries[ $taxable_address[0] ] ) : ''; $value .= '' . sprintf( __( '(includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) . $estimated_text ) . ''; diff --git a/templates/cart/cart-shipping.php b/templates/cart/cart-shipping.php index 0574edf7e5f..facab7b1f18 100644 --- a/templates/cart/cart-shipping.php +++ b/templates/cart/cart-shipping.php @@ -44,7 +44,7 @@ if ( ! defined( 'ABSPATH' ) ) { printf( '%3$s ', $index, esc_attr( $method->id ), wc_cart_totals_shipping_method_label( $method ) ); do_action( 'woocommerce_after_shipping_rate', $method, $index ); ?> - customer->has_calculated_shipping() ) : ?> + customer->get_calculated_shipping() ) : ?> diff --git a/templates/cart/cart-totals.php b/templates/cart/cart-totals.php index 481f296a439..fcd53312348 100644 --- a/templates/cart/cart-totals.php +++ b/templates/cart/cart-totals.php @@ -21,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) { } ?> -
+
@@ -67,7 +67,7 @@ if ( ! defined( 'ABSPATH' ) ) { cart->tax_display_cart ) : $taxable_address = WC()->customer->get_taxable_address(); - $estimated_text = WC()->customer->is_customer_outside_base() && ! WC()->customer->has_calculated_shipping() + $estimated_text = WC()->customer->is_customer_outside_base() && ! WC()->customer->get_calculated_shipping() ? sprintf( ' (' . __( 'estimated for %s', 'woocommerce' ) . ')', WC()->countries->estimated_for_prefix( $taxable_address[0] ) . WC()->countries->countries[ $taxable_address[0] ] ) : ''; diff --git a/tests/framework/helpers/class-wc-helper-customer.php b/tests/framework/helpers/class-wc-helper-customer.php index 0867fe55973..0693f63ad94 100644 --- a/tests/framework/helpers/class-wc-helper-customer.php +++ b/tests/framework/helpers/class-wc-helper-customer.php @@ -34,7 +34,34 @@ class WC_Helper_Customer { WC_Helper_Customer::set_customer_details( $customer_data ); - return new WC_Customer(); + $customer = new WC_Customer(); + $customer->load_session(); + return $customer; + } + + /** + * Creates a customer in the tests DB. + */ + public static function create_customer() { + $customer = new WC_Customer(); + $customer->set_billing_country( 'US' ); + $customer->set_first_name( 'Justin' ); + $customer->set_billing_state( 'PA' ); + $customer->set_billing_postcode( '19123' ); + $customer->set_billing_city( 'Philadelphia' ); + $customer->set_billing_address( '123 South Street' ); + $customer->set_billing_address_2( 'Apt 1' ); + $customer->set_shipping_country( 'US' ); + $customer->set_shipping_state( 'PA' ); + $customer->set_shipping_postcode( '19123' ); + $customer->set_shipping_city( 'Philadelphia' ); + $customer->set_shipping_address( '123 South Street' ); + $customer->set_shipping_address_2( 'Apt 1' ); + $customer->set_username( 'testcustomer' ); + $customer->set_password( 'hunter2' ); + $customer->set_email( 'test@woo.local' ); + $customer->create(); + return $customer; } /** diff --git a/tests/framework/helpers/class-wc-helper-order.php b/tests/framework/helpers/class-wc-helper-order.php index 480f03e03a3..01b5de73513 100644 --- a/tests/framework/helpers/class-wc-helper-order.php +++ b/tests/framework/helpers/class-wc-helper-order.php @@ -34,7 +34,7 @@ class WC_Helper_Order { * * @return WC_Order Order object. */ - public static function create_order() { + public static function create_order( $customer_id = 1 ) { // Create product $product = WC_Helper_Product::create_simple_product(); @@ -42,7 +42,7 @@ class WC_Helper_Order { $order_data = array( 'status' => 'pending', - 'customer_id' => 1, + 'customer_id' => $customer_id, 'customer_note' => '', 'total' => '', ); diff --git a/tests/unit-tests/customer/crud.php b/tests/unit-tests/customer/crud.php new file mode 100644 index 00000000000..91ceac4c588 --- /dev/null +++ b/tests/unit-tests/customer/crud.php @@ -0,0 +1,450 @@ +set_username( 'testusername-' . time() ); + $customer->set_password( 'test123' ); + $customer->set_email( 'test@woo.local' ); + $customer->create(); + $wp_user = new \WP_User( $customer->get_id() ); + + $this->assertEquals( $username, $customer->get_username() ); + $this->assertNotEquals( 0, $customer->get_id() ); + $this->assertEquals( strtotime( $wp_user->user_registered ), $customer->get_date_created() ); + } + + /** + * Test updating a customer. + * @since 2.7.0 + */ + public function test_update_customer() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + $this->assertEquals( 'test@woo.local', $customer->get_email() ); + $this->assertEquals( 'Apt 1', $customer->get_billing_address_2() ); + $customer->set_email( 'test@wc.local' ); + $customer->set_first_name( 'Justin' ); + $customer->set_billing_address_2( 'Apt 5' ); + $customer->update(); + + $customer = new \WC_Customer( $customer_id ); // so we can read fresh copies from the DB + $this->assertEquals( 'test@wc.local', $customer->get_email() ); + $this->assertEquals( 'Justin', $customer->get_first_name() ); + $this->assertEquals( 'Apt 5', $customer->get_billing_address_2() ); + } + + + /** + * Test saving a customer. + * @since 2.7.0 + */ + public function test_save_customer() { + // test save() -> Create + $customer = new \WC_Customer(); + $customer->set_username( 'testusername-' . time() ); + $customer->set_password( 'test123' ); + $customer->set_email( 'test@woo.local' ); + $this->assertEquals( 0, $customer->get_id() ); + $customer->save(); + $customer_id = $customer->get_id(); + $wp_user = new \WP_User( $customer->get_id() ); + + $this->assertNotEquals( 0, $customer->get_id() ); + + // test save() -> Update + $this->assertEquals( 'test@woo.local', $customer->get_email() ); + $customer->set_email( 'test@wc.local' ); + $customer->save(); + + $customer = new \WC_Customer( $customer_id ); + $this->assertEquals( 'test@wc.local', $customer->get_email() ); + } + + /** + * Test deleting a customer. + * @since 2.7.0 + */ + public function test_delete_customer() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + $this->assertNotEquals( 0, $customer->get_id() ); + $customer->delete(); + $customer->read( $customer_id ); + $this->assertEquals( 0, $customer->get_id() ); + } + + /** + * Test reading a customer. + * @since 2.7.0 + */ + public function test_read_customer() { + $username = 'user-' . time(); + $customer = new \WC_Customer(); + $customer->set_username( $username ); + $customer->set_email( 'test@woo.local' ); + $customer->set_password( 'hunter2' ); + $customer->set_first_name( 'Bob' ); + $customer->set_last_name( 'Bob' ); + $customer->create(); + $customer_id = $customer->get_id(); + $customer_read = new \WC_Customer(); + $customer_read->read( $customer_id ); + + $this->assertEquals( $customer_id, $customer_read->get_id() ); + $this->assertEquals( 'test@woo.local', $customer_read->get_email() ); + $this->assertEquals( 'Bob', $customer_read->get_first_name() ); + $this->assertEquals( 'Bob', $customer_read->get_last_name() ); + $this->assertEquals( $username, $customer_read->get_username() ); + } + + /** + * Tests backwards compat / legacy handling. + * @expectedDeprecated WC_Customer::is_vat_exempt + * @expectedDeprecated WC_Customer::has_calculated_shipping + * @expectedDeprecated WC_Customer::get_default_country + * @expectedDeprecated WC_Customer::get_default_state + * @expectedDeprecated WC_Customer::is_paying_customer + * @expectedDeprecated WC_Customer::calculated_shipping + * @since 2.7.0 + */ + public function test_customer_backwards_compat() { + // Properties. + // Accessing properties directly will throw some wanted deprected notices + // So we need to let PHPUnit know we are expecting them and it's fine to continue + $legacy_keys = array( + 'id', 'country', 'state', 'postcode', 'city', 'address', 'address_1', 'address_2', + 'shipping_country', 'shipping_state', 'shipping_postcode', 'shipping_city', + 'shipping_address', 'shipping_address_1', 'shipping_address_2', + 'is_vat_exempt', 'calculated_shipping', + ); + + $this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, $legacy_keys ); + + $customer = \WC_Helper_Customer::create_customer(); + + $this->assertEquals( $customer->get_id(), $customer->id ); + $this->assertEquals( $customer->get_billing_country(), $customer->country ); + $this->assertEquals( $customer->get_billing_state(), $customer->state ); + $this->assertEquals( $customer->get_billing_postcode(), $customer->postcode ); + $this->assertEquals( $customer->get_billing_city(), $customer->city ); + $this->assertEquals( $customer->get_billing_address(), $customer->address ); + $this->assertEquals( $customer->get_billing_address(), $customer->address_1 ); + $this->assertEquals( $customer->get_billing_address_2(), $customer->address_2 ); + $this->assertEquals( $customer->get_shipping_country(), $customer->shipping_country ); + $this->assertEquals( $customer->get_shipping_state(), $customer->shipping_state ); + $this->assertEquals( $customer->get_shipping_postcode(), $customer->shipping_postcode ); + $this->assertEquals( $customer->get_shipping_city(), $customer->shipping_city ); + $this->assertEquals( $customer->get_shipping_address(), $customer->shipping_address ); + $this->assertEquals( $customer->get_shipping_address(), $customer->shipping_address_1 ); + $this->assertEquals( $customer->get_shipping_address_2(), $customer->shipping_address_2 ); + $this->assertEquals( $customer->get_is_vat_exempt(), $customer->is_vat_exempt ); + $this->assertEquals( $customer->get_calculated_shipping(), $customer->calculated_shipping ); + + // Functions + $this->assertEquals( $customer->get_is_vat_exempt(), $customer->is_vat_exempt() ); + $this->assertEquals( $customer->get_calculated_shipping(), $customer->has_calculated_shipping() ); + $default = wc_get_customer_default_location(); + $this->assertEquals( $default['country'], $customer->get_default_country() ); + $this->assertEquals( $default['state'], $customer->get_default_state() ); + $this->assertFalse( $customer->get_calculated_shipping() ); + $customer->calculated_shipping( true ); + $this->assertTrue( $customer->get_calculated_shipping() ); + $this->assertEquals( $customer->get_is_paying_customer(), $customer->is_paying_customer() ); + } + + /** + * Test generic getters & setters + * @since 2.7.0 + */ + public function test_customer_setters_and_getters() { + $time = time(); + $standard_getters_and_setters = array( + 'username' => 'test', 'email' => 'test@woo.local', 'first_name' => 'Bob', 'last_name' => 'tester', + 'role' => 'customer', 'last_order_id' => 5, 'last_order_date' => $time, 'orders_count' => 2, + 'total_spent' => 10.57, 'date_created' => $time, 'date_modified' => $time, 'billing_postcode' => 11010, + 'billing_city' => 'New York', 'billing_address' => '123 Main St.', 'billing_address_1' => '123 Main St.', 'billing_address_2' => 'Apt 2', 'billing_state' => 'NY', + 'billing_country' => 'US', 'shipping_state' => 'NY', 'shipping_postcode' => 11011, 'shipping_city' => + 'New York', 'shipping_address' => '123 Main St.', 'shipping_address_1' => '123 Main St.', + 'shipping_address_2' => 'Apt 2', 'is_vat_exempt' => true, 'calculated_shipping' => true, + 'is_paying_customer' => true + ); + + $customer = new \WC_Customer; + foreach ( $standard_getters_and_setters as $function => $value ) { + $customer->{"set_{$function}"}( $value ); + $this->assertEquals( $value, $customer->{"get_{$function}"}(), $function ); + } + } + + /** + * Test getting a customer's last order ID and date + * @since 2.7.0 + */ + public function test_customer_get_last_order_info() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + $order = \WC_Helper_Order::create_order( $customer_id ); + $customer->read( $customer_id ); + $this->assertEquals( $order->id, $customer->get_last_order_id() ); + $this->assertEquals( strtotime( $order->order_date ), $customer->get_last_order_date() ); + } + + /** + * Test getting a customer's order count from DB. + * @since 2.7.0 + */ + public function test_customer_get_orders_count_read() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + \WC_Helper_Order::create_order( $customer_id ); + \WC_Helper_Order::create_order( $customer_id ); + \WC_Helper_Order::create_order( $customer_id ); + $customer->read( $customer_id ); + $this->assertEquals( 3, $customer->get_orders_count() ); + } + + /** + * Test getting a customer's total amount spent from DB. + * @since 2.7.0 + */ + public function test_customer_get_total_spent_read() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + $order = \WC_Helper_Order::create_order( $customer_id ); + $customer->read( $customer_id ); + $this->assertEquals( 0, $customer->get_total_spent() ); + $order->update_status( 'wc-completed' ); + $customer->read( $customer_id ); + $this->assertEquals( 40, $customer->get_total_spent() ); + } + + /** + * Test getting a customer's avatar URL. + * @since 2.7.0 + */ + public function test_customer_get_avatar_url() { + $customer = \WC_Helper_Customer::create_customer(); + $this->assertContains( 'gravatar.com/avatar', $customer->get_avatar_url() ); + $this->assertContains( md5( 'test@woo.local' ), $customer->get_avatar_url() ); + } + + /** + * Test getting a customer's creation date from DB. + * @since 2.7.0 + */ + public function test_customer_get_date_created_read() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + $user = new \WP_User( $customer_id ); + $this->assertEquals( strtotime( $user->data->user_registered ), $customer->get_date_created() ); + } + + /** + * Test getting a customer's modification date from DB. + * @since 2.7.0 + */ + public function test_customer_get_date_modified_read() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + $last = get_user_meta( $customer_id, 'last_update', true ); + sleep(1); + $this->assertEquals( $last, $customer->get_date_modified() ); + $customer->set_billing_address( '1234 Some St.' ); + $customer->save(); + $update = get_user_meta( $customer_id, 'last_update', true ); + $this->assertEquals( $update, $customer->get_date_modified() ); + $this->assertNotEquals( $update, $last ); + } + + /** + * Test getting a customer's taxable address. + * @since 2.7.0 + */ + public function test_customer_get_taxable_address() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + $customer->set_shipping_postcode( '11111' ); + $customer->set_shipping_city( 'Test' ); + $customer->save(); + $customer->read( $customer_id ); + + update_option( 'woocommerce_tax_based_on', 'shipping' ); + $taxable = $customer->get_taxable_address(); + $this->assertEquals( 'US', $taxable[0] ); + $this->assertEquals( 'PA', $taxable[1] ); + $this->assertEquals( '11111', $taxable[2] ); + $this->assertEquals( 'Test', $taxable[3] ); + + update_option( 'woocommerce_tax_based_on', 'billing' ); + $taxable = $customer->get_taxable_address(); + $this->assertEquals( 'US', $taxable[0] ); + $this->assertEquals( 'PA', $taxable[1] ); + $this->assertEquals( '19123', $taxable[2] ); + $this->assertEquals( 'Philadelphia', $taxable[3] ); + + update_option( 'woocommerce_tax_based_on', 'base' ); + $taxable = $customer->get_taxable_address(); + $this->assertEquals( WC()->countries->get_base_country(), $taxable[0] ); + $this->assertEquals( WC()->countries->get_base_state(), $taxable[1] ); + $this->assertEquals( WC()->countries->get_base_postcode(), $taxable[2] ); + $this->assertEquals( WC()->countries->get_base_city(), $taxable[3] ); + } + + /** + * Test getting a customer's downloadable products. + * @since 2.7.0 + */ + public function test_customer_get_downloadable_products() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + $this->assertEquals( wc_get_customer_available_downloads( $customer_id ), $customer->get_downloadable_products() ); + } + + /** + * Test setting a password on update - making sure it actually changes the users password. + * @since 2.7.0 + */ + public function test_customer_password() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + + $user = get_user_by( 'id', $customer_id ); + $this->assertTrue( wp_check_password( 'hunter2', $user->data->user_pass, $user->ID ) ); + + $customer->set_password( 'hunter3' ); + $customer->save(); + + $user = get_user_by( 'id', $customer_id ); + $this->assertTrue( wp_check_password( 'hunter3', $user->data->user_pass, $user->ID ) ); + } + + /** + * Test setting a customer's address to the base address. + * @since 2.7.0 + */ + public function test_customer_set_address_to_base() { + $customer = \WC_Helper_Customer::create_customer(); + $customer->set_billing_address_to_base(); + $base = wc_get_customer_default_location(); + $this->assertEquals( $base['country'], $customer->get_billing_country() ); + $this->assertEquals( $base['state'], $customer->get_billing_state() ); + $this->assertEmpty( $customer->get_billing_postcode() ); + $this->assertEmpty( $customer->get_billing_city() ); + } + + /** + * Test setting a customer's shipping address to the base address. + * @since 2.7.0 + */ + public function test_customer_set_shipping_address_to_base() { + $customer = \WC_Helper_Customer::create_customer(); + $customer->set_shipping_address_to_base(); + $base = wc_get_customer_default_location(); + $this->assertEquals( $base['country'], $customer->get_shipping_country() ); + $this->assertEquals( $base['state'], $customer->get_shipping_state() ); + $this->assertEmpty( $customer->get_shipping_postcode() ); + $this->assertEmpty( $customer->get_shipping_city() ); + } + + /** + * Test setting a customer's location (multiple address fields at once) + * @since 2.7.0 + */ + public function test_customer_set_location() { + $customer = \WC_Helper_Customer::create_customer(); + $customer->set_billing_location( 'US', 'OH', '12345', 'Cleveland' ); + $this->assertEquals( 'US', $customer->get_billing_country() ); + $this->assertEquals( 'OH', $customer->get_billing_state() ); + $this->assertEquals( '12345', $customer->get_billing_postcode() ); + $this->assertEquals( 'Cleveland', $customer->get_billing_city() ); + } + + /** + * Test setting a customer's shipping location (multiple address fields at once) + * @since 2.7.0 + */ + public function test_customer_set_shipping_location() { + $customer = \WC_Helper_Customer::create_customer(); + $customer->set_shipping_location( 'US', 'OH', '12345', 'Cleveland' ); + $this->assertEquals( 'US', $customer->get_shipping_country() ); + $this->assertEquals( 'OH', $customer->get_shipping_state() ); + $this->assertEquals( '12345', $customer->get_shipping_postcode() ); + $this->assertEquals( 'Cleveland', $customer->get_shipping_city() ); + } + + /** + * Test is_customer_outside_base. + * @since 2.7.0 + */ + public function test_customer_is_customer_outside_base() { + $customer = \WC_Helper_Customer::create_customer(); + $this->assertTrue( $customer->is_customer_outside_base() ); + update_option( 'woocommerce_tax_based_on', 'base' ); + $customer->set_billing_address_to_base(); + $this->assertFalse( $customer->is_customer_outside_base() ); + } + + /** + * Test WC_Customer's session handling code. + * @since 2.7.0 + */ + public function test_customer_sessions() { + $customer = \WC_Helper_Customer::create_customer(); + $session = \WC_Helper_Customer::create_mock_customer(); // set into session.... + + $this->assertNotEmpty( $session->get_id() ); + $this->assertFalse( is_numeric( $session->get_id() ) ); + $this->assertEquals( '19123', $session->get_billing_postcode() ); + $this->assertEquals( '123 South Street', $session->get_billing_address() ); + $this->assertEquals( 'Philadelphia', $session->get_billing_city() ); + + $session->set_billing_address( '124 South Street' ); + $session->save_to_session(); + + $session = new \WC_Customer(); + $session->load_session(); + $this->assertEquals( '124 South Street', $session->get_billing_address() ); + } + + /** + * Test getting meta. + * @since 2.7.0 + */ + public function test_get_meta() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + $meta_value = time() . '-custom-value'; + add_user_meta( $customer_id, 'test_field', $meta_value, true ); + $customer->read( $customer_id ); + $fields = $customer->get_meta_data(); + $this->assertCount( 1, $fields ); + $this->assertEquals( $meta_value, $customer->get_meta( 'test_field') ); + } + + /** + * Test setting meta. + * @since 2.7.0 + */ + public function test_set_meta() { + $customer = \WC_Helper_Customer::create_customer(); + $customer_id = $customer->get_id(); + $meta_value = time() . '-custom-value'; + $customer->add_meta_data( 'my-field', $meta_value, true ); + $customer->save(); + $customer->read( $customer_id ); + $this->assertEquals( $meta_value, $customer->get_meta( 'my-field' ) ); + } + +} diff --git a/woocommerce.php b/woocommerce.php index 00eec9066f7..d9ef96adb5e 100644 --- a/woocommerce.php +++ b/woocommerce.php @@ -234,6 +234,8 @@ final class WooCommerce { include_once( 'includes/class-wc-post-data.php' ); include_once( 'includes/class-wc-ajax.php' ); + include_once( 'includes/abstracts/abstract-wc-data.php' ); // WC_Data for CRUD + if ( $this->is_request( 'admin' ) ) { include_once( 'includes/admin/class-wc-admin.php' ); } @@ -255,7 +257,6 @@ final class WooCommerce { include_once( 'includes/class-wc-auth.php' ); // Auth Class include_once( 'includes/class-wc-post-types.php' ); // Registers post types - include_once( 'includes/abstracts/abstract-wc-data.php' ); // WC_Data for CRUD include_once( 'includes/abstracts/abstract-wc-payment-token.php' ); // Payment Tokens include_once( 'includes/abstracts/abstract-wc-product.php' ); // Products include_once( 'includes/abstracts/abstract-wc-order.php' ); // Orders @@ -328,6 +329,7 @@ final class WooCommerce { if ( $this->is_request( 'frontend' ) ) { $this->cart = new WC_Cart(); // Cart class, stores the cart contents $this->customer = new WC_Customer(); // Customer class, handles data such as customer location + $this->customer->load_session(); } $this->load_webhooks();