Post views count

<?php /**
 * Post Views Counter with Cache Support
 * 
 * This implementation uses AJAX to bypass caching mechanisms and 
 * provides accurate view counting even in heavily cached environments.
 */

/**
 * Register post views counter assets and AJAX handlers
 */
function custom_post_views_init() {
    // Register and enqueue the JavaScript for AJAX view counting
    wp_register_script(
        'custom-post-views',
        get_template_directory_uri() . '/inc/js/post-views.js',
        array('jquery'),
        '1.0.0',
        true
    );
    
    // Pass data to our script
    wp_localize_script(
        'custom-post-views',
        'customPostViews',
        array(
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('custom_post_views_nonce')
        )
    );
    
    // Only enqueue on single posts
    if (is_single()) {
        wp_enqueue_script('custom-post-views');
    }
    
    
}
add_action('wp_enqueue_scripts', 'custom_post_views_init');

// Register AJAX handlers
    add_action('wp_ajax_custom_increment_post_views', 'custom_increment_post_views');
    add_action('wp_ajax_nopriv_custom_increment_post_views', 'custom_increment_post_views');

/**
 * AJAX handler to increment post views
 */
function custom_increment_post_views() {
    // Verify security nonce
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'custom_post_views_nonce')) {
        wp_send_json_error('Security check failed');
    }
    
    // Get post ID
    $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
    
    if ($post_id <= 0) {
        wp_send_json_error('Invalid post ID');
    }
    
    // Use transients to prevent multiple counts from same user in a session
    $visitor_ip = custom_get_visitor_ip();
    $user_viewed_key = 'post_viewed_' . $post_id . '_' . $visitor_ip;
    
    if (get_transient($user_viewed_key)) {
        // User already viewed this post recently
        wp_send_json_success(array(
            'message' => 'View already counted',
            'views' => custom_get_post_views($post_id)
        ));
        return;
    }
    
    // Set transient to prevent duplicate counts (expires after 24 hours)
    set_transient($user_viewed_key, 1, 24 * HOUR_IN_SECONDS);
    
    // Increment the post view count
    $views = custom_get_post_views($post_id);
    $views++;
    update_post_meta($post_id, 'custom_post_views', $views);
    
    // Return success with updated view count
    wp_send_json_success(array(
        'message' => 'View counted successfully',
        'views' => $views
    ));
}

/**
 * Get visitor IP (with privacy considerations)
 */
function custom_get_visitor_ip() {
    $ip = '';
    
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } else {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    
    // Hash the IP for privacy
    return md5($ip);
}

/**
 * Get post views count
 */
function custom_get_post_views($post_id = null) {
    if (!$post_id) {
        $post_id = get_the_ID();
    }
    
    $views = get_post_meta($post_id, 'custom_post_views', true);
    
    // Return views or 0 if none found
    return empty($views) ? 0 : intval($views);
}

/**
 * Display post views in your theme
 */
function custom_display_post_views($post_id = null, $suffix = ' views') {
    if (!$post_id) {
        $post_id = get_the_ID();
    }
    
    $views = custom_get_post_views($post_id);
    
    // Format the number for better readability
    if ($views > 999 && $views < 1000000) {
        $formatted = number_format($views / 1000, 1) . 'K';
    } elseif ($views > 999999) {
        $formatted = number_format($views / 1000000, 1) . 'M';
    } else {
        $formatted = $views;
    }
    
    echo '<span class="post-views"><i class="fa fa-eye" aria-hidden="true"></i> ' . esc_html($formatted . $suffix) . '</span>';
}

/**
 * Add views column to admin posts list
 */
function custom_add_views_column($columns) {
    $columns['post_views'] = 'Views';
    return $columns;
}
add_filter('manage_posts_columns', 'custom_add_views_column');

/**
 * Display views count in admin column
 */
function custom_display_views_column($column, $post_id) {
    if ($column === 'post_views') {
        echo esc_html(custom_get_post_views($post_id));
    }
}
add_action('manage_posts_custom_column', 'custom_display_views_column', 10, 2);

/**
 * Make views column sortable in admin
 */
function custom_sortable_views_column($columns) {
    $columns['post_views'] = 'post_views';
    return $columns;
}
add_filter('manage_edit-post_sortable_columns', 'custom_sortable_views_column');

/**
 * Handle admin sorting by views count
 */
function custom_views_column_orderby($query) {
    if (!is_admin() || !$query->is_main_query()) {
        return;
    }
    
    if ($query->get('orderby') === 'post_views') {
        $query->set('meta_key', 'custom_post_views');
        $query->set('orderby', 'meta_value_num');
    }
}
add_action('pre_get_posts', 'custom_views_column_orderby');

/**
 * Add function to quickly add post views display to theme templates
 */
function custom_the_post_views($suffix = ' views') {
    custom_display_post_views(get_the_ID(), $suffix);
}

Post-views.js

/**
 * JavaScript for post views counter
 * This file handles the AJAX request to increment post views
 * Save this as post-views.js in your theme's js directory
 */

jQuery(document).ready(function($) {
    // Only run on single posts that have an ID
    if ($('body').hasClass('single') && $('article').length > 0) {
        var postId = $('article').attr('id');
        
        // Extract the post ID from the article ID (usually in format post-123)
        if (postId) {
            postId = postId.replace('post-', '');
        } else {
            // Fallback: try to get from body class
            var bodyClasses = $('body').attr('class').split(' ');
            $.each(bodyClasses, function(index, className) {
                if (className.indexOf('postid-') === 0) {
                    postId = className.replace('postid-', '');
                    return false;
                }
            });
        }
        
        if (postId && !isNaN(postId)) {
            // Add a small delay to ensure the page has fully loaded
            setTimeout(function() {
                // Send AJAX request to count the view
                $.ajax({
                    type: 'POST',
                    url: customPostViews.ajaxurl,
                    data: {
                        action: 'custom_increment_post_views',
                        post_id: postId,
                        nonce: customPostViews.nonce
                    },
                    success: function(response) {
                        if (response.success) {
                            // Update view count on page if needed
                            $('.post-views-count').text(response.data.views);
                        }
                    },
                    error: function() {
                        console.log('Failed to register post view');
                    }
                });
            }, 1500); // 1.5 second delay
        }
    }
});
×
Post views count

Post views count

<?php /** * Post ...