WP-PostViews

Сүрөттөө

WP-PostViews counts how many times each post, page or custom post type has been read and gives you somewhere to show the number. The count is kept as post meta, so it sorts, queries and exports like anything else WordPress stores about a post.

Features

  • A view count on any post, page or custom post type, printed by a template tag or by the [views] shortcode.
  • Two templates you edit yourself, with tokens for the count, the title, the date, the excerpt, the thumbnail, the author and more.
  • Choose who is counted — everyone, guests only or logged in users only — and leave known robots out.
  • Template tags and a widget for the most and least viewed posts, optionally within a category or a tag.
  • A sortable Views column on the post and page list tables.
  • The count on the REST API as a views field, and an AJAX counting path for sites behind a page cache.
  • A section on the WP-Stats page when that plugin is installed.

Donations

I spent most of my free time creating, updating, maintaining and supporting these plugins, if you really love my plugins and could spare me a couple of bucks, I will really appreciate it. If not feel free to use it without any obligations.

Usage

The simplest way, and the only one that works in a block theme without editing template files, is the shortcode. Put it in the post or page whose count you want shown:

  • [views] shows the count for the post it appears in.
  • [views id="1"] shows the count for post 1, wherever you put it.

To show the count on every post automatically, a classic theme calls the template tag from index.php, archive.php, single.php or page.php, anywhere inside the loop:

<?php if ( function_exists( 'the_views' ) ) { the_views(); } ?>

The settings live at WP-Admin -> Settings -> WP-PostViews, on two tabs. Settings is where you choose who gets counted and whether WP-Stats is offered a Views section; Templates is where you edit the markup a count is rendered with.

Where the count appears is decided by where your theme calls the_views() or where you put the shortcode. To hide it somewhere in particular, answer the wp_postviews_should_display filter:

add_filter( 'wp_postviews_should_display', function ( $show ) {
    return ! is_archive() && ! is_search();
} );

Showing The View Count In A Block

One block is available in the editor, under Widgets:

  • Post Views — the view count, rendered with the template from the Templates tab. Leave Post ID at zero to show the count of the post the block is in, which is what an empty [views] does, or set it to another post’s ID to show that post’s count instead.

It renders on the server, so the block preview in the editor is the real number rather than an approximation, and the count keeps rising in every post showing it without anything being re-saved. Previewing the block in the editor does not count a view.

The shortcode still works and is not going anywhere. [views] and [views id="1"] behave exactly as they always have, and a post already containing one needs no change. The block calls the same code the shortcode calls, so the two render identically — use whichever suits the post.

WP-CLI

wp postviews list
wp postviews list --limit=50 --format=json
wp postviews get 42

The command reads and never writes. No screen in this plugin edits a view count, so the command does not offer one either — wp post meta update <id> views <n> is still there for whoever genuinely needs it, and says plainly that it is reaching past the plugin.

REST API

POST /wp-json/postviews/v1/post/<id>/view

Reading a count needs no route of its own. The count is already published as a read-only views field on the core post resource, so /wp-json/wp/v2/posts/<id> answers with the post and its count together, and a list of posts carries every count in one response.

What the core field cannot do is write, which is what this route is for: it counts a view, and it exists for sites serving cached pages, where the view has to be reported after the page is delivered. It takes the same wp_postviews_nonce the counting script is given, as a nonce parameter.

It is refused unless the site defers counting — that is, unless it has a page cache and has turned the AJAX counting path on. Otherwise the view has already been counted while the page rendered, and counting again here would record every view twice.

A refusal answers 403 — a bad nonce, or a site that counts views while the page renders. A post that does not exist is 404.

This route is an addition. The admin-ajax.php wp_postviews action is unchanged and still supported.

Скриншоттор

Блоктор

This plugin provides 1 block.

  • Post Views How many times a post has been viewed, rendered with the stored template.

Орнотуу

  1. Install and activate the plugin. Counting starts immediately; you do not have to do anything for the numbers to be recorded.
  2. Show the count where you want it: type [views] into a post, add the Post Views block, add the widget, or call the_views() from your theme.
  3. Go to WP-Admin -> Settings -> WP-PostViews to choose who is counted and how the number reads.

FAQ.KG

How To View Stats With Widgets?

  • Go to WP-Admin -> Appearance -> Widgets
  • The widget name is Views.

To Display Least Viewed Posts

<?php if (function_exists('get_least_viewed')): ?>
    <ul>
        <?php get_least_viewed(); ?>
    </ul>
<?php endif; ?>
  • The first value you pass in is the post type that you want. If you want to get every post types, just use ‘both’. It also supports PHP array: example array('post', 'page').
  • The second value you pass in is the maximum number of post you want to get.
  • Default: get_least_viewed(‘both’, 10);

To Display Most Viewed Posts

<?php if (function_exists('get_most_viewed')): ?>
    <ul>
        <?php get_most_viewed(); ?>
    </ul>
<?php endif; ?>
  • The first value you pass in is the post type that you want. If you want to get every post types, just use ‘both’. It also supports PHP array: example array('post', 'page').
  • The second value you pass in is the maximum number of post you want to get.
  • Default: get_most_viewed(‘both’, 10);

To Display Least Viewed Posts By Tag

<?php if (function_exists('get_least_viewed_tag')): ?>
    <ul>
        <?php get_least_viewed_tag(); ?>
    </ul>
<?php endif; ?>
  • The first value you pass in is the tag id.
  • The second value you pass in is the post type that you want. If you want to get every post types, just use ‘both’. It also supports PHP array: example array('post', 'page').
  • The third value you pass in is the maximum number of post you want to get.
  • Default: get_least_viewed_tag(1, ‘both’, 10);

To Display Most Viewed Posts By Tag

<?php if (function_exists('get_most_viewed_tag')): ?>
    <ul>
        <?php get_most_viewed_tag(); ?>
    </ul>
<?php endif; ?>
  • The first value you pass in is the tag id.
  • The second value you pass in is the post type that you want. If you want to get every post types, just use ‘both’. It also supports PHP array: example array('post', 'page').
  • The third value you pass in is the maximum number of post you want to get.
  • Default: get_most_viewed_tag(1, ‘both’, 10);

To Display Least Viewed Posts For A Category

<?php if (function_exists('get_least_viewed_category')): ?>
    <ul>
        <?php get_least_viewed_category(); ?>
    </ul>
<?php endif; ?>
  • The first value you pass in is the category id.
  • The second value you pass in is the post type that you want. If you want to get every post types, just use ‘both’. It also supports PHP array: example array('post', 'page').
  • The third value you pass in is the maximum number of post you want to get.
  • Default: get_least_viewed_category(1, ‘both’, 10);

To Display Most Viewed Posts For A Category

<?php if (function_exists('get_most_viewed_category')): ?>
    <ul>
        <?php get_most_viewed_category(); ?>
    </ul>
<?php endif; ?>
  • The first value you pass in is the category id.
  • The second value you pass in is the post type that you want. If you want to get every post types, just use ‘both’. It also supports PHP array: example array('post', 'page').
  • The third value you pass in is the maximum number of post you want to get.
  • Default: get_most_viewed_category(1, ‘both’, 10);

To Sort Most/Least Viewed Posts

  • You can use: <?php query_posts( array( 'meta_key' => 'views', 'orderby' => 'meta_value_num', 'order' => 'DESC' ) ); ?>
  • Or pass in the variables to the URL: https://yoursite.com/?v_sortby=views&v_orderby=desc
  • You can replace DESC with ASC if you want the least viewed posts.

To Display Updating View Count With LiteSpeed Cache

Use: <div id="postviews_lscwp"></div> to replace <?php if(function_exists('the_views')) { the_views(); } ?>.
NOTE: The id can be changed, but the div id and the script must match.

The plugin’s js/wp-postviews-cache.js already posts the view and receives the new count back, so you only need to write that count into your div. Add this to your theme, or to a small script of your own enqueued after wp-postviews-cache:

document.addEventListener( 'postviews:updated', function ( event ) {
    const target = document.getElementById( 'postviews_lscwp' );

    if ( target ) {
        target.textContent = event.detail.views + ' views';
    }
} );

Purge the cache to use the updated pages.

To Get Views With REST API

You can obtain the number of post views by adding views to your _fields parameter:
/wp/v2/posts?_fields=views,title

Сын-пикирлер

Октябрь 21, 2025-ж.
I’ve been using WP-PostViews for some time now, and it’s a very straightforward and effective plugin for displaying post views. The settings to count views only from guests and exclude bots work well. However, I’ve noticed that if a guest refreshes a page multiple times, each refresh is counted as a new view. While this is typical behavior for a basic hit counter, it makes the view count less representative of actual unique visitors. I would highly recommend considering an enhancement to include an option to count unique views based on IP address (e.g., once per IP within a specified timeframe like 24 hours). This would significantly improve the accuracy of the statistics and make the plugin even more valuable for site owners who want to track genuine reader engagement. Thank you for this plugin!
Апрель 26, 2024-ж.
Have been using this a while along side Advanced Queries and Elementors Loop widget to display a list grid of most popular articles on a website. Doesnt seem to be working anymore. I think its still keeping count of the post views, but the views template variable isnt pulling in the correct posts. From the posts it is showing it looked like it stopped updating in January of this year. Will need to find another solution!
Декабрь 6, 2021-ж.
This is the Plugin that I was looking for. Thanks a lot!
Read all 65 reviews

Contributors & Developers

“WP-PostViews” is open source software. The following people have contributed to this plugin.

Мүчөлөрү

“WP-PostViews” has been translated into 19 locales. Thank you to the translators for their contributions.

Translate “WP-PostViews” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Өзгөртүүлөр

2.0.0

  • FIXED: The two templates are echoed as markup on the strength of being wp_kses_post()‘d when saved — and that was true only of the settings screen. The 2.0.0 migration writes through a different door, and the row it folds in comes from a release that stored the field with no filtering at all, so a hostile template on a site upgrading from 1.78.1 was carried across verbatim and echoed to every visitor. The filtering now happens where the row is written, so WP-CLI, cron, a restored backup and another plugin all pass through it too
  • FIXED: The deferred counting endpoint checked only that an ID named something, and every row in wp_posts answers to that — revisions, autosaves, auto-drafts, attachments, trashed posts, drafts, menu items, reusable blocks. An unauthenticated caller could walk the ID space writing a view row against each one, and read back the count of unpublished posts while doing it. It now requires a real, publicly viewable post, which is what the other counting path already knew
  • FIXED: A view count that is not a number — the meta key is unprefixed, so anyone who can edit a post can type one into Custom Fields — turned every listing containing that post into a fatal error on PHP 8, because both count tokens are built whether or not the template uses them
  • NEW: An editor block, Post Views, under Widgets. It renders on the server through the same code the shortcode uses, so a block and a shortcode showing the same post produce the same markup, and previewing it in the editor never counts a view. The [views] shortcode is unchanged and still supported — nothing needs converting, and posts already containing it keep working.
  • NEW: A wp postviews WP-CLI command — list and get. It reads and never writes.
  • NEW: A postviews/v1 REST API carrying one route, for counting a view from a cached page. Reading a count is already a views field on the core post resource. The admin-ajax.php wp_postviews action is unchanged and still supported.
  • BREAKING: Requires WordPress 6.8 and PHP 8.2, up from 6.0 and 7.4.
  • BREAKING: The the_views filter is now wp_postviews_the_views. The template tag the_views() is unchanged.
  • BREAKING: The postviews_should_count filter is now wp_postviews_should_count.
  • BREAKING: The postviews_increment_views and postviews_increment_views_ajax actions are now wp_postviews_increment_views and wp_postviews_increment_views_ajax.
  • BREAKING: The settings are stored in wp_postviews_options instead of views_options, and the upgrade markers in wp_postviews_version instead of views_version. Both are migrated automatically.
  • BREAKING: The WP-Stats toggles move out of the shared stats_display and stats_mostlimit rows into this plugin’s own settings, and the shared rows are deleted. Update all seven WP-Stats plugins together.
  • BREAKING: The widget class WP_Widget_PostViews is now WP_PostViews_Widget. Configured widgets are unaffected.
  • BREAKING: The AJAX action a cached page posts to is now wp_postviews instead of postviews.
  • BREAKING: The six Display Options settings — home page, single posts, pages, archives, searches and other pages — are removed, and the stored keys are dropped on upgrade. Their replacement is the wp_postviews_should_display filter.
  • NEW: Restructured into includes/ classes. The template tags — the_views(), get_most_viewed(), get_least_viewed(), and the category and tag variants — are unchanged and keep working exactly as before.
  • NEW: The options screen is rebuilt on the WordPress Settings API and no longer loads jQuery.
  • NEW: The WP-Stats section, and how many entries its most viewed lists carry, are now settings on Settings -> WP-PostViews.
  • NEW: The wp_postviews_should_display filter decides whether a count is shown. It is read by the_views() only; the [views] shortcode and the admin Views column are explicit requests and ignore it.
  • CHANGED: The settings screen is two tabs, Settings and Templates, over one settings group and one option row.
  • CHANGED: The settings screen is titled “Post Views Settings”, matching the other settings screens in this family.
  • CHANGED: WP-Stats now receives one Views section rather than three separately toggled panels, so the most viewed pages list appears alongside the posts list.
  • FIXED: %VIEW_COUNT_ROUNDED% picked its unit before rounding, so 999,950 displayed as “1000K” instead of “1M” and 999,999,999 as “1000M” instead of “1B”.
  • FIXED: Titles were truncated on bytes rather than characters, because the multibyte branch was gated on MB_OVERLOAD_STRING, which PHP 8.0 removed. A CJK title cut mid-character disappeared from the most/least viewed lists entirely.
  • FIXED: The AJAX endpoint recorded views against post IDs that do not exist, letting anyone add rows to wp_postmeta indefinitely.
  • FIXED: ?v_orderby=ASC was compared against lowercase only, so an uppercase direction — which is what the FAQ tells you to use — silently fell back to descending, the opposite of what was asked for.
  • FIXED: The widget silently discarded changes made in the block widget editor and the customizer, because it required a hidden form field neither of them sends.
  • FIXED: The widget warned about undefined array keys when rendered from the block widget editor or the customizer.
  • FIXED: Uninstalling on a network of more than 100 sites left options and view counts behind on every site after the hundredth, and reported success. Network activation could fatal on the removed wp_get_sites().
  • NOTE: The settings screen moved from options-general.php?page=wp-postviews/postviews-options.php to options-general.php?page=wp-postviews. Update any bookmark; the Settings -> WP-PostViews menu item is where it always was.
  • NOTE: Templates are now stored unslashed. Existing templates are migrated automatically the first time 2.0.0 loads.
  • NOTE: should_views_be_displayed(), postviews_round_number() and snippet_text() are no longer global functions. They were never documented; they are now WP_PostViews_Display::should_be_displayed(), WP_PostViews_Display::round_number() and WP_PostViews_Display::snippet_text().