woocommerce / woocommerce-rest-api

This is the WooCommerce core REST API Package. It runs standalone as a feature plugin too.
70 stars 46 forks source link

Add User-friendly Attribute Names and Values to Order Line Items Metadata #229

Closed shiki closed 4 years ago

shiki commented 4 years ago

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:

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 (https://github.com/woocommerce/woocommerce-ios/issues/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 commented 4 years ago

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

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

shiki commented 4 years ago

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?

vedanshujain commented 4 years ago

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

vedanshujain commented 4 years ago

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

shiki commented 4 years ago

Thank you, @vedanshujain! 🙏

vedanshujain commented 4 years ago

Closing in favor of https://github.com/woocommerce/woocommerce/pull/27492