5 replaced http://wordpress.stackexchange.com/ with https://wordpress.stackexchange.com/
source | link
  1. Option 1: Turn it into a pluginTurn it into a plugin
  2. Option 2: Turn it into a library file (see below)
  3. Option 3: Add it to the bottom of your themes functions.php file.
  4. Option 4: Add it to the top of the template you want to use it in.
  1. Option 1: Turn it into a plugin
  2. Option 2: Turn it into a library file (see below)
  3. Option 3: Add it to the bottom of your themes functions.php file.
  4. Option 4: Add it to the top of the template you want to use it in.
  1. Option 1: Turn it into a plugin
  2. Option 2: Turn it into a library file (see below)
  3. Option 3: Add it to the bottom of your themes functions.php file.
  4. Option 4: Add it to the top of the template you want to use it in.
4 Revised completely and put a lot more commenting in
source | link

This function will let you add view logs to the tableHere is a revised version written as a class with logging, provided you set prefix aboveerror handling, and an example usage script to whatever your wordpress databaseshow what is using as the db prefix. (your wp_config.php file has this informationgoing on. It is wp_ by default)

function do_my_add_post_view( $post_id ) {
    try {
        global $wpdb;

        # See note 2 below
        $query = <<<SQL
INSERT INTO {$wpdb->prefix}post_views (
    post_id, entry_day, num_views
 ) VALUES (
    %d, UTC_DATE(), 1
 ) ON DUPLICATE KY UPDATE num_views = num_views + 1
SQL;

        # See note 3 below
        $query = $wpdb->prepare( $query, $post_id );

        # See note 4 below
        $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
            throw new Exception("Bad Query: {$query}, Database claims no records updated!", 10002);
        }
    } catch ( Exception $e ) {
        # Bad juju. Log the exception, die, print it, etc.
        echo '<p><b>Exception Ahoy!</b></p>';
        echo '<pre>';
        echo print_r( $e, true );
        echo '</pre>';
    }
}

Notes about above:The Handler Class

  1. Using exception requires PHP 5. If you aren't running at least php 5 this needs modified.
  2. The following query will attempt to add a new record on post_id and entry_day, the primary key. If the record already exists, it will instead simply update the num_views column by one. We use UTC_Date() here to ensure that no time information is logged ... so we can properly have lists of views by post by day. Of course, you might need to translate from UTC to your timezone if you want complete accuracy.
  3. Escape any bad data trying to be instered via post id
  4. Run the query and check for any errors

The above will get data into the system.

To pull out the most viewed posts in a time period, you might write a function like the following.

function get_highest_posts_in_range( $oldest_date, $newest_date = null, $num_to_get = 4 ) {
    $found = array();
    try {
        global $wpdb;

        # NOTE - you will need to pass days in like YYYY-MM-DD
        if ( 10 !== strlen($oldest_date) ) {
            throw new Exception("Parameter 1: Must be of the form YYYY-MM-DD", 10001);
        } else {
            $oldest_date .= ' 00:00:00';
        }
        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 {
            $newest_date .= ' 23:59:59';
        }
        $num_to_get = (int) $num_to_get;
        if ( $num_to_get <= 0 ) {
            throw new Exception("Parameter 3: Must be a positive integer", 10003);
        }

        $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;

        $query = $wpdb->prepare( $query, $oldest_date, $newest_date, $num_to_get );
        $results = $wpdb->query( $query );
        if ( false === $results ) {
            # Error
            $error = $wpdb->last_error;
            throw new Exception("Bad Database query: {$query}, DB Error: {$error}", 10004);
        } else if ( 0 < count($results) ) {
            foreach ( $results as $row ) {
                $found["{$row['post_id']}"] = $row['views'];
            }
        }
    } catch ( Exception $e ) {
        # Bad juju. Log, wp_die, whatever.
    }
    return $found;
}

We modified the input days to make sureThe below code is a small class that before forces starting at the 1st second of the day by adding 00:00:00 to the entered start date and last second of the day by adding 23:59:59 to the ending date enteredincludes debugging information so that you can see where any problems are.

Note that this returns an array, so you would have to useI've sprinkled it like:with notes to explain what is going on

$fromclass My_Most_Viewed_Posts {
    protected $errors = '2015-01-01';null;
$to    protected $notices = '2015-01-07';null;
$to_get    protected $debug = 4;false;

$most_viewed = get_highest_posts_in_range( $from, $to, $to_get );
    # 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();
    }
}

You would now have something likeTo make use of this class, you will need to do the following:

array(
  post_id => number_of_views,
  post_id => number_of_views,
  post_id => number_of_views,
  post_id => number_of_views
)
  1. Option 1: Turn it into a plugin
  2. Option 2: Turn it into a library file (see below)
  3. Option 3: Add it to the bottom of your themes functions.php file.
  4. Option 4: Add it to the top of the template you want to use it in.

To grab an array with the post_ids, you could alter the above function or use something like the following once you get the results.Turning a class into a simple library file

$wanted_ids = array_keys( $most_viewed );

If you want to use this as needed, you could create a new file ( say class-my-most-viewed-posts.php ) and copy the code into it with <?php on the first line of the file

Here is a revised version written as a class with logging, error handling,Drop it into your theme directory and an example usage script to show what is going on.you can then call it as follows from within your template:

class# My_Most_Viewed_PostsLoad {
the class file so that protectedthe $errorsclass =is null;made available
$found = locate_template('class-my-most-viewed-posts.php', true);
if protected( $noticesempty($found) =) null;{
    protectedecho $debug"<p>Failed =to false;locate template class-my-most-viewed-posts.php</p>";
} else {
    function# __construct($debugNOTE =- false)If {
you copy this into functions.php or into the template $this->clear_all(instead of creating its own file);:
    }# - copy from the line below to the line further down labeled INLINE DECLARATION METHOD END

    protected functionif add_notice($msg =! ''class_exists('My_Most_Viewed_Posts') ) {
        ifecho ("<p>Failed is_arrayto find class My_Most_Viewed_Posts</p>";
    } else {
        # Create an instance of the class in debug mode
        $Popularity = new My_Most_Viewed_Posts($msg true );
 ||       if ( !is_object($msg $Popularity ) ) {
            $this->notices[]echo ="<p>Failed print_r($msg,to true);create My_Most_Viewed_Posts object</p>";
        } else {
            $this->notices[] =# $msg;
NOTE - the $post_id here should be the }
post to add it }
for!
    function get_highest_posts_in_range( $oldest_date, $newest_date = null, $num_to_get = 4 ) {
        $found$entries_added = array();
        if ( $this->debug ) {
            $this$Popularity->add_notice( "Starting get_highest_posts_in_range>add_post_view( '{$oldest_date}', '{$newest_date}', {$num_to_get} )"$post_id );
        }
        try {
            global $wpdb;

            # NOTE - you will need to pass days in like YYYY-MM-DD
            if ( 100 !===== strlen($oldest_date)$entries_added ) {
                throw new Exception("Parameter 1: Must be of the form# YYYY-MM-DD"Failed, 10001);
            } else {
                $oldest_dateshow problems.= ' 00:00:00';
            }
          echo "<p>Notices:</p><pre>" if. print_r( is_null$Popularity->get_notices(), $newest_datetrue ) ). {"</pre>";
                $newest_date = date('Y-m-d') . 'echo 23:59"<p>Errors:59';
            } else</p><pre>" if. print_r( 10 !== strlen$Popularity->get_errors( $newest_date ) ) {
                # Error
                throw new Exception("Parameter 2: Must be null or in, thetrue form) YYYY-MM-DD",. 10002);"</pre>";
            } else {
                $newest_date .= ' 23:59:59';
            }
            $num_to_get = (int) $num_to_get;
            if ( $num_to_get <= 0 ) {
                throw new Exception("Parameter 3: Must be a positive integer", 10003);
            }
            if ( $this->debug ) {
                $this->add_notice( "Oldest: {$oldest_date}, Newest: {$newest_date}, Number to get: {$num_to_get}" );
            }
        $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;

            $query = $wpdb->prepare( $query, $oldest_date, $newest_date, $num_to_get );
            if ( $this->debug ) {
                $this->add_notice( "Prepared Query:<br />{$query}" );
            }
            $results = $wpdb->query( $query );
            if ( false === $results ) {
                # Error
                $error = $wpdb->last_error;
                throw new Exception("Bad Database query: {$query}, DB Error: {$error}", 10004);
            } else if ( 0 < count($results) ) {
                $this->add_notice("Results detected:");
                $this->add_notice( $results );
                foreach ( $results as $row ) {
                    $found["{$row['post_id']}"] = $row['views'];
                }
            } else if (Clear $this->debugnotices )so {far
                $this$Popularity->add_notice>clear_all("Found no results for query");
            }
        } catch ( Exception $e ) {
            # Bad juju. Log, wp_die, whatever.
            $this->errors[] = $e;
        }
        return $found;
    }

    function add_post_view( $post_id ) {
        if# (Tell $this->debuguser )we {
are making progress - comment out when done debugging
    $this->add_notice("Called add_post_view( {$post_id} )");
        }
  echo "<p>It seems to have worked. $addedAdded ={$entries_added} 0;record(s).</p>";
        try {
           echo global"<p>Checking $wpdb;counts</p>";

                # SeeGet notethe 2highest belowcounts now that we have added a record (from the first of the year to tonight at midnight)
            $query    $highest_counts = <<<SQL$Popularity->get_highest_posts_in_range( '2015-01-01', null, $num_to_get = 4 );
INSERT INTO {$wpdb->prefix}post_views              if ( ! is_array($highest_counts) ) {
    post_id, entry_day, num_views              echo "<p>Bad return value for highest posts in range</p>";
 ) VALUES                  echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
    %d, UTC_DATE               echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), 1
true ) ON. DUPLICATE"</pre>";
 KY UPDATE num_views = num_views + 1         } else {
SQL;                    # We have some highest counts in the form post_id => views

                    # SeeGet the ids of the posts (see note 32 below)
            $query = $wpdb      # see: http://php.net/manual/en/function.array->prepare(keys.php
 $query, $post_id                  $wanted_ids = array_keys( $highest_counts );

            if        # Build arguments for [WP_Query] (see $this->debugnote )3 {below)
                $this    # ->add_notice("Prepared Queryposts_per_page : {$query}");-1 means to show them all
            }        # - post_type : any will show all but those flagged exclude from search
                    # See- notepost_parent__in 4will belowrequire that the results have keys in the provided array
            $result        # see http://codex.wordpress.org/Class_Reference/WP_Query
                    $wanted_args = $wpdb->queryarray( 
 $query );                      'posts_per_page' => -1,
            if ( false === $result ) {      'post_type' => 'any',
                # Error       'post_parent__in' => $wanted_ids
                $error = $wpdb->last_error;  );
                throw new Exception("Bad Query: {$query},$wanted Database= Claims:new {$error}",WP_Query( 10001$wanted_args );
            } else       if ( 0$wanted->have_posts() ===) $result{
                        while ( $wanted->have_posts() ) {
                # Should never happen - would be an error    $most_viewed = $wanted->next_post();
                throw new Exception("Bad Query: {$query}, Database claims no records updated!"   echo "<p>Post Found:</p><pre>" . print_r( $most_viewed, 10002true ); . "</pre>";
            } else {          }
                if        unset( $this->debug$wanted );
                    } else {
                    $this->add_notice("Query completed with {$result} results"echo "<p>No posts found for wp_query using args:</p><pre>" . print_r( $wanted, true ); . "</pre>";
                    }
                }
                $added = $added + $result;
            }
        } catch ( Exception $e ) {
            # Bad juju. Log the exception, die, print it, etc.
            $this->errors[] = "Exception Ahoy!";
            $this->errors[] = $e;
        }
        if ( $this->debug ) {
            $this->add_notice("Leaving add_post_view");
        }
        return $added;
    }

    function get_errors() {
        if ( is_null( $this->errors ) ) {
            $errors = array();
        } else {
            $errors = $this->errors;
        }
        return $errors;
    }

    function get_notices() {
        if ( is_null( $this->notices ) ) {
            $notices = array();
        } else {
            $notices = $this->notices;
        }
        return $notices;
    }

    function clear_all() {
        $this->notices = array();
        $this->errors = array();
# INLINE DECLARATION METHOD }END
}

To make use of this classObviously, you will need to do the following:

To make sure that seems seem tocode could be added properlya lot shorter without all of the debug messages, you would do:but they should be helpful in tracking down the problem.

$Popularity = new My_Most_Viewed_Posts( true );
if ( is_object( $Popularity ) ) {
    $entries_added = $Popularity->add_post_view( $post_id );
    if ( 0 === $entries_added ) {
        echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
        echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), true ) . "</pre>";
    } else {
        $Popularity->clear_all();
        echo "<p>It seems to have worked. Added {$entries_added} record(s).</p>";
        echo "<p>Checking counts</p>";
        $highest_counts = $Popularity->get_highest_posts_in_range( '2015-01-01', null, $num_to_get = 4 );
        if ( ! is_array($highest_counts) ) {
            echo "<p>Bad return value for highest posts in range</p>";
            echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
            echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), true ) . "</pre>";
        } else {
            echo "<p>Found results:</p><pre>" . print_r($highest_counts, true) . "</pre>";
            $wanted_ids = array_keys( $highest_counts );

            # Time to grab the posts and draw them out
            $wanted_args = array(
                'posts_per_page' => -1,
                'post_type' => 'any',
                'post_parent__in' => array( $wanted_ids )
            );
            $wanted = new WP_Query( $wanted_args );
            if ( $wanted->have_posts() ) {
                while ( $wanted->have_posts() ) {
                    $most_viewed = $wanted->next_post();
                    echo "<p>Post Found:</p><pre>" . print_r( $most_viewed, true ) . "</pre>";
                }
                unset( $wanted );
            } else {
                echo "<p>Failed to list wanted posts</p>";
            }
        }
    }
} else {
    echo "<p>Error creating My_Most_Viewed_Posts object</p>";
}

If you usechoose to place the above, revised code and run into any problemsclass structure in your themes functions.php or in your template, it should displaycopy the problems, which should let me hopefully fix any typos / logical errors or point outsection just between INLINE DECLARATION METHOD for running the problemcode. (e.g. you do not use locate_template )

This function will let you add view logs to the table, provided you set prefix above to whatever your wordpress database is using as the db prefix. (your wp_config.php file has this information. It is wp_ by default)

function do_my_add_post_view( $post_id ) {
    try {
        global $wpdb;

        # See note 2 below
        $query = <<<SQL
INSERT INTO {$wpdb->prefix}post_views (
    post_id, entry_day, num_views
 ) VALUES (
    %d, UTC_DATE(), 1
 ) ON DUPLICATE KY UPDATE num_views = num_views + 1
SQL;

        # See note 3 below
        $query = $wpdb->prepare( $query, $post_id );

        # See note 4 below
        $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
            throw new Exception("Bad Query: {$query}, Database claims no records updated!", 10002);
        }
    } catch ( Exception $e ) {
        # Bad juju. Log the exception, die, print it, etc.
        echo '<p><b>Exception Ahoy!</b></p>';
        echo '<pre>';
        echo print_r( $e, true );
        echo '</pre>';
    }
}

Notes about above:

  1. Using exception requires PHP 5. If you aren't running at least php 5 this needs modified.
  2. The following query will attempt to add a new record on post_id and entry_day, the primary key. If the record already exists, it will instead simply update the num_views column by one. We use UTC_Date() here to ensure that no time information is logged ... so we can properly have lists of views by post by day. Of course, you might need to translate from UTC to your timezone if you want complete accuracy.
  3. Escape any bad data trying to be instered via post id
  4. Run the query and check for any errors

The above will get data into the system.

To pull out the most viewed posts in a time period, you might write a function like the following.

function get_highest_posts_in_range( $oldest_date, $newest_date = null, $num_to_get = 4 ) {
    $found = array();
    try {
        global $wpdb;

        # NOTE - you will need to pass days in like YYYY-MM-DD
        if ( 10 !== strlen($oldest_date) ) {
            throw new Exception("Parameter 1: Must be of the form YYYY-MM-DD", 10001);
        } else {
            $oldest_date .= ' 00:00:00';
        }
        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 {
            $newest_date .= ' 23:59:59';
        }
        $num_to_get = (int) $num_to_get;
        if ( $num_to_get <= 0 ) {
            throw new Exception("Parameter 3: Must be a positive integer", 10003);
        }

        $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;

        $query = $wpdb->prepare( $query, $oldest_date, $newest_date, $num_to_get );
        $results = $wpdb->query( $query );
        if ( false === $results ) {
            # Error
            $error = $wpdb->last_error;
            throw new Exception("Bad Database query: {$query}, DB Error: {$error}", 10004);
        } else if ( 0 < count($results) ) {
            foreach ( $results as $row ) {
                $found["{$row['post_id']}"] = $row['views'];
            }
        }
    } catch ( Exception $e ) {
        # Bad juju. Log, wp_die, whatever.
    }
    return $found;
}

We modified the input days to make sure that before forces starting at the 1st second of the day by adding 00:00:00 to the entered start date and last second of the day by adding 23:59:59 to the ending date entered.

Note that this returns an array, so you would have to use it like:

$from = '2015-01-01';
$to = '2015-01-07';
$to_get = 4;

$most_viewed = get_highest_posts_in_range( $from, $to, $to_get );

You would now have something like:

array(
  post_id => number_of_views,
  post_id => number_of_views,
  post_id => number_of_views,
  post_id => number_of_views
)

To grab an array with the post_ids, you could alter the above function or use something like the following once you get the results.

$wanted_ids = array_keys( $most_viewed );

Here is a revised version written as a class with logging, error handling, and an example usage script to show what is going on.

class My_Most_Viewed_Posts {
    protected $errors = null;
    protected $notices = null;
    protected $debug = false;

    function __construct($debug = false) {
        $this->clear_all();
    }

    protected function add_notice($msg = '') {
        if ( is_array($msg) || is_object($msg) ) {
            $this->notices[] = print_r($msg, true);
        } else {
            $this->notices[] = $msg;
        }
    }

    function get_highest_posts_in_range( $oldest_date, $newest_date = null, $num_to_get = 4 ) {
        $found = array();
        if ( $this->debug ) {
            $this->add_notice( "Starting get_highest_posts_in_range( '{$oldest_date}', '{$newest_date}', {$num_to_get} )" );
        }
        try {
            global $wpdb;

            # NOTE - you will need to pass days in like YYYY-MM-DD
            if ( 10 !== strlen($oldest_date) ) {
                throw new Exception("Parameter 1: Must be of the form YYYY-MM-DD", 10001);
            } else {
                $oldest_date .= ' 00:00:00';
            }
            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 {
                $newest_date .= ' 23:59:59';
            }
            $num_to_get = (int) $num_to_get;
            if ( $num_to_get <= 0 ) {
                throw new Exception("Parameter 3: Must be a positive integer", 10003);
            }
            if ( $this->debug ) {
                $this->add_notice( "Oldest: {$oldest_date}, Newest: {$newest_date}, Number to get: {$num_to_get}" );
            }
        $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;

            $query = $wpdb->prepare( $query, $oldest_date, $newest_date, $num_to_get );
            if ( $this->debug ) {
                $this->add_notice( "Prepared Query:<br />{$query}" );
            }
            $results = $wpdb->query( $query );
            if ( false === $results ) {
                # Error
                $error = $wpdb->last_error;
                throw new Exception("Bad Database query: {$query}, DB Error: {$error}", 10004);
            } else if ( 0 < count($results) ) {
                $this->add_notice("Results detected:");
                $this->add_notice( $results );
                foreach ( $results as $row ) {
                    $found["{$row['post_id']}"] = $row['views'];
                }
            } else if ( $this->debug ) {
                $this->add_notice("Found no results for query");
            }
        } catch ( Exception $e ) {
            # Bad juju. Log, wp_die, whatever.
            $this->errors[] = $e;
        }
        return $found;
    }

    function add_post_view( $post_id ) {
        if ( $this->debug ) {
            $this->add_notice("Called add_post_view( {$post_id} )");
        }
        $added = 0;
        try {
            global $wpdb;

            # See note 2 below
            $query = <<<SQL
INSERT INTO {$wpdb->prefix}post_views (
    post_id, entry_day, num_views
 ) VALUES (
    %d, UTC_DATE(), 1
 ) ON DUPLICATE KY UPDATE num_views = num_views + 1
SQL;

            # See note 3 below
            $query = $wpdb->prepare( $query, $post_id );

            if ( $this->debug ) {
                $this->add_notice("Prepared Query: {$query}");
            }
            # See note 4 below
            $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
                throw new Exception("Bad Query: {$query}, Database claims no records updated!", 10002);
            } else {
                if ( $this->debug ) {
                    $this->add_notice("Query completed with {$result} results");
                }
                $added = $added + $result;
            }
        } catch ( Exception $e ) {
            # Bad juju. Log the exception, die, print it, etc.
            $this->errors[] = "Exception Ahoy!";
            $this->errors[] = $e;
        }
        if ( $this->debug ) {
            $this->add_notice("Leaving add_post_view");
        }
        return $added;
    }

    function get_errors() {
        if ( is_null( $this->errors ) ) {
            $errors = array();
        } else {
            $errors = $this->errors;
        }
        return $errors;
    }

    function get_notices() {
        if ( is_null( $this->notices ) ) {
            $notices = array();
        } else {
            $notices = $this->notices;
        }
        return $notices;
    }

    function clear_all() {
        $this->notices = array();
        $this->errors = array();
    }
}

To make use of this class, you will need to do the following:

To make sure that seems seem to be added properly, you would do:

$Popularity = new My_Most_Viewed_Posts( true );
if ( is_object( $Popularity ) ) {
    $entries_added = $Popularity->add_post_view( $post_id );
    if ( 0 === $entries_added ) {
        echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
        echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), true ) . "</pre>";
    } else {
        $Popularity->clear_all();
        echo "<p>It seems to have worked. Added {$entries_added} record(s).</p>";
        echo "<p>Checking counts</p>";
        $highest_counts = $Popularity->get_highest_posts_in_range( '2015-01-01', null, $num_to_get = 4 );
        if ( ! is_array($highest_counts) ) {
            echo "<p>Bad return value for highest posts in range</p>";
            echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
            echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), true ) . "</pre>";
        } else {
            echo "<p>Found results:</p><pre>" . print_r($highest_counts, true) . "</pre>";
            $wanted_ids = array_keys( $highest_counts );

            # Time to grab the posts and draw them out
            $wanted_args = array(
                'posts_per_page' => -1,
                'post_type' => 'any',
                'post_parent__in' => array( $wanted_ids )
            );
            $wanted = new WP_Query( $wanted_args );
            if ( $wanted->have_posts() ) {
                while ( $wanted->have_posts() ) {
                    $most_viewed = $wanted->next_post();
                    echo "<p>Post Found:</p><pre>" . print_r( $most_viewed, true ) . "</pre>";
                }
                unset( $wanted );
            } else {
                echo "<p>Failed to list wanted posts</p>";
            }
        }
    }
} else {
    echo "<p>Error creating My_Most_Viewed_Posts object</p>";
}

If you use the above, revised code and run into any problems, it should display the problems, which should let me hopefully fix any typos / logical errors or point out the problem.

Here is a revised version written as a class with logging, error handling, and an example usage script to show what is going on.

The Handler Class

The below code is a small class that includes debugging information so that you can see where any problems are.

I've sprinkled it with notes to explain what is going on

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();
    }
}

To make use of this class, you will need to do the following:

  1. Option 1: Turn it into a plugin
  2. Option 2: Turn it into a library file (see below)
  3. Option 3: Add it to the bottom of your themes functions.php file.
  4. Option 4: Add it to the top of the template you want to use it in.

Turning a class into a simple library file

If you want to use this as needed, you could create a new file ( say class-my-most-viewed-posts.php ) and copy the code into it with <?php on the first line of the file

Drop it into your theme directory and you can then call it as follows from within your template:

# Load the class file so that the class is made available
$found = locate_template('class-my-most-viewed-posts.php', true);
if ( empty($found) ) {
    echo "<p>Failed to locate template class-my-most-viewed-posts.php</p>";
} else {
    # NOTE - If you copy this into functions.php or into the template (instead of creating its own file):
    # - copy from the line below to the line further down labeled INLINE DECLARATION METHOD END

    if ( ! class_exists('My_Most_Viewed_Posts') ) {
        echo "<p>Failed to find class My_Most_Viewed_Posts</p>";
    } else {
        # Create an instance of the class in debug mode
        $Popularity = new My_Most_Viewed_Posts( true );
        if ( !is_object( $Popularity ) ) {
            echo "<p>Failed to create My_Most_Viewed_Posts object</p>";
        } else {
            # NOTE - the $post_id here should be the post to add it for!
            $entries_added = $Popularity->add_post_view( $post_id );
            if ( 0 === $entries_added ) {
                # Failed, show problems.
                echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
                echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), true ) . "</pre>";
            } else {
                # Clear notices so far
                $Popularity->clear_all();

                # Tell user we are making progress - comment out when done debugging
                echo "<p>It seems to have worked. Added {$entries_added} record(s).</p>";
                echo "<p>Checking counts</p>";

                # Get the highest counts now that we have added a record (from the first of the year to tonight at midnight)
                $highest_counts = $Popularity->get_highest_posts_in_range( '2015-01-01', null, $num_to_get = 4 );
                if ( ! is_array($highest_counts) ) {
                    echo "<p>Bad return value for highest posts in range</p>";
                    echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
                    echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), true ) . "</pre>";
                } else {
                    # We have some highest counts in the form post_id => views

                    # Get the ids of the posts (see note 2 below)
                    # see: http://php.net/manual/en/function.array-keys.php
                    $wanted_ids = array_keys( $highest_counts );

                    # Build arguments for [WP_Query] (see note 3 below)
                    # - posts_per_page : -1 means to show them all
                    # - post_type : any will show all but those flagged exclude from search
                    # - post_parent__in will require that the results have keys in the provided array
                    # see http://codex.wordpress.org/Class_Reference/WP_Query
                    $wanted_args = array( 
                        'posts_per_page' => -1,
                        'post_type' => 'any',
                        'post_parent__in' => $wanted_ids
                    );
                    $wanted = new WP_Query( $wanted_args );
                    if ( $wanted->have_posts() ) {
                        while ( $wanted->have_posts() ) {
                            $most_viewed = $wanted->next_post();
                            echo "<p>Post Found:</p><pre>" . print_r( $most_viewed, true ) . "</pre>";
                        }
                        unset( $wanted );
                    } else {
                        echo "<p>No posts found for wp_query using args:</p><pre>" . print_r( $wanted, true ) . "</pre>";
                    }
                }
            }
        }
    }
    # INLINE DECLARATION METHOD END
}

Obviously, the code could be a lot shorter without all of the debug messages, but they should be helpful in tracking down the problem.

If you choose to place the class structure in your themes functions.php or in your template, copy the section just between INLINE DECLARATION METHOD for running the code. (e.g. you do not use locate_template )

3 Rewrote as a simple class and posted a usage example. Provided this does the trick I'll revise the answer.
source | link
function do_my_add_post_view( $post_id ) {
    try {
        global $wpdb;

        # See note 2 below
        $query = <<<SQL
INSERT INTO {$wpdb->prefix}post_views (
    post_id, entry_day, num_views
 ) VALUES (
    %d, UTC_DATE(), 1
 ) ON DUPLICATE KY UPDATE num_views = num_views + 1
SQL;

        # See note 3 below
        $query = $wpdb->prepare( $query, $post_id );

        # See note 4 below
        $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
            throw new Exception("Bad Query: {$query}, Database claims no records updated!", 10002);
        }
    } catch ( Exception $e ) {
        # Bad juju. Log the exception, die, print it, etc.
        echo '<p><b>Exception Ahoy!</b></p><pre>'p>';
 .       echo '<pre>';
        echo print_r( $e, true );
 .       echo '</pre>';
    }
}
$wanted_ids = array_keys( $most_viewed );

Here is a revised version written as a class with logging, error handling, and an example usage script to show what is going on.

class My_Most_Viewed_Posts {
    protected $errors = null;
    protected $notices = null;
    protected $debug = false;

    function __construct($debug = false) {
        $this->clear_all();
    }

    protected function add_notice($msg = '') {
        if ( is_array($msg) || is_object($msg) ) {
            $this->notices[] = print_r($msg, true);
        } else {
            $this->notices[] = $msg;
        }
    }

    function get_highest_posts_in_range( $oldest_date, $newest_date = null, $num_to_get = 4 ) {
        $found = array();
        if ( $this->debug ) {
            $this->add_notice( "Starting get_highest_posts_in_range( '{$oldest_date}', '{$newest_date}', {$num_to_get} )" );
        }
        try {
            global $wpdb;

            # NOTE - you will need to pass days in like YYYY-MM-DD
            if ( 10 !== strlen($oldest_date) ) {
                throw new Exception("Parameter 1: Must be of the form YYYY-MM-DD", 10001);
            } else {
                $oldest_date .= ' 00:00:00';
            }
            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 {
                $newest_date .= ' 23:59:59';
            }
            $num_to_get = (int) $num_to_get;
            if ( $num_to_get <= 0 ) {
                throw new Exception("Parameter 3: Must be a positive integer", 10003);
            }
            if ( $this->debug ) {
                $this->add_notice( "Oldest: {$oldest_date}, Newest: {$newest_date}, Number to get: {$num_to_get}" );
            }
        $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;

            $query = $wpdb->prepare( $query, $oldest_date, $newest_date, $num_to_get );
            if ( $this->debug ) {
                $this->add_notice( "Prepared Query:<br />{$query}" );
            }
            $results = $wpdb->query( $query );
            if ( false === $results ) {
                # Error
                $error = $wpdb->last_error;
                throw new Exception("Bad Database query: {$query}, DB Error: {$error}", 10004);
            } else if ( 0 < count($results) ) {
                $this->add_notice("Results detected:");
                $this->add_notice( $results );
                foreach ( $results as $row ) {
                    $found["{$row['post_id']}"] = $row['views'];
                }
            } else if ( $this->debug ) {
                $this->add_notice("Found no results for query");
            }
        } catch ( Exception $e ) {
            # Bad juju. Log, wp_die, whatever.
            $this->errors[] = $e;
        }
        return $found;
    }

    function add_post_view( $post_id ) {
        if ( $this->debug ) {
            $this->add_notice("Called add_post_view( {$post_id} )");
        }
        $added = 0;
        try {
            global $wpdb;

            # See note 2 below
            $query = <<<SQL
INSERT INTO {$wpdb->prefix}post_views (
    post_id, entry_day, num_views
 ) VALUES (
    %d, UTC_DATE(), 1
 ) ON DUPLICATE KY UPDATE num_views = num_views + 1
SQL;

            # See note 3 below
            $query = $wpdb->prepare( $query, $post_id );

            if ( $this->debug ) {
                $this->add_notice("Prepared Query: {$query}");
            }
            # See note 4 below
            $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
                throw new Exception("Bad Query: {$query}, Database claims no records updated!", 10002);
            } else {
                if ( $this->debug ) {
                    $this->add_notice("Query completed with {$result} results");
                }
                $added = $added + $result;
            }
        } catch ( Exception $e ) {
            # Bad juju. Log the exception, die, print it, etc.
            $this->errors[] = "Exception Ahoy!";
            $this->errors[] = $e;
        }
        if ( $this->debug ) {
            $this->add_notice("Leaving add_post_view");
        }
        return $added;
    }

    function get_errors() {
        if ( is_null( $this->errors ) ) {
            $errors = array();
        } else {
            $errors = $this->errors;
        }
        return $errors;
    }

    function get_notices() {
        if ( is_null( $this->notices ) ) {
            $notices = array();
        } else {
            $notices = $this->notices;
        }
        return $notices;
    }

    function clear_all() {
        $this->notices = array();
        $this->errors = array();
    }
}

To make use of this class, you will need to do the following:

To make sure that seems seem to be added properly, you would do:

$Popularity = new My_Most_Viewed_Posts( true );
if ( is_object( $Popularity ) ) {
    $entries_added = $Popularity->add_post_view( $post_id );
    if ( 0 === $entries_added ) {
        echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
        echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), true ) . "</pre>";
    } else {
        $Popularity->clear_all();
        echo "<p>It seems to have worked. Added {$entries_added} record(s).</p>";
        echo "<p>Checking counts</p>";
        $highest_counts = $Popularity->get_highest_posts_in_range( '2015-01-01', null, $num_to_get = 4 );
        if ( ! is_array($highest_counts) ) {
            echo "<p>Bad return value for highest posts in range</p>";
            echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
            echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), true ) . "</pre>";
        } else {
            echo "<p>Found results:</p><pre>" . print_r($highest_counts, true) . "</pre>";
            $wanted_ids = array_keys( $highest_counts );

            # Time to grab the posts and draw them out
            $wanted_args = array(
                'posts_per_page' => -1,
                'post_type' => 'any',
                'post_parent__in' => array( $wanted_ids )
            );
            $wanted = new WP_Query( $wanted_args );
            if ( $wanted->have_posts() ) {
                while ( $wanted->have_posts() ) {
                    $most_viewed = $wanted->next_post();
                    echo "<p>Post Found:</p><pre>" . print_r( $most_viewed, true ) . "</pre>";
                }
                unset( $wanted );
            } else {
                echo "<p>Failed to list wanted posts</p>";
            }
        }
    }
} else {
    echo "<p>Error creating My_Most_Viewed_Posts object</p>";
}

If you use the above, revised code and run into any problems, it should display the problems, which should let me hopefully fix any typos / logical errors or point out the problem.

function do_my_add_post_view( $post_id ) {
    try {
        global $wpdb;

        # See note 2 below
        $query = <<<SQL
INSERT INTO {$wpdb->prefix}post_views (
    post_id, entry_day, num_views
 ) VALUES (
    %d, UTC_DATE(), 1
 ) ON DUPLICATE KY UPDATE num_views = num_views + 1
SQL;

        # See note 3 below
        $query = $wpdb->prepare( $query, $post_id );

        # See note 4 below
        $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
            throw new Exception("Bad Query: {$query}, Database claims no records updated!", 10002);
        }
    } catch ( Exception $e ) {
        # Bad juju. Log the exception, die, print it, etc.
        echo '<p><b>Exception Ahoy!</b></p><pre>' . print_r( $e, true ) . '</pre>';
    }
}
$wanted_ids = array_keys( $most_viewed );
function do_my_add_post_view( $post_id ) {
    try {
        global $wpdb;

        # See note 2 below
        $query = <<<SQL
INSERT INTO {$wpdb->prefix}post_views (
    post_id, entry_day, num_views
 ) VALUES (
    %d, UTC_DATE(), 1
 ) ON DUPLICATE KY UPDATE num_views = num_views + 1
SQL;

        # See note 3 below
        $query = $wpdb->prepare( $query, $post_id );

        # See note 4 below
        $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
            throw new Exception("Bad Query: {$query}, Database claims no records updated!", 10002);
        }
    } catch ( Exception $e ) {
        # Bad juju. Log the exception, die, print it, etc.
        echo '<p><b>Exception Ahoy!</b></p>';
        echo '<pre>';
        echo print_r( $e, true );
        echo '</pre>';
    }
}
$wanted_ids = array_keys( $most_viewed );

Here is a revised version written as a class with logging, error handling, and an example usage script to show what is going on.

class My_Most_Viewed_Posts {
    protected $errors = null;
    protected $notices = null;
    protected $debug = false;

    function __construct($debug = false) {
        $this->clear_all();
    }

    protected function add_notice($msg = '') {
        if ( is_array($msg) || is_object($msg) ) {
            $this->notices[] = print_r($msg, true);
        } else {
            $this->notices[] = $msg;
        }
    }

    function get_highest_posts_in_range( $oldest_date, $newest_date = null, $num_to_get = 4 ) {
        $found = array();
        if ( $this->debug ) {
            $this->add_notice( "Starting get_highest_posts_in_range( '{$oldest_date}', '{$newest_date}', {$num_to_get} )" );
        }
        try {
            global $wpdb;

            # NOTE - you will need to pass days in like YYYY-MM-DD
            if ( 10 !== strlen($oldest_date) ) {
                throw new Exception("Parameter 1: Must be of the form YYYY-MM-DD", 10001);
            } else {
                $oldest_date .= ' 00:00:00';
            }
            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 {
                $newest_date .= ' 23:59:59';
            }
            $num_to_get = (int) $num_to_get;
            if ( $num_to_get <= 0 ) {
                throw new Exception("Parameter 3: Must be a positive integer", 10003);
            }
            if ( $this->debug ) {
                $this->add_notice( "Oldest: {$oldest_date}, Newest: {$newest_date}, Number to get: {$num_to_get}" );
            }
        $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;

            $query = $wpdb->prepare( $query, $oldest_date, $newest_date, $num_to_get );
            if ( $this->debug ) {
                $this->add_notice( "Prepared Query:<br />{$query}" );
            }
            $results = $wpdb->query( $query );
            if ( false === $results ) {
                # Error
                $error = $wpdb->last_error;
                throw new Exception("Bad Database query: {$query}, DB Error: {$error}", 10004);
            } else if ( 0 < count($results) ) {
                $this->add_notice("Results detected:");
                $this->add_notice( $results );
                foreach ( $results as $row ) {
                    $found["{$row['post_id']}"] = $row['views'];
                }
            } else if ( $this->debug ) {
                $this->add_notice("Found no results for query");
            }
        } catch ( Exception $e ) {
            # Bad juju. Log, wp_die, whatever.
            $this->errors[] = $e;
        }
        return $found;
    }

    function add_post_view( $post_id ) {
        if ( $this->debug ) {
            $this->add_notice("Called add_post_view( {$post_id} )");
        }
        $added = 0;
        try {
            global $wpdb;

            # See note 2 below
            $query = <<<SQL
INSERT INTO {$wpdb->prefix}post_views (
    post_id, entry_day, num_views
 ) VALUES (
    %d, UTC_DATE(), 1
 ) ON DUPLICATE KY UPDATE num_views = num_views + 1
SQL;

            # See note 3 below
            $query = $wpdb->prepare( $query, $post_id );

            if ( $this->debug ) {
                $this->add_notice("Prepared Query: {$query}");
            }
            # See note 4 below
            $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
                throw new Exception("Bad Query: {$query}, Database claims no records updated!", 10002);
            } else {
                if ( $this->debug ) {
                    $this->add_notice("Query completed with {$result} results");
                }
                $added = $added + $result;
            }
        } catch ( Exception $e ) {
            # Bad juju. Log the exception, die, print it, etc.
            $this->errors[] = "Exception Ahoy!";
            $this->errors[] = $e;
        }
        if ( $this->debug ) {
            $this->add_notice("Leaving add_post_view");
        }
        return $added;
    }

    function get_errors() {
        if ( is_null( $this->errors ) ) {
            $errors = array();
        } else {
            $errors = $this->errors;
        }
        return $errors;
    }

    function get_notices() {
        if ( is_null( $this->notices ) ) {
            $notices = array();
        } else {
            $notices = $this->notices;
        }
        return $notices;
    }

    function clear_all() {
        $this->notices = array();
        $this->errors = array();
    }
}

To make use of this class, you will need to do the following:

To make sure that seems seem to be added properly, you would do:

$Popularity = new My_Most_Viewed_Posts( true );
if ( is_object( $Popularity ) ) {
    $entries_added = $Popularity->add_post_view( $post_id );
    if ( 0 === $entries_added ) {
        echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
        echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), true ) . "</pre>";
    } else {
        $Popularity->clear_all();
        echo "<p>It seems to have worked. Added {$entries_added} record(s).</p>";
        echo "<p>Checking counts</p>";
        $highest_counts = $Popularity->get_highest_posts_in_range( '2015-01-01', null, $num_to_get = 4 );
        if ( ! is_array($highest_counts) ) {
            echo "<p>Bad return value for highest posts in range</p>";
            echo "<p>Notices:</p><pre>" . print_r( $Popularity->get_notices(), true ) . "</pre>";
            echo "<p>Errors:</p><pre>" . print_r( $Popularity->get_errors(), true ) . "</pre>";
        } else {
            echo "<p>Found results:</p><pre>" . print_r($highest_counts, true) . "</pre>";
            $wanted_ids = array_keys( $highest_counts );

            # Time to grab the posts and draw them out
            $wanted_args = array(
                'posts_per_page' => -1,
                'post_type' => 'any',
                'post_parent__in' => array( $wanted_ids )
            );
            $wanted = new WP_Query( $wanted_args );
            if ( $wanted->have_posts() ) {
                while ( $wanted->have_posts() ) {
                    $most_viewed = $wanted->next_post();
                    echo "<p>Post Found:</p><pre>" . print_r( $most_viewed, true ) . "</pre>";
                }
                unset( $wanted );
            } else {
                echo "<p>Failed to list wanted posts</p>";
            }
        }
    }
} else {
    echo "<p>Error creating My_Most_Viewed_Posts object</p>";
}

If you use the above, revised code and run into any problems, it should display the problems, which should let me hopefully fix any typos / logical errors or point out the problem.

2 Placed function into own block and added notes to bottom for clarity
source | link
1
source | link