The best way to do this would be to set up a custom table. For each view you would add a new row which would contain (at least) a uid, the post id and the date/time. The beauty of this method is you can store as much data per view as you like, such as IP or the current user if they’re logged in. I can’t really give any more advise than that as I’ve never attempted to use custom tables however there are plenty of plugins out there that can do it. The codex article can be found here.
Another way to do it would be using post meta similar to how you’ve been doing it. What you do is store an array of view times. This way, you wouldn’t have to store the view count although I’m sure you’d want to keep the old data for the purpose of records. However this would end up with a really bloated function trying to sort your posts.
I’ve done up some code below that should work in theory but I haven’t had a chance to test it.
//Track page view
function track_post_view( $post_id ) {
$views_key = 'post_views_times';
$views = get_post_meta( $post_id, $views_key, true );
$count = count( $views );
if( $count === 0 ) {
$views = array();
}
//Adds another entry to the views with the current UNIX timestamp
$views[] = time();
return update_post_meta( $post_id, $views_key, $views );
}
//Get all posts
function get_popular_posts( $limit = 3 ) {
$all_posts = new WP_Query( 'post_type' => 'post', 'post_status' => 'publish' );
//Store these posts
while($all_posts->get_posts()){
$all_posts->the_post();
$post_views = get_post_meta( get_the_ID(), 'post_views_times' );
$week_ago_time = time() - 7 * 24 * 60 * 60; //This is the timestamp of 1 week ago
for( $i = 0; $i < count( $post_views ); $i++ ){
if( $post_views[$i] < $week_ago_time ){
unset($post_views[$i]); //If the timestamp is less than 1 week ago get remove it from the variable
}
}
$posts_list[] = array( 'views' => count( $post_views ), 'post_id' => get_the_ID() );
}
//Get the column to sort the $posts_list by
foreach ($posts_list as $key => $row) {
$views[$key] = $row['volume'];
}
array_multisort( $views, SORT_DESC, $posts_list ); //This sorts descending by views.
//Get the top 3 viewed posts and store that it yet another array
for( $i = 0; $i < $limit; $i++ ){
$most_viewed_ids[] = $posts_list[$i]['post_id'];
}
$popular = new WP_Query( 'p' => $most_viewed_ids ); //Run a query getting our 3 top posts
wp_reset_postdata();
return $popular;
}
I hope this answer helps in some way or another