wc_get_orders() and WC_Order_Query are the correct API for querying WooCommerce orders — they respect HPOS (High-Performance Order Storage) and work whether orders are stored in custom tables or post meta. Using get_posts() or WP_Query on shop_order directly breaks on HPOS-enabled stores.
Problem: A WooCommerce plugin or theme uses get_posts() with post_type='shop_order' to query orders — but after migrating to HPOS (High-Performance Order Storage), these queries bypass the new order tables and return incorrect or empty results.
Solution: Replace all order queries with wc_get_orders() or WC_Order_Query, which abstracts the storage backend. Check HPOS compatibility by running WooCommerce → Status → Tools → Verify database. Use wc_get_order() for single order lookups instead of get_post().
The examples below demonstrate the most common query patterns — filtering by status, customer, date range, and product — and show the equivalent WP_Query that should be replaced.
'completed',
'limit' => 20,
'orderby' => 'date',
'order' => 'DESC',
'return' => 'objects', // or 'ids'
] );
// 2. Orders by a specific customer
$customer_orders = wc_get_orders( [
'customer_id' => 42,
'status' => [ 'processing', 'on-hold' ],
'limit' => -1, // all matching orders
] );
// 3. Orders in a date range
$orders_this_month = wc_get_orders( [
'date_created' => '2024-09-01...2024-09-30',
'status' => 'completed',
'limit' => -1,
] );
// 4. Orders containing a specific product (by product ID)
$orders_for_product = wc_get_orders( [
'limit' => -1,
'status' => 'completed',
'product_id' => 123,
] );
// 5. Paginated query with total count
$query = new WC_Order_Query( [
'status' => 'processing',
'limit' => 10,
'paged' => 2,
'paginate' => true, // returns object with ->orders, ->total, ->max_num_pages
] );
$result = $query->get_orders();
echo "Total processing orders: {$result->total}";
Read order data correctly via the HPOS-safe API:
post_title etc.
$order_id = $order->get_id();
$status = $order->get_status(); // without 'wc-' prefix
$total = $order->get_total();
$customer_id = $order->get_customer_id();
$customer_note = $order->get_customer_note();
$date_created = $order->get_date_created(); // WC_DateTime object
// Get order items
foreach ( $order->get_items() as $item_id => $item ) {
$product_id = $item->get_product_id();
$qty = $item->get_quantity();
$line_total = $item->get_total();
}
// Get order meta (works on both HPOS and legacy)
$tracking_number = $order->get_meta( '_tracking_number', true );
// Save meta back
$order->update_meta_data( '_tracking_number', 'TRK123456' );
$order->save();
}
// ── WRONG — breaks on HPOS stores ──
// $orders = get_posts( [ 'post_type' => 'shop_order', ... ] );
// $order_post = get_post( $order_id );
// get_post_meta( $order_id, '_billing_email', true ); // unreliable on HPOS
NOTE: Enable HPOS in WooCommerce → Settings → Advanced → Features and run the migration wizard. After migration, always audit your codebase for get_posts( ['post_type' => 'shop_order'] ) calls and replace them with wc_get_orders().