【当サイトはアフィリエイト広告を利用しています】

WordPress Popular Postsでカテゴリ毎の人気記事ランキングを作る

2012年12月28日

パラメータの組み合わせでいろんなことが出来る

Medal Ceremony by gripso_banana_prune

Medal Ceremony by gripso_banana_prune

当ブログは右サイドバーに月間とデイリー、2つの期間でアクセス数を集計した人気記事ランキングのウィジェットを設置しています。(PCブラウザで見ることが出来ます)

このウィジェットの作り方は以前にも解説エントリーを書いたのですが、仕様変更が発生して内容を部分的に修正したため、ヤヤコシイ内容になってしまってます。

【参考】【カスタマイズ】月間とデイリー、2つの人気記事ランキングを設置する*

なので今回改めて書き直し、というか、まとめ直し。

WordPressのプラグイン「WordPress Popular Posts」は、各記事のアクセス数を自動的に集計し、データベースに記録を残してくれます。

そのデータベースに対して「1ヶ月単位で」「24時間以内で」など、好みの抽出条件を指定し、PHPコードで命令してあげることで人気記事のアクセスランキングを作る、という仕組み。

この仕組みを応用し、「現在表示してるページが属しているカテゴリー限定で」という抽出条件を加えたのが、今回「年末カスタマイズ祭り」で新たに実装した「カテゴリ毎の人気記事ランキング」です。

R0010207.jpg by bizmac

「年末カスタマイズ祭り」では、人気記事ランキングの画像を数字画像からアイキャッチ画像に変えるという仕様変更も実施しました。この記事では仕様変更内容もあわせて解説します。

まずはプラグインの準備

ウィジェットが追加される

↑プラグイン「Wordpress Popular Posts」をインストール済みの場合、管理画面の「外観」>「ウィジェット」と移動すると、「Wordpress Popular Posts」のウィジェットが使えるようになっています。

ドラッグ&ドロップでウィジェットが作れる

↑ウィジェットをブログの表示させたい場所(右サイドバーなど)にドラッグ&ドロップすると、「Wordpress Popular Posts」のウィジェットが展開され、各種パラメータを指定するだけでブログに表示させることが出来ます。

この方法が一般的。PHPコードなど一切知らない人でも人気記事ランキングのウィジェットを作成することが出来ます。簡単です。

しかし。

文末の「カテゴリ毎の人気記事」は、このウィジェット方式では作れません。PHPコードで作ってあげる必要があります。

なので右サイドバーも、PHPコードによるウィジェットの作成方法で解説します。

Exectable PHP Widget

↑サイドバーにPHPコードでオリジナルのウィジェットを設置するには、プラグイン「Executable PHP widget」をインストールしてウィジェットに追加する方法があります。「テキスト」というウィジェットはPHPコードが動作しないため、このプラグインが必要になります。

【追記】プラグイン検索の際に表示される一覧には「Executable PHP widget」ではなく「PHP Code Widget」という名称になっているようです。インストール後は「Executable PHP widget」で表示されます。

「Executable PHP widget」を導入するとエラーになって動かない、という場合もあるらしいです。その場合はサイドバーのテンプレートファイル(sidebar.phpなど)に直接PHPコードを挿入する方法もあります。

ウィジェットが追加された

↑「Executable PHP widget」をインストールし有効化させると、ウィジェットページに「PHP Code」というウィジェットが追加されます。これをサイドバーなどにドラッグ&ドロップ。

PHP Codeウィジェット

↑タイトル(何でもいいです)を入力し、その下にある入力欄にPHPコードを書いていきます。

月間記事ランキング(アイキャッチ版)の作り方

まずは月間記事ランキング。これは旧バージョン(数値画像)のPHPコードをチョコッと変更しただけ。

「デイリーランキング」「カテゴリ毎の人気記事」も同じPHPコードの応用になるので、この「月間ランキング」で作り方や仕様を押さえられると、以降の理解度がグッと高まります。

<div class="content_wrap">
<h2 class="kijitabtitle">人気記事ランキング(<?php echo date('n/j',strtotime('-30 day')); ?>~<?php echo date('n/j',strtotime('-1 day')); ?>)</h2>
<?php if (function_exists('wpp_get_mostpopular')) {
 ob_start();
 wpp_get_mostpopular('limit=10&range=monthly&order_by=views&post_type=post&stats_comments=0&thumbnail_width=40&thumbnail_height=40');
 $popular = ob_get_clean();
 $popular = str_replace('<ul>', '<ul class="postrank">', $popular);
 echo $popular; 
} ?>
</div>

↑これが月間の人気記事ランキングを生成するPHPコード。

2行目は見出しの<h2>タグに過去1ヶ月の日付をPHPコードで計算して表示させてます。詳細は旧バージョンの解説エントリーに細かく書いたので今回は省略。

7行目は、CSSで見た目などを加工したいため、<ul>タグに「postrank」というクラス名をくっつけてる(置換してる)処理。

5行目でアクセス数データを抽出する命令が登場します。カッコの中にズラリと書いてるのが抽出条件。この機能で最も大切な、キモとなる部分です。

limit=10 ← 記事の最大数
&range=monthly ← 抽出範囲
&order_by=views ← 並び条件
&post_type=post ← ランキング対象の投稿タイプ
&stats_comments=0 ← コメント数表示
&thumbnail_width=40 ← 画像の幅
&thumbnail_height=40 ← 画像の高さ

↑見やすいように各抽出条件で改行させてみました。「&」で連結させることで複数の抽出条件を同時に指定できます。

「limit」は抽出する記事の最大数。「10」と指定すれば最大10件を抽出します。

「range」はデータ抽出期間の範囲指定。1ヶ月間なので「monthly」。他のパラメータは、1日分なら「daily」、1週間分なら「weekly」、プラグインを導入してからの全期間なら「all」。

「order_by」は並び条件。「views」はアクセス数の多い順。他のパラメータは、コメント数の多い順に並べる「comments」と、1日の平均アクセス数の多い順に並べる「avg」があります。

「post_type」は抽出する記事の投稿タイプをどうするか。「post」は通常の「投稿ページ」と言われる記事のこと。他に「固定ページ」もランキング対象にしたい場合は「page」というパラメータを追加することで抽出できます。

さらに、WordPressの「カスタム投稿タイプ」という仕組みを利用して記事を書いてる場合は、独自に付けたカスタム投稿タイプ名を「post_type」に指定することでランキング対象にすることも出来ます。

投稿ページも固定ページも、それからカスタム投稿タイプも(仮に名前を「ABCD」とします)、全部ランキング対象にしちゃう!という場合の指定方法は、

post_type=post,page,ABCD

とカンマで繋ぐだけ。

【注意!】
この「post_type」パラメータ関連は、2012年9月の仕様変更で一部の人にトラブルが発生してました。当ブログも問い合わせでそのことを知り、原因が判明するまで大変苦労した思い出があります。詳しくは後述しますので、今回のサンプルコードを利用される方は必ずお読みください。

「stats_comments」は記事タイトルの後ろにコメント数を表示させるかどうかの指定。私は表示させたくない(=そもそもコメントもらってない)ので「0」を指定。コメント数を表示させたい場合は「1」を指定します。

「thumbnail_width」と「thumbnail_height」が今回新たに付け加えた新パラメータ。アイキャッチ画像の幅と高さの指定で、それぞれ「40」としました。数値を調整することで画像の大きさを変更できます。

この2つのパラメータを追加するだけで、各記事が所有しているアイキャッチ画像のデータを取ってきてくれて、画像サイズも指定できるので大変便利。旧バージョンの時は数値画像を表示させるのにPHPで小細工をしてましたが、その必要もなくなりました。

【注意!】
「thumbnail_width」と「thumbnail_height」は大変便利なのですが、このまま利用するとセキュリティー的に危険らしく、「使わないように」と警告してるブログもありました。ただ、回避策も見つけましたので(テスト済み)、これも後述します。今回のサンプルコードを利用される方は必ずお読みください。

月間ランキングのコードで重要な部分の解説は以上です。あとはCSSで見た目を調整するなどすれば、サイドバーにウィジェットがアイキャッチ画像付きで表示されるはず。

デイリー記事ランキング(アイキャッチ版)の作り方

月間ランキングで仕様を理解していれば、ここから先は応用ですので簡単なはず。解説もなるべく短めで。

<div>
<h2 class="kijitabtitle">今日のアクセスランキング</h2>
<?php if (function_exists('wpp_get_mostpopular')) {
 ob_start();
 wpp_get_mostpopular('limit=10&range=daily&order_by=views&post_type=post&stats_comments=0&thumbnail_width=40&thumbnail_height=40');
 $popular = ob_get_clean();
 $popular = str_replace('<ul>', '<ul class="postrank">', $popular);
 echo $popular;
} ?>
</div>

月間ランキングと違うのは、2行目の<h2>タグの中身と、5行目の抽出条件で「range」がmonthly(月間)ではなくdaily(デイリー)になっただけ。あとは同じ。以上。

カテゴリ毎人気記事ランキングの作り方

月間ランキングやデイリーランキングと違うのは、いま表示してるページのカテゴリーIDを取ってこないと始まらない、ということです。

あと、PHPコードの難易度が少し上がります。説明が下手で分かりづらかったらスミマセン。

まず、ウィジェットを作成する前に「functions.php」にカテゴリーID取得用のコードを組み込む必要があります。

functions.phpは、WordPress全体の表示にも関わる重要なファイルです。改造に失敗するとブログが真っ白になり何も表示されなくなる、なんてことにもなります(私も何度かやらかしてます)。
改造はくれぐれも慎重に、そして自己責任でお願いします。改造前は必ずバックアップを取っておきましょう!
// カテゴリーIDの取得(カテゴリー別ランキング用)
add_action('wp_head', 'get_current_category');

function get_current_category()
{
    global $_curcat;
    $cate = null;
    if( is_category() ) {
        //カテゴリー表示だったら
         
        $cat_now = get_the_category();
        // 親の情報を$cat_nowに格納
        $cate = $cat_now[0];
         
    } else if (is_single() ) {
        //シングルページ表示だったら
        $cates = get_the_category();
        $i = 0;
        $use_category = 0;
        foreach ($cates as $cate) {
            //未分類を除外した配列の一番初めのカテゴリを選択
            if($cate->category_parent > 0 && $use_category == 0) {
                $use_category = $i;
            }
            $i++;
        }
        $cate = $cates[$use_category];
    }
    //カテゴリーのオブジェクトごと保持
    $_curcat = $cate;
    return $cate;
}

ものっすごく簡単に解説すると、ブログのページを表示する度に4~32行目の関数「get_current_category」を毎回処理しなさい、って命令が2行目。

最終的にカテゴリーに関する情報を「$_curcat」というグローバル変数(=値を入れておく箱だと思って下さい)にセットする、ってのが30行目。以上!

さて、functions.phpが取ってくれた情報を基に、カテゴリ毎の人気記事ランキングを作っていきますよ。以下のコードをサイドバーのウィジェットに書いていくだけです。

<?php
if (is_single()) :
	global $_curcat;
	$caca = $_curcat->cat_ID;
	if (function_exists('wpp_get_mostpopular')) :
		ob_start();
		get_mostpopular('range=monthly&order_by=views&cat=' . $caca 
		. '&limit=10&stats_comments=0&post_type=post' 
		. '&thumbnail_width=40&thumbnail_height=40');
		$popular = ob_get_clean();
		$popular = str_replace('<ul>', '<ul class="catRankSide clearfix">', $popular);
		$cat_now = get_the_category();
		$cat_now = $cat_now[0];
		$relCatName = $cat_now->cat_name;
?>
<h2 class="kijitabtitle">「<?php echo $relCatName; ?>」カテゴリー人気記事</h2>
<?php
		echo $popular; // カテゴリ毎人気記事を出力
	endif;
endif;
?>

2行目は、表示しているページの種類を判断してます。「is_single」は、「このページがシングルページ(投稿ページ・記事ページ)だったら、以下の処理を実行しなさい」という命令。

なので、トップページでは処理もされないし、表示もされません。各エントリーページの時だけ人気記事ランキングが表示されます。

    global $_curcat;
    $caca = $_curcat->cat_ID;

3~4行目はカテゴリーIDを取得している処理。さっきfunctions.phpに登場していたグローバル変数「$_curcat」が3行目で再び登場。functions.phpで取ってくれた値がここで受け渡されてます。

これを基に「$caca」という別の変数(=箱)にカテゴリーIDをセットしているのが4行目。

		get_mostpopular('range=monthly&order_by=views&cat=' . $caca 
		. '&limit=10&stats_comments=0&post_type=post' 
		. '&thumbnail_width=40&thumbnail_height=40');

7~9行目は、もうお馴染みですね。人気記事ランキングでも使用したランキング記事の抽出命令。見やすいように3行で分けて表示してますが、人気記事ランキングの時みたいに1行で書いても問題ありません。

人気記事の時は関数名が「wpp_get_mostpopular」だったんですが、今回の参考記事では関数名が「get_mostpopular」になってます。どっちも正常に動いたから気にしなくていいんだろうか…。

【2013年1月18日追記】
プラグインのコードを確認したところ、「get_mostpopular」という関数が指定された時には「wpp_get_mostpopular」を実行せよ、という処理がプラグイン内部に書かれていました。
なので結論としては「どっちも正常に動く」のですが、今後のことも考えると「wpp_get_mostpopular」に統一して書いた方が良さそうに思います。(仕様変更で「get_mostpopular」のスキップ処理が消えてしまう可能性もあるので)

カッコ内のパラメータは人気記事の時とほぼ同じ。1つだけ新しいのが加わってます。7行目の最後。

&cat=’ . $caca

「cat」というパラメータにカテゴリーIDをセットしてあげることで、そのカテゴリーだけを抽出対象にするよう制限できます。うちのブログだと、ウォーキングの記事を表示中は「ウォーキングのカテゴリー記事」だけを引っ張ってくる。

で、制限したいカテゴリーIDは、さっきセットした「$caca」という変数に入ってますので、これをピリオド(.)で連結してあげてます。

カッコ内に変数(=箱)を入れてしまうと変数の中身を認識してもらえない(プラグインが「$cacaってなんじゃこりゃ?」となってしまう)ので、いったんシングルクォーテーション(’)で条件指定を中断させ、カッコの外で$cacaを指定してあげると認識してもらえます。

ちなみにピリオド(.)は、文字と文字を連結させる時に使う命令で、プラグインの機能ではなくPHPの機能です。なので、このプラグインだけでなくPHPならどこでも使えます。

		$cat_now = get_the_category();
		$cat_now = $cat_now[0];
		$relCatName = $cat_now->cat_name;
?>
<h2 class="kijitabtitle">「<?php echo $relCatName; ?>」カテゴリー人気記事</h2>

12~16行目はオマケみたいなもんです。カテゴリーIDではなく「カテゴリーの名前」が欲しかったので、12~14行の処理で「$relCatName」という変数に名前をセットし、16行目で表示しているだけ。

本文の最後に表示している「横に5個×縦2行のカテゴリ毎人気記事」に関しても、記事を抽出する条件指定のところまでは全く同じコードです。

ただ、それ以降の処理(サイドバーのは「画像の右側に記事タイトル」ですが、本文最後のは「画像の下に記事タイトル」で、しかも2行に分割してるので処理が少し違ってきます)の解説はプラグイン以外にPHPのループ処理とか連想配列とか別の知識も入ってしまいます。

そこまで書くと長くなり過ぎて読む気をなくされると思うので(今も既に長過ぎてますゴメンナサイ)、機会があれば別記事で書きます。

11行目はタグの置換処理ですが、サンプルコードに書いてるクラス名などは、あくまで私の例なので、ここはお好きな名前に変更して頂いて問題ありません。CSSで変更しやすい名前にして頂ければ。

サイドバーのカテゴリ毎人気記事ウィジェット

↑というわけで、サイドバーのカテゴリ毎人気記事ウィジェットの完成です。

注意その1:pagesパラメータは廃止されたらしい

今回、カテゴリ毎の人気記事機能を作りたくて、いろんなサイトやブログを調べ、たくさんの有益な記事を見つけ、参考にさせて頂きました。

ただ、一部のサンプルコードに「pages」というパラメータが使われているのを散見しました。

この「pages」というパラーメータは以前存在し、私も最初に書いた人気記事ランキングのエントリーではpagesを使ったサンプルコードを紹介してました。

ところが2012年の8月か9月にプラグインがアップデートされた際に表示がおかしくなり、問い合わせも頂いていろいろ調べたところ、仕様変更があったらしく、「pages」パラメータが消滅していることに気付きました

「pages」は、ランキングに固定ページを含めるかどうかを指定する条件で、「pages=0」と書くと固定ページを除外し、投稿ページだけを抽出対象とする、というものでした。(「pages=1」と指定すれば固定ページも抽出される)

ところが、このパラメータが消滅したことで、それまでのコードのまま使い続けると、固定ページもランキングに表示されてしまう現象が一部のブログで発生していたようです。私のブログは固定ページのアクセスが全然ないので、問い合わせがあるまで発覚しなかった。

まとめると、

「pages=0」の指定は、現在は無意味です。正常に機能しません。固定ページを除外したいのであれば、今回サンプルコードに書いた通り「post_type=post」を指定しなければなりません。
※この記事を書いてる時点でのプラグインのバージョンは「2.3.2」です。

【参考】WordPress Popular Postsのpagesに関する変更点

注意その2:サムネイル(アイキャッチ)表示機能に脆弱性があるそうです

カテゴリ人気記事の機能を完成させ、ホッと安心した後でもう1つの問題点を知りました。

WordPress Popular Postsではサムネイルを表示させる際、timthumb.phpというサムネイルを生成できるライブラリを使っています。このtimthumb.phpに脆弱性が見つかっています。

via:Wordpress Popular Postsでサムネイルを表示している方は要注意! | PLUS

この脆弱性により、第三者が任意のPHPコードをTimThumbキャッシュディレクトリにアップロードでき、そのコードを実行されてしまいます。

timthumb.php もしくは thumb.php が無くても動作するならこのファイルをサイトから削除するようおすすめします。もし使っていないテーマやプラグインの中にこのファイルがあったら、そのテーマやプラグインのディレクトリごと削除したほうがいいでしょう。

via:WordPressのテーマやプラグインでtimthumb.phpをお使いの方は脆弱性が見つかったのでご注意! | め組の小ネタ

今回、私の人気記事ウィジェットでは条件指定でアイキャッチ画像を自動取得する「thumbnail_width」と「thumbnail_height」という2つのパラメータを新たに使用しました。

この2つが、おもいっきり上記の「timthumb.php」ってのを見てるらしいんですよ。おいおい、使えねえのかよ~って。焦りまくりましたが、回避策がありました。

この回避策は、プラグイン「Wordpress Popular Posts」を直接改造する方法です。改造前のバックアップをお忘れなく!

それと、プラグイン「Wordpress Popular Posts」がアップデートされたら、たぶんまた同じ改造をしなきゃならない気がします。これもお忘れなく。

$thumb .= "<img src=¥"". $this->pluginDir ."/timthumb.php?src={$path}&amp;h={$tbHeight}&amp;w={$tbWidth}¥" width=¥"{$tbWidth}¥" height=¥"{$tbHeight}¥" alt=¥"{$title}¥" border=¥"0¥" class=¥"wpp-thumbnail wpp_fi¥" />";
$thumb .= “<img src=¥””. $this->pluginDir .”/timthumb.php?src={$path}&amp;h={$tbHeight}&amp;w={$tbWidth}¥” width=¥”{$tbWidth}¥” height=¥”{$tbHeight}¥” alt=¥”{$title}¥” border=¥”0¥” class=¥”wpp-thumbnail wpp_fi¥” />”;

検索してみると、修正対象となる上のコードが「wordpress-popular-posts.php」の中に2箇所あったので、私は2箇所とも修正しました。

$thumb .= "<img src=¥"{$path}¥" width=¥"60¥" height=¥"40¥" alt=¥"{$title}¥" border=¥"0¥" />";
$thumb .= “<img src=¥”{$path}¥” width=¥”60¥” height=¥”40¥” alt=¥”{$title}¥” border=¥”0¥” />”;

参考記事では、上のように修正することで回避できると解説されてます。

しかし、この方法だと全てのサムネイル画像が「幅60、高さ40」で固定されてしまいます。

当ブログは右サイドバーと文末で画像の大きさを変えてます。プラグインのパラメータで画像の大きさを変更できるのが大変便利なのに、固定されてしまうのは困る。

ってことで私なりに変更してみました。

$thumb .= "<img src=¥"{$path}¥" width=¥"{$tbWidth}¥" height=¥"{$tbHeight}¥" alt=¥"{$title}¥" border=¥"0¥" />";
$thumb .= “<img src=¥”{$path}¥” width=¥”{$tbWidth}¥” height=¥”{$tbHeight}¥” alt=¥”{$title}¥” border=¥”0¥” />”;

【追記】こちらのコードをコピペしてしまうと、ダブルクォーテーション(”)が全角に変換されてしまい、保存時にエラーが発生することが判りました。この枠内にあるコードではなく、1つ上にある「カスタマイズした生コード」の方をコピペして頂くようお願いいたします。

上の赤い部分が変更箇所。つまりウィジェットなどのパラメータで指定した数値をそのまんま使うという方法です。

テストしてみたところ、ウィジェットで指定した通りの画像サイズで表示されました。パラメータの数値を変えると画像サイズも変わったので、上の修正内容で大丈夫だと思います。

サムネイル画像を表示させず、記事タイトルだけ表示させてる場合は、ここで書いてる脆弱性の心配もないし、改造する必要もありません…よね?

まとめ

今回はプラグイン「Wordpress Popular Posts」を使って人気記事ランキングをサイドバーにウィジェットとして作成する方法を3種類紹介しました。

「Wordpress Popular Posts」は他にもいろんなパラメータ指定があり、「文末に表示しているカテゴリ毎人気記事」のコードでも今回紹介していない別のパラメータを指定して作りました。

パラメータを応用・駆使することでいろんな人気記事ランキングが作成できます。いつか別記事で紹介しますね。

-WordPress
-