web-dev-qa-db-ja.com

今日の訪問数と日付に基づいて投稿を質問する最も効率的な方法は何ですか?

私は自分のサイトがX日前の最も人気のある投稿を表示するためのコードを開発しようとしています。これを最も効率的な方法で達成するために、皆さんからの助けをお願いします。

これが私が計画していることです。それを行うより効率的な方法があるかどうか教えてください。

  1. 各投稿の表示を、その日にのみ存在する投稿メタに保存します。私はjetpackを有効にしているので、各投稿のビューを取得するためにそれを使うことができます。

  2. その日の訪問を含む投稿メタで投稿を(WP_queryで)検索します。

  3. 日付によるフィルタを適用します(X日前の投稿を取得するため)。だから私は投稿が何歳でなければならないかを選ぶことができます。たとえば、1か月以内の最も人気のある投稿を表示できます。 1か月以上前の投稿はクエリの対象になりません。

  4. 1時間ごとに更新される一時的なクエリでクエリを保存します(そのため、人気のある投稿を表示する必要があるたびにクエリが呼び出されることはありません)。 1時間ごとに訪問者に新しいコンテンツを表示したいので、これを1時間ごとにします。

  5. 翌日、その投稿がユーザーによって訪問されると、その投稿メタは削除され、新しい投稿が現在の日に作成されます。

注:私は何十万もの投稿を持っています。

足りない場合は、教えてください。

5
Gixty

私はあなたがパフォーマンスを向上させることができると思います

  • ポストメタではなく単一のオプションでビュー情報を保存する
  • 取得時ではなく保存時にフィルター日付を適用する
  • マークアップを作成し、クエリを保存する代わりに一時的に保存する(フラグメントキャッシュ)

クラスでの大まかな実装

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

}

使用法

投稿ビューを更新するカウンター

add_action('shutdown', function() {
  if (is_single()) { // maybe check for post type using is_singular()
    $popularposts = new PopularPosts;
    $popularposts->save(get_queried_object());
  }     
});

そして、あなたのテンプレートにマークアップを表示するには:

<?= PopularPosts::getMarkup() ?>

ガッチャと可能な改善

Counterオプションは毎日リセットする必要があります、そのためのコードはここでは提供されていませんが、実装はかなり簡単なはずです。

WP-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に慣れていないので、そこから投稿の統計情報を取得する方法がわかりません。意味をわかりやすくするために、オプションのカウンタを増やすために'shutdown'にフックを使用しました。ユーザーが単にページを更新しただけでもカウンターが増加するので、もちろんそれは理想的ではありません...もちろんそれを改善することができます。

ご注意ください

コードは完全にテストされていません

3
gmazzap