Have you tried called $order->get_downloadable_items() and it returns an empty array?

We had the same issue.

Are you trying to get the user downloads from a WooCommerce order?

The following code snippet is meant to be run after init or even better woocommerce_init hook.

// Blog post - https://orbisius.com/7624
$order_id = 123;

$data_store = WC_Data_Store::load( 'customer-download' );
$downloads = $data_store->get_downloads(
        'order_id' => $order_id,
        'orderby'  => 'product_id',

if (empty($downloads)) {
    echo "No download";

$cnt = 0;
$total_cnt = count($downloads);

foreach ( $downloads as $wc_custom_dl_obj ) {
    $product = wc_get_product( $wc_custom_dl_obj->get_product_id() );

    if (empty($product)) {


    echo "[$cnt / $total_cnt] processing download id: " . $wc_custom_dl_obj->get_download_id();
    $wc_prod_dl_obj = $product->get_file( $wc_custom_dl_obj->get_download_id() );

    if (empty($wc_prod_dl_obj)) {
        echo "... not found. Skipping. \n";

    echo "\n";

    $dl_id = $wc_prod_dl_obj->get_id(); // Get the product name
    $name = $wc_prod_dl_obj->get_name(); // Get the product name
    $download_url = $wc_prod_dl_obj->get_file(); // Get the download files

    $dl_rec = [ 'id' => $dl_id, 'name' => $name, 'download_url' => $download_url, ];


    echo "\n" . str_repeat('-', 50) . "\n";

We're calling unset() to free up some memory in case you have lots of downloads.

Sometimes get_file() returns null/false and this means the download wasn't found so we'll skip those records.

download id in WooCommerce is not an integer but string such as 08032b6f-0167-4615-a386-4bfb0f5a2390 generated by wp_generate_uuid4() function.

Disclaimer: The content in this post is for educational purposes only. Always remember to take a backup before doing any of the suggested steps just to be on the safe side.
Referral Note: When you purchase through an referral link (if any) on this page, we may earn a commission.
If you're feeling thankful, you can buy me a coffee or a beer