Show Trending Posts by Views Count using Custom Query In Elementor

Elementor PHP July 24, 2026

Quick answer: To show trending posts by real view count in Elementor, count views into a post-meta field with a small AJAX counter, then point an Elementor Posts widget at a custom query that orders by that field. Set the widget’s Query ID to popular_posts_filter and it sorts most-viewed first.

How it works

WordPress has no built-in view counter, so this adds a lightweight one: a tiny script pings admin-ajax.php once per visitor (tracked in the browser’s localStorage so refreshes do not inflate the count), and the server stores the running total in a post_views_count meta field. A query filter then tells any Elementor Posts widget to order by that field, and a shortcode lets you display the number anywhere.

The code

Add it as one PHP snippet. It gives you three things: the counter, the Elementor query filter (popular_posts_filter), and a [post_views_count] shortcode.

<?php
// 1. Count a view once per visitor, via a tiny AJAX ping in the footer.
function hmwp_enqueue_view_counter() {
    if ( ! is_singular( 'post' ) ) {
        return;
    }
    ?>
    <script type="text/javascript">
    window.addEventListener("load", function () {
        const postId  = <?php echo (int) get_the_ID(); ?>;
        const ajaxUrl = '<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>';
        if ( ! localStorage.getItem( 'post_viewed_' + postId ) ) {
            fetch( ajaxUrl, {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
                body: new URLSearchParams( { action: 'track_post_views', post_id: postId } )
            } ).then( function ( r ) {
                if ( r.ok ) {
                    localStorage.setItem( 'post_viewed_' + postId, 'true' );
                }
            } );
        }
    });
    </script>
    <?php
}
add_action( 'wp_footer', 'hmwp_enqueue_view_counter', 100 );

// 2. Store the incremented count in post meta.
function hmwp_track_post_views() {
    if ( isset( $_POST['post_id'] ) ) {
        $post_id = absint( $_POST['post_id'] );
        $views   = (int) get_post_meta( $post_id, 'post_views_count', true );
        update_post_meta( $post_id, 'post_views_count', $views + 1 );
    }
    wp_die();
}
add_action( 'wp_ajax_track_post_views', 'hmwp_track_post_views' );
add_action( 'wp_ajax_nopriv_track_post_views', 'hmwp_track_post_views' );

// 3. An Elementor query filter that orders by the view count.
//    Set the Posts widget's "Query ID" to: popular_posts_filter
function hmwp_popular_posts_query( $query ) {
    $query->set( 'meta_key', 'post_views_count' );
    $query->set( 'orderby', 'meta_value_num' );
    $query->set( 'order', 'DESC' );
}
add_action( 'elementor/query/popular_posts_filter', 'hmwp_popular_posts_query' );

// 4. A [post_views_count] shortcode to show the count anywhere.
function hmwp_post_views_shortcode() {
    $views = (int) get_post_meta( get_the_ID(), 'post_views_count', true );
    return number_format_i18n( $views );
}
add_shortcode( 'post_views_count', 'hmwp_post_views_shortcode' );

How to use it

  1. Add an Elementor Posts (or Loop Grid) widget.
  2. Under Query, set the Query ID to popular_posts_filter.
  3. Publish. The widget now lists posts by most-viewed.

Drop [post_views_count] into any post to show its view total.

Notes and how to undo

  • Counts build up over time — a brand-new site shows low numbers until traffic accrues.
  • Views are de-duplicated per browser via localStorage, so they approximate unique views rather than raw hits.
  • To remove it, delete the snippet. The stored counts remain in the database harmlessly; the widget just needs its Query ID cleared.