Sort query loop by post view count for logged out users

The following code does the following:

  • Creates a custom field named post_views_count.
  • When a logged out visits a posts, the visit counter is incremented by 1.
  • Query loop displays most visited posts in a descending order.
  • Any posts with no visits get added to the query after the visited posts in a published date descending order.
//Record the number of post views
add_action('generate_after_do_template_part', function(){
    setPostViews(get_the_ID());
} );

function setPostViews($postID) {
    if (!is_single()) {
        return; // Abort if not a single post
    }

    // Check if user is logged in
    $user_id = get_current_user_id();
    if ($user_id != 0) {
        return; // Abort if user is logged in
    }

    $count_key = 'post_views_count';
    $count = get_post_meta($postID, $count_key, true);

    // If count is blank or not set, initialize it to 1
    if ($count === '') {
        $count = 1;
        update_post_meta($postID, $count_key, $count);
    } else {
        $count++; // Increment the count
        update_post_meta($postID, $count_key, $count);
    }
}

// Sort trending posts
function gb_query_by_views( $query_args, $attributes ) {
    if ( ! empty( $attributes['className'] ) && strpos( $attributes['className'], 'trending-articles' ) !== false ) {
        
        $custom_args = array(
            'orderby'  => array(
                'meta_value_num' => 'DESC', // Sort by views
                'date'           => 'DESC'  // Then sort by date
            ),
            'order'    => 'DESC',
            'ignore_sticky_posts' => 1, // Treat sticky posts as regular posts
            'meta_query' => array(
                'relation' => 'OR',
                array(
                    'key' => 'post_views_count',
                    'compare' => 'NOT EXISTS'
                ),
                array(
                    'key' => 'post_views_count',
                    'compare' => 'EXISTS'
                )
            )
        );
    } else {
        return $query_args;
    }
    
    // Merge the custom args into the original query args
    $merged_args = array_merge( $query_args, $custom_args );

    return $merged_args;
}
add_filter( 'generateblocks_query_loop_args', 'gb_query_by_views', 10, 2 );

Just insert the code to your child theme’s functions.php file. Insert your query loop and add the class of trending-articles to the query loop grid block.