diff --git a/includes/abstracts/abstract-wc-data.php b/includes/abstracts/abstract-wc-data.php index 30c88e98364..b47f511e9b1 100644 --- a/includes/abstracts/abstract-wc-data.php +++ b/includes/abstracts/abstract-wc-data.php @@ -264,6 +264,16 @@ abstract class WC_Data { } } + /** + * Callback to remove unwanted meta data. + * + * @param object $meta + * @return bool + */ + protected function exclude_internal_meta_keys( $meta ) { + return ! in_array( $meta->meta_key, $this->get_internal_meta_keys() ); + } + /** * Read Meta Data from the database. Ignore any internal properties. * @since 2.6.0 @@ -296,10 +306,8 @@ abstract class WC_Data { ", $this->get_id() ) ); if ( $raw_meta_data ) { + $raw_meta_data = array_filter( $raw_meta_data, array( $this, 'exclude_internal_meta_keys' ) ); foreach ( $raw_meta_data as $meta ) { - if ( in_array( $meta->meta_key, $this->get_internal_meta_keys() ) ) { - continue; - } $this->_meta_data[] = (object) array( 'id' => (int) $meta->{ $db_info['meta_id_field'] }, 'key' => $meta->meta_key, @@ -390,6 +398,9 @@ abstract class WC_Data { foreach ( $props as $prop => $value ) { try { + if ( 'meta_data' === $prop ) { + continue; + } $setter = "set_$prop"; if ( ! is_null( $value ) && is_callable( array( $this, $setter ) ) ) { $this->{$setter}( $value ); diff --git a/includes/api/class-wc-rest-coupons-controller.php b/includes/api/class-wc-rest-coupons-controller.php index f81a5584a94..5f9d6322aeb 100644 --- a/includes/api/class-wc-rest-coupons-controller.php +++ b/includes/api/class-wc-rest-coupons-controller.php @@ -495,6 +495,29 @@ class WC_REST_Coupons_Controller extends WC_REST_Posts_Controller { 'context' => array( 'view', 'edit' ), 'readonly' => true, ), + 'meta_data' => array( + 'description' => __( 'Order meta data.', 'woocommerce' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'properties' => array( + 'id' => array( + 'description' => __( 'Meta ID.', 'woocommerce' ), + 'type' => 'int', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'key' => array( + 'description' => __( 'Meta key.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'value' => array( + 'description' => __( 'Meta value.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + ), + ), ), ); return $this->add_additional_fields_schema( $schema ); diff --git a/includes/api/class-wc-rest-customers-controller.php b/includes/api/class-wc-rest-customers-controller.php index 3b01624066b..20bfa41ce75 100644 --- a/includes/api/class-wc-rest-customers-controller.php +++ b/includes/api/class-wc-rest-customers-controller.php @@ -507,7 +507,7 @@ class WC_REST_Customers_Controller extends WC_REST_Controller { if ( $last_order_data = $customer->get_last_order() ) { $data['last_order'] = array( 'id' => $last_order_data->get_id(), - 'date' => wc_rest_prepare_date_response( $last_order_data->get_date_created() ), + 'date' => $last_order_data->get_date_created() ? wc_rest_prepare_date_response( $last_order_data->get_date_created() ) : null, ); } @@ -536,6 +536,15 @@ class WC_REST_Customers_Controller extends WC_REST_Controller { protected function update_customer_meta_fields( $customer, $request ) { $schema = $this->get_item_schema(); + // Meta data + if ( isset( $request['meta_data'] ) ) { + if ( is_array( $request['meta_data'] ) ) { + foreach ( $request['meta_data'] as $meta ) { + $coupon->update_meta_data( $meta['key'], $meta['value'], $meta['id'] ); + } + } + } + // Customer first name. if ( isset( $request['first_name'] ) ) { $customer->set_first_name( wc_clean( $request['first_name'] ) ); @@ -801,6 +810,35 @@ class WC_REST_Customers_Controller extends WC_REST_Controller { ), ), ), + 'is_paying_customer' => array( + 'description' => __( 'Is the customer a paying customer?', 'woocommerce' ), + 'type' => 'bool', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'meta_data' => array( + 'description' => __( 'Order meta data.', 'woocommerce' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + 'properties' => array( + 'id' => array( + 'description' => __( 'Meta ID.', 'woocommerce' ), + 'type' => 'int', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'key' => array( + 'description' => __( 'Meta key.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'value' => array( + 'description' => __( 'Meta value.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + ), + ), ), ); diff --git a/includes/class-wc-customer.php b/includes/class-wc-customer.php index c12d048b982..95162e5cd71 100644 --- a/includes/class-wc-customer.php +++ b/includes/class-wc-customer.php @@ -79,9 +79,10 @@ class WC_Customer extends WC_Legacy_Customer { 'shipping_address_2', 'shipping_state', 'shipping_country', 'paying_customer', 'last_update', 'first_name', 'last_name', 'show_admin_bar_front', 'use_ssl', 'admin_color', 'rich_editing', 'comment_shortcuts', 'dismissed_wp_pointers', 'show_welcome_panel', - '_woocommerce_persistent_cart', 'session_tokens', + '_woocommerce_persistent_cart', 'session_tokens', 'nickname', 'description', 'billing_first_name', 'billing_last_name', 'billing_company', 'billing_phone', 'billing_email', - 'shipping_first_name', 'shipping_last_name', 'shipping_company', + 'shipping_first_name', 'shipping_last_name', 'shipping_company', 'default_password_nag', + 'primary_blog', 'source_domain', ); /** @@ -244,7 +245,7 @@ class WC_Customer extends WC_Legacy_Customer { $spent = 0; } - return wc_format_decimal( $spent ); + return wc_format_decimal( $spent, 2 ); } /** @@ -1072,7 +1073,7 @@ class WC_Customer extends WC_Legacy_Customer { * @return mixed */ private function flatten_post_meta( $value ) { - return current( $value ); + return is_array( $value ) ? current( $value ) : $value; } /** @@ -1096,7 +1097,7 @@ class WC_Customer extends WC_Legacy_Customer { } $this->set_id( $user_object->ID ); - $this->set_props( array_map( array( $this, 'flatten_post_meta'), get_post_meta( $id ) ) ); + $this->set_props( array_map( array( $this, 'flatten_post_meta'), get_user_meta( $id ) ) ); $this->set_props( array( 'is_paying_customer' => get_user_meta( $id, 'paying_customer', true ), 'email' => $user_object->user_email, @@ -1113,12 +1114,10 @@ class WC_Customer extends WC_Legacy_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() ) ); + wp_update_user( array( 'ID' => $this->get_id(), 'user_email' => $this->get_email() ) ); // Only update password if a new one was set with set_password if ( ! empty( $this->_password ) ) { - wp_update_user( array( 'ID' => $customer_ID, 'user_pass' => $this->_password ) ); + wp_update_user( array( 'ID' => $this->get_id(), 'user_pass' => $this->_password ) ); $this->_password = ''; } @@ -1211,4 +1210,18 @@ class WC_Customer extends WC_Legacy_Customer { } } + /** + * Callback to remove unwanted meta data. + * + * @param object $meta + * @return bool + */ + protected function exclude_internal_meta_keys( $meta ) { + global $wpdb; + return ! in_array( $meta->meta_key, $this->get_internal_meta_keys() ) + && 0 !== strpos( $meta->meta_key, 'closedpostboxes_' ) + && 0 !== strpos( $meta->meta_key, 'metaboxhidden_' ) + && 0 !== strpos( $meta->meta_key, 'manageedit-' ) + && ! strstr( $meta->meta_key, $wpdb->prefix ); + } } diff --git a/includes/legacy/class-wc-legacy-customer.php b/includes/legacy/class-wc-legacy-customer.php index c413daca666..b10bec9b16b 100644 --- a/includes/legacy/class-wc-legacy-customer.php +++ b/includes/legacy/class-wc-legacy-customer.php @@ -20,7 +20,7 @@ abstract class WC_Legacy_Customer extends WC_Data { */ public function __isset( $key ) { $legacy_keys = array( - 'country', 'state', 'postcode' ,'city', 'address_1', 'address', 'address_2', 'shipping_country', 'shipping_state', + 'id', 'country', 'state', 'postcode' ,'city', 'address_1', 'address', 'address_2', 'shipping_country', 'shipping_state', 'shipping_postcode', 'shipping_city', 'shipping_address_1', 'shipping_address', 'shipping_address_2', 'is_vat_exempt', 'calculated_shipping', ); $key = $this->filter_legacy_key( $key ); @@ -39,7 +39,7 @@ abstract class WC_Legacy_Customer extends WC_Data { if ( in_array( $key, array( 'country', 'state', 'postcode' ,'city', 'address_1', 'address', 'address_2' ) ) ) { $key = 'billing_' . $key; } - return is_callable( $this, "get_{$key}" ) ? $this->{"get_{$key}"}() : ''; + return is_callable( array( $this, "get_{$key}" ) ) ? $this->{"get_{$key}"}() : ''; } /** @@ -52,7 +52,7 @@ abstract class WC_Legacy_Customer extends WC_Data { _doing_it_wrong( $key, 'Customer properties should not be set directly.', '2.7' ); $key = $this->filter_legacy_key( $key ); - if ( is_callable( $this, "set_{$key}" ) ) { + if ( is_callable( array( $this, "set_{$key}" ) ) ) { $this->{"set_{$key}"}( $value ); } } diff --git a/tests/framework/helpers/class-wc-helper-customer.php b/tests/framework/helpers/class-wc-helper-customer.php index b585bd4582b..769841617ee 100644 --- a/tests/framework/helpers/class-wc-helper-customer.php +++ b/tests/framework/helpers/class-wc-helper-customer.php @@ -60,7 +60,7 @@ class WC_Helper_Customer { $customer->set_username( $username ); $customer->set_password( $password ); $customer->set_email( $email ); - $customer->create(); + $customer->save(); return $customer; } diff --git a/tests/unit-tests/api/coupons.php b/tests/unit-tests/api/coupons.php index 0b190efdfb4..078087e5a06 100644 --- a/tests/unit-tests/api/coupons.php +++ b/tests/unit-tests/api/coupons.php @@ -406,7 +406,7 @@ class WC_Tests_API_Coupons extends WC_REST_Unit_Test_Case { $data = $response->get_data(); $properties = $data['schema']['properties']; - $this->assertEquals( 23, count( $properties ) ); + $this->assertEquals( 24, count( $properties ) ); $this->assertArrayHasKey( 'id', $properties ); $this->assertArrayHasKey( 'code', $properties ); $this->assertArrayHasKey( 'date_created', $properties ); diff --git a/tests/unit-tests/api/customers.php b/tests/unit-tests/api/customers.php index a7db36a3d9b..cc8eaf826dc 100644 --- a/tests/unit-tests/api/customers.php +++ b/tests/unit-tests/api/customers.php @@ -18,8 +18,8 @@ class Customers extends WC_REST_Unit_Test_Case { /** * Test route registration. - * - * @since 2.7.0 + * + * @since 2.7.0 */ public function test_register_routes() { $routes = $this->server->get_routes(); @@ -29,88 +29,90 @@ class Customers extends WC_REST_Unit_Test_Case { $this->assertArrayHasKey( '/wc/v1/customers/batch', $routes ); } - /** - * Test getting customers. - * - * @since 2.7.0 - */ - public function test_get_customers() { - wp_set_current_user( 1 ); + /** + * Test getting customers. + * + * @since 2.7.0 + */ + public function test_get_customers() { + wp_set_current_user( 1 ); - $customer_1 = WC_Helper_Customer::create_customer(); - WC_Helper_Customer::create_customer( 'test2', 'test2', 'test2@woo.local' ); + $customer_1 = WC_Helper_Customer::create_customer(); + WC_Helper_Customer::create_customer( 'test2', 'test2', 'test2@woo.local' ); - $request = new WP_REST_Request( 'GET', '/wc/v1/customers' ); - $request->set_query_params( array( + $request = new WP_REST_Request( 'GET', '/wc/v1/customers' ); + $request->set_query_params( array( 'orderby' => 'id', ) ); - $response = $this->server->dispatch( $request ); - $customers = $response->get_data(); + $response = $this->server->dispatch( $request ); + $customers = $response->get_data(); - $this->assertEquals( 200, $response->get_status() ); - $this->assertEquals( 2, count( $customers ) ); + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( 2, count( $customers ) ); - $this->assertContains( array( - 'id' => $customer_1->get_id(), - 'date_created' => wc_rest_prepare_date_response( date( 'Y-m-d H:i:s', $customer_1->get_date_created() ) ), - 'date_modified' => wc_rest_prepare_date_response( date( 'Y-m-d H:i:s', $customer_1->get_date_modified() ) ), - 'email' => 'test@woo.local', - 'first_name' => 'Justin', - 'last_name' => '', - 'username' => 'testcustomer', - 'last_order' => null, - 'orders_count' => 0, - 'total_spent' => '0.00', - 'avatar_url' => $customer_1->get_avatar_url(), - 'billing' => array( - 'first_name' => '', - 'last_name' => '', - 'company' => '', - 'address_1' => '123 South Street', - 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', - 'country' => 'US', - 'email' => '', - 'phone' => '', - ), - 'shipping' => array( - 'first_name' => '', - 'last_name' => '', - 'company' => '', - 'address_1' => '123 South Street', - 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', - 'country' => 'US', - ), - '_links' => array( - 'self' => array( - array( - 'href' => rest_url( '/wc/v1/customers/' . $customer_1->get_id() . '' ), - ), - ), - 'collection' => array( - array( - 'href' => rest_url( '/wc/v1/customers' ), - ), - ), - ), - ), $customers ); - } + $this->assertContains( array( + 'id' => $customer_1->get_id(), + 'date_created' => wc_rest_prepare_date_response( date( 'Y-m-d H:i:s', $customer_1->get_date_created() ) ), + 'date_modified' => wc_rest_prepare_date_response( date( 'Y-m-d H:i:s', $customer_1->get_date_modified() ) ), + 'email' => 'test@woo.local', + 'first_name' => 'Justin', + 'last_name' => '', + 'username' => 'testcustomer', + 'billing' => array( + 'first_name' => '', + 'last_name' => '', + 'company' => '', + 'address_1' => '123 South Street', + 'address_2' => 'Apt 1', + 'city' => 'Philadelphia', + 'state' => 'PA', + 'postcode' => '19123', + 'country' => 'US', + 'email' => '', + 'phone' => '', + ), + 'shipping' => array( + 'first_name' => '', + 'last_name' => '', + 'company' => '', + 'address_1' => '123 South Street', + 'address_2' => 'Apt 1', + 'city' => 'Philadelphia', + 'state' => 'PA', + 'postcode' => '19123', + 'country' => 'US', + ), + 'is_paying_customer' => false, + 'last_order' => null, + 'orders_count' => 0, + 'total_spent' => '0.00', + 'avatar_url' => $customer_1->get_avatar_url(), + 'meta_data' => array(), + '_links' => array( + 'self' => array( + array( + 'href' => rest_url( '/wc/v1/customers/' . $customer_1->get_id() . '' ), + ), + ), + 'collection' => array( + array( + 'href' => rest_url( '/wc/v1/customers' ), + ), + ), + ), + ), $customers ); + } - /** - * Test getting customers without valid permissions. - * - * @since 2.7.0 - */ - public function test_get_customers_without_permission() { + /** + * Test getting customers without valid permissions. + * + * @since 2.7.0 + */ + public function test_get_customers_without_permission() { wp_set_current_user( 0 ); $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/customers' ) ); $this->assertEquals( 401, $response->get_status() ); - } + } /** * Test creating a new customer. @@ -139,10 +141,6 @@ class Customers extends WC_REST_Unit_Test_Case { 'first_name' => '', 'last_name' => '', 'username' => 'create_customer_test', - 'last_order' => null, - 'orders_count' => 0, - 'total_spent' => '0', - 'avatar_url' => $data['avatar_url'], 'billing' => array( 'first_name' => '', 'last_name' => '', @@ -167,12 +165,18 @@ class Customers extends WC_REST_Unit_Test_Case { 'postcode' => '', 'country' => '', ), + 'is_paying_customer' => false, + 'meta_data' => array(), + 'last_order' => null, + 'orders_count' => 0, + 'total_spent' => '0.00', + 'avatar_url' => $data['avatar_url'], ), $data ); // Test extra data $request = new WP_REST_Request( 'POST', '/wc/v1/customers' ); $request->set_body_params( array( - 'username' => 'create_customer_test2', + 'username' => 'create_customer_test2', 'password' => 'test123', 'email' => 'create_customer_test2@woo.local', 'first_name' => 'Test', @@ -198,10 +202,6 @@ class Customers extends WC_REST_Unit_Test_Case { 'first_name' => 'Test', 'last_name' => 'McTestFace', 'username' => 'create_customer_test2', - 'last_order' => null, - 'orders_count' => 0, - 'total_spent' => '0', - 'avatar_url' => $data['avatar_url'], 'billing' => array( 'first_name' => '', 'last_name' => '', @@ -226,6 +226,12 @@ class Customers extends WC_REST_Unit_Test_Case { 'postcode' => '', 'country' => 'US', ), + 'is_paying_customer' => false, + 'meta_data' => array(), + 'last_order' => null, + 'orders_count' => 0, + 'total_spent' => '0.00', + 'avatar_url' => $data['avatar_url'], ), $data ); // Test without required field @@ -275,12 +281,6 @@ class Customers extends WC_REST_Unit_Test_Case { 'date_modified' => $data['date_modified'], 'email' => 'get_customer_test@woo.local', 'first_name' => 'Justin', - 'last_name' => '', - 'username' => 'get_customer_test', - 'last_order' => null, - 'orders_count' => 0, - 'total_spent' => '0.00', - 'avatar_url' => $data['avatar_url'], 'billing' => array( 'first_name' => '', 'last_name' => '', @@ -305,6 +305,14 @@ class Customers extends WC_REST_Unit_Test_Case { 'postcode' => '19123', 'country' => 'US', ), + 'is_paying_customer' => false, + 'meta_data' => array(), + 'last_name' => '', + 'username' => 'get_customer_test', + 'last_order' => null, + 'orders_count' => 0, + 'total_spent' => '0.00', + 'avatar_url' => $data['avatar_url'], ), $data ); } @@ -483,7 +491,7 @@ class Customers extends WC_REST_Unit_Test_Case { $data = $response->get_data(); $properties = $data['schema']['properties']; - $this->assertEquals( 14, count( $properties ) ); + $this->assertEquals( 16, count( $properties ) ); $this->assertArrayHasKey( 'id', $properties ); $this->assertArrayHasKey( 'date_created', $properties ); $this->assertArrayHasKey( 'date_modified', $properties ); diff --git a/tests/unit-tests/customer/crud.php b/tests/unit-tests/customer/crud.php index b064dc62d4d..09fc034079f 100644 --- a/tests/unit-tests/customer/crud.php +++ b/tests/unit-tests/customer/crud.php @@ -110,8 +110,6 @@ class WC_Tests_CustomerCRUD extends WC_Unit_Test_Case { /** * 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