From 90d5a8e7e98c20066ffae9a7a679efc73c2b0203 Mon Sep 17 00:00:00 2001 From: Shiki Date: Mon, 20 Jul 2020 15:14:41 -0600 Subject: [PATCH 01/18] Orders V3 Schema: Add display_key and display_value for meta props --- .../Version3/class-wc-rest-orders-controller.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php b/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php index 5e4ea622fc8..6867e4bd612 100644 --- a/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php +++ b/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php @@ -244,6 +244,18 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller { $schema['properties']['coupon_lines']['items']['properties']['discount']['readonly'] = true; + $meta_data_item_properties_ref = &$schema['properties']['line_items']['items']['properties']['meta_data']['items']['properties']; + $meta_data_item_properties_ref['display_key'] = array( + 'description' => __( 'Meta key for UI display.', 'woocommerce-rest-api' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ); + $meta_data_item_properties_ref['display_value'] = array( + 'description' => __( 'Meta value for UI display.', 'woocommerce-rest-api' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ); + return $schema; } From ea63d5aaf97f0c1e1e233a8fd66fadb5199a1566 Mon Sep 17 00:00:00 2001 From: Shiki Date: Mon, 20 Jul 2020 18:00:38 -0600 Subject: [PATCH 02/18] Orders V3: Include display_key and display_value in item meta_data --- .../class-wc-rest-orders-controller.php | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php b/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php index 6867e4bd612..13a5311b5de 100644 --- a/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php +++ b/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php @@ -280,4 +280,52 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller { return $params; } + + /** + * Expands an order item to get its data. + * + * @param WC_Order_item $item Order item data. + * @return array + */ + protected function get_order_item_data( $item ) { + $data = parent::get_order_item_data( $item ); + + $product = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : false; + + $data['meta_data'] = array_map( + array( $this, 'get_order_item_meta_data' ), + $data['meta_data'], + array_fill( 0, count( $data['meta_data'] ), $product ) + ); + + return $data; + } + + /** + * Convert a {@link WC_Meta_Data} to an array with the expected API response keys and values. + * + * @param WC_Meta_Data $meta The metadata taken from the {@link WC_Order_Item::$meta_data} array. + * @param WC_Product $product The product that the metadata belongs to. + * @return array + */ + private function get_order_item_meta_data( $meta, $product ) { + $attribute_key = str_replace( 'attribute_', '', $meta->key ); + $display_key = wc_attribute_label( $attribute_key, $product ); + + $display_value = wp_kses_post( $meta->value ); + if ( taxonomy_exists( $attribute_key ) ) { + $term = get_term_by( 'slug', $meta->value, $attribute_key ); + if ( ! is_wp_error( $term ) && is_object( $term ) && $term->name ) { + $display_value = $term->name; + } + } + + return array( + 'id' => $meta->id, + 'key' => $meta->key, + 'value' => $meta->value, + 'display_key' => $display_key, + 'display_value' => $display_value, + ); + } } From 9678a286e393b5e5a0c22e85eb7cde655721c513 Mon Sep 17 00:00:00 2001 From: Shiki Date: Wed, 12 Aug 2020 14:58:21 -0600 Subject: [PATCH 03/18] Orders V3: Reuse WC_Order_Item->get_formatted_meta_data Previously, I was using my own function. This time, we're using the function available in WC_Order_Item but sanitizing the results after. --- .../class-wc-rest-orders-controller.php | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php b/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php index 13a5311b5de..0d3ecc81215 100644 --- a/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php +++ b/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php @@ -292,40 +292,32 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller { $product = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : false; + $formatted_meta_data = $item->get_formatted_meta_data( null, true ); $data['meta_data'] = array_map( - array( $this, 'get_order_item_meta_data' ), - $data['meta_data'], - array_fill( 0, count( $data['meta_data'] ), $product ) + array( $this, 'clean_formatted_meta_data' ), + $formatted_meta_data, + array_keys( $formatted_meta_data ) ); return $data; } /** - * Convert a {@link WC_Meta_Data} to an array with the expected API response keys and values. + * Sanitizes an object from the array returned by {@link WC_Order_Item::get_formatted_meta_data} and includes + * the {@link WC_Meta_Data} `id` in the resulting array. * - * @param WC_Meta_Data $meta The metadata taken from the {@link WC_Order_Item::$meta_data} array. - * @param WC_Product $product The product that the metadata belongs to. + * @param Object $meta_data An object result from {@link WC_Order_Item::get_formatted_meta_data}. + * This is expected to have the properties `key`, `value`, `display_key`, and `display_value`. + * @param integer $meta_data_id The id of the {@link WC_Meta_Data}. * @return array */ - private function get_order_item_meta_data( $meta, $product ) { - $attribute_key = str_replace( 'attribute_', '', $meta->key ); - $display_key = wc_attribute_label( $attribute_key, $product ); - - $display_value = wp_kses_post( $meta->value ); - if ( taxonomy_exists( $attribute_key ) ) { - $term = get_term_by( 'slug', $meta->value, $attribute_key ); - if ( ! is_wp_error( $term ) && is_object( $term ) && $term->name ) { - $display_value = $term->name; - } - } - + private function clean_formatted_meta_data( $meta_data, $meta_data_id ) { return array( - 'id' => $meta->id, - 'key' => $meta->key, - 'value' => $meta->value, - 'display_key' => $display_key, - 'display_value' => $display_value, + 'id' => $meta_data_id, + 'key' => $meta_data->key, + 'value' => $meta_data->value, + 'display_key' => wc_clean( $meta_data->display_key ), + 'display_value' => wc_clean( $meta_data->display_value ), ); } } From 5ab863e64936c4015d5d42f1fe0c753e95aa5531 Mon Sep 17 00:00:00 2001 From: Shiki Date: Wed, 12 Aug 2020 15:23:38 -0600 Subject: [PATCH 04/18] Fix formatting in Orders V2 unit test --- .../Version2/class-wc-rest-orders-v2-controller.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php b/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php index 0f2cfcbf28d..3dd928fc3eb 100644 --- a/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php +++ b/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php @@ -590,8 +590,8 @@ class WC_REST_Orders_V2_Controller extends WC_REST_CRUD_Controller { * Gets the product ID from the SKU or posted ID. * * @throws WC_REST_Exception When SKU or ID is not valid. - * @param array $posted Request data. - * @param string $action 'create' to add line item or 'update' to update it. + * @param array $posted Request data. + * @param string $action 'create' to add line item or 'update' to update it. * @return int */ protected function get_product_id( $posted, $action = 'create' ) { From 35ed2df4fb938d18d994eaa00f44fe108304fa7e Mon Sep 17 00:00:00 2001 From: Shiki Date: Wed, 12 Aug 2020 15:25:18 -0600 Subject: [PATCH 05/18] Schema: Make display_key and *_value available for v3 and v2 This is just the schema and the actual functionality isn't implemented yet. --- .../Version2/class-wc-rest-orders-v2-controller.php | 10 ++++++++++ .../Version3/class-wc-rest-orders-controller.php | 12 ------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php b/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php index 3dd928fc3eb..b9b10e6f6f0 100644 --- a/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php +++ b/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php @@ -1285,6 +1285,16 @@ class WC_REST_Orders_V2_Controller extends WC_REST_CRUD_Controller { 'type' => 'mixed', 'context' => array( 'view', 'edit' ), ), + 'display_key' => array( + 'description' => __( 'Meta key for UI display.', 'woocommerce-rest-api' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'display_value' => array( + 'description' => __( 'Meta value for UI display.', 'woocommerce-rest-api' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), ), ), ), diff --git a/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php b/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php index 0d3ecc81215..3dd8f1aa6db 100644 --- a/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php +++ b/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php @@ -244,18 +244,6 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller { $schema['properties']['coupon_lines']['items']['properties']['discount']['readonly'] = true; - $meta_data_item_properties_ref = &$schema['properties']['line_items']['items']['properties']['meta_data']['items']['properties']; - $meta_data_item_properties_ref['display_key'] = array( - 'description' => __( 'Meta key for UI display.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ); - $meta_data_item_properties_ref['display_value'] = array( - 'description' => __( 'Meta value for UI display.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ); - return $schema; } From 2e366ef76b70de855ee8783b8924d3eb011f3f60 Mon Sep 17 00:00:00 2001 From: Shiki Date: Wed, 12 Aug 2020 15:43:04 -0600 Subject: [PATCH 06/18] Orders: Make display_key and _value meta available for v3 and v3 This resolves the intentionally failing WC_Tests_API_Orders_V2::test_get_item_with_line_items_meta_data. --- .../class-wc-rest-orders-v2-controller.php | 27 +++++++++++++ .../class-wc-rest-orders-controller.php | 40 ------------------- 2 files changed, 27 insertions(+), 40 deletions(-) diff --git a/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php b/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php index b9b10e6f6f0..199d294768e 100644 --- a/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php +++ b/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php @@ -197,9 +197,36 @@ class WC_REST_Orders_V2_Controller extends WC_REST_CRUD_Controller { unset( $data['order_id'] ); unset( $data['type'] ); + // Expand meta_data to include user-friendly values. + $formatted_meta_data = $item->get_formatted_meta_data( null, true ); + $data['meta_data'] = array_map( + array( $this, 'clean_formatted_order_item_meta_data' ), + $formatted_meta_data, + array_keys( $formatted_meta_data ) + ); + return $data; } + /** + * Sanitizes an object from the array returned by {@link WC_Order_Item::get_formatted_meta_data} and includes + * the {@link WC_Meta_Data} `id` in the resulting array. + * + * @param Object $meta_data An object result from {@link WC_Order_Item::get_formatted_meta_data}. + * This is expected to have the properties `key`, `value`, `display_key`, and `display_value`. + * @param integer $meta_data_id The id of the {@link WC_Meta_Data}. + * @return array + */ + private function clean_formatted_order_item_meta_data( $meta_data, $meta_data_id ) { + return array( + 'id' => $meta_data_id, + 'key' => $meta_data->key, + 'value' => $meta_data->value, + 'display_key' => wc_clean( $meta_data->display_key ), + 'display_value' => wc_clean( $meta_data->display_value ), + ); + } + /** * Get formatted item data. * diff --git a/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php b/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php index 3dd8f1aa6db..5e4ea622fc8 100644 --- a/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php +++ b/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php @@ -268,44 +268,4 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller { return $params; } - - /** - * Expands an order item to get its data. - * - * @param WC_Order_item $item Order item data. - * @return array - */ - protected function get_order_item_data( $item ) { - $data = parent::get_order_item_data( $item ); - - $product = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : false; - - $formatted_meta_data = $item->get_formatted_meta_data( null, true ); - $data['meta_data'] = array_map( - array( $this, 'clean_formatted_meta_data' ), - $formatted_meta_data, - array_keys( $formatted_meta_data ) - ); - - return $data; - } - - /** - * Sanitizes an object from the array returned by {@link WC_Order_Item::get_formatted_meta_data} and includes - * the {@link WC_Meta_Data} `id` in the resulting array. - * - * @param Object $meta_data An object result from {@link WC_Order_Item::get_formatted_meta_data}. - * This is expected to have the properties `key`, `value`, `display_key`, and `display_value`. - * @param integer $meta_data_id The id of the {@link WC_Meta_Data}. - * @return array - */ - private function clean_formatted_meta_data( $meta_data, $meta_data_id ) { - return array( - 'id' => $meta_data_id, - 'key' => $meta_data->key, - 'value' => $meta_data->value, - 'display_key' => wc_clean( $meta_data->display_key ), - 'display_value' => wc_clean( $meta_data->display_value ), - ); - } } From d681a8c7a46a2688a2fb650adb271867b740eb58 Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 30 Jul 2020 12:34:48 -0600 Subject: [PATCH 07/18] Add unit test for an Order's line item meta data. --- .../rest-api/Tests/Version3/orders.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php index ea5768c73aa..2b1f56eb0f6 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php @@ -146,6 +146,36 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { $this->assertEquals( 401, $response->get_status() ); } + /** + * Tests line items have the expected meta_data properties when getting a single order. + */ + public function test_get_item_with_line_items_meta_data() { + wp_set_current_user( $this->user ); + + $product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product(); + $variation = wc_get_product( $product->get_children()[0] ); + + $order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order(); + $line_item = new WC_Order_Item_Product(); + $line_item->set_product( $variation ); + $order->add_item( $line_item ); + $order->save(); + + $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) ); + $data = $response->get_data(); + + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( $order->get_id(), $data['id'] ); + + $last_line_item = array_slice( $data['line_items'], -1 )[0]; + $first_meta_data = $last_line_item['meta_data'][0]; + $this->assertEquals( $line_item->get_meta_data()[0]->id, $first_meta_data['id'] ); + $this->assertEquals( 'pa_size', $first_meta_data['key'] ); + $this->assertEquals( 'size', $first_meta_data['display_key'] ); + $this->assertEquals( 'small', $first_meta_data['value'] ); + $this->assertEquals( 'small', $first_meta_data['display_value'] ); + } + /** * Tests getting an order with an invalid ID. * @since 3.5.0 From 00a5c3101eed837950796b2a9ebd17356f41dbbe Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 30 Jul 2020 15:13:34 -0600 Subject: [PATCH 08/18] WC_Tests_API_Orders: Rename first_meta_data to size_* --- .../unit-tests/rest-api/Tests/Version3/orders.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php index 2b1f56eb0f6..0eb15406d1e 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php @@ -168,12 +168,13 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { $this->assertEquals( $order->get_id(), $data['id'] ); $last_line_item = array_slice( $data['line_items'], -1 )[0]; - $first_meta_data = $last_line_item['meta_data'][0]; - $this->assertEquals( $line_item->get_meta_data()[0]->id, $first_meta_data['id'] ); - $this->assertEquals( 'pa_size', $first_meta_data['key'] ); - $this->assertEquals( 'size', $first_meta_data['display_key'] ); - $this->assertEquals( 'small', $first_meta_data['value'] ); - $this->assertEquals( 'small', $first_meta_data['display_value'] ); + + $size_meta_data = $last_line_item['meta_data'][0]; + $this->assertEquals( $line_item->get_meta_data()[0]->id, $size_meta_data['id'] ); + $this->assertEquals( 'pa_size', $size_meta_data['key'] ); + $this->assertEquals( 'size', $size_meta_data['display_key'] ); + $this->assertEquals( 'small', $size_meta_data['value'] ); + $this->assertEquals( 'small', $size_meta_data['display_value'] ); } /** From dc2a4d1ccc804469d4e5aad8565a64eeb7d44d9e Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 30 Jul 2020 15:14:08 -0600 Subject: [PATCH 09/18] WC_Tests_API_Orders: Rearrange order variable for clarity --- tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php index 0eb15406d1e..f17889ca90c 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php @@ -155,9 +155,9 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { $product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product(); $variation = wc_get_product( $product->get_children()[0] ); - $order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order(); $line_item = new WC_Order_Item_Product(); $line_item->set_product( $variation ); + $order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order(); $order->add_item( $line_item ); $order->save(); From 2a01aa968f3f97d316acadef453c59c0026b3347 Mon Sep 17 00:00:00 2001 From: Shiki Date: Thu, 30 Jul 2020 15:15:06 -0600 Subject: [PATCH 10/18] WC_Tests_API_Orders: Add test data for site-level attributes --- .../rest-api/Tests/Version3/orders.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php index f17889ca90c..f811fed0f76 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php @@ -152,11 +152,24 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { public function test_get_item_with_line_items_meta_data() { wp_set_current_user( $this->user ); + $site_level_attribute_id = wc_create_attribute( array( 'name' => 'Site Level Color' ) ); + $site_level_attribute_slug = wc_attribute_taxonomy_name_by_id( $site_level_attribute_id ); + + // Register the attribute so that wp_insert_term will be successful + register_taxonomy( $site_level_attribute_slug, array( 'product' ), array() ); + + $site_level_term_insertion_result = wp_insert_term( 'Site Level Value - Blue', $site_level_attribute_slug ); + $site_level_term = get_term( $site_level_term_insertion_result['term_id'] ); + $product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product(); $variation = wc_get_product( $product->get_children()[0] ); $line_item = new WC_Order_Item_Product(); $line_item->set_product( $variation ); + $line_item->set_props( array( + 'variation' => array( "attribute_{$site_level_attribute_slug}" => $site_level_term->slug ) + ) ); + $order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order(); $order->add_item( $line_item ); $order->save(); @@ -175,6 +188,13 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { $this->assertEquals( 'size', $size_meta_data['display_key'] ); $this->assertEquals( 'small', $size_meta_data['value'] ); $this->assertEquals( 'small', $size_meta_data['display_value'] ); + + $color_meta_data = $last_line_item['meta_data'][1]; + $this->assertEquals( $line_item->get_meta_data()[1]->id, $color_meta_data['id'] ); + $this->assertEquals( $site_level_attribute_slug, $color_meta_data['key'] ); + $this->assertEquals( 'Site Level Color', $color_meta_data['display_key'] ); + $this->assertEquals( $site_level_term->slug, $color_meta_data['value'] ); + $this->assertEquals( 'Site Level Value - Blue', $color_meta_data['display_value'] ); } /** From ad00eb3a9831487ffc058e9c52bef61fc99b896d Mon Sep 17 00:00:00 2001 From: Shiki Date: Wed, 12 Aug 2020 15:24:07 -0600 Subject: [PATCH 11/18] Add line items meta_data schema test for Orders V2 and V3 This currently fails because the expected meta_data properties are only available in V3. --- .../rest-api/Tests/Version2/orders.php | 21 +++++++++++++++++++ .../rest-api/Tests/Version3/orders.php | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version2/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version2/orders.php index e80fbab5fb8..f994fe0ffa9 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version2/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version2/orders.php @@ -718,4 +718,25 @@ class WC_Tests_API_Orders_V2 extends WC_REST_Unit_Test_Case { $this->assertEquals( 42, count( $properties ) ); $this->assertArrayHasKey( 'id', $properties ); } + + /** + * Test the order line items schema. + */ + public function test_order_line_items_schema() { + wp_set_current_user( $this->user ); + $order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order(); + $request = new WP_REST_Request( 'OPTIONS', '/wc/v2/orders/' . $order->get_id() ); + $response = $this->server->dispatch( $request ); + + $data = $response->get_data(); + + $line_item_properties = $data['schema']['properties']['line_items']['items']['properties']; + $this->assertEquals( 14, count( $line_item_properties ) ); + $this->assertArrayHasKey( 'id', $line_item_properties ); + $this->assertArrayHasKey( 'meta_data', $line_item_properties ); + + $meta_data_item_properties = $line_item_properties['meta_data']['items']['properties']; + $this->assertEquals( 5, count( $meta_data_item_properties ) ); + $this->assertEquals( [ 'id', 'key', 'value', 'display_key', 'display_value' ], array_keys( $meta_data_item_properties ) ); + } } diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php index f811fed0f76..545a100196e 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php @@ -851,4 +851,25 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { $this->assertEquals( 42, count( $properties ) ); $this->assertArrayHasKey( 'id', $properties ); } + + /** + * Test the order line items schema. + */ + public function test_order_line_items_schema() { + wp_set_current_user( $this->user ); + $order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order(); + $request = new WP_REST_Request( 'OPTIONS', '/wc/v3/orders/' . $order->get_id() ); + $response = $this->server->dispatch( $request ); + + $data = $response->get_data(); + + $line_item_properties = $data['schema']['properties']['line_items']['items']['properties']; + $this->assertEquals( 14, count( $line_item_properties ) ); + $this->assertArrayHasKey( 'id', $line_item_properties ); + $this->assertArrayHasKey( 'meta_data', $line_item_properties ); + + $meta_data_item_properties = $line_item_properties['meta_data']['items']['properties']; + $this->assertEquals( 5, count( $meta_data_item_properties ) ); + $this->assertEquals( [ 'id', 'key', 'value', 'display_key', 'display_value' ], array_keys( $meta_data_item_properties ) ); + } } From face3fe27efd23cff8e245610088516526e9ae06 Mon Sep 17 00:00:00 2001 From: Shiki Date: Wed, 12 Aug 2020 15:32:14 -0600 Subject: [PATCH 12/18] OrdersV2: Add test for line items meta_data This currently fails because it's not implemented yet. --- .../rest-api/Tests/Version2/orders.php | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version2/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version2/orders.php index f994fe0ffa9..ca214eb2a05 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version2/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version2/orders.php @@ -68,6 +68,57 @@ class WC_Tests_API_Orders_V2 extends WC_REST_Unit_Test_Case { $this->assertEquals( 401, $response->get_status() ); } + /** + * Tests line items have the expected meta_data properties when getting a single order. + */ + public function test_get_item_with_line_items_meta_data() { + wp_set_current_user( $this->user ); + + $site_level_attribute_id = wc_create_attribute( array( 'name' => 'Site Level Color' ) ); + $site_level_attribute_slug = wc_attribute_taxonomy_name_by_id( $site_level_attribute_id ); + + // Register the attribute so that wp_insert_term will be successful + register_taxonomy( $site_level_attribute_slug, array( 'product' ), array() ); + + $site_level_term_insertion_result = wp_insert_term( 'Site Level Value - Blue', $site_level_attribute_slug ); + $site_level_term = get_term( $site_level_term_insertion_result['term_id'] ); + + $product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product(); + $variation = wc_get_product( $product->get_children()[0] ); + + $line_item = new WC_Order_Item_Product(); + $line_item->set_product( $variation ); + $line_item->set_props( array( + 'variation' => array( "attribute_{$site_level_attribute_slug}" => $site_level_term->slug ) + ) ); + + $order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order(); + $order->add_item( $line_item ); + $order->save(); + + $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v2/orders/' . $order->get_id() ) ); + $data = $response->get_data(); + + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( $order->get_id(), $data['id'] ); + + $last_line_item = array_slice( $data['line_items'], -1 )[0]; + + $size_meta_data = $last_line_item['meta_data'][0]; + $this->assertEquals( $line_item->get_meta_data()[0]->id, $size_meta_data['id'] ); + $this->assertEquals( 'pa_size', $size_meta_data['key'] ); + $this->assertEquals( 'size', $size_meta_data['display_key'] ); + $this->assertEquals( 'small', $size_meta_data['value'] ); + $this->assertEquals( 'small', $size_meta_data['display_value'] ); + + $color_meta_data = $last_line_item['meta_data'][1]; + $this->assertEquals( $line_item->get_meta_data()[1]->id, $color_meta_data['id'] ); + $this->assertEquals( $site_level_attribute_slug, $color_meta_data['key'] ); + $this->assertEquals( 'Site Level Color', $color_meta_data['display_key'] ); + $this->assertEquals( $site_level_term->slug, $color_meta_data['value'] ); + $this->assertEquals( 'Site Level Value - Blue', $color_meta_data['display_value'] ); + } + /** * Tests getting a single order. * @since 3.0.0 From ecb2936f9e0ffb4933aa64a108b216fbcaa78302 Mon Sep 17 00:00:00 2001 From: Shiki Date: Wed, 12 Aug 2020 16:06:12 -0600 Subject: [PATCH 13/18] Use different terms to avoid clash with the similar V2 test I suppose I could have deleted the attribute and term first but I think this is better and shorter. Maybe. --- .../legacy/unit-tests/rest-api/Tests/Version3/orders.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php index 545a100196e..65f645beac5 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php @@ -152,13 +152,13 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { public function test_get_item_with_line_items_meta_data() { wp_set_current_user( $this->user ); - $site_level_attribute_id = wc_create_attribute( array( 'name' => 'Site Level Color' ) ); + $site_level_attribute_id = wc_create_attribute( array( 'name' => 'Site Level Type' ) ); $site_level_attribute_slug = wc_attribute_taxonomy_name_by_id( $site_level_attribute_id ); // Register the attribute so that wp_insert_term will be successful register_taxonomy( $site_level_attribute_slug, array( 'product' ), array() ); - $site_level_term_insertion_result = wp_insert_term( 'Site Level Value - Blue', $site_level_attribute_slug ); + $site_level_term_insertion_result = wp_insert_term( 'Site Level Value - Wood', $site_level_attribute_slug ); $site_level_term = get_term( $site_level_term_insertion_result['term_id'] ); $product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product(); @@ -192,9 +192,9 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { $color_meta_data = $last_line_item['meta_data'][1]; $this->assertEquals( $line_item->get_meta_data()[1]->id, $color_meta_data['id'] ); $this->assertEquals( $site_level_attribute_slug, $color_meta_data['key'] ); - $this->assertEquals( 'Site Level Color', $color_meta_data['display_key'] ); + $this->assertEquals( 'Site Level Type', $color_meta_data['display_key'] ); $this->assertEquals( $site_level_term->slug, $color_meta_data['value'] ); - $this->assertEquals( 'Site Level Value - Blue', $color_meta_data['display_value'] ); + $this->assertEquals( 'Site Level Value - Wood', $color_meta_data['display_value'] ); } /** From 64bd1e0fd5031fb7c7a380341de9ce950c7a104d Mon Sep 17 00:00:00 2001 From: Shiki Date: Tue, 1 Sep 2020 14:21:14 -0600 Subject: [PATCH 14/18] Fix formatting errors in orders.php --- .../unit-tests/rest-api/Tests/Version3/orders.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php index 65f645beac5..e84d57c30ea 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php @@ -155,7 +155,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { $site_level_attribute_id = wc_create_attribute( array( 'name' => 'Site Level Type' ) ); $site_level_attribute_slug = wc_attribute_taxonomy_name_by_id( $site_level_attribute_id ); - // Register the attribute so that wp_insert_term will be successful + // Register the attribute so that wp_insert_term will be successful. register_taxonomy( $site_level_attribute_slug, array( 'product' ), array() ); $site_level_term_insertion_result = wp_insert_term( 'Site Level Value - Wood', $site_level_attribute_slug ); @@ -166,9 +166,9 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { $line_item = new WC_Order_Item_Product(); $line_item->set_product( $variation ); - $line_item->set_props( array( - 'variation' => array( "attribute_{$site_level_attribute_slug}" => $site_level_term->slug ) - ) ); + $line_item->set_props( + array( 'variation' => array( "attribute_{$site_level_attribute_slug}" => $site_level_term->slug ) ) + ); $order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order(); $order->add_item( $line_item ); @@ -870,6 +870,6 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { $meta_data_item_properties = $line_item_properties['meta_data']['items']['properties']; $this->assertEquals( 5, count( $meta_data_item_properties ) ); - $this->assertEquals( [ 'id', 'key', 'value', 'display_key', 'display_value' ], array_keys( $meta_data_item_properties ) ); + $this->assertEquals( array( 'id', 'key', 'value', 'display_key', 'display_value' ), array_keys( $meta_data_item_properties ) ); } } From 5651befdd9bf13c36a88dde69b1c358ebd291d4b Mon Sep 17 00:00:00 2001 From: Shiki Date: Tue, 1 Sep 2020 14:22:38 -0600 Subject: [PATCH 15/18] Version3/orders.php: Remove assertion for `meta_data` The new meta_data output will include keys like `display_key` and `display_value`. The assertion will be re-added in a later commit. --- .../legacy/unit-tests/rest-api/Tests/Version3/orders.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php index e84d57c30ea..e96f887a39a 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php @@ -316,8 +316,9 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { $this->assertEquals( $order->get_shipping_country(), $data['shipping']['country'] ); $this->assertEquals( 1, count( $data['line_items'] ) ); $this->assertEquals( 1, count( $data['shipping_lines'] ) ); + $shipping = current( $order->get_items( 'shipping' ) ); - $expected = array( + $expected_shipping_line = array( 'id' => $shipping->get_id(), 'method_title' => $shipping->get_method_title(), 'method_id' => $shipping->get_method_id(), @@ -325,9 +326,10 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { 'total' => wc_format_decimal( $shipping->get_total(), '' ), 'total_tax' => wc_format_decimal( $shipping->get_total_tax(), '' ), 'taxes' => array(), - 'meta_data' => $shipping->get_meta_data(), ); - $this->assertEquals( $expected, $data['shipping_lines'][0] ); + foreach ( $expected_shipping_line as $key => $value ) { + $this->assertEquals( $value, $data['shipping_lines'][0][ $key ] ); + } } /** From d6600d8338ce801bf52c87ec085b403e57f7ade1 Mon Sep 17 00:00:00 2001 From: Shiki Date: Tue, 1 Sep 2020 14:29:38 -0600 Subject: [PATCH 16/18] Version3/orders.php: Re-add assertion for `meta_data` --- .../legacy/unit-tests/rest-api/Tests/Version3/orders.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php index e96f887a39a..ce6fee73f38 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/orders.php @@ -330,6 +330,14 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case { foreach ( $expected_shipping_line as $key => $value ) { $this->assertEquals( $value, $data['shipping_lines'][0][ $key ] ); } + + $actual_shipping_line_meta_data = $data['shipping_lines'][0]['meta_data']; + $this->assertCount( 3, $actual_shipping_line_meta_data ); + foreach ( $shipping->get_meta_data() as $index => $expected_meta_item ) { + $this->assertEquals( $expected_meta_item->id, $actual_shipping_line_meta_data[ $index ]['id'] ); + $this->assertEquals( $expected_meta_item->key, $actual_shipping_line_meta_data[ $index ]['key'] ); + $this->assertEquals( $expected_meta_item->value, $actual_shipping_line_meta_data[ $index ]['value'] ); + } } /** From 398076627ace25745fea83b9c6893c29a3925fd5 Mon Sep 17 00:00:00 2001 From: Shiki Date: Tue, 1 Sep 2020 14:37:55 -0600 Subject: [PATCH 17/18] Orders API: Fix mismatched domain error --- .../Version2/class-wc-rest-orders-v2-controller.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php b/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php index 199d294768e..2907d7a3498 100644 --- a/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php +++ b/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php @@ -1313,12 +1313,12 @@ class WC_REST_Orders_V2_Controller extends WC_REST_CRUD_Controller { 'context' => array( 'view', 'edit' ), ), 'display_key' => array( - 'description' => __( 'Meta key for UI display.', 'woocommerce-rest-api' ), + 'description' => __( 'Meta key for UI display.', 'woocommerce' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), ), 'display_value' => array( - 'description' => __( 'Meta value for UI display.', 'woocommerce-rest-api' ), + 'description' => __( 'Meta value for UI display.', 'woocommerce' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), ), From ac4cba3faba30fa58f33fd956e2a88ebcdcdb3d4 Mon Sep 17 00:00:00 2001 From: Shiki Date: Tue, 1 Sep 2020 14:38:28 -0600 Subject: [PATCH 18/18] Orders API: Fix regression in `meta_data` `display_*` values Previously, we were using the `$formatted_meta_data` to build the final array. However, this does not consider the fact that `WC_Order_Item->get_formatted_meta_data` can exclude `meta_data` from the result. There would be less `meta_data` objects return than the previous implementation. This fixes the issue by using the `$data['meta_data']` value as the main list of meta data and only using `$formatted_meta_data` to optionally apply the `display_key` and `display_value` properties. --- .../class-wc-rest-orders-v2-controller.php | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php b/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php index 2907d7a3498..cdd9f98f021 100644 --- a/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php +++ b/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php @@ -200,31 +200,41 @@ class WC_REST_Orders_V2_Controller extends WC_REST_CRUD_Controller { // Expand meta_data to include user-friendly values. $formatted_meta_data = $item->get_formatted_meta_data( null, true ); $data['meta_data'] = array_map( - array( $this, 'clean_formatted_order_item_meta_data' ), - $formatted_meta_data, - array_keys( $formatted_meta_data ) + array( $this, 'merge_meta_item_with_formatted_meta_display_attributes' ), + $data['meta_data'], + array_fill( 0, count( $data['meta_data'] ), $formatted_meta_data ) ); return $data; } /** - * Sanitizes an object from the array returned by {@link WC_Order_Item::get_formatted_meta_data} and includes - * the {@link WC_Meta_Data} `id` in the resulting array. + * Merge the `$formatted_meta_data` `display_key` and `display_value` attribute values into the corresponding + * {@link WC_Meta_Data}. Returns the merged array. + * + * @param WC_Meta_Data $meta_item An object from {@link WC_Order_Item::get_meta_data()}. + * @param Object[] $formatted_meta_data An object result from {@link WC_Order_Item::get_formatted_meta_data}. + * The keys are the IDs of {@link WC_Meta_Data}. * - * @param Object $meta_data An object result from {@link WC_Order_Item::get_formatted_meta_data}. - * This is expected to have the properties `key`, `value`, `display_key`, and `display_value`. - * @param integer $meta_data_id The id of the {@link WC_Meta_Data}. * @return array */ - private function clean_formatted_order_item_meta_data( $meta_data, $meta_data_id ) { - return array( - 'id' => $meta_data_id, - 'key' => $meta_data->key, - 'value' => $meta_data->value, - 'display_key' => wc_clean( $meta_data->display_key ), - 'display_value' => wc_clean( $meta_data->display_value ), + private function merge_meta_item_with_formatted_meta_display_attributes( $meta_item, $formatted_meta_data ) { + $result = array( + 'id' => $meta_item->id, + 'key' => $meta_item->key, + 'value' => $meta_item->value, + 'display_key' => null, + 'display_value' => null, ); + + if ( array_key_exists( $meta_item->id, $formatted_meta_data ) ) { + $formatted_meta_item = $formatted_meta_data[ $meta_item->id ]; + + $result['display_key'] = wc_clean( $formatted_meta_item->display_key ); + $result['display_value'] = wc_clean( $formatted_meta_item->display_value ); + } + + return $result; } /**