Answer the question
In order to leave comments, you need to log in
How to show the most viewed posts for a certain period?
Hello.
The task seems to be simple, but still I don’t know where to look ..
You need to display the top entries by views for the last 7 days, for example, but not the entries that were added to the site in 7 days, but the entries that collected the most views in 7 days.
I tried to collect views in the meta field of the post, but in this case everything is in a bunch for the whole time, how would I change this thing so that you can pull data for a certain period.
Thank you.
UPD. Without plugins of course)
Answer the question
In order to leave comments, you need to log in
The task seems simple, but still I don’t know where to look
CREATE TABLE {$prefix}post_views (
post_id bigint(20) NOT NULL,
entry_day datetime NOT NULL,
num_views int NOT NULL,
PRIMARY KEY (post_id,entry_day),
KEY idx_pv_ed (entry_day)
);
class My_Most_Viewed_Posts {
protected $errors = null;
protected $notices = null;
protected $debug = false;
# This just sets up the errors, notices, and debug variables able
function __construct($debug = false) {
$this->clear_all();
if ( $debug ) {
$this->debug = true;
}
}
# This lets you add notices about what is going on so you can display them later
protected function add_notice($msg = '') {
if ( is_array($msg) || is_object($msg) ) {
$this->notices[] = print_r($msg, true);
} else {
$this->notices[] = $msg;
}
}
# Get an array of the most viewed posts as an array of the form ( post_id => number_of_views )
# - $oldest_date : should be of the form YYYY-MM-DD
# - $newest_date : should be of the form YYYY-MM-DD ( if null is provided, it will default to the current day )
# - $num_to_get : the number of results to return (e.g. 4 highest by default)
function get_highest_posts_in_range( $oldest_date, $newest_date = null, $num_to_get = 4 ) {
# Set up our return value
$found = array();
# Debug notice noting what was passed in
if ( $this->debug ) {
$this->add_notice( "Starting get_highest_posts_in_range( '{$oldest_date}', '{$newest_date}', {$num_to_get} )" );
}
# Do all real processing in a try / catch block to ensure can log problems instead of just throwing errors
try {
# Get a handle to the global database connection
global $wpdb;
# Verify that the provided $oldest_date is 10 characters long
if ( 10 !== strlen($oldest_date) ) {
throw new Exception("Parameter 1: Must be of the form YYYY-MM-DD", 10001);
} else {
# Appends time to the oldest date to make any between query include everything on the date
$oldest_date .= ' 00:00:00';
}
# Initialize the $newest_date variable OR validate that any non null value could be in the right format
if ( is_null( $newest_date ) ) {
$newest_date = date('Y-m-d') . ' 23:59:59';
} else if ( 10 !== strlen( $newest_date ) ) {
# Error
throw new Exception("Parameter 2: Must be null or in the form YYYY-MM-DD", 10002);
} else {
# Appends time to make any between query contain everything entered that day
$newest_date .= ' 23:59:59';
}
# Make sure that the number of records to get is sane
$num_to_get = (int) $num_to_get;
if ( $num_to_get <= 0 ) {
throw new Exception("Parameter 3: Must be a positive integer", 10003);
}
# Debug message to note the final values of provided variables after validation
if ( $this->debug ) {
$this->add_notice( "After Validation - Oldest: {$oldest_date}, Newest: {$newest_date}, Number to get: {$num_to_get}" );
}
# Build our query
# It will return the post_id and number of views (as views_in_period) for the most viewed items in the given date range
$query = <<<SQL
SELECT post_id, SUM(num_views) as views_in_period
FROM {$wpdb->prefix}post_views
WHERE entry_day BETWEEN %s AND %s
GROUP BY post_id
ORDER BY views_in_period DESC
LIMIT %d
SQL;
# Add our variables to the mysql query above safely
$query = $wpdb->prepare( $query, $oldest_date, $newest_date, $num_to_get );
# Debug message to note what the final prepared query is
if ( $this->debug ) {
$this->add_notice( "Prepared Query:<br />{$query}" );
}
# Run the query and get the results
$results = $wpdb->query( $query );
if ( false === $results ) {
$error = $wpdb->last_error;
throw new Exception("Bad Database query: {$query}, DB Error: {$error}", 10004);
} else if ( 0 < count($results) ) {
# There is at least one result. Add a debug message to show what the results are
$this->add_notice("Results detected:");
$this->add_notice( $results );
# Cycle through each result and add it to our return value
foreach ( $results as $row ) {
$found["{$row['post_id']}"] = $row['views'];
}
} else if ( $this->debug ) {
# No results returned, add a notice if in debug mode
$this->add_notice("Found no results for query");
}
} catch ( Exception $e ) {
# Exception detected, add it to the array of errors
$this->errors[] = $e;
}
return $found;
}
# This adds a new row to the post views table OR updates an existing row's num_views by 1
# The record is automatically added as viewed on the current day
function add_post_view( $post_id ) {
# Log how we were called
if ( $this->debug ) {
$this->add_notice("Called add_post_view( {$post_id} )");
}
# Initialize our return value
$added = 0;
try {
# Get hold of the database
global $wpdb;
# Add a new record. If there is a key violation, update the number of views instead.
# ( the unique key on the table is on the post_id and entry_day )
$query = <<<SQL
INSERT INTO {$wpdb->prefix}post_views (
post_id, entry_day, num_views
) VALUES (
%d, UTC_DATE(), 1
) ON DUPLICATE KEY UPDATE num_views = num_views + 1
SQL;
# Add our variables to the query in a safe manner
$query = $wpdb->prepare( $query, $post_id );
# Log the query to be ran so we can look at it if needed
if ( $this->debug ) {
$this->add_notice("Prepared Query: {$query}");
}
# Determine our results
$result = $wpdb->query( $query );
if ( false === $result ) {
# Error
$error = $wpdb->last_error;
throw new Exception("Bad Query: {$query}, Database Claims: {$error}", 10001);
} else if ( 0 === $result ) {
# Should never happen - would be an error as result is numer affected and there should be at least 1 row affected
throw new Exception("Bad Query: {$query}, Database claims no records updated!", 10002);
} else {
# Note how many changes were made (anything over 1 is fine)
if ( $this->debug ) {
$this->add_notice("Query completed with {$result} results");
}
$added = $added + $result;
}
} catch ( Exception $e ) {
# Make note of the exception
$this->errors[] = "Exception Ahoy!";
$this->errors[] = $e;
}
if ( $this->debug ) {
$this->add_notice("Leaving add_post_view");
}
return $added;
}
# Get the list of all errors as an array
function get_errors() {
if ( is_null( $this->errors ) ) {
$errors = array();
} else {
$errors = $this->errors;
}
return $errors;
}
# Get the list of all notices as an array
function get_notices() {
if ( is_null( $this->notices ) ) {
$notices = array();
} else {
$notices = $this->notices;
}
return $notices;
}
# Clear all errors and notices
# Used on initialization and between calls
function clear_all() {
$this->notices = array();
$this->errors = array();
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question