Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Conversation

@shiki
Copy link

@shiki shiki commented Jul 31, 2020

Fixes #9.

Ref: p91TBi-2Lt-p2

This will also allow us to fix these issues for the WooCommerce iOS and Android apps:

Background

For both the iOS and Android apps, we regularly receive feedback from users that they could not view the details of the variable products in the orders. Example: C013AAPA4G0-p1596070344020400-slack. To find a solution, @AmandaRiu investigated what the iOS and Android apps can do using the REST API and posted her findings at p91TBi-2Lt-p2.

The apps use the line_items name in the GET /v3/orders response. However, the name does not include all the selected variations. Consider an order for a variable product with color "Blue" and size "Medium". The API endpoint would return something like this (simplified result):

    "line_items": [
        {
            "id": 5,
            "name": "Variable Hoodie - Blue",

            "meta_data": [
                {
                    "id": 51,
                    "key": "pa_store-level-size",
                    "value": "medium",
                },
                {
                    "id": 52,
                    "key": "product-level-color",
                    "value": "Blue",
                },
            ],
    
        }

As shown above, the size was not included in the name. This is how it would look like in the iOS app:

WCAdmin shows the attribute that was omitted:

Why Not Use Metadata?

We could use the meta_data array to find the missing attributes. However, this may be unreliable because:

  • We have to analyze name to figure out which attribute is already filled in. This can include finding the dash separator, which I think can be customized too.
  • The value in meta_data is the sanitized value. In the example above, "medium" should be "Medium" (capital M).

Solution

The name not showing all the attributes is probably attributed to the generate_product_title function in WooCommerce. It's probably possible to solve the issue by making sure that all attributes are included. However, this won't solve one of our other design requirements (woocommerce/woocommerce-ios#2280) which is to present the attributes separately:

We would still have to do a string operation to split out the attribute values.

In this PR, I'm proposing adding the displayable attribute name and values in the meta_data instead:

    "line_items": [
        {
            "id": 5,
            "name": "Variable Hoodie - Blue",

            "meta_data": [
                {
                    "id": 51,
                    "key": "pa_store-level-size",
                    "value": "medium",
                    "display_key": "Store Level Size",
                    "display_value": "Medium"
                },
                {
                    "id": 52,
                    "key": "product-level-color",
                    "value": "Blue",
                    "display_key": "Product Level Color",
                    "display_value": "Blue"
                },
            ],
    
        }

With these available properties, the API clients (e.g. iOS and Android apps) would be able to easily decide how to present the attributes.

There is still the problem with the name possibly showing one of the attributes. I'm planning to submit another PR to fix that after this one.

Schema

I added the new properties above in the schema.

                            "meta_data": {
                                "description": "Meta data.",
                                "type": "array",
                                "context": [
                                    "view",
                                    "edit"
                                ],
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "id": {
                                            "description": "Meta ID.",
                                            "type": "integer",
                                            "context": [
                                                "view",
                                                "edit"
                                            ],
                                            "readonly": true
                                        },
                                        "key": {
                                            "description": "Meta key.",
                                            "type": "string",
                                            "context": [
                                                "view",
                                                "edit"
                                            ]
                                        },
                                        "value": {
                                            "description": "Meta value.",
                                            "type": "mixed",
                                            "context": [
                                                "view",
                                                "edit"
                                            ]
                                        },
                                        "display_key": {
                                            "description": "Meta key for UI display.",
                                            "type": "string",
                                            "context": [
                                                "view",
                                                "edit"
                                            ]
                                        },
                                        "display_value": {
                                            "description": "Meta value for UI display.",
                                            "type": "string",
                                            "context": [
                                                "view",
                                                "edit"
                                            ]
                                        }
                                    }
                                }
                            },

Changes

These new properties are only applied to Orders API V3 since we are hoping to get fixed in the mobile apps soon. I did this by overriding the get_order_item_data in Controllers\Version3\ WC_REST_Orders_Controller.

Please let me know if I should include this in V4 as well.

Testing

This is just a suggestion but please feel free to test other scenarios. 🙂

  1. In wp-admin → Products → Attributes, add a new attribute and add terms to that attribute.
  2. Add a new Variable product in wp-admin → Products → Add New.
  3. Set this product as Variable.
  4. In the product's Attributes section, add the attribute created in Step 1. Set this as "Used for variations". Add values.
  5. Add a Custom product attribute. Set this as "Used for variations". Add values.
  6. Save the attributes.
  7. In the product's Variations section, create variations for all the options. Or create a few variations only.
  8. Set prices for all the variations.
  9. Publish the product.
  10. As a customer, place an order of the created Variable product. Make note of the Order ID.
  11. In the API, run GET /wp-json/wc/v3/orders/{OrderID}.
  12. Confirm that the line_items meta_data has the display_key and display_value properties and they are correct.

Unit Test

I have also added a unit test that I think covers the manual testing scenario above.

@peterfabian
Copy link
Contributor

peterfabian commented Aug 4, 2020

Thanks for creating the PR, great job (the description is 🥇 )!

cc @vedanshujain as we're going to move the API to the core repo (woocommerce/woocommerce#27100), so we might need to move this one over to the woo/woo repo.

@shiki
Copy link
Author

shiki commented Aug 4, 2020

Hi @peterfabian! Thank you. 🙇

I didn't know that we were merging this back into Core. 😱 Should I wait until woocommerce/woocommerce#27100 is merged then and submit the PR in Core?

Copy link
Contributor

@vedanshujain vedanshujain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! For showing display_value, instead of getting term name by slug, I would recommend using the get_formatted_meta_data function instead because it takes care of any custom filter that someone may have added as well.
So this function is defined for WC_Order_Item and the best place to call this is probably in src/Controllers/Version2/class-wc-rest-orders-v2-controller.php in method get_order_item_data.

You can probably test out with adding this line: $data['formatted_meta_data'] = $item->get_formatted_meta_data(); inside get_order_item_data but there will be some logic foo needed to merge it in the appropriate meta fields.


$schema['properties']['coupon_lines']['items']['properties']['discount']['readonly'] = true;

$meta_data_item_properties_ref = &$schema['properties']['line_items']['items']['properties']['meta_data']['items']['properties'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we can add these additional fields for both V2 and V3

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! With the recent commits, these fields are now available for both V2 and V3.

@vedanshujain
Copy link
Contributor

Also, don't worry about opening the API core, I will move when the PR is approved and ready to be merged 👍

shiki added 7 commits August 12, 2020 14:58
Previously, I was using my own function. This time, we're using the function
available in WC_Order_Item but sanitizing the results after.
This currently fails because the expected meta_data properties are only
available in V3.
This is just the schema and the actual functionality isn't implemented yet.
This currently fails because it's not implemented yet.
This resolves the intentionally failing
WC_Tests_API_Orders_V2::test_get_item_with_line_items_meta_data.
I suppose I could have deleted the attribute and term first but I think
this is better and shorter. Maybe.
Copy link
Author

@shiki shiki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for reviewing this, @vedanshujain! 🙇

I would recommend using the get_formatted_meta_data function instead because it takes care of any custom filter that someone may have added as well.

✅ Done.

Thanks for the nudge. I think the reason why I avoided that initially was because it returned HTML entities for display_key and display_value. This wasn't ideal for our use case.

But looking at it again today, I found that I could use the wc_clean function to remove the HTML. So, in commit 4b4bb97, I changed it so that the WC_Order_Item->get_formatted_meta_data function is used. And then I used wc_clean to clear the HTML elements.

Please let me know if there's a better way to do this though. 🙂

Also, don't worry about opening the API core, I will move when the PR is approved and ready to be merged 👍

Thank you!


This is now ready for another look, @vedanshujain! 🙏


$schema['properties']['coupon_lines']['items']['properties']['discount']['readonly'] = true;

$meta_data_item_properties_ref = &$schema['properties']['line_items']['items']['properties']['meta_data']['items']['properties'];
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! With the recent commits, these fields are now available for both V2 and V3.

@vedanshujain
Copy link
Contributor

Looks good and testing well, I am going to move this in a PR in core repo and close this PR.

@shiki
Copy link
Author

shiki commented Aug 26, 2020

Thank you, @vedanshujain! 🙏

@vedanshujain
Copy link
Contributor

Closing in favor of woocommerce/woocommerce#27492

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Display all variation attributes in orders endpoint

3 participants