Search code examples
phpwordpresswoocommerceorderswoocommerce-subscriptions

WC_Order->get_items() returns empty items


Using the hook 'woocommerce_order_status_completed' I can get $order_id then get the WC_Order object with $order = wc_get_order($order_id). But the following $logger->add("send-order-debug", json_encode($order->get_items()) returns empty item objects

{"257":{},"258":{},"259":{}}

I have no idea why this happening because I can see from the woocommerce orders page that there are actual items inside this order. Does anyone have any idea what is going on?

My end goal is to filter out products that are of category "Subscription" but this is impossible if I can't do $item->get_product_id

function send_order($order_id) {
    $order = wc_get_order($order_id);
    $logger = wc_get_logger();
    $logger->add("send-order-debug", json_encode($order->get_items()));
}

Contents of order object: enter image description here


Solution

  • Update 1:

    You can't use json_encode() on $order->get_items() as you will always get something like "257":{} (where 257 is the item ID) for each order item. So json_encode() fails encoding each order item data located in the array of items, as order items are protected.

    Now the only way to JSON encode order items is to unprotect each order item using the WC_Data method get_data() and set it back in the order items array.

    This can be done in a compact way using array_map() with a custom function like:

    add_action( 'woocommerce_order_status_completed', 'send_order', 10, 2 );
    function send_order( $order_id, $order ) {
        // Unprotect each order item in the array of order items
        $order_items_data = array_map( function($item){ return $item->get_data(); }, $order->get_items() );
    
        $logger = wc_get_logger();
        $logger->add("send-order-debug", json_encode($order_items_data));
    }
    

    Now it works.


    Original answer:

    The WC_Order Object is already an included argument in woocommerce_order_status_completed hook, so in your code it should be:

    add_action( 'woocommerce_order_status_completed', 'send_order', 10, 2 );
    function send_order( $order_id, $order ) {
        $order_items = $order->get_items();
    }
    

    That works… see this related answers threads

    So the problem is maybe related in the way you try to send the order items using:

    $logger->add($TAG, json_encode($order->get_items()));
    

    But it's not possible to help as your code is not testable: the $logger and $TAG variables are not defined in your code.

    Now to target subscription products you will use something like:

    // Loop through order items
    foreach( $order->get_items() as $item ) {
        $product = $item->get_product(); // get the WC_Product Object
        
        // Targeting subscription products only
        if ( in_array( $product->get_type(), ['subscription', 'subscription_variation'] ) ) {
            // Do something
        }
    }