Counting Post Views in WordPress without PlugIn

No, this is not the first post on how to count WordPress post views without a plugin. At the time of writing, I entered this post’s title in quotation marks at Google and there were about 4.5 million results. So I am really curious on how many views I will see for this one 😉

What many of the posts I read on that topic do not mention is that, at least from my point of view, it is really helpful to have (or create) a child theme based on your current theme. As searching for “wordpress create child theme” returns about 34.7 million results on Google, I will not add a link here.

Reason why I think it is a good idea to use a child theme is the fact that you have to change some of the theme’s files. In case an update arrives and you install it, but have not created your own child theme, all of your changes will be lost.

Luckily, I already had a child theme for this blog, so I only had to make a few changes:

  • Add some functions to the child theme’s functions.php, and
  • Copy the single.php from the theme template and modify it to count the views.

Because I do not show the number of views within the post, that was it.

Here is what I added to functions.php. To avoid counting views of non-published posts, e.g. previews when creating a post, I added a filter to set_post_views.

/*
* Functions to add view counters and display the value in the Admin's Posts overview
*
* Code base found at https://www.isitwp.com/track-post-views-without-a-plugin-using-post-meta/
*/

function get_post_views($postID) {
   $count_key = 'post_views_count';
   $count = get_post_meta($postID, $count_key, true);
   if($count==''){
       delete_post_meta($postID, $count_key);
       add_post_meta($postID, $count_key, '0');
       return "0 Views";
   }
   if ($count=='1') {
      return "1 View";
   }
   return $count.' Views';
}

function set_post_views($postID) {
   // Only count views on published posts
   if (get_post_status($postID) !== 'publish'){
       return;
   }

   $count_key = 'post_views_count';
   $count = get_post_meta($postID, $count_key, true);
   if($count=='') {
       $count = 0;
       delete_post_meta($postID, $count_key);
       add_post_meta($postID, $count_key, '0');
   } else {
       $count++;
       update_post_meta($postID, $count_key, $count);
   }
}

// Remove issues with prefetching adding extra views
remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0); 

// Add to a column in WP-Admin
function posts_column_views($defaults) {
    $defaults['post_views'] = __('Views');
    return $defaults;
}

function posts_custom_column_views($column_name, $id) {
    if($column_name === 'post_views'){
        echo get_post_views(get_the_ID());
    }
}

add_filter('manage_posts_columns', 'posts_column_views');
add_action('manage_posts_custom_column', 'posts_custom_column_views',5,2);

/*
* End of view counter functions; see also single.php for changes
*/

In the single.php file, I add these two lines at the end of the while loop:

// Added to count post views, see https://www.isitwp.com/track-post-views-without-a-plugin-using-post-meta/
set_post_views(get_the_ID());

Due to some changes made in function.php, WP Admin Posts view now shows the number of views per post:

Extended WP Admin Posts vierw

Useful SQL Queries

Depending on the number of your posts, it might be helpful to get the number of views per post from the database instead of scanning the Posts view. Here is a small collection of SQL statements that I created for a quick overview. I run theses statements directly against the database.

Get the total Number of Views

select sum(cast(meta_value as signed)) as views_total
from wp_postmeta 
where meta_key = 'post_views_count';

Get the Number of Views per Post, only listing those Postings having Views at all

select pm.*, po.post_title from wp_postmeta as pm
inner join wp_posts as po on pm.post_id = po.ID
where pm.meta_key = 'post_views_count' and meta_value <> '0';

Get the Posts having Views at all, sorted by the Number of Views in descending Order

This statement tells me which post is the most popular one:

select pm.*, po.post_title from wp_postmeta as pm
inner join wp_posts as po on pm.post_id = po.ID
where pm.meta_key = 'post_views_count' and pm.meta_value <> '0'
order by cast(pm.meta_value as signed) desc;

It is important to cast the value of the column pm.meta_value to a numeric value here. Otherwise the sort is based on alpha characters, which will lead to a undesired sort order.

Reset Counter when Publishing a new Post

In case the method to increase the view counter does not contain a filter to only count views on published posts, the view counter is also increased every time the preview is loaded / refreshed while editing. This of course falsifies the numbers (see if (get_post_status($postID) !== 'publish') in set_post_views).

To reset the counter these statements are helpful.

-- check the value first
select * from wp_postmeta where post_id = <id of the post> and meta_key = 'post_views_count';
-- reset the counter
update wp_postmeta set meta_value = '0' where post_id = <id of the post> and meta_key = 'post_views_count';

Retrieve Counter Values via REST API

In case you would like to get the view counter values without login to WordPress, have a look at my post “REST API to retrieve WordPress View Counters“.