Implementing Post Views in WordPress
Tracking post views and generating popularity rankings is a common requirement for many websites. This guide presents two implementation methods: a basic version and an enhanced AJAX version compatible with caching and CDN services.
Method 1: Basic Implementation (No Caching/CDN)
This method is suitable for standard dynamic WordPress sites without page caching plugins or CDN. Add the following code to your theme's functions.php file.
The code automatically updates a custom field named views. To display the view count in your template (e.g., single.php), call <?php get_post_views($post->ID); ?>.
// Function to get and display post views
function get_post_views($post_id) {
$count_key = 'views';
$count = get_post_meta($post_id, $count_key, true);
if ($count == '') {
delete_post_meta($post_id, $count_key);
add_post_meta($post_id, $count_key, '0');
$count = '0';
}
echo number_format_i18n($count);
}
// Function to increment view count
function set_post_views() {
global $post;
if ( !is_single() || !$post ) return;
$post_id = $post->ID;
$count_key = 'views';
$count = get_post_meta($post_id, $count_key, true);
if ($count == '') {
$count = 0;
delete_post_meta($post_id, $count_key);
add_post_meta($post_id, $count_key, '0');
} else {
$count = intval($count) + 1;
update_post_meta($post_id, $count_key, $count);
}
}
add_action('get_header', 'set_post_views');
Note: If your site uses caching plugins (e.g., W3 Total Cache, WP Super Cache) or a CDN, the server-side PHP code (set_post_views) won't execute on cached page loads, making statistics inaccurate. Use the AJAX method in such cases.
Method 2: AJAX Implementation (Caching/CDN Compatible)
This method uses JavaScript to send asynchronous requests, bypassing page cache to ensure every real visit is recorded.
Step 1: Create the Server-Side Handler
Create a file named views-ajax.php in your WordPress root directory with the following code:
<?php
define('WP_USE_THEMES', false);
require('./wp-load.php');
// Security: accept only AJAX requests
if ( !isset($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest' ) {
status_header(403);
exit('Forbidden');
}
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
if ( $post_id <= 0 || get_post_status($post_id) === false ) {
wp_send_json_error('Invalid post ID');
exit;
}
$current_views = get_post_meta($post_id, 'views', true);
if ( $current_views === '' ) {
$new_views = 1;
add_post_meta($post_id, 'views', $new_views, true);
} else {
$new_views = intval($current_views) + 1;
update_post_meta($post_id, 'views', $new_views);
}
wp_send_json_success(array('views' => $new_views));
?>
Step 2: Add the Front-End Script
Add this script to your theme's footer.php (before </body>) or via the wp_footer hook. It uses localStorage to prevent duplicate counts from the same browser within 24 hours.
<?php if ( is_single() ) : ?>
<script>
(function() {
if (typeof jQuery === 'undefined') return;
function recordView() {
var postId = <?php echo get_the_ID(); ?>;
var storageKey = 'wp_viewed_posts';
var expireHours = 24;
if (typeof Storage === 'undefined') {
sendViewRequest(postId);
return;
}
var viewedData = localStorage.getItem(storageKey);
var now = new Date().getTime();
var shouldCount = true;
if (viewedData) {
try {
viewedData = JSON.parse(viewedData);
var validData = {};
for (var pid in viewedData) {
if (now - viewedData[pid] < expireHours * 3600000) {
validData[pid] = viewedData[pid];
}
}
viewedData = validData;
if (viewedData.hasOwnProperty(postId)) shouldCount = false;
} catch(e) {
viewedData = {};
}
} else {
viewedData = {};
}
if (shouldCount) {
sendViewRequest(postId);
viewedData[postId] = now;
localStorage.setItem(storageKey, JSON.stringify(viewedData));
}
}
function sendViewRequest(postId) {
jQuery.ajax({
type: 'POST',
url: '/views-ajax.php',
data: { post_id: postId },
dataType: 'json'
}).fail(function(jqXHR, textStatus, errorThrown) {
console.error('View count request failed:', textStatus, errorThrown);
});
}
jQuery(document).ready(recordView);
})();
</script>
<?php endif; ?>
Step 3: Display the View Count
In your template, use this code to show the view count:
<?php
$views = get_post_meta(get_the_ID(), 'views', true);
echo number_format_i18n( empty($views) ? 0 : intval($views) ) . ' views';
?>
Comparison and Recommendations
- Basic Method: Simple to implement but incompatible with any page caching. Use only for purely dynamic, uncached sites.
- AJAX Method: More complex but fully compatible with server caching, caching plugins, and CDNs. Recommended for production environments using performance optimizations.
Choose based on your site's technical stack. If you use any caching for speed, the AJAX method is essential for accurate statistics.