WooCommerce 2.0 renamed the order meta you were reading

WooCommerce 2.0 moved order line items out of a serialised _order_items post meta value and into two dedicated tables. Anything that read that key directly — a sales report, a CSV export, an accounting integration — returns an empty array for every order placed since the upgrade and perfectly good data for everything before it.

// 1.x: one serialised array holding every line of the order
$items = maybe_unserialize( get_post_meta( $order_id, '_order_items', true ) );

foreach ( $items as $item ) {
    echo $item['name'] . ' x ' . $item['qty'];
}

// 2.0: woocommerce_order_items + woocommerce_order_itemmeta, behind an API
$order = new WC_Order( $order_id );

foreach ( $order->get_items() as $item_id => $item ) {
    echo $item['name'] . ' x ' . $item['qty'];
    echo $order->get_item_meta( $item_id, '_product_id', true );
}

The upgrade routine migrates existing orders into the new tables, and on a store with tens of thousands of them that runs in the background over some hours — so for a while both shapes are live and a report handling only one of them looks intermittently wrong rather than plainly broken. Going through WC_Order is the version that keeps working: item meta now belongs to the line item id, not the order id, and no amount of get_post_meta() will reach it. Take the database backup before the update rather than after. The migration is one way, and there is no supported path back to the serialised form.