Add extra meta for orders in Woocommerce

78,748

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:

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
Share:
78,748
Mo Saeedi
Author by

Mo Saeedi

Updated on June 11, 2020

Comments

  • Mo Saeedi
    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
    Rodrigo Murillo almost 8 years
    Where 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
    gregdev almost 7 years
    You 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
    Garconis over 6 years
    Thoughts on how to add a custom meta field (that is assigned to the Customer/User that ordered the item) to the order meta?
  • coccoinomane
    coccoinomane over 6 years
    That's very clever @LoicTheAztec! I have just one doubt: is it as future-proof as using woocommerce_checkout_update_order_meta? It seems like woocommerce_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
    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
    coccoinomane over 6 years
    Hi 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
    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 was woocommerce_checkout_update_order_meta using update_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
    coccoinomane over 6 years
    Thanks 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
    Reza Ramezanpour over 3 years
    Please note that using closures for hooks is not good idea because you can't remove them later using remove_action.
  • Petschko
    Petschko about 3 years
    Note you should use new WC_Order($order_id); these days instead of wc_get_order