Home » Php » php – WooCommerce Display Purchased Items Only

php – WooCommerce Display Purchased Items Only

Posted by: admin July 12, 2020 Leave a comment

Questions:

So I have done a bunch of looking around the web and couldn’t find a solution for this…

Basically what I am trying to do is display a product loop of all the products the user has purchased in the store just like displaying normal products.

If you still don’t understand maybe this will help you get what I mean..

Here is the example product loop on the WooCommerce documentation…

<ul class="products">
    <?php
        $args = array(
            'post_type' => 'product',
            'posts_per_page' => 12
            );
        $loop = new WP_Query( $args );
        if ( $loop->have_posts() ) {
            while ( $loop->have_posts() ) : $loop->the_post();
                woocommerce_get_template_part( 'content', 'product' );
            endwhile;
        } else {
            echo __( 'No products found' );
        }
        wp_reset_postdata();
    ?>
</ul><!--/.products-->

So what if I wanted to display basically this same exact product loop however filter it out so that it only displays products that the user has already purchased.

I honestly do not know where to go with this one and I am sure there are others that have done research on this in the past so maybe this will help out a bunch of people!

Thanks in advance!

How to&Answers:

There are at least two different approaches you can take to solve this problem.

The first is to get the product from each post, and then get the product ID from each product and then use an if statement to filter using wc_customer_bought_product or woocommerce_customer_bought_product (if you are using old WooCommerece).

The second is to pass the correct arguments to filter the WP_Query to only include orders purchased by a user and then filter products only in those orders. More information on the second approach is available at Get All User Orders and Products bought by user in WooCommerce based shop (archive.org).

An example of the first approach is something like

<!-- code started -->

<ul class="products">
    <?php
        $user_id = get_current_user_id();
        $current_user= wp_get_current_user();
        $customer_email = $current_user->email;
        $args = array(
            'post_type' => 'product',
            'posts_per_page' => 12
            );
        $loop = new WP_Query( $args );
        if ( $loop->have_posts() ) {
            while ( $loop->have_posts() ) : $loop->the_post(); $_product = get_product( $loop->post->ID );
            if (wc_customer_bought_product($customer_email, $user_id,$_product->id)){
                woocommerce_get_template_part( 'content', 'product' );
            }
            endwhile;
        } else {
            echo __( 'No products found' );
        }
        wp_reset_postdata();
    ?>
</ul><!--/.products-->

Answer:

Kudos to Appleman1234 for providing two answers, both of which will work.

ApppleMan1234’s first answer that he provided an example for is to loop through all products and then filter them by calling wc_customer_bought_product(). This certainly will work. If you have n products then you are going to make n+1 database queries.

His second suggestion is a link to a post written by Brajesh Singh who, on June 2, 2013, published a solution on fusedpress.com. The original post is no longer available. I found a cached copy at Google.

Brajesh Singh’s solution queries the user’s orders, then queries the order details, and last queries the product id in the order item’s metadata. This solution then is always only 3 queries. Unless your shop only has 1 or 2 products, this solution is far better.

Here is a slightly edited version of Brajesh Singh’s code.

/**
 * Get all Products Successfully Ordered by the user
 * @return bool|array false if no products otherwise array of product ids
 */
function so28362162_get_all_products_ordered_by_user() {
    $orders = so28362162_get_all_user_orders(get_current_user_id(), 'completed');
    if(empty($orders)) {
        return false;
    }
    $order_list = '(' . join(',', $orders) . ')';//let us make a list for query
    //so, we have all the orders made by this user that were completed.
    //we need to find the products in these orders and make sure they are downloadable.
    global $wpdb;
    $query_select_order_items = "SELECT order_item_id as id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id IN {$order_list}";
    $query_select_product_ids = "SELECT meta_value as product_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_key=%s AND order_item_id IN ($query_select_order_items)";
    $products = $wpdb->get_col($wpdb->prepare($query_select_product_ids, '_product_id'));
    return $products;
}

/**
 * Returns all the orders made by the user
 * @param int $user_id
 * @param string $status (completed|processing|canceled|on-hold etc)
 * @return array of order ids
 */
function so28362162_get_all_user_orders($user_id, $status = 'completed') {
    if(!$user_id) {
        return false;
    }
    $args = array(
        'numberposts' => -1,
        'meta_key' => '_customer_user',
        'meta_value' => $user_id,
        'post_type' => 'shop_order',
        'post_status' => 'publish',
        'tax_query' => array(
            array(
                'taxonomy' => 'shop_order_status',
                'field' => 'slug',
                'terms' => $status
            )
        )
    );
    $posts = get_posts($args);
    //get the post ids as order ids
    return wp_list_pluck($posts, 'ID');
}

Combining that with a product loop from the question, plus a non-deprecated wc_get_template_part() and an addition of posts_per_page=-1 gives us

<ul class="products">
        <?php
        $args = array(
            'post_type' => 'product',
            'post__in' => so28362162_get_all_products_ordered_by_user(),
            'posts_per_page' => -1
        );
        $loop = new WP_Query($args);
        if($loop->have_posts()) {
            while($loop->have_posts()) : $loop->the_post();
                wc_get_template_part('content', 'product');
            endwhile;
        }
        else {
            echo __('No products found');
        }
        wp_reset_postdata();
        ?>
    </ul><!--/.products-->

Answer:

Not sure if this helps you out at all, but there is a plugin developed by WooThemes to support purchase history.