Webhooks are one of the most common ways to integrate two apps or services between each other. Basically, a webhook is a notification that a certain event was triggered. Every webhook consists of the data about the event and the URL to which the data should be sent.
Earlier, we’ve already discussed how to add custom params to WooCommerce REST API requests. Just like many other parts of WooCommerce, the WooCommerce webhooks can be customized and modified through actions and filters.
So, as you might have guessed, today, I’m going to show you how to add custom fields to WooCommerce webhooks.
Introduction
For example, if you choose the Order created topic (event), here’s a piece of the JSON code you’ll receive on your Delivery URL:
{
"id": 70,
"parent_id": 0,
"status": "processing",
"currency": "UAH",
"version": "6.5.1",
"prices_include_tax": false,
"date_created": "2022-05-24T04:23:51",
"date_modified": "2022-05-24T04:23:51",
"discount_total": "0.00",
"discount_tax": "0.00",
"shipping_total": "0.00",
"shipping_tax": "0.00",
"cart_tax": "0.00",
"total": "55.00",
"total_tax": "0.00"
...
This JSON object contains different data about the new order. And we can modify it by adding our own field here.
So, in this post, I’m going to show you how to add custom fields to the payload objects. To make this tutorial more realistic, here’s the goal we’ll try to achieve:
- We’ve got two customer groups: premium and non-premium
- In the webhook payload, I want to check if the custom is premium
- One of the ways to do this is to add a new field to the customer object
- We’re going to add the customer_is_premium field with the boolean value
- The value of the customer_is_premium field will depend on the customer’s meta field
Let’s get started!
How to modify the payload object?
There are many different ways of implementing the logic of splitting users into groups. In our case, we’ve got two groups: premium and non-premium (or regular).
Since we need this logic to demonstrate how to modify webhook payload objects, I’ll go the easiest way: we’ll work with the is_premium user meta field. This field will be boolean, so its value will be true or false.
To add custom fields to WooCommerce webhooks, we can use the woocommerce_webhook_payload filter hook. This filter’s handlers accept four parameters: the payload object, the current resource’s name, the resource’s ID, and the webhook’s ID.
However, we’ll need only two first parameters to modify webhook payloads.
We need to modify orders’ payloads, so, first of all, in our function, we need to check if the current resource is order.
add_filter( 'woocommerce_webhook_payload', 'my_woocommerce_webhook_payload', 10, 4 );
function my_woocommerce_webhook_payload( $payload, $resource, $resource_id, $id ) {
if ( $resource !== 'order' ) {
return $payload;
}
// Our logic will be here
return $payload;
}
The payload object is a regular PHP associative array, so we can easily modify it.
add_filter( 'woocommerce_webhook_payload', 'modify_order_webhook_payload', 10, 4 );
function modify_order_webhook_payload( $payload, $resource, $resource_id, $id ) {
if ( $resource !== 'order' ) {
return $payload;
}
$customer_is_premium = false;
$customer_id = (int) $payload['customer_id'];
// All guest users will have the customer_id field set to 0
if ( $customer_id > 0 ) {
$customer_is_premium = (boolean) get_user_meta( $customer_id, 'is_premium', true );
}
$payload['customer_is_premium'] = $customer_is_premium;
return $payload;
}
Now, if I check the payload of the new order, I’ll see my new field at the end of the object:
...
"_links": {
"self": [
{
"href": "https://test.com/wp-json/wc/v3/orders/81"
}
],
"collection": [
{
"href": "https://test.com/wp-json/wc/v3/orders"
}
],
"customer": [
{
"href": "https://test.com/wp-json/wc/v3/customers/1"
}
]
},
"customer_is_premium": true
}
So, I guess you get the idea: if you’ll need to modify user payloads or coupon payloads, just check the current resource and add your fields to the $payload array.
The same logic can be applied if you need to change any already existing fields.
How to add product categories to the order webhook payloads
This section was a added almost a year after this post was published. I received a lot of questions about how to add custom fields to the order line items to the order webhook payloads. So I decided to update this post with an additional code snippet that’s gonna be helpful for anyone who wants to add some more info about the order items:
add_filter( 'woocommerce_webhook_payload', 'add_categories_to_order_payload', 99, 4 );
function add_categories_to_order_payload( $payload, $resource, $resource_id, $event ) {
if ( $resource !== 'order' ) {
return $payload;
}
$line_items = $payload['line_items'];
$updated_line_items = [];
foreach ( $line_items as $line_item ) {
$product_id = $line_item['product_id'];
$product_categories = get_the_terms( $product_id, 'product_cat' );
$updated_line_item = $line_item;
if ( ! empty( $product_categories ) ) {
$category_names = wp_list_pluck( $product_categories, 'name' );
$updated_line_item['categories'] = $category_names;
} else {
$updated_line_item['categories'] = [];
}
$updated_line_items[] = $updated_line_item;
}
$payload['line_items'] = $updated_line_items;
return $payload;
}
In this specific example, we’re iterating through the line_items array and get a list of the categories of each product. I used the wp_list_pluck() function to keep only the category names in the array. However, keep in mind that the get_the_terms() function returns an array of WP_Term objects.
You can also replace the wp_list_pluck() function with the array_map() function if you prefer to use the core functions.
Summary
As you see, all you need to modify WooCommerce webhook payloads is to know the right hook 🙂
I hope you found the answers you were looking for. Otherwise, feel free to write about your issues in the comments or even contact me directly.
Don’t forget to follow me on LinkedIn to stay updated with new posts and tweets on things I learn or do.
Thank you for your attention; see you in the next one!
Thanks for the post. I’m completely new to WordPress, so I’m not entirely sure where exactly we’d place this code. Would I put this in the functions.php file?
How would I go about appending all the details of an order on order creation to a woocommerce_payment_complete payload? Thank you kindly.
Hi Alexandros! Yes, you can add this code to functions.php, or you can create a plugin (there’s a lot of tutorials on how to create your first simple plugin). About the woocommerce_payment_complete payload: it really depends on what data you need to add because “all the details” is a pretty vague description. However, my post gives a basic explanation of how to add custom fields to webhook payloads, so you can use my code to add additional fields containing the missing order’s data you need.
Thanks a bunch for the response! I’m slowly starting to get how WordPress works, and I’m honestly impressed by how much customization you can actually do. Was just having a tough time figuring out how to make modifications, but I think I’ve finally figured it out.
Thanks once again!
Thanks for this. It was really helpful.
You’re welcome; glad I could help 🙂
Hi kayart, loved your post, I have a question, what if I want to display data from the product custom attribute that can be added when editing the product in woocommerce?
Hello, Gabriel, thank you for your comment! Do you mean the regular product attributes? Or do you use some custom plugins for editable options?
The regular, I’m trying to stay away from plugins which is why I was looking for a solution for this
Got you. Well, you’ll have to write some custom code depending on what exactly you want to achieve. I don’t think that the comments section is the best place to discuss it, but feel free to email me on @kayart.dev">artemy@kayart.dev
Thanks! I sent you an email
Thank you for the post.
I have a similar problem. I create a webhook under woocommerce to send the content of an order (order.created event webhook).
The content of the json contains ll the fields of the order. I only need a subset of them because there are many fields that I do not use.
How can I filter the json to keep only some fields (id, who ordered, list of items ordered for example) and send only that to the url ?
Any tip would be useful.
Regards,
Hello Alain! In this post, I described how you can add custom fields to they $payload object by using the woocommerce_webhook_payload hook. You can use the same hook and the same object to remove the fields you don’t need. The only difference is that you need to use unset($payload[‘field_name’]) instead of creating a new one.
Thank you very much for the indication. I’ll try that!
Regards
What if I wanted use the payload to display some value from the database?
Hey Gabriel! Talking about your issue, here’s what I think:
1) First of all, you need to get an order item’s attribute value. You can use this answer from WordPress StackExchange as a reference on how to get a variation’s attribute value:
https://wordpress.stackexchange.com/a/380680/191232
2) Now, all you need to do is to use my post and add your custom field to the payload 🙂
Sorry for waiting 🙂
Thanks for the Post , I’ve a Question how to get full country name and full state name in Json response instead of country code and state code
Thanks in Advance
Hi! Take a look at this thread on StackOverflow:
https://stackoverflow.com/questions/25528454/getting-country-name-from-country-code-in-woocommerce
Thanks for the Post, But I want to change the order > list_items data with some custom data and want to fetch the product from mysql. Can you help me in how this can be done ?
Hi! You can use my post as a reference. The only difference is that I added a custom field to the payload while you’ll need to change the already existing one (or ones, depending on what exactly you want to achieve).
I have added a new column to products database and want to fetch that field, but i am not understanding how to do that nor getting any resources around it, if possible would you be able to give me small code snippet on how that can be done. Thanks!
It is a bad idea to add your custom columns to WordPress default tables. You should either create your custom table, or it’s even better to use meta fields. Unfortunately, I can’t write the code for you because I don’t have enough details to understand what data you want to fetch and what is the source of this data.
Thanks for your response, I followed your advice and created some meta fields for my use case but those fields are not present in webhook payload data, Can you help me ?
Because you need to add them to your payload
That’s what my post is about 🙂
Great post thanks!
You mention the some concepts like woocommerce_webhook_payload, resource’s ID, and the function get_user_meta()
Is there a website or documentationsite where to find more info about those concepts?
I tried the documentation site (https://woocommerce.com/documentation/) but when searching for those 3 things, the results are not very clear, and do not include those expressions at all.
Hi Felipe! Unfortunately, the WooCommerce official documentation leaves much to be desired. If you want to learn more about how exactly this hook works, the best way is to look at the source code. At least that’s how I learned about this hook.
Good news: get_user_meta() is a part of WordPress code so it’s much more well-documented. You can learn more about this function here and here.
Thanks again! Yes after looking up a bit more I found that almost everything is in WordPress documentation. add_filter, apply_filter, and most other functions are very thoroughly explained there, woocommerce is just wordpress underneath. Did not know about wp_kama, looks a nice site for checking this too. As soon as I wrap up and deliver my first freelance job (a few weeks away) I’ll drop a coffee to you.
Good luck, Felipe, and welcome to our WordPress community! 🙂
What if I want to do this for only Order update?
Hey, Thank you so much for this post.
I’m just a tiny bit stuck.
Where you used:
How would I access the product ID inside of line items?
I’ve tried various ways of
But I’m clearly not quite there.
Thanks in advance
Hi Abbi! What webhook topic (event) do you use?
Hey, I’m using the exact same one as you. 🙂
$payload[‘line_items’][0][‘product_id’] should work