按周代码列出的WordPress热门帖子

时间:2015-01-27 作者:Dolomats

我正在尝试制作一个按周列出热门帖子的代码。到目前为止,我能够创建一个veiws计数器并显示4个流行帖子。所以我仍然需要的是使这个查询更加准确。我想得到缩略图和链接,并得到本周最受欢迎的。

Functions.php

remove_action( \'wp_head\', \'adjacent_posts_rel_link_wp_head\', 10, 0);
function wpb_track_post_views ($post_id) {
    if ( !is_single() ) return;
    if ( empty ( $post_id) ) {
        global $post;
        $post_id = $post->ID;    
    }

    wpb_set_post_views($post_id);
}
add_action( \'wp_head\', \'wpb_track_post_views\');

function wpb_get_post_views($postID){
    $count_key = \'wpb_post_views_count\';
    $count = get_post_meta($postID, $count_key, true);
    if($count==\'\'){
        delete_post_meta($postID, $count_key);
        add_post_meta($postID, $count_key, \'0\');
        return "0 View";
    }

    return $count.\' Views\';
}

Single.php

wpb_set_post_views(get_the_ID());
<?php echo wpb_get_post_views(get_the_ID()); ?>

// show 4 most popular posts
<?php 
    $popularpost = new WP_Query( array( 
        \'posts_per_page\' => 4,
        \'meta_key\' => \'wpb_post_views_count\',
        \'orderby\' => \'meta_value_num\', 
        \'order\' => \'DESC\'
    ) );

    while ( $popularpost->have_posts() ) : $popularpost->the_post();

        the_title();

    endwhile;
?>

2 个回复
最合适的回答,由SO网友:Privateer 整理而成

目前,我认为没有办法做到这一点,因为您没有很好的参考来获取基于日期的统计数据。

Notice:您正在按如下方式存储post视图:

add_post_meta($postID, $count_key, \'0\');
为了能够获取“最受关注的时期”,您必须做一些更复杂的事情,可能需要一个额外的数据库表。现在,视图的数量与任何时间段都没有关系。

例如,如果在数据库中创建了下表:

{$prefix} 应使用wordpress数据库表前缀(例如wp\\uu1)

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)
);
使用该表,您现在可以跟踪一段时间内的最高职位。

下面是作为类编写的修订版本,其中包含日志记录、错误处理和一个示例使用脚本,以显示正在发生的情况。

The Handler Class

下面的代码是一个小类,其中包含调试信息,以便您可以查看问题所在。

我在上面撒了笔记来解释发生了什么

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();
    }
}
要使用此类,您需要执行以下操作:

选项1:Turn it into a plugin

Turning a class into a simple library file

如果您想根据需要使用它,可以创建一个新文件(比如class-my-most-viewed-posts.php),并使用<?php 在文件的第一行

将其放入主题目录,然后可以从模板中按如下方式调用它:

# 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
}
显然,如果没有所有调试消息,代码可能会短得多,但它们应该有助于跟踪问题。

如果选择在主题函数中放置类结构。php或在模板中,复制用于运行代码的内联声明方法之间的部分。(例如,您不使用locate\\u模板)

SO网友:Andrey

Privateer,非常感谢您的示例和解释。就我而言,只有当我change a bit 在里面get_highest_posts_in_range() 类文件的功能:

  • $results=$wpdb->query($query);

    $results=$wpdb->get_results($query,ARRAY_A);


  • $found["{$row[\'post_id\']}"]=$row[\'views\'];

    $found["{$row[\'post_id\']}"]=$row[\'views_in_period\'];

主题代码也需要做一些更改-args可以获得最受欢迎的帖子:

$wanted_args = array(
    \'posts_per_page\' => 4,
    \'post_type\' => \'post\',
    \'post_status\' => \'publish\',
    \'post__in\' => $wanted_ids
);
由于如果我有一个错误,数据库的所有记录都被捕获了,所以我将数量限制为4. 我选择了post only(在我的例子中),而不是parents记录,而是post的简单id。

结束

相关推荐