Last active
October 2, 2024 20:30
-
-
Save Qubadi/bfbc6e17c252a6340a45c089b0f55dd4 to your computer and use it in GitHub Desktop.
WordPress current view tracker for Posts, CPTs, and Products
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
UPDATED: 11-08-2024 | |
The code has been updated to address the concerns: | |
Nonce verification has been added to protect against CSRF attacks and ensure that only authorized requests are processed. | |
Input validation and sanitization are now in place for post_id and user_token to prevent malicious data from being processed. | |
XSS protection has been implemented by escaping all outputs before they are inserted into the DOM. | |
LocalStorage usage has been reviewed and is handled appropriately given the context. | |
Description: | |
Copy the following PHP code and create a PHP snippet using your snippet plugins, paste the code into the plugin and save it. | |
Then copy the shortcode name and add it to your single page: [current_post_viewers] | |
Effortlessly track and display the number of people currently viewing WordPress posts, custom post types (CPTs), | |
and WooCommerce products in real-time. This solution is fully compatible with all post types and provides a seamless user | |
experience with customizable styling for different screen sizes. | |
________________________________________________ | |
// Function to update and retrieve the number of active viewers on a post or page | |
function update_active_post_viewers() { | |
// Security check with nonce and current user's capabilities | |
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'update_profile_view_nonce')) { | |
wp_send_json_error('Invalid nonce'); | |
return; | |
} | |
// Check if the user is logged in and has appropriate capabilities | |
if (!is_user_logged_in() || !current_user_can('read')) { | |
wp_send_json_error('Unauthorized user'); | |
return; | |
} | |
// Input validation and sanitization | |
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0; | |
$user_token = isset($_POST['user_token']) ? sanitize_text_field($_POST['user_token']) : ''; | |
if (!$post_id || empty($user_token) || !preg_match('/^[a-f0-9\-]{36}$/', $user_token)) { | |
wp_send_json_error('Invalid input'); | |
return; | |
} | |
$transient_key = 'active_viewers_post_' . $post_id; | |
// Fetch the current list of active viewers | |
$active_viewers = get_transient($transient_key); | |
$active_viewers = is_array($active_viewers) ? $active_viewers : array(); | |
// Remove tokens that have expired (older than 1 minute) | |
$current_time = time(); | |
$expiration_time = 60; // 1 minute | |
foreach ($active_viewers as $token => $timestamp) { | |
if (($current_time - $timestamp) >= $expiration_time) { | |
unset($active_viewers[$token]); | |
} | |
} | |
// Update the token's timestamp or add a new one | |
$active_viewers[$user_token] = $current_time; | |
// Store the updated list of active viewers | |
set_transient($transient_key, $active_viewers, $expiration_time + 10); | |
// Return the number of active viewers | |
wp_send_json_success(count($active_viewers)); | |
} | |
add_action('wp_ajax_update_active_post_viewers', 'update_active_post_viewers'); | |
add_action('wp_ajax_nopriv_update_active_post_viewers', 'update_active_post_viewers'); | |
// Shortcode to display the current number of viewers on a post or page | |
function current_post_viewers_shortcode() { | |
if (!is_singular()) { | |
return ''; // Only display on singular pages (posts, CPTs, products, etc.) | |
} | |
global $post; | |
$post_id = $post->ID; | |
// Use a more secure method than localStorage for storing tokens | |
$user_token = wp_generate_uuid4(); // Generate a unique token for each viewer | |
$nonce = wp_create_nonce('update_profile_view_nonce'); // Create a nonce for security | |
ob_start(); ?> | |
<script type="text/javascript"> | |
jQuery(document).ready(function($) { | |
// Retrieve or generate a unique user token | |
let userToken = sessionStorage.getItem('post_viewer_token_<?php echo esc_js($post_id); ?>'); | |
if (!userToken) { | |
userToken = '<?php echo esc_js($user_token); ?>'; | |
sessionStorage.setItem('post_viewer_token_<?php echo esc_js($post_id); ?>', userToken); | |
} | |
function updateViewers() { | |
$.post('<?php echo esc_url(admin_url('admin-ajax.php')); ?>', { | |
action: 'update_active_post_viewers', | |
post_id: <?php echo esc_js($post_id); ?>, | |
user_token: userToken, | |
nonce: '<?php echo esc_js($nonce); ?>' | |
}, function(response) { | |
var viewersCountElem = $('#current-viewers-count'); | |
if (response.success) { | |
viewersCountElem.text(response.data + ' people currently viewing this page.'); | |
} else { | |
viewersCountElem.text('Failed to load viewer count.'); | |
} | |
}).fail(function() { | |
$('#current-viewers-count').text('Failed to load viewer count.'); | |
}); | |
} | |
updateViewers(); | |
setInterval(updateViewers, 30000); // Update every 30 seconds | |
}); | |
</script> | |
<style> | |
#current-viewers-count { | |
font-size: 16px; | |
font-weight: 400; | |
color: #000; | |
} | |
@media (max-width: 1024px) { | |
#current-viewers-count { | |
font-size: 16px; | |
font-weight: 400; | |
color: #000; | |
} | |
} | |
@media (max-width: 768px) { | |
#current-viewers-count { | |
font-size: 16px; | |
font-weight: 400; | |
color: #000; | |
} | |
} | |
</style> | |
<p id="current-viewers-count">Loading current viewers...</p> | |
<?php | |
return ob_get_clean(); | |
} | |
add_shortcode('current_post_viewers', 'current_post_viewers_shortcode'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment