The correct way to Display recently purchased Products in Member’s area

Before implementing this tutorial I recommend to make a look at Order Items tutorial and My account menu tutorial. And this is what we are going to create.

Display customer purchased products on the My Account page in WooCommerce.
Customers can easily find the products purchased before and… purchase them again πŸ™‚

Ok, now I’m going to do some stuff with $wpdb and WP_Query but before implementing the code, please read these key points.

The code below is for you custom (child) theme functions.php file or for your custom plugin.

add_filter ( 'woocommerce_account_menu_items', 'misha_purchased_products_link', 40 );
add_action( 'init', 'misha_add_products_endpoint' );
add_action( 'woocommerce_account_purchased-products_endpoint', 'misha_populate_products_page' );

// here we hook the My Account menu links and add our custom one
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
function misha_add_products_endpoint() {
	add_rewrite_endpoint( 'purchased-products', EP_PAGES );

// here we populate the new page with the content
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
	) );

	// 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'
		) );
		echo '
'; 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(); echo '
'; else: echo 'Nothing purchased yet.'; endif; }

You can add any icon to your menu element with a couple lines of CSS code, you can read more about it here.

body.woocommerce-account ul li.woocommerce-MyAccount-navigation-link--purchased-products a:before{
	content: "\f1b2";

Remember that you can always suggest me the ideas πŸ’‘ for the new tutorials on the contact me page.

Misha Rudrastyh

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

Follow me on Twitter