行き着く先はあんこ

WordPressにプラグインを使わず定期的に更新される人気記事を表示する

プラグインを使わずにWordPressで人気記事を表示させる

WordPressには便利なプラグインがたくさんあり、人気記事を表示する「WordPress Popular Posts」も非常に便利です。しかし、なんでもかんでもプラグインを使っているとサイトが重くなってしまうこともあります。

そこで今回はプラグインを使わずにWordPressで人気記事を表示する方法を備忘録もかねてまとめておきます。

スポンサーリンク

WordPressに人気記事を表示する

「WordPress プラグイン使わずに 人気記事」などで検索するとカスタムフィールドを使った方法がヒットします。今回は以下のサイトで紹介されているコードを改良して使います。

参考[WordPress]プラグイン無しで記事のアクセス数をカウントする関数と、アクセスランキングの表示を行うスニペット|increment Log

紹介されているコードをそのまま使うとアクセスの集計期間が過去全てになってまうので、今回は集計期間を1日にするために少し改良します。また、アクセス数は1時間ごとに分けて保存し、1時間ごとに1日前のアクセス数を削除するようにします。

人気記事を表示するfunctions.phpコード

まずfunctions.phpに書くコード全体はこのようになります。

//アクセス数をカウントする
function set_post_views() {
  $postID = get_the_ID();
  $num = (int)date_i18n('H'); // 現在時間で番号取得
  $key = 'pv_count';
  $count_key = '_pv_count';
  $count_array = get_post_meta( $postID, $count_key, true );
  $sum_count = get_post_meta( $postID, $key, true );

  if( !is_array($count_array) ) { //配列ではない
    $count_array = array();
    $count_array[$num] = 1;
  } else { //配列である
    if ( isset( $count_array[$num] ) ) { //カウント配列[n]が存在する
      $count_array[$num] += 1;
    } else { //カウント配列[n]が存在しない
      $count_array[$num] = 1;
    }
  }

  //アクセス数を更新する
  update_post_meta( $postID, $count_key, $count_array );
  update_post_meta( $postID, $key, $sum_count + 1 );
}

//アクセス数をリセットする
function reset_post_views() {
  $num = (int)date_i18n('H');
  $key = 'pv_count';
  $reset_key = '_pv_count';

  $args = array(
    'posts_per_page'   => -1,
    'post_type' => 'post',
    'post_status'=>'publish',
    'meta_key' => $reset_key,
  );

  $reset_posts = get_posts($args);
  if($reset_posts):
    foreach($reset_posts as $reset_post):
      $postID = $reset_post->ID;
      $count_array = get_post_meta( $postID , $reset_key, true );

      if ( isset( $count_array[$num] ) ) { //カウント配列[n]が存在する
        $count_array[$num] = 0;
      }

      //アクセス数をリセットする
      update_post_meta( $postID, $reset_key, $count_array );
      update_post_meta( $postID, $key, array_sum( $count_array ) );
    endforeach;
  endif;
}

//リセット関数を実行するアクションフックを追加
add_action( 'set_hours_event', 'reset_post_views' );

//実行間隔の追加
function my_interval( $schedules ) {
  // 1時間ごとを追加
  $schedules['1hours'] = array(
    'interval' => 3600,
    'display' => 'every 1 hours'
  );
  return $schedules;
}
add_filter( 'cron_schedules', 'my_interval' );

//アクションフックを定期的に実行するスケジュールイベントの追加
function my_activation() {
  if ( ! wp_next_scheduled( 'set_hours_event' ) ) {
    wp_schedule_event( 1451574000, '1hours', 'set_hours_event' );
  }
}
add_action('wp', 'my_activation');

//ボットの判別
function isBot() {
    $bot_list = array (
        'Googlebot',
        'Yahoo! Slurp',
        'Mediapartners-Google',
        'msnbot',
        'bingbot',
        'MJ12bot',
        'Ezooms',
        'pirst; MSIE 8.0;',
        'Google Web Preview',
        'ia_archiver',
        'Sogou web spider',
        'Googlebot-Mobile',
        'AhrefsBot',
        'YandexBot',
        'Purebot',
        'Baiduspider',
        'UnwindFetchor',
        'TweetmemeBot',
        'MetaURI',
        'PaperLiBot',
        'Showyoubot',
        'JS-Kit',
        'PostRank',
        'Crowsnest',
        'PycURL',
        'bitlybot',
        'Hatena',
        'facebookexternalhit',
        'NINJA bot',
        'YahooCacheSystem',
        'NHN Corp.',
        'Steeler',
        'DoCoMo',
    );
    $is_bot = false;
    foreach ($bot_list as $bot) {
        if (stripos($_SERVER['HTTP_USER_AGENT'], $bot) !== false) {
            $is_bot = true;
            break;
        }
    }
    return $is_bot;
}

それぞれの関数を簡単に見ていきます。

アクセス数をカウント

function set_post_views()

この関数は呼ばれるごとにカスタムフィールドの保存してあるデータにアクセス数をカウントしていきます。

基本的には1時間ごとのアクセス数を配列_pv_countに保存して、合計値をpv_countに保存します。つまり過去1日のアクセス数はカスタムフィールドpv_countに保存されている値になります。

アクセス数をリセット

function reset_post_views()

この関数では、すべての記事においてアクセス数が保存されている配列_pv_count[現在時間H]の値を0にリセットします。これと以下のコードが定期的に人気記事ランキングを更新する方法のキモになります。

定期的にreset_post_viewを実行する

function my_interval( $schedules ) 

function my_activation()

これは先程のreset_post_viewを定期的に実行するためのコードです。1時間ごとに動作するようにスケジュールイベントを追加してreset_post_viewsを実行させます。

WordPressでイベントを定期的に動作させる方法はLIGさんのサイトで詳しく紹介されています。

参考ルーティンを効率化。WordPressで定期的な処理をさせる方法|株式会社LIG

ボットの判別


function isBot() {
  $bot_list = array (
     //除外したいボットのユーザーエージェントをここに追加
  );
}

これはアクセスしているのがボットなのかを判別するためのコードです。ボットならtrueを、ボットでなければfalseを返します。ちなみにこれがないとアクセス数が異常に多くなるため、正確なランキング表示ができなくなる可能性があります。また、アクセスから除外したいボットが別途あれば「bot_list」にユーザーエージェントを追加することで対応できます。

参考【PHP】アクセスがBOTかどうか判断する|PHP初心者コピペTIPS

以上でfunctions.phpのコードは全てです。あとはサイドバーなり記事下なりに人気記事を表示するコードを書いていきます。

人気記事を表示する

実際に人気記事を表示するコードの一例はこんな感じです。これをsidebar.phpの表示したいところに追加します。

<?php if( is_single() && !is_user_logged_in() && !isBot() ): //個別記事 かつ ログインしていない かつ 非ボット
    set_post_views(); //アクセスをカウントする
endif; ?>

<section class="popular-box">
  <h4>人気記事</h4>
  <?php
  $args = array(
    'post_type'     => 'post',
    'numberposts'   => 8,       //表示数
    'meta_key'      => 'pv_count',
    'orderby'       => 'meta_value_num',
    'order'         => 'DESC',
  );
  $posts = get_posts( $args );
  if( $posts ): ?>
    <ul>
      <?php foreach( $posts as $post ) : setup_postdata( $post ); ?>
      <li>
        <a href="<?php the_permalink(); ?>" >
          <div><?php the_post_thumbnail( 'thumbnail' ); ?></div>
          <div><h5><?php the_title(); ?></h5></div>
        </a>
      </li>
      <?php endforeach;
      wp_reset_postdata(); ?>
    </ul>
  <?php else : ?>
    <p>アクセスランキングはまだ集計されていません。</p>
  <?php endif; ?>
</section>

問題がなければこれで人気記事が表示されるはずです。個別の記事を見てみるとカスタムフィールドにアクセス数が保存されていることが分かります。

問題点

この人気記事を表示する方法の問題点は、大きく3つあります。

1つ目は、1時間ごとにreset_post_viewを実行するには1時間ごとにサイトにアクセスされる必要があることです。WordPressには擬似cronを使って定期的にイベントを実行させることができますが、これが実行されるタイミングはサイトへのアクセスが確認された時です。

今回の場合だと、1時間たってもアクセスが無ければ1日前のその時間におけるアクセスがリセットされない、ということになります。

これを解決するには、指定時間内に最低1回はアクセスされるサイトにすることが重要です。

2つ目は、ボットのアクセス除去です。今回のコードでもボットによるアクセスはできるだけ除去するようになっていますがどうしても除外できていないボットもあります。そのためAnalyticsなどと比べると若干アクセスが多くなってしまいます。

これを解決するにはボットのユーザーエージェントをひとつひとつ追加するしかないのかな?

3つ目は、記事が多くなると処理が重くなることです。今回の人気記事を表示する方法には、ページが表示されるごとに全ての記事のカスタムフィールドを検索するようになっています。そのため数万記事くらいになるともしかすると処理が重くなる可能性もあります。この問題に関しては、今後対処する予定です。

また、(いつになるか分かりませんが)集計期間やリセット間隔の変更が柔軟に行えるようにしたいとも思っています。

さいごに

とりあえずこれでWordPressでプラグインを使わずに定期的にランキングを更新する人気記事を表示することができるようになりました。

問題点はありますが、使えないほどの影響が出るわけではありません。

更新内容

2016年6月29日
アクセス数をリセットする関数の改善。

2016年7月2日
無駄にカスタムフィールドが生成・削除を繰り返す問題を解決。

スポンサーリンク

スポンサーリンク

コメント

  1. 2016.11.30 16:33

    […] →WordPressにプラグインを使わず定期的に更新される人気記事を表示する […]

コメントを残す