我认为你可以提高绩效
将视图信息保存在单个选项中,而不是保存在post meta中,在保存时而不是检索时应用筛选日期创建标记并在瞬态中保存,而不是在类中保存查询(片段缓存
class PopularPosts
{
const OPT = \'myplugin_popular_posts\';
/**
* After checking post date to see if save or not, increment a counter in a option
* as an array where keys are post ids and values number of views
*/
public function save(WP_Post $post)
{
if ( ! $this->shouldSave($post))
return;
$opt = get_option(self::OPT, array());
if ( ! isset($opt[$post->ID]) ) {
$opt[$post->ID] = 0;
}
$opt[$post->ID]++;
update_option(self::OPT, $opt);
}
/**
* Get markup from cache or rebuild it.
* In latter case setup an action on shutdown to defer cache of the markup.
* @return string
*/
public static function getMarkup()
{
$key = self::OPT . date(\'Yz\'); // change everyday
$cached = get_transient($key);
if ( ! empty($cached))
return $cached; // if cache is available just output it
$instance = new static;
$markup = $instance->buildMarkup();
if (empty($markup))
return \'\'; // return without cache empty results
add_action(\'shutdown\', function() use($markup,$key) {
set_transient($key, $markup, HOUR_IN_SECONDS);
});
return $markup;
}
/**
* Get popular posts and return proper markup
* @return string
*/
public function buildMarkup()
{
$opt = get_option(self::OPT);
if(empty($opt))
return; // nothing to get and show
$posts = $this->getPosts($opt); // obtain posts
$out = \'\';
$format = \'<li><a href="%s">%s</a><span>(%d %s)</span></li>\';
foreach($posts as $post) {
$title = apply_filters(\'the_title\', $post->post_title);
$plink = get_permalink($post);
$out .= sprintf($format, $plink, $title, $opt[$post->ID], __(\'views\', \'txdmn\'));
}
return \'<ul class="popular_posts">\' . $out . \'</ul>\';
}
/**
* Return true if the posts is not older than X days, where X is filterable
* @return boolean
*/
private function shouldSave( WP_Post $post )
{
$max_old = apply_filters( \'myplugin_popular_posts_max_days\', 31 );
$ptime = DateTime::createFromFormat(\'Y-m-d H:i:s\', $post->post_date);
$now = new DateTime(\'now\');
return (int) $now->diff($ptime)->days <= (int) $max_old;
}
/**
* Return X popular posts, where X number is filterable
* @return array
*/
private function getPosts($opt)
{
arsort($opt); // reverse order: more to less popular
$num = apply_filters(\'myplugin_popular_posts_num\', 5);
$ids = array_keys(array_slice($opt, 0, $num));
return (array) get_posts(array(\'post__in\' => $ids));
}
}
用法
update posts views 计数器:
add_action(\'shutdown\', function() {
if (is_single()) { // maybe check for post type using is_singular()
$popularposts = new PopularPosts;
$popularposts->save(get_queried_object());
}
});
和至
show markup 在模板中:
<?= PopularPosts::getMarkup() ?>
计数器选项的问题和可能的改进
should be reset evey day, 这里没有提供这方面的代码,但应该很容易实现。
使用lib-likeWP-TLC-Transient 您可以改进getMarkup
方法使用软过期和后台更新。类似这样:
public static function getMarkup()
{
$key = self::OPT . date(\'Yz\'); // change everyday
return tlc_transient( $key )
->updates_with(array(new static, \'buildMarkup\'))
->expires_in(HOUR_IN_SECONDS)
->get();
}
请注意,我不熟悉Jetpack,所以我不知道如何从中获取post统计数据。为了方便起见,我用了一个钩子
\'shutdown\'
只需增加选项中的计数器。这并不理想,因为即使用户只是刷新页面,计数器也会以这种方式递增。。。当然你可以改进它。
请注意,代码为completely untested.