Recently one of my clients asked me to display recently viewed prodcust section in the products categories and since the website is build using Elementor and didn't want to use a plugin for to achieve this I created this solution.
1. First I created a function which tracks the recently viewed product by a customer.
```php
add_action( 'template_redirect', 'track_recently_viewed_products' );
function track_recently_viewed_products() {
if ( ! is_singular( 'product' ) ) {
return;
}
global $post;
$product_id = $post->ID;
// Step 1: Generate a unique session ID and store it in a cookie if not already set
if ( empty( $_COOKIE['session_id'] ) ) {
$session_id = uniqid( 'session_', true );
setcookie( 'session_id', $session_id, time() + ( 86400 ), '/' ); //Cookie duration is one day
} else {
$session_id = $_COOKIE['session_id'];
}
if ( is_user_logged_in() ) {
// Step 2: Get the current user ID and session-specific meta key
$user_id = get_current_user_id();
$meta_key = 'recently_viewed_products_' . $session_id;
// Retrieve and update the recently viewed products for this session
$viewed_products = get_user_meta( $user_id, $meta_key, true );
if ( ! is_array( $viewed_products ) ) {
$viewed_products = array();
}
if ( ( $key = array_search( $product_id, $viewed_products ) ) !== false ) {
unset( $viewed_products[$key] );
}
$viewed_products[] = $product_id;
$viewed_products = array_slice( $viewed_products, -6 ); // Limit to 6 products
update_user_meta( $user_id, $meta_key, $viewed_products );
} else {
// Non-logged-in users use the regular cookie method
$viewed_products = ! empty( $_COOKIE['recently_viewed_products'] ) ? explode( ',', $_COOKIE['recently_viewed_products'] ) : array();
if ( ( $key = array_search( $product_id, $viewed_products ) ) !== false ) {
unset( $viewed_products[$key] );
}
$viewed_products[] = $product_id;
$viewed_products = array_slice( $viewed_products, -6 ); // Limit to 6 products
setcookie( 'recently_viewed_products', implode( ',', $viewed_products ), time() + 86400, '/' );
}
}
```
2. Than to display the recently viewed products I used the loop grid widget by Elementor (since I wanted the recently viewed products layout to be the same as the standart products layout in the categories) and added this custom query
```php
add_action( 'elementor/query/recently_viewed', function( $query ) {
if ( is_user_logged_in() ) {
// Logged-in user: get user ID and session-specific meta key
$user_id = get_current_user_id();
$session_id = $_COOKIE['session_id'] ?? '';
if ( $session_id ) {
$meta_key = 'recently_viewed_products_' . $session_id;
$viewed_product_ids = get_user_meta( $user_id, $meta_key, true );
if ( is_array( $viewed_product_ids ) && ! empty( $viewed_product_ids ) ) {
$viewed_product_ids = array_reverse( $viewed_product_ids ); // Show the most recently viewed first
} else {
$viewed_product_ids = array( 0 ); // Show no products if none viewed
}
} else {
$viewed_product_ids = array( 0 ); // No session ID, show no products
}
} else {
// Non-logged-in user: use cookie to get recently viewed products
if ( isset( $_COOKIE['recently_viewed_products'] ) ) {
$viewed_product_ids = explode( ',', $_COOKIE['recently_viewed_products'] );
$viewed_product_ids = array_reverse( $viewed_product_ids ); // Show the most recently viewed first
} else {
$viewed_product_ids = array( 0 ); // Show no products if none viewed
}
}
// Set up the query with the viewed product IDs
$query->set( 'post_type', 'product' );
$query->set( 'post__in', $viewed_product_ids );
$query->set( 'orderby', 'post__in' ); // Keep the custom order
} );
```