Recently Viewed Posts Bricks Query Loop

Updated on 6 Mar 2024

This Pro tutorial provides the steps to output the most recent x number of posts (can be of any specified post type) viewed by the current visitor (need not be logged-in) in a Bricks query loop.

We shall use cookies to track the posts viewed. If you have a GDPR cookie notice in place and the user has yet to agree to store the cookies on their computer, this solution won’t work. In such a case, there will be simply no output.

Update 1: Added instructions for showing the recently viewed products.

Step 1

Add the following in child theme‘s functions.php (w/o the opening PHP tag) or a code snippets plugin:

<?php 

add_action( 'template_redirect', function () {
    // Check if the current page is a single post
    if ( ! is_singular( 'post' ) ) {
        return;
    }
    
    // Get the current post ID
    $post_id = get_the_ID();

    // Empty array to store the recently viewed posts
    $recently_viewed = [];

    // If the 'recently_viewed' cookie is set
    if ( isset( $_COOKIE['recently_viewed'] ) ) {
        // Decode the JSON-encoded 'recently_viewed' cookie, removing any slashes added by WordPress for security, and convert it to an array.
        $recently_viewed = json_decode( wp_unslash( $_COOKIE['recently_viewed'] ), true );
    }

    // Prepend the current post ID to the recently viewed posts array
    array_unshift( $recently_viewed, $post_id );

    // Remove duplicates
    $recently_viewed = array_unique( $recently_viewed );

    // Limit the array size to 5 posts
    $recently_viewed = array_slice( $recently_viewed, 0, 5 );

    // Set or update the cookie with the new list
    // This line sets a cookie named 'recently_viewed' with the JSON-encoded array of recently viewed post IDs, 
    // expires in 7 days, and is available across the entire domain. It also sets the cookie to secure if the site is accessed via HTTPS.
    setcookie( 'recently_viewed', json_encode( $recently_viewed ), time() + 3600 * 24 * 7, COOKIEPATH, COOKIE_DOMAIN, is_ssl() );
} );

// Function to check if a given cookie is set
function bl_is_cookie_set( $cookie_name ): string {
    return isset( $_COOKIE[$cookie_name] );
}

Set your desired post type in if ( ! is_singular( 'post' ) ) {.

Replace 5 with the number of desired posts that should be shown.

Step 2

Set up a query loop in a Template/Page where you’d like to output the 5 most posts that the visitor has recently viewed.

Enable PHP query editor and paste:

return [
	'post_type' => 'post', // your post type here
	'posts_per_page' => 5, // posts per page here
	'no_found_rows' => true,
	'post__in' => json_decode( wp_unslash( $_COOKIE['recently_viewed'] ), true ),
	'orderby' => 'post__in',
];

Select the Section (or any other element of your choice) that should be output only if there is at least 1 post in the recently viewed cookie for the current visitor.

Apply this dynamic data condition:

{echo:bl_is_cookie_set(recently_viewed)}

Note: If a post page is open the first time it is considered a view. If the user leaves this post open in a tab, visits another page in the site, and returns to the post, it does not count as a view. For it to be considered a view, it must be reloaded.

Update 1

For showing recently viewed products

If you use a query loop change

if ( ! is_singular( 'post' ) ) {

to

if ( ! is_singular( 'product' ) ) {

If you use a Products element, add this code:

add_filter( 'bricks/posts/query_vars', function( $query_vars, $settings, $element_id ) {
    if ( $element_id === 'kgwlzp' ) {
        $query_vars['no_found_rows'] = true;
        $query_vars['post__in'] = json_decode( wp_unslash( $_COOKIE['recently_viewed'] ), true );
        $query_vars['orderby'] = 'post__in';
    }

    return $query_vars;
}, 10, 3 );

Replace kgwlzp with the Bricks ID of the query loop-enabled element.