How to Display All Products Purchased by User
Before diving into this tutorial I recommend you to make a look at order items and my account menu tutorials.
And below on the screenshot you can see what we are going to create.

The code below is for your current theme functions.php
file or for your custom plugin.
/**
* @snippet Display All Products Purchased by User
* @author Misha Rudrastyh
* @link https://rudrastyh.com/woocommerce/display-purchased-products.html
*/
// here we hook the My Account menu links and add our custom one
add_filter( 'woocommerce_account_menu_items', 'misha_purchased_products_link', 40 );
function misha_purchased_products_link( $menu_links ){
// we use array_slice() because we want our link to be on the 3rd position
return array_slice( $menu_links, 0, 2, true )
+ array( 'purchased-products' => 'Purchased Products' )
+ array_slice( $menu_links, 2, NULL, true );
}
// here we register our rewrite rule
add_action( 'init', 'misha_add_products_endpoint' );
function misha_add_products_endpoint() {
add_rewrite_endpoint( 'purchased-products', EP_PAGES );
}
// here we populate the new page with the content
add_action( 'woocommerce_account_purchased-products_endpoint', 'misha_populate_products_page' );
function misha_populate_products_page() {
global $wpdb;
// this SQL query allows to get all the products purchased by the current user
// in this example we sort products by date but you can reorder them another way
$purchased_products_ids = $wpdb->get_col(
$wpdb->prepare(
"
SELECT itemmeta.meta_value
FROM " . $wpdb->prefix . "woocommerce_order_itemmeta itemmeta
INNER JOIN " . $wpdb->prefix . "woocommerce_order_items items
ON itemmeta.order_item_id = items.order_item_id
INNER JOIN $wpdb->posts orders
ON orders.ID = items.order_id
INNER JOIN $wpdb->postmeta ordermeta
ON orders.ID = ordermeta.post_id
WHERE itemmeta.meta_key = '_product_id'
AND ordermeta.meta_key = '_customer_user'
AND ordermeta.meta_value = %s
ORDER BY orders.post_date DESC
",
get_current_user_id()
)
);
// some orders may contain the same product, but we do not need it twice
$purchased_products_ids = array_unique( $purchased_products_ids );
// if the customer purchased something
if( ! empty( $purchased_products_ids ) ) {
// it is time for a regular WP_Query
$purchased_products = new WP_Query( array(
'post_type' => 'product',
'post_status' => 'publish',
'post__in' => $purchased_products_ids,
'orderby' => 'post__in',
'posts_per_page' => -1,
) );
woocommerce_product_loop_start();
while ( $purchased_products->have_posts() ) : $purchased_products->the_post();
wc_get_template_part( 'content', 'product' );
endwhile;
woocommerce_product_loop_end();
woocommerce_reset_loop();
wp_reset_postdata();
} else {
echo 'Nothing purchased yet.';
}
}
Some key points from the code above:
- You can’t access WooCommerce tables this way:
$wpdb->woocommerce_order_itemmeta
, so better use$wpdb->prefix . 'woocommerce_order_itemmeta
instead. - The
post_author
column in$wpdb->posts
table is not a customer ID, the customer IDs are stored in$wpdb->postmeta
under_customer_user
meta key. - We need the only one
_product_id
value fromwp_woocommerce_order_itemmeta
table. So$wpdb->get_col()
is pretty good for this purpose. - WooCommerce has a native function
wc_customer_bought_product( $email, $user_id, $id )
that allows to check if a customer purchased a specific product. You may think that it is OK to loop through all the products and a condition with this function inside the loop. No, it is not OK! Imagine if your WooCommerce shop has 20K products. - Keep in mind, that rewrite endpoint
purchased-products
on line 17 should be the part of the action on line 3woocommerce_account_{REWRITE ENDPOINT}_endpoint
. And do not forget to go to Settings > Permalinks and to Save Changes once you insert this code, otherwise you will get 404 error trying to access this page.
You can also add any icon to your menu element with a couple lines of CSS code, you can read more about it here.
.woocommerce-MyAccount-navigation ul li.woocommerce-MyAccount-navigation-link--purchased-products a:before{
content: "\f1b2";
}

Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
Hi!
Thanks for an excellent blog.
One question;
Is it possible to add to the code above a check of the status of the order?
Example, just to get the orders with status completed.
Hi Maria,
Just add one more condition after line 39
AND orders.post_status = 'wc-completed'
Great! Thank you!
Hi! Love the blog post, has helped so much in setting up my eCommerce store. I have added in the extra condition mentioned above, but what if I wanted to check for two different types of status’ (i.e. Completed & Processing; or Completed & On-hold)?
Hi Cole,
I am happy to hear that!
Easy peasy lemon squeezy
AND ( orders.post_status = 'wc-completed' OR orders.post_status = 'wc-processing' )
for Completed and On-hold orders:
AND ( orders.post_status = 'wc-completed' OR orders.post_status = 'wc-on-hold' )
Hello Misha
I used your code in my development site.Although I didn’t make any purchase I see all the products inside the tab.Maybe I did something wrong
Regards
Hi again!
I customized your code a little bit to see posts connected with a specific product.
But I also have the same problem like Leonidas. If I havenΒ΄t made a purchase I see all the
posts connected with the all the products. But if I purchase one product I see the correct
post connected to it.
Best regards
Hello guys,
The code in the tutorial just has been fixed π
Thank you very much!
Thanks! Very elegant way of doing this. Any thoughts on how to display ALL products a person purchased (with pagination). Thanks!
Hey,
Yes, actually we use WP_Query here, so, to make pagination, you can use any example for a custom query.
Some ideas you can find here and here.
Thanks for this very helpful post. I was wondering how to change the misha_populate_products_page() function so the page displays only products from a category example book or videos.
Hey,
Hmmm.. Try to add
tax_query
parameter to this array.Not sure if it will work with
post__in
param together but it is the easiest way to do it. Otherwise you have to modify the SQL query, there would be even more INNER JOINs and WHERE statements.If it doesn’t work for you, let me know, because I have another idea π
Hi Misha, i added ‘tax_query’ => array(), it didn’t change anything. how do i specify the particular txaonomy i want like Books category?
Thanks
Ok, I see.
There is another way to do it.
hi Misha, thanks a lot for the suggestions. it actually worked when i added
'product_cat' => 'books'
to the query array, where ‘books’ is the category slug, and then adding this code in the while loop:Thanks for sharing.
This solution is OK, unless you have 1000+ products in your online shop.
To exclude the books product category you can use this:
Hello. Can you create short codes for this feature? For example [products_user] ?
Hello,
Sure, here it is:
add_shortcode( 'products_user', 'misha_populate_products_page' );
WOW
Thank you for this tutorial.
I have learnt something new.
Just have question,
How do you add ‘pagination?’…like limit the number of products per page.
Hey,
This pagination function should help you.
..it didnt work.
It actually broke the site, so I ended up removing it..
Hmmm… It looks like I have to publish more pagination tutorials..
&,
I have something else I would like to enquire. Am sure even others may find this very helpful.
Is it possible to make ALL My Account page Menus toggleable?
I ask this cause on mobile, they show as a single list, which makes the user browsing experience ‘longer.’
Thank you for the idea!
Nope,
thank you for coding it, and thank you for your time.
Once coded, please do share the code.
I will apply it, and provide feedback.
Thank you once again..
Hello,
I just want to get total number of products client has purchased (only completed order). in out side of Woo-commerce page. Could you please help me?
Hello,
You can use
echo count( $purchased_products_ids );
I want get only Completed order, is it possible?
If you want to get completed orders only, your SQL query should like like that:
Please take a look on line 40, by the way you can also use other WooCommerce statuses like:
wc-processing
,wc-on-hold
,wc-pending
,wc-cancelled
,wc-refunded
,wc-failed
.Thank you so much for all of this. This works great on my site. I’ve added the code to enable display via shortcode.
I want to display on the “My Account” page, below the [woocommerce_my_account] information. Regardless of where I place the shortcode, the products always show up above the [woocommerce_my_account] information.
How do I change the order so the purchase products show up at the bottom of the page?
Thank you in advance.
Hey Brian,
It is because when you use a shortcode, you have to return a value, not to print it.
Is there a way to add a sorting dropdown (like in the store itself)?
Sure, it is,
But how you would like to sort products?
You can read about filters a little bit here.
I would like to sort products similar to sorting on woocommerce product archive – or at least by product name (alphabetical) and by order date (asc and desc)
By order date DESC:
ORDER BY orders.post_date DESC
By order date ASC:
ORDER BY orders.post_date ASC
If you would like to sort by product names, you can do it with the help of WP_Query parameters:
Thank you so much! Is there some easy way to have a dropdown sorting choice on the frontend?
Just HTML input
<select>
. Easy peasy πAs I am a real beginner can you give me some more advice how / where to implement it, please? I am so thankful for all your help <3
It should be inserted where you would like to display the dropdown
Very nice! I tried tried to use something similar from businessbloomer.com but it never worked (theme: storefront + PHP 7). This worked like a charm!
Thank you, I’m glad to help π
Misha, from a user perspective I have a suggestion. Currently a logged in user can view all their previously purchased products but if they want to repurchase they’ll need to click on each and every product. Could your code create form inputs similar to what’s seen on the checkout page where the user can increase/decrease the quantity for each previously purchased product then click an add to cart button? As few clicks as possible for the user will benefit the UX.
Yes, I can,
btw It would be awesome to create a tutorial for that, but I try to publish more common tuts which can help more people.
By the way, you can just add the add to cart button near the products, using this URL
?add-to-cart=PRODUCT ID
, example?add-to-cart=5
.In case you would like to add quantity, change it too
?add-to-cart=5&quantity=1
.I have used your awesome code and at first everything really worked like a charme. No I am facing a new problem. It only occurs if a customer already has purchased a lot of products. Then loading lasts really long and there is this error:
Fatal error
: Maximum execution time of 30 seconds exceeded in
/www/htdocs/w015b851/miriamkreativ.de/wp-includes/functions.php
on line
2251
Can you help me?
Hey Miriam,
Try this:
Where 10 is the number of product IDs to get.
This of course makes things faster but only shows 10 products. Is there maybe another way, some kind of pagination or so? Because this “overview” only makes sence for my customers if they can see all purchased products (im selling digital cutting files).
I recommend to integrate it with the load more solution.
Hey Misha,
what a great tutorial!
I have a little question, is it possible to create a PDF or HTML file from this recently purchased items for the customer. I mean the customer should be able to download this file as a list what he purchased before ( checklist,customer should be able to control his own inventory) and reorder it with using this checklist.
thank you in advance :)
Hey Mehmet,
Thank you ;)
Definitely, it is possible!
Thank you for your reply Misha :)
How much does it cost for me, when you script it?
Thank you :)
Could you please contact me and my team via this form and describe your task in details, we will help :)
Nice tutorial and works perfectly.
One question, please. How should be the query to display only the products from the last order?
Not all purchased products.
Thanks :)
Hi
This is great. Thank you for this code.
I have a question though. I’m testing this on a woocommerce Subscriptions site and there are a few problems.
1. When you click through to an order it doesn’t remember the state of the “Product Variation”
2. If doesn’t show active or inactive subscriptions on the product.
Could you help with this?
I would be so grateful.
Kevin
Hello,
Your code works well as well,
Just want to know how can we show only a specific category ordered products.
Thanks
Hello, we have already discussed it :)