0

I have this code, its function is to add a column in woocommerce order details email template, but when I send an invoice I get this error message saying:

Fatal error: Uncaught Error: Call to a member function get() on null in http:\mysite.com\functions.php on line 1245

when using this code:

add_action( 'woocommerce_order_item_meta_end', 'order_custom_field_in_item_meta_end', 10, 4 );
function order_custom_field_in_item_meta_end( $item_id, $item, $order, $cart_item) {
    global $woocommerce;

    do_action( 'woocommerce_review_order_before_cart_contents' );

    foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
        $_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );

        if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_checkout_cart_item_visible', true, $cart_item, $cart_item_key ) ) {
            echo '<td class="td">'.$_product->get_price_html().'</td>';
        }
    }

    do_action( 'woocommerce_review_order_after_cart_contents' );

}

This is the result of the email template, I used a plugin called woocommerce email test

My problem here, is that when I send an invoice or any other email notification from the order it gets an error.

What I am doing wrong and how to solve this?

Thanks

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Francis Alvin Tan
  • 1,057
  • 3
  • 21
  • 42

2 Answers2

1

Sorry but you can't use WC()->cart object for the orders or emails as the cart is already processed in checkout and emptied. Instead you can use the variable arguments that your function has when hooked in woocommerce_order_item_meta_end, which are $item_id, $item, $order and $plain_text

You don't need any foreach loop here to get the order items data as you can use directly $item argument to get the ID of your product.

Here is the right code that will work with simple or variable products as well (but see at the end):

add_action( 'woocommerce_order_item_meta_end', 'order_custom_field_in_item_meta_end', 10, 4 );
function order_custom_field_in_item_meta_end( $item_id, $item, $order, $plain_text ) {

    do_action( 'woocommerce_review_order_before_cart_contents' );

    if( $item['variation_id'] > 0 ){
        $product = wc_get_product($item['variation_id']); // variable product
    } else {
        $product = wc_get_product($item['product_id']); // simple product 
    }

    // Be sure to have the corresponding "Cost each" column before using <td> tag
    echo '<td class="td">'.$product->get_price_html().'</td>';

    do_action( 'woocommerce_review_order_after_cart_contents' );

}

You can't use a html <td> tag if your "Cost each" column haven't been created (or defined) before.

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

The code is tested and works.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
0

The problem is that the action woocommerce_order_item_meta_end is get triggered only after placing the order. so that the scope of the WC()->cart is not exists inside your code snippet.

You can use $order->get_items() to get order items.

Please modify your code this way to make it work

add_action( 'woocommerce_order_item_meta_end', 'order_custom_field_in_item_meta_end', 10, 4 );
function order_custom_field_in_item_meta_end( $item_id, $item, $order) {
    do_action( 'woocommerce_review_order_before_cart_contents' );

    foreach ( $order->get_items() as $cart_item_key => $cart_item ) {
        // Do something here
    }

    do_action( 'woocommerce_review_order_after_cart_contents' );

}
Nishad Up
  • 3,457
  • 1
  • 28
  • 32