Search code examples
phpwordpresswoocommercedownloadhook-woocommerce

How to display WooCommerce downloads table using PHP code or Shotcode


I'm trying to display woocommerce download table on the dashboard endpoint. After studying the woocommerce download endpoint file i notice woocommerce uses the below code to display the download table;

$downloads     = WC()->customer->get_downloadable_products();
$has_downloads = (bool) $downloads;

do_action( 'woocommerce_before_account_downloads', $has_downloads ); ?>

<?php if ( $has_downloads ) : ?>

    <?php do_action( 'woocommerce_before_available_downloads' ); ?>

    <?php do_action( 'woocommerce_available_downloads', $downloads ); ?>

    <?php do_action( 'woocommerce_after_available_downloads' ); ?>

<?php else : ?>
    <div class="woocommerce-Message woocommerce-Message--info woocommerce-info">
        <a class="woocommerce-Button button" href="<?php echo esc_url( apply_filters( 'woocommerce_return_to_shop_redirect', wc_get_page_permalink( 'shop' ) ) ); ?>">
            <?php esc_html_e( 'Go shop', 'woocommerce' ); ?>
        </a>
        <?php esc_html_e( 'No downloads available yet.', 'woocommerce' ); ?>
    </div>
<?php endif; ?>

<?php do_action( 'woocommerce_after_account_downloads', $has_downloads ); ?>

what I want to achieve is to display the 5 latest downloads in table format. will like to know how to limit this action <?php do_action( 'woocommerce_available_downloads', $downloads ); ?> to only display the latest 5 downloads.

UPDATE

This is the download table in the Woocommerce Download Endpoint Page enter image description here

in which I want to display the same exact table structure on the dashboard endpoint page

enter image description here


Solution

  • You can use 2 ways:

    Option 1 - Using a filter hook (filtering on a specific endpoint):

    The filter woocommerce_customer_get_downloadable_products is located inside the code from WC_CUstomer get_downloadable_products() method.

    The following will give you the 5 latest downloads in a specific endpoint (Here on My Account > downloads endpoint):

    add_filter( 'woocommerce_customer_get_downloadable_products', 'filter_customer_downloadable_products', 10, 1 );
    function filter_customer_downloadable_products( $downloads ) {
        $limit = 5; // Number of downloads to keep
    
        // Only on My account Downloads section for more than 5 downloads
        if( is_wc_endpoint_url( 'downloads' ) && sizeof($downloads) > $limit ) {
            $keys_by_order_id = $sorted_downloads = array();
            $count = 0;
    
            // Loop through the downloads array
            foreach( $downloads as $key => $download ) {
                // Store the array key with the order ID
                $keys_by_order_id[$key] = $download['order_id']; 
            }
    
            // Sorting the array by Order Ids in DESC order
            arsort($keys_by_order_id); 
    
            // Loop through the sorted array
            foreach( $keys_by_order_id as $key => $order_id ) {
                // Set the corresponding  download in a new array (sorted)
                $sorted_downloads[] = $downloads[$key];
                $count++; // Increase the count
                // When the count reaches the limit
                if( $count === $limit ) {
                    break; // We stop the loop
                }
            }
            return $sorted_downloads;
        }
        return $downloads;
    }
    

    Code goes in function.php file of your active child theme (or active theme). Tested and works.


    Option 2 - Using a custom function that filters:

    Just use this function, to get from customer $downloads variable the latest 5 downloads.

    It can be used anywhere.

    function get_customer_latest_downloads( $downloads, $limit = 5 ) {
        // Only on my account pages for more than 5 downloads
        if( sizeof($downloads) > $limit ) {
            $keys_by_order_id = $sorted_downloads = array();
            $count = 0;
    
            // Loop through the downloads array
            foreach( $downloads as $key => $download ) {
                // Store the array key with the order ID
                $keys_by_order_id[$key] = $download['order_id']; 
            }
    
            // Sorting the array by Order Ids in DESC order
            arsort($keys_by_order_id); 
    
            // Loop through the sorted array
            foreach( $keys_by_order_id as $key => $order_id ) {
                // Set the corresponding  download in a new array (sorted)
                $sorted_downloads[] = $downloads[$key];
                $count++; // Increase the count
                // When the count reaches the limit
                if( $count === $limit ) {
                    break; // We stop the loop
                }
            }
            return $sorted_downloads;
        }
        return $downloads;
    }
    

    Code goes in function.php file of your active child theme (or active theme). Tested and works.

    USAGE Example (in a template or a shortcode):

    $downloads     = WC()->customer->get_downloadable_products();
    
    $downloads     = get_customer_latest_downloads( $downloads ); // The 5 latest downloads
    
    // Testing the array raw output
    echo '<pre>'; print_r($downloads); echo '</pre>';
    

    Note: Action hooks doesn't filter data.