1
votes

before WooCommerce 3.0 came out my code had worked like a charm to save custom values from the cart into the order on checkout. But since then I'm not able to create custom meta for orders.

Environment: Wordpress 4.9.4 & WooCommerce 3.3.3

Hooks

  1. add_action('woocommerce_checkout_update_order_meta', 'custom_meta_to_order', 20, 1);
  2. add_action('woocommerce_checkout_create_order', 'custom_meta_to_order', 20, 1);

The Hook number 1 is the one I tried the most, the 2 one was just an experiment with some literal changes mentioned in this topic.

Function

The following functions-code is related to hook number 1:

if (!function_exists('custom_meta_to_order')) {
    function custom_meta_to_order($order_id, $values) {
        $order = wc_get_order( $order_id );

        $order->update_meta_data('_TESTKEYstart', 'Hello');

        if (isset($values['myValue'])) {
            $myValue = $values['myValue'];
            if (!empty($myValue)) $order->update_meta_data('_myKey', $myValue);
        }

        $order->update_meta_data('_TESTKEYend', 'Bye');

        $order->save();
    }
}

I've checked also in the mySQL table table wp_woocommerce_order_itemmeta if at least the two _TESTKEY*-meta-entrys will be created (because they don't have a condition).

  • But it seems that the meta-keys and values don't getting created via this hook and function.
  • The function itself getting called, so at least the hooks itselfs are working.

So my question is: "What am I doing wrong?"

2

2 Answers

5
votes

UPDATED: There is some errors in your code…

  • Both hooks have only 1 argument (not 2, so $values doesn't exist)
  • To get your custom field you should use $_POST['myValue'] instead.
  • and other things like each hook has a different argument:
    • $order_id for woocommerce_checkout_update_order_meta
    • $order for woocommerce_checkout_create_order

Below I have replaced $_POST['myValue'] by $_POST['billing_country'] as you don't give the code for this custom checkout field…

So here are both ways:

1) The best way for me, as explained here:

if ( ! function_exists('custom_meta_to_order') ) {
    add_action( 'woocommerce_checkout_create_order', 'custom_meta_to_order', 20, 1 );
    function custom_meta_to_order( $order ) {

        $order->update_meta_data('_TESTKEYstart', 'Hello');

        if (isset($_POST['billing_country'])) {
            $myValue = $_POST['billing_country'];
            if (!empty($myValue)) $order->update_meta_data('_my_key', $myValue);
        }

        $order->update_meta_data('_TESTKEYend', 'Bye');
    }
}

Code goes in function.php file of your active child theme (or theme). Tested and works.


2) The other way:

if ( ! function_exists('custom_meta_to_order') ) {
    add_action('woocommerce_checkout_update_order_meta', 'custom_meta_to_order', 20, 1);
    function custom_meta_to_order( $order_id ) {
        // get an instance of the WC_Order object
        $order = wc_get_order( $order_id );

        $order->update_meta_data('_TESTKEYstart', 'Hello');

        if (isset($_POST['billing_country'])) {
            $myValue = $_POST['billing_country'];
            if (!empty($myValue)) $order->update_meta_data('_my_key', $myValue);
        }

        $order->update_meta_data('_TESTKEYend', 'Bye');

        // Save the order data and meta data
        $order->save();
    }
}

Code goes in function.php file of your active child theme (or theme). Tested and works.

The proof:

enter image description here

And (in database wp_postmeta table for this order ID):

enter image description here

Tested in WooCommerce version 3.3+


You can use the old way too (which works):

if ( ! function_exists('custom_meta_to_order') ) {
    add_action('woocommerce_checkout_update_order_meta', 'custom_meta_to_order', 20, 1);
    function custom_meta_to_order( $order_id ) {

        update_post_meta( $order_id, '_TESTKEYstart', 'Hello' );

        if ( isset( $_POST['billing_country'] ) ) {
            $myValue = $_POST['billing_country'];
            if (!empty($myValue)) 
                update_post_meta( $order_id, '_my_key', $myValue);
        }

        update_post_meta( $order_id, '_TESTKEYend', 'Bye');
    }
}

Code goes in function.php file of your active child theme (or theme). Tested and works.


Related: Add extra meta for orders in Woocommerce

0
votes

Because comments are really hard to read (because of to much restricted formatation), this answer is just a response to the answer from LoicTheAztec.

I wrote a longer answer but it seems gone, so I sorry now for the much shorter one!

First our misunderstanding

You understood that I would like to use custom values from products but in my case it was a little bit other. I wrote an external application which included the wp-load.php and posted then data back to the product-page into the cart.

So the problem showed up here was the attempt to write the data from the cart into the order on checkout.

Recommend ways doesn't worked at first

The recommend ways you suggested all doesn't worked. I also stripped them so much down that they have should work and just write something into the meta. I've no clue which plugin/theme-function pranked me this time here.

But I was able to solve the problem

And many more! Just because I found the blog-post where I found out in the past, how to do this and as addition to my personal luck the author wrote already the changes for WP3.0, related to this process.

Still your post helped me

The errors you showed me bugged me since then and because it was hard to follow and inspect everything with Sublime and CodeIntel (and my start with Symfony itself) I decided to buy PHPStorm which showed and allowed me to fix all of my deprecated (legacy-using) functions by updating them properly.

( Finally no more global-variables: Yay. )

I mean, showing up parameters inline and deprecation-strokes already did a great job. But a bug-free working code-intel/reference which doesn't dies on big projects is just awesome.

That's why I marked your answer now as solution, thanks. Otherwise I would have just fixed the problem maybe (thanks to the authors blog-post) but still would sit on a ticking time bomb.