34

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!

svelandiag
  • 4,231
  • 1
  • 36
  • 72
Mo Saeedi
  • 575
  • 1
  • 5
  • 15

4 Answers4

60

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.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • 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. – coccoinomane Feb 01 '18 at 17:58
  • @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… – LoicTheAztec Feb 01 '18 at 18:13
  • 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 – coccoinomane Feb 02 '18 at 17:44
  • 1
    @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… – LoicTheAztec Feb 02 '18 at 18:37
  • 1
    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 – coccoinomane Feb 05 '18 at 11:04
31

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:

coccoinomane
  • 858
  • 8
  • 24
6

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' );
        } 
Mo Saeedi
  • 575
  • 1
  • 5
  • 15
5

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
Sorin C
  • 984
  • 10
  • 8
  • 1
    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 https://shop.example.com/wc-api/v3/orders/1248 – Rodrigo Murillo Jul 09 '16 at 21:00
  • 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. – gregdev May 15 '17 at 23:24