Add extra meta for orders in Woocommerce
Solution 1
The 2018 way:
Built on Guido W.P. answer you can use instead woocommerce_checkout_create_order
action hook in
a more lighter and effective version code (using WC 3+ CRUD methods):
add_action('woocommerce_checkout_create_order', 'before_checkout_create_order', 20, 2);
function before_checkout_create_order( $order, $data ) {
$order->update_meta_data( '_custom_meta_key', 'value' );
}
Code goes in function.php file of your active child theme (or active theme).
Tested and works in WooCommerce 3+ (only).
SOME EXPLANATIONS:
The woocommerce_checkout_create_order
action hook is just one step before saving the order data. See below in an extract of the WC_Checkout
create_order()
method (with both hooks):
/**
* Action hook to adjust order before save.
* @since 3.0.0
*/
do_action( 'woocommerce_checkout_create_order', $order, $data );
// Save the order.
$order_id = $order->save();
do_action( 'woocommerce_checkout_update_order_meta', $order_id, $data );
return $order_id;
Why using
woocommerce_checkout_create_order
instead?:
- Because You don't need to use
$order = wc_get_order( $order_id );
as you already got$order
as an argument in the hooked function.- You don't need to use
$order->save();
as this will be done just after anyway (see the source code)- This hook has been released since WooCommerce version 3 and it's made for the same purpose, allowing to use all available
WC_Order
methods.So this just works with a single line of code inside the function.
Solution 2
Building on Mo Saeedi answer, I believe this snippet is more in line with the new CRUD approach introduced by WooCommerce 3.0:
add_action('woocommerce_checkout_update_order_meta',function( $order_id, $posted ) {
$order = wc_get_order( $order_id );
$order->update_meta_data( 'my_custom_meta_key', 'my data' );
$order->save();
} , 10, 2);
See also this threads on the WordPress forums:
- Oh CRUD! Custom Meta to order from cart
- What is the correct way to update meta fields in Woocommerce?
Solution 3
answer is:
I should use woocommerce_checkout_update_order_meta
for add_action and also i should simply use update_post_meta()
to add extra meta to my order
function add_item_meta( $order_id ) {
//global $woocommerce;
update_post_meta( $order_id, '_has_event', 'yes' );
}
Solution 4
The 2016 way:
add_action('woocommerce_checkout_update_order_meta',function( $order_id, $posted ) {
update_post_meta( $order_id, 'my_custom_meta_key', 'my data' );
} , 10, 2);
$order_id
is the id of the order, which is stored as a custom post type$posted
is all the data from$_POST
Mo Saeedi
Updated on June 11, 2020Comments
-
Mo Saeedi almost 4 years
I'm creating a custom plugin for my website.
In some part of this plugin I need to store extra meta in
wp_postmeta
for each orders.I added this in my plugin's class:
add_action ('woocommerce_before_checkout_process', array( &$this, 'add_item_meta', 10, 2) );
And this is
add_item_meta()
function:function add_item_meta( $item_id, $values ) { wc_add_order_item_meta($item_id, '_has_event', 'yes' ); }
This function is not complete, but nothing happens with this codes; I think I need to use another hook but I can't find a proper one.
Does anyone know anything about this?
I also have another problem with
$item_id
: this is woocommerce global variable but I can't see it in my plugin!I mean I don't have access to this variable from my plugin or something like this!
-
Rodrigo Murillo almost 8 yearsWhere is that code placed in the system? In what file? Will this approach expose the custom data to the Order API call such as shop.example.com/wc-api/v3/orders/1248
-
gregdev almost 7 yearsYou can place this code straight into your theme's
functions.php
file. WooCommerce will run the function just after the order is created and saved to the database. -
Garconis over 6 yearsThoughts on how to add a custom meta field (that is assigned to the Customer/User that ordered the item) to the order meta?
-
coccoinomane over 6 yearsThat's very clever @LoicTheAztec! I have just one doubt: is it as future-proof as using
woocommerce_checkout_update_order_meta
? It seems likewoocommerce_checkout_update_order_meta
was placed there by WooCommerce devs for the specific purpose of updating order meta. I might be wrong, but using another filter for that specific purpose makes me a bit uncomfortable. -
LoicTheAztec over 6 years@GuidoWalterPettinari You can use in the same hooked function, code for different purposes, or have 2 different functions hooked in the same hook with different priorities… That is not a big deal :) … So both code works as well… The only difference is that mine is just a bit lighter than yours as I don't recall an instance of the WC_Order object and I don't need to use the save() method…
-
coccoinomane over 6 yearsHi Loic! I Your solution is indeed faster than mine, but I would not say that this is the only difference. Based on the filter name, it is likely that the WooCommerce team wants us to update order meta using the filter
woocommerce_checkout_update_order_meta
. My point is that it might be unwise to disregard that cue to gain a few milliseconds in execution time, especially because WooCommerce updates are so frequent and do not always respect backward compatibility. I am a bit paranoid, I know 😅 -
LoicTheAztec over 6 years@GuidoWalterPettinari I don't agree, because
woocommerce_checkout_create_order
is maid for CRUD setters and getters and has been released at the same time with WC 3… Before CRUD setters and getters methods (so before WooCommerce 3), the only way waswoocommerce_checkout_update_order_meta
usingupdate_post_meta()
WP functions like… So no problem, I just offer here in my answer a good alternative regarding CRUD methods usage. That's all. No big deal… -
coccoinomane over 6 yearsThanks for the clarification, @LoicTheAztec! It makes sense, let's hope the WooCommerce team clarifies this (small) issue at some point. Have a nice day, Guido
-
Reza Ramezanpour over 3 yearsPlease note that using closures for hooks is not good idea because you can't remove them later using
remove_action
. -
Petschko about 3 yearsNote you should use
new WC_Order($order_id);
these days instead ofwc_get_order