Back in October, we created a GitHub discussion regarding an issue with the storage of metadata concerning coupons applied to orders. The short version is that once a coupon is applied to an order, a coupon_data
metadata item is stored for the corresponding discount order line item (needed to apply the coupon again when doing recalculations on the order when the coupon no longer exists) in the wp_woocommerce_order_itemmeta
table; but that metadata item is an entire copy of the coupon object itself, which is overkill and is causing issues in sites with heavy coupon usage (the database size is growing up to unacceptable levels).
We’re glad to announce that a fix for this has been implemented and will land in WooCommerce 8.7. In this blog post, we’ll explain the changes made.
Changes to metadata storage
From now on, when a coupon is applied to an order, the corresponding line item won’t get a coupon_data
metadata item. Instead, it will get a coupon_info
item whose value is a string representing a JSON array with the following information:
- Coupon id.
- Coupon code.
- Discount type. The default value
fixed_cart
will be stored asnull
. - Nominal amount of the coupon, it’s a number that represents either a fixed amount or a percent, depending on the coupon type.
- Whether the coupon grants free shipping or not. This value is stored only if it has a value of
true
.
For example, a coupon with id 1234 and code 20off
granting a 20% discount and free shipping will get a metadata entry with this value:
[1234,"20off","percent",20,true]
while for a coupon with the same id and code, 10bucks
, granting a fixed discount of 10$/โฌ/… and no free shipping the value will be:
[1234,"10bucks",null,10]
Migrating metadata on existing orders
Coupon metadata for existing orders won’t get automatically migrated to the new format (and meta key name). If additional coupons are added to the order, these will get coupon_info
metadata entries, but existing coupon_data
for other coupons previously applied to the order won’t be touched.
If the database space taken up by existing coupon_data
entries is an issue in your site, you can use the new metadata migration tool available in the WooCommerce tools page (WooCommerce – Status – Tools):
Click the Start converting button and a background process that converts existing coupon_data
entries to simplified coupon_info
entries will be initiated. Once the process has started, the button text turns into Stop converting and, you guessed it, pressing it will stop the process (you can restart it at any time). 1000 metadata entries are converted in each iteration.
Changes in REST API
The order details REST API endpoint (/wp-json/wc/v3/orders/<order id>
) also gets changes, more precisely in the objects returned inside the array keyed as coupon_lines
:
- Since the raw existing metadata for coupon line items is returned inside the
meta_data
key, this means that you’ll getcoupon_info
entries (instead ofcoupon_data
entries) for new orders and for old orders that have got their metadata entries migrated. One of the two (but not both) will always exist for any given coupon line item. - Three new keys are added to the coupon line item object (outside of
meta_data
):discount_type
(string),nominal_amount
(float) andgrants_free_shipping
(boolean). In this way, you get basic coupon information without having to parse the metadata, be it the oldcoupon_data
or the newcoupon_info
.
Here’s an example of the information returned for an order having one coupon applied and a coupon_data
metadata entry in the corresponding coupon line item:
{
"coupon_lines": [
{
"id": 100,
"code": "20off",
"discount": "80.65",
"discount_tax": "19.36",
"meta_data": [
{
"id": 200,
"key": "coupon_data",
"value": {
"id": 300,
"code": "20off",
"amount": "20",
"status": "publish",
"discount_type": "percent",
"date_created": {
"date": "2021-03-29 10:54:30.000000",
"timezone_type": 1,
"timezone": "+00:00"
},
//...and a lot more!
}
And this is the same example, but with the line item having being created with (or having been migrated to) a coupon_info
entry:
"coupon_lines": [
{
"id": 100,
"code": "20off",
"discount": "80.65",
"discount_tax": "19.36",
"discount_type": "percent",
"nominal_amount": 20,
"free_shipping": true
"meta_data": [
{
"id": 200,
"key": "coupon_info",
"value": "[300,\"20off\",\"percent\",20,true]",
"display_key": "coupon_info",
"display_value": "[300,\"20off\",\"percent\",20,true]"
}
]
}
]
Please notice the difference betwee the nominal_amount
field (this tells the discount amount as defined in the coupon itself, and can be either a fixed monetary value or a percent) and the discount
field (this is the actual value discounted from the order, and is always a fixed monetary value).
Also note (this can be confusing) that three id
values are in play here: the id of the order line corresponding to the coupon usage (100 in the example), the id of the metadata entry created for the order line (200) and the id of the coupon itself (300).
Finally, keep in mind that as in the case of coupon_data
entries, the referenced coupon could no longer exist (a site administrator might have deleted it after it was applied to orders).
How can I tell if this affects me?
This change affects you if you have custom code that makes direct use of the old coupon_data
metadata entries, either by directly retrieving it from the database (wp_woocommerce_order_itemmeta
table) or from the order details REST API endpoint. Your code should be changed so that it’s prepared for coupon line items that have a coupon_info
entry instead of a coupon_data
entry (one of the two will always be available for any given coupon line item).
Leave a Reply