When developing the News theme, we needed a way to get the number of times a post (or any post type) was viewed.
What we’ve developed is a lightweight file that updates post metadata with the meta key of Views. This will keep track of each singular page view a post gets. We’re giving this script away for you to use in your projects. Think of it as a starting point that you can build all sorts of cool functionality on top of.
Complications
If you’re familiar at all with updating post meta, this would sound like an easy task. However, some browsers like Firefox prefetch URLs. What this means is that any link with rel="prefetch" or rel="next" will be pre-loaded as the browser is trying to guess what page you might go to next. Unfortunately, this has the side effect of artificially inflating the view count.
This script fixes that problem.
I’m telling you this up front because some of you may be wondering why this extension uses Ajax. JavaScript isn’t prefetched, which makes it a good solution. Of course, any user with JavaScript turned off in their browser will not register as a view.
Adding the Entry Views extension to your theme
You can use this in both plugins and themes, but this tutorial will show you how to add it to a theme. I assume most plugin authors can figure out how to add it to their plugin.
The first step is to download Entry Views. Unzip the file and add the entry-views.php file to your theme folder.
Then, add this line to your theme’s functions.php file:
if ( !function_exists( 'entry_views_update' ) ) require_once( TEMPLATEPATH . '/entry-views.php' );
Making Entry Views work
The Entry Views extesion will handle all the complex stuff for you. However, it works based on post types. For example, you could use this for the “post” post type but have it disabled for the “page” post type. It’s completely customizable.
So, let’s suppose we want it to update the view counts for the post, movie, and recipe post types. We’d add this to our functions.php file:
add_action( 'init', 'my_add_post_type_support' );
function my_add_post_type_support() {
add_post_type_support( 'post', array( 'entry-views' ) );
add_post_type_support( 'movie', array( 'entry-views' ) );
add_post_type_support( 'recipe', array( 'entry-views' ) );
}
You can also register support in the supports array when adding a custom post type like so:
register_post_type(
'example',
array(
'supports' => array( 'entry-views', 'title', 'editor' )
)
);
Doing one of those two things will make posts of your post type(s) available to the Entry Views script. It will count the number of times a singular post has been viewed. Note that this does not count views on archives, search results, and the posts page.
Showing the view count
There are two ways to show the view count. You can use a template tag or shortcode.
To use the template tag, drop this somewhere within The Loop:
<?php if ( function_exists( 'entry_views_get' ) ) entry_views_get( array( 'before' => 'Views: ' ) ); ?>
To use the shortcode, add this in a shortcode ready area within The Loop:
[entry-views before="Views "]
Both the template tag and shortcode will take in one of three arguments:
before: Text to show before the view count.after: Text to show after the view count.post_id: Show the view count of a specific post. This defaults to the current post ID.
Overwriting the default meta key
Some people may have used other view count plugins or functions in their themes before, so Entry Views has a filter hook to change this. Its default meta key is Views. If you need to customize this for whatever reason, just add a custom filter to it like below.
add_filter( 'entry_views_meta_key', 'my_entry_views_meta_key' );
function my_entry_views_meta_key( $meta_key ) {
return 'custom_view_key';
}
Building your own features on top of Entry Views
The code we’re handing over is fairly basic. It didn’t make much sense to build a lot of custom functionality directly within it because there are so many different things that can be done. It made more sense to leave it flexible and make it reusable for others.
One good example is from our News theme. It has a built-in Popular Tabs widget that allows you to select a specific post type and display the view count in one of the tabs.
It uses an instance of WP_Query to query posts by the number of views. Here’s what a basic query and loop would look like to show the most-viewed posts:
<?php $loop = new WP_Query( array( 'post_type' => 'post', 'posts_per_page' => 10, 'meta_key' => 'Views', 'orderby' => 'meta_value_num', 'order' => 'DESC' ) ); ?>
<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>
Add custom HTML and functionality here.
<?php endwhile; ?>
I don’t want to limit your imagination though. You can do all sorts of things. Mix and match post types. Pull the least-viewed posts. Get the most-viewed posts from a category or even for a specific month. Just have fun with it.
Get the code
If you make use of this code, please let us know how you’re using it in your projects.
Haven’t managed to get it working yet, but thanks a lot for this very valuable tut (+ files)!
Hi Justin,
Interested to know why you didn’t just recommend that people use use an established plugin such as WP-PostViews by Lester Chan – is there any particular reason you didn’t?
It’s probably worth pointing out to people what happens if they use a caching plugin, as many people do (including this site I see from the source).
Because you’re counting the views via JavaScript, it should count them correctly (except for W3 Total Cache if the Database cache is turned on). Having said that, I’ve had problems with nonces and caching plugins, so it may not count them after all with the nonce in place.
When displaying the count (entry_views_get), if the page is cached, you won’t see the current count, you’ll see the count at the time the page was cached. Shameless plug: I’ve written a WordPress plugin called Ajax_the_views which uses Ajax to display the count for WP-PostViews. If this issue is important for anyone, I’m sure they could adapt it to work with the Entry Views script.
Anyway, thanks for contributing this script.
Reason #1: We didn’t want our users to have to install a third-party plugin for something so simple, especially when it plays an integral part within our theme.
Reason #2: I see no reason for recommending that plugin/theme authors rely on a plugin with loads of stuff they don’t need when they can use a small, 6kb file to include the functionality within their projects.
Really I had similar views of about WP-PostViews plugin by Lester Chan.A 6kb file for the same purpose is really incredible.I am surely make use of it every theme of mine…
Thanks
I agree completely and this has been a huge help. Thank you, Justin
Brilliant! I love deactivating plugins because my theme can do the coolness.
Hmm unfortunately I’m not able to get it working yet. I don’t think I have any custom post types (just taxonomies?). Following on from what you said above, I’d have to add “post” to make it work on post, is that right?
The file definitely gets loaded and I added the php snippet unchanged to my single php file (withing the loop). Sorry for being a bit slow with adoption here.
You can also get this info from the WP.com Stats plugin API pretty efficiently, without causing any extra writes to your DB. Shoot me an email if you need any pointers.
I was thinking about that the other day. It’d be neat to offer integration with the WP Stats plugin within our themes that use this functionality.
Hi Justin,
I’ve been trying News out on one of my sites when I came across a ‘problem’ I traced back to the views functionality. It’s not really a ‘problem’ and won’t occur for most people, only people like a bit of extra security like me!
The views functionality seems to send information to wp-admin/admin-ajax.php. I password protect my wp-admin directory, so visitors to my site get a pop up dialog box asking them to enter the password for wp-admin on each page load.
As I said, it won’t happen for most people, but it will happen for some.
In my own plugins I steer away from using anything in the wp-admin folder on the client side. It’s not that hard to write your own server side script to deal with Ajax requests – although I’ve found you can’t use nonces because caching plugins won’t work with them.
Anyway, I’ve just disabled the theme support for entry-views so I’m good – I just thought I’d let you know.
hi Justin,
first of all i would like to thank you very much for this article and code sharing,
i would like to use your code in my theme but i can’t make it work with the template tag you suggest,
the only way to get the number of views in a post is by using the shortcode.
so, now i will use it in a template like this:
‘ echo do_shortcode(‘[entry-views after=" Views"]‘); ‘
if you know a better way to do this i will really appreciate it,
thanks a lot!!!
Philip
Thanks Philip!
I was wondering why I can’t get the number of views working, but this
‘ echo do_shortcode(‘[entry-views after=" Views"]‘); ‘
works in my loops also.
Justin,
I was able to whip up a simple Dashboard Widget for displaying the Top 10 Posts with the help of your extension. I plan to customize it even further for use with Custom Post Types. This had added more value to my theme and future themes, thanks bro!
Top 10 Posts Dashboard Widget
http://www.pastie.org/1396682
I love keeping post views… is there any way to sync the post view count of this with Lester Chan’s plugin? Or maybe sync is the wrong word… just catch it up to speed when you first install it?
I’d consider using this instead of WP PostViews if it’s lighter, but I’ve already got post views racked up and starting from ground zero probably won’t fly.
Actually maybe this would work:
WP-PostViews saves the count in the meta key “views”. This saves it in “Views”. So if I change Views to views in your plugin, then disable WP-PostViews, it should be a flawless transition… right?
sounds right to me…of course as long as you then disable the old plugin
did it work?
//Frankie
Thanks for sharing the code. I managed to add the widget from News theme to WooThemes Estate theme. However it will be very useful if we have the ability to choose a timeframe, for example popular posts during the latest 7 days.
Hey guys,
What would the WP community be without people like you? Thanks so much!
Here’s how I’m using your wonderful extension: http://www.themedigital.com/popular-wordpress-themes/
I’m thinking of creating extra page templates for viewing popular posts (themes) by month, week, day… it currently (obviously) show all time popular posts.
Thanks again… for being!
That’s an awesome use of the script!
handy little script.. Would it be possible to count +1 for all articles on an archive page?
I would like to count all views of titles, no matter if people click and read the single post.. Like attaching the script to the title or so. How to go about?
Got it working.. extended the file a bit
I would like to use this on a photo blogging theme, where you see 1 last post with full size image straight on the home page so there is no need to click the post title. visitors are simply paging through the homepage’s pages to see older pics.
it rarely happens that someone clicks on an actual post.
could this script track this kind of views too?
Take a look at the
entry_views_update()function and the notes at the top of the script. You only have to pass the post ID to update the post view count.Can you post a screen shot so we can see how the end results are supposed to look?
It’s not supposed to “look” like anything. It’s just data that’s saved as post metadata.
Thanks for the script! I do have one mysterious problem though. The script works like a charm locally, but when I uploaded the blog to the company website it does not print the post links. There does not seem to be an error. It simply does not get/display the links.
Any thoughts?
Jeff
If you want to print a line on your post entry like “Viewed x times” or in the case of 1 view, “Viewed 1 time”, then you will need to make a comparison using a pure numeric version of the views meta data to determine whether to use “view” or “views”.
The function entry_views_get() returns a number formatted with the Wordpress number_format_i18n() function which will format the number according to your localization, which may not be an integer and will cause problems for your comparison. In my case it adds a comma to numbers larger than 999.
You will either need to get the views as a number from meta data field directly, modify the function to out put singular or plural versions of words, or use a regular expression to remove the comma from the value returned by entry_views_get().
Welldone, I have no words, how to thank you…. man
Advice to everybody.. dont waste time on using plugins use this Justin script, this is the best and easy to manage..
Thumbs Up…!!!
Thanks Alot Good Bye
Hey, Justin.
I cannot make it work. Could you please send me an email and explain like for really stupid people exactly what to do?….and I mean step-by-step instructions. I tried it, but all I could do in the end is upload the entry-views.php in the theme folder. I would really appreciate it if you could spare some time and help me with this.
I want to display weekly popular posts, monthly popular posts and all time popular posts (and to display the number of views on every post). Can you help?
Looks like your template tag is missing a bit of code? There needs to be an “echo” to display the view count.
should be: