WordPressでプラグインを使わずに閲覧数の多い人気記事を取得し、管理画面に閲覧数を表示する

WordPressで閲覧数の多い人気記事を表示するプラグインは数多くありますが、今回はプラグインの力を借りずに自力で実装してみたいと思います。

そもそも、データベースを有するWordPressにおいて、なぜ簡単に閲覧数の多い記事を表示することができないか。それは、WordPressのデータベースには、閲覧数を保持するカラムがないからです。何やら雲行きが怪しくなってきましたが、メゲズに最後までお付き合いいただければと思います。

閲覧数を保持するカスタムフィールド

話を単純にするためにWordPress初期構築時に作成するデータベースの各テーブルの接頭辞はwp_とします。また、記事執筆時のWordPressのバージョンは、4.2.2です。バージョンが異なる場合、以下のコードが正常に動作しない場合があります。

さて、記事を保持するWordPressのテーブルはというとwp_postsです。このテーブルには、コメント数をカウントするカラム(comment_count)はあっても、閲覧数をカウントするものはありません。

このテーブルにpost_viewsのようなカラムがあれば苦労しなくてすむのですが…。では、自分でカラムを追加すればよいのか?いいえ、それもできません(技術的には可能ですが…)。WordPressのコアとなるテーブルの構造を変更することになり、仕様通りに動作しなくなる可能性があるからです。将来的なバージョンアップのことを考えれば、影響範囲は極力最小限に抑えたいものです。

そこで、今回はいったんこのテーブルのことを忘れて、wp_postmetaテーブルに注目します。wp_postsと比較すると、単純な構造をしています。このテーブルには、記事のメタ情報が格納されています。

分かりやすい例が、WordPress標準機能のアイキャッチ画像です。上図をご覧ください。記事を一意に識別するpost_idと共に、アイキャッチ画像のファイル名や、画像ファイルのメタ情報が保存されていることがわかります。

wp_postmetaには、カスタムフィールドの情報が格納されます。アイキャッチ画像もカスタムフィールドの一種です。弊サイトでは、検索エンジン向けの記事ごとのキーワード情報を格納しています。これを応用すれば、何となく実装できそうな気がしませんか。

  • 記事ごとに閲覧数を保持するメタ情報をwp_postmetaテーブルに格納する
  • 記事が閲覧される都度、同テーブルに格納した値をインクリメントする
  • 人気記事を表示したい場合は、同テーブルに格納した閲覧数をもとに記事をソートする

記事表示時にカスタムフィールドを更新する

wp_postmetaテーブルの値を更新するためには、update_post_meta関数を使います。同関数のパラメータには記事のIDを指定しますが、該当のIDが同テーブルに存在しない場合は、新規にキーと値を追加します。

Function Reference/update post meta ” WordPress Codex

Please note that if your database collation is case insensitive (has with suffix _ci) then update_post_meta and delete_post_meta and will update/delete/query the meta records with keys that are upper or lower case. However get_post_meta will apparently be case sensitive due to WordPress caching. See https://core.trac.wordpress.org/ticket/18210 for more info.

また、カスタムフィールドの値を取得するためには、get_post_meta関数を使います。メタ情報は記事ごとに保持していますから、パラメータには記事のIDを指定する必要があります。詳細な使用方法については、後半に記述します。

get_post_meta() | Function | WordPress Developer Resources

Please note that if a db collation is case insensitive (has with suffix _ci) then update_post_meta and delete_post_meta and will update/delete/query the meta records with keys that are upper or lower case. However get_post_meta will apparently be case sensitive due to WordPress caching. See https://core.trac.wordpress.org/ticket/18210 for more info.

以降、閲覧数を表すカスタムフィールドのキーの名称は_custom_meta_viewsとします。記事が表示された場合に、このカスタムフィールドをインクリメントできるように、以下のコードをfunctions.phpに追加します。

function update_custom_meta_views() {
    global $post;
    if ( 'publish' === get_post_status( $post ) && is_single() ) {
      $views = intval( get_post_meta( $post->ID, '_custom_meta_views', true ) );
      update_post_meta( $post->ID, '_custom_meta_views', ( $views + 1 ) );
    }
}
add_action( 'wp_head', 'update_custom_meta_views' );

wp_headにアクションを追加しています。wp_head関数が呼ばれた際に、今回追加した関数が呼ばれるようになります。逆に言えば、自作テーマ等で同関数が呼ばれない場合、カスタムフィールドはインクリメントされないことになりますので注意してください

また、is_single関数で記事(固定ページ除く)の場合、get_post_status関数で記事の状態が「publish」(公開済み)である場合のみ、メタ情報を更新するようにしています。ドラフト(下書き)状態の場合、メタ情報は更新されません。

閲覧数でソートして人気記事を表示する

記事が閲覧されるたびにインクリメントされるカスタムフィールドの作成はここまでです。続いて、このカスタムフィールドを使用して、閲覧数の多い人気記事を取得する関数を作成しましょう。以下のコードをfunctions.phpに追加します。

function get_most_viewed() {
    $args = array(
      'post_type' => 'post',
      'post_status' => 'publish',
      'posts_per_page' => 5,
      'orderby' => 'meta_value_num',
      'meta_key' => '_custom_meta_views',
      'order' => 'DESC'
    );
    $posts = get_posts( $args );
    $output = "<ul>¥n";
    foreach( $posts as $post ) {
      $output .= "<li>" . $post->post_title . " - " . $post->_custom_meta_views . "Views</li>n";
    }

    $output .= "</ul>n";
    echo $output;
}

get_postsは指定された条件にもとづき合致する記事を配列で取得します。$argsに指定しているパラメータの意味は以下の通りです。

パラメータ 説明
post_type 投稿タイプを表します。投稿タイプが「post」(記事)に限定します。
post_status 投稿の状態を表します。状態が「publish」(公開済み)に限定します。
posts_per_page 取得する記事の件数です。
orderby ソートする基準を指定します。閲覧数でソートしたいためwp_postmetaテーブルのmeta_valueを指定します。 また、meta_value_numを指定することでmeta_valueの値を数値に変換してソートできます。
meta_key meta_valuemeta_value_numを指定する場合は、必ずmeta_keyも合わせて指定します。閲覧数でソートしたいため、_custom_meta_viewsを指定します。
order DESC(降順)、ASC(昇順)のいずれかを指定します。デフォルトは昇順です。

Template Tags/get posts ” WordPress Codex

The most appropriate use for get_posts is to create an array of posts based on a set of parameters. It retrieves a list of recent posts or posts matching this criteria. get_posts can also be used to create Multiple Loops, though a more direct reference to using new WP_Query is preferred in this case.

あとはget_postsで取得した配列をforeachでループします。$post変数には、wp_postsテーブルの情報が含まれています。例外的に、カスタムフィールドの値を取得する場合は、$post->_custom_meta_viewsとカスタムフィールドのキー名を指定します。その他、$post変数に含まれる情報としてよく使うものを挙げておきます。

パラメータ 内容
ID 記事のIDです。
post_author 記事の投稿者のIDです(投稿者名ではありません)
post_date 投稿日時(現地時間:日本語版なら日本時間)です。YYYY-MM-DD HH:MM:SSの形式。
post_modified 投稿の最終更新日時(現地時間:日本語版なら日本時間)です。YYYY-MM-DD HH:MM:SSの形式。
post_content 記事の内容。
post_title 記事のタイトルです。
post_excerpt 記事の抜粋です。
comment_count 記事に対するコメント数です。

今回自作したget_most_viewed関数を使用すれば、好きな位置に人気記事一覧を表示できます。そのまま使用すると、以下のようなHTMLが出力されます。適宜カスタマイズして使用してください。

<ul>
<li>WordPressのfunctions.phpの肥大化を防ぐ2つの方法 - 2Views</li>
<li>Alfredのカスタムサーチを利用して検索エンジンをハックする - 2Views</li>
<li>三日坊主でもできる、魅力にあふれた日記をiPhoneでつける方法 - 2Views</li>
<li>体が疲れてなかなか眠れない時はiPhoneを枕の下に置いてみよう - 1Views</li>
<li>Alfredで簡単にApp Storeのリンクを作成できる「iTunes Link Maker with Alfred」 - 1Views</li>
</ul>

get_most_viewed()関数の問題

get_most_viewed()関数は、閲覧数の多い記事を順に表示しますが、閲覧数は常に上書きされるため、ある程度人気記事が固定されて表示される可能性があります。そのため、例えば、先月から今月にかけて投稿した記事に絞って人気記事を表示したい場合には、date_query等を使って下記のように編集します。

function get_most_viewed() {
  $args = array(
    'post_type' => 'post',
    'post_status' => 'publish',
    'posts_per_page' => 5,
    'orderby' => 'meta_value_num',
    'meta_key' => '_custom_meta_views',
    'order' => 'DESC',
    'date_query' => array(
      array(
        'after' => date( 'Y/n/j', strtotime( date( 'Y-m-1' ) . '-1 month' ) ),
        'inclusive' => true,
      ),
    ),
  );
  $posts = get_posts( $args );
  $output = "<ul>¥n";
  foreach( $posts as $post ) {
    $output .= "<li>" . $post->post_title . " - " . $post->_custom_meta_views . "Views</li>n";
  }

  $output .= "</ul>n";
  echo $output;
}

管理画面の投稿一覧で閲覧数を確認する

ここまでで閲覧数で人気記事一覧を表示できることはわかりました。さらに、各々の記事がどれぐらい閲覧されているのか、管理画面の投稿一覧で見られると何かと便利ですよね。そこで、投稿一覧に追加したカスタムフィールドを表示できるようカスタマイズします。カスタマイズ後のイメージは以下の通りです。

まず、投稿一覧にカラムを追加します。以下のコードをfunctions.phpに追加します。

function add_column_custom_meta_views( $columns ) {
  $columns['views'] = 'Views';
  return $columns;
}
add_filter( 'manage_posts_columns', 'add_column_custom_meta_views' );

$columnsは、 投稿一覧のカラムを表しています。今回は、viewsというIDのカラムを追加します。また、Viewsは実際に投稿一覧の列名として表示される名前です。注意点として、デフォルトのカラムと重複してはいけません$columnsを出力した結果は以下の通りです。

Array (
    [cb] => <input type="checkbox" />
    [title] => タイトル
    [author] => 作成者
    [categories] => カテゴリー
    [tags] => タグ
    [comments] => <span class="vers"><span title="コメント" class="comment-grey-bubble"></span></span>
    [date] => 日時 )

追加するカラムには、HTMLタグを使用できることもわかります。例えば、コメントカラムにはWebフォントが指定されていますね。

これで投稿一覧に「Views」という名前のカラムを追加することはできましたが、まだ肝心要な値の表示ができません。値を表示するためには、以下のコードをfunctions.php追加します。

function add_column_custom_meta_views_content( $column_name, $post_id ) {
  $views = intval( get_post_meta( $post_id, '_custom_meta_views', true ) );
  echo $views;
}
add_action( 'manage_posts_custom_column', 'add_column_custom_meta_views_content', 10, 2 );

get_post_metaは、前述のようにパラメータに指定した記事のID、カスタムフィールドのキーをもとに値を取得する関数です。get_post_metaの最後のパラメータは、値を配列、または文字列のどちらで取得するかを指定します。デフォルト値は配列を取得するfalseですが、単独の値を取得する場合にはtrueを指定したほうが便利です。

管理画面の投稿一覧で閲覧数でソートする

せっかくなら管理画面で閲覧数でソートできれば素敵だと思いませんか。人気記事一覧を表示しなくても投稿一覧を見れば一目瞭然です。閲覧数でソートするためには、以下のコードをfunctions.phpに追加してください。

function sortable_column_custom_meta_views( $columns ) {
    $columns['views'] = 'Views';
    return $columns;
}
add_filter( 'manage_edit-post_sortable_columns', 'sortable_column_custom_meta_views' );

$columnsは、投稿一覧のカラムを表しています。追加するカラムのIDは、投稿一覧に追加したカラムのIDと同一にしてください。Viewsは、ソートするときURLのorderby=の後ろに表示される値です。何でも構いませんが、分かりやすく投稿一覧のカラム名と同一にしておくのが無難でしょう。

今回のポイントはフィルタです。管理画面には、様々なソート可能なカラムが存在します。カテゴリー、タグ、固定ページ一覧など、全てソートできるカラムが存在します。投稿一覧の管理画面のカラムをソートするためには、manage_edit-post_sortable_columnsをフィルタする必要があります。この、edit-postは、投稿一覧を表しています。

Viewsを数値としてソートする

以上で、管理画面でviewsをソートすることができるようになりましたが、viewsは数値として認識されないため、正しくソートされません。そこで、数値としてソートされるように、functions.phpに以下のコードを追加します。

function custom_orderby_custom_meta_views( $vars ) {
  if ( isset( $vars['orderby'] ) && 'Views' == $vars['orderby'] ) {
    $vars = array_merge( $vars, array(
      'meta_key' => '_custom_meta_views',
      'orderby' => 'meta_value_num'
      ));
    }
    return $vars;
}
add_filter( 'request', 'custom_orderby_custom_meta_views' );

URLにorderbyが含まれ、かつorderbyの値がViewsに等しいときのみ、meta_key、およびorderbyに指定した値に従ってソートするよう、requestをフィルタします。meta_value_numは、閲覧数でソートして人気記事を取得するために指定した値と同様の意味を持ちます。

まとめ

今回作成したコードはあくまで実装を目的として記載しています。例えば、同じページを何回もリロードした場合、その記事の閲覧数がその都度更新されます。そのため、あっという間に人気記事のねつ造が可能になってしまいます。

そのあたりの深掘りした考察については、長くなりそうなのでまた別の機会に譲ることとしたいと思います。最後まで長文にお付き合いいただきまして、ありがとうございました。

参考リンク

今回、この記事を執筆するにあたって参考にさせていただいたサイトは以下の通りです。

WordPressのカスタムフィールドがかなり便利になっている件(3.5対応)

meta_query の進化はバージョン3.5から WP_User_Query と WP_Comment_Query にも対応したということです。前から内部的には WP_Meta_Query を使ってたんですが、3.5では WP_User_Query のプロパティに $query_vars が追加され、ゲッターとセッターが増えています。WP_Queryと同じですね。 どちらも get_posts, get_users 関数から利用する人が多いと思いますし自分もそうしていますが、なんかこういう変化を見ると、もう直接 new WP_Query, new WP_User_Query して使うほうが推奨される書き方になるのかなぁ?まだここは決めかねております。みなさんはどうしていますか。

WordPress管理画面の投稿記事一覧をカスタマイズする | webOpixel

WordPressで記事を管理するときは投稿一覧画面を表示していろいろとやったりしているかと思います。 これはこれで結構便利に使えるんですが、この項目はいらねえなとか…

管理画面の投稿一覧に自分で設定したフィールドをソート

なかなか情報が無いので、忘れないようにメモ。 // 追加したフィールド項目のソートの設定 function column_orderby_myfield( $vars ) { if ( isset( $vars[‘orderby’] ) && ‘myfield’ == $vars[‘orderby’] ) { $vars = array_merge( $vars, array( ‘meta_key’ => ‘myfield’, ‘orderby’ => ‘meta_value_num’ )); } return $vars; } add_filter( ‘request’, ‘column_orderby_myfield’ ); // フィールド項目を一覧タイトルに登録 function customize_posts_columus($columns_view_option) { $columns_view_option[‘myfield’] = ‘myfield_name’; return $columns_view_option; } // フィールド項目を各データに表示 function customize_posts_custom_columus($column_name, $post_id) { $res = get_post_meta($post_id, ‘myfield’, true); echo $res; } add_filter( ‘manage_posts_columns’, ‘customizePostsColumus’ ); add_action( ‘manage_posts_custom_column’, ‘customize_posts_custom_columus’, 10, 2 ); // ソートする項目を登録 function myfield_register_sortable( $sortable_column ) { $sortable_column[‘myfield’] = ‘myfield’; return $sortable_column; } add_filter( ‘manage_edit-post_sortable_columns’, ‘myfield_register_sortable’ );

この記事が気に入ったら
いいね ! しよう

Twitter で