徹底解説!query_postsを使ってWordPressで表示する記事数をカテゴリごとに変更する(プラグイン不使用)

WordPressでサイト・ブログを構築していると、1ページに表示する記事数をカテゴリごとに変えたい場合があります。(なお、全記事・全ページ共通で変えたいだけなら、ダッシュボードの「表示設定」で変更できます)

このような場合プラグインを利用して実現することもできるようですが、サイトが重くなることを避けたい場合、PHPとWordPressの関数を利用して簡単に実現できます

以下、query_posts関数の説明を兼ねつつ、手順を説明したいと思います。

query_postsの利用

WordPressでは、query_postsという非常に便利な関数があらかじめ定義されています。
このquery_postsは、引数部分(括弧内)にカテゴリや投稿数を指定することで、その直後に現れる投稿ループを操作する関数です。

・query posts – WordPress Codex

もっとも単純な使用例

query_postsは、WordPressのループが始まる直前に記載します。
もっとも単純な使用例は以下のようなパターンです。

<?php
	query_posts('&posts_per_page=20');
	if (have_posts()) : while (have_posts()) : the_post();
?>

たとえば上記のように「category.php」に記載した場合、ダッシュボードの表示設定で「1ページに表示する最大投稿数」を10件に指定していても、カテゴリページでは記事は常に20件表示されるようになります。

これはたとえば、トップページ(index.php)では最新記事は10件までしか表示したくないが、カテゴリページでは20件まで表示したい、といった場合に有効です。

なお、query_posts()の引数になっている「posts_per_page」は「1ページに表示する記事数」を指定するための引数です。
また、URLにクエリとして引き渡すため、先頭には必ず「&」をつけることを忘れないようにしてください。

特定のカテゴリにだけ使用する

ただし「posts_per_page」のみを指定した場合、カテゴリごとに記事数を変更することはできず、すべてのカテゴリの表示記事数が一様に変更されます。

そこでカテゴリごとに表示記事数を細かく指定するためには「category_name」という引数を使います。category_nameを使うと、カテゴリのスラッグ名を利用して、特定のカテゴリだけを指定できます。
※そのほか「cat」という引数でカテゴリーIDを指定するなどの方法もあります。

query_postsの間違った使用例

ですが、以下のように単純に「category.php」内のquery_postsに「category_name」を追加すると困ったことになります。

<?php
	//悪い例。すべてのカテゴリに日記の記事しか表示されなくなる。
	query_posts('&category_name=diary&posts_per_page=20');
	if (have_posts()) : while (have_posts()) : the_post();
?>

category.phpに上記のように設定してしまうと、どのカテゴリを開いても「diary」の記事しか表示されなくなってしまいます。
これは、category.phpを使用するすべてのカテゴリに対して「diaryカテゴリの記事を20件表示しろ」という命令になってしまうためです。

これを避けるためには、ページを開いた際のURLをその都度取得し、category_nameに入れるようにしないといけません。

正しい例

WordPressでは、現在開いているページのカテゴリ情報を取得するための「get_the_category」という関数があります。これを利用して、カテゴリ名を取得します。

・get the category – WordPress Codex

実際の使用例は以下の通りです。

<?php
	//カテゴリ情報を配列として取得
	$catinfo = get_the_category();
	//配列の一つ目の要素にあるオブジェクトからカテゴリ名を取り出す
	$catname = $catinfo[0]->category_nicename;
	//カテゴリ名(スラッグ名)がdiaryならば、表示する記事数を5件に制限
	if($catname == diary)
	{
		query_posts('&posts_per_page=5');
	}
	if (have_posts()) : while (have_posts()) : the_post();
?>

ページング(ページ送り)を利用できるようにする

カテゴリごとの表示記事数そのものは、ここまでで変更できます。
しかし記事数が多い場合には当然、次のページへ・前のページへといったページ送りが必要になります。

ですが、query_postsはそのままだと、ページ送りの動作に必須の「現在のページ数」をURLから取得できません。そのため、いくらページ送りを実行しても、常に最新の記事ばかりが表示されてしまいます。

WordPressにはこうした事態を防ぐための変数もじつは用意されています。
それが「$query_string」です。
$query_stringはグローバル変数ですので、category.phpのなかからでも「global」宣言さえすれば簡単に取り出すことできます。

よって、コードは以下のようになります。

<?php
	//グローバル変数$query_stringを取得
	global $query_string;
	$catinfo = get_the_category();
	$catname = $catinfo[0]->category_nicename;
	if($catname == diary)
	{
		//$query_stringとクエリ部分は.で繋ぐ
		query_posts($query_string . '&posts_per_page=5');
	}
	if (have_posts()) : while (have_posts()) : the_post();
?>

これで特定のカテゴリ(この例ではdiary)のみ表示記事数を変更することができました。

おまけ:コードをスマートにする

前述まででコードとしてはきちんと動きますが、カテゴリごとに記事数を細かく変更したいといった場合には、if文の行数が増えて可読性が悪いです。

そこで三項演算子を使って書くとスマートになります。
ちなみに三項演算子とは、「 A ? B : C 」の形で使うもので、Aの部分がTRUEであればBを実行、FALSEならばCを実行します。
これを使うと、以下のように書けます。

<?php
	global $query_string;
	$catinfo = get_the_category();
	$catname = $catinfo[0]->category_nicename;
	//カテゴリ名(スラッグ名)がdiaryなら5件まで、それ以外は10件
	$catname == 'diary' ? query_posts($query_string . '&posts_per_page=5')
	 : query_posts($query_string . '&posts_per_page=10');
	if (have_posts()) : while (have_posts()) : the_post();
?>

三項演算子は、PHP5.1や5.2ではFALSE時の挙動を省くことができないため、上記例では他カテゴリを10件にするという指定をしています。

5.3以降であればFALSEの挙動を省くこともできるため、特定のカテゴリの表示記事数を指定するだけで、他のカテゴリの表示記事数は変えない(ダッシュボードからの設定のままでいい)のであれば、さらに短く書けます。

<?php
	//PHP5.3以降
	global $query_string;
	$catinfo = get_the_category();
	$catname = $catinfo[0]->category_nicename;
	$catname == 'diary' ? query_posts($query_string . '&posts_per_page=5');
	if (have_posts()) : while (have_posts()) : the_post();
?>

このようなコードにしておけば、表示記事数を変えたいカテゴリが複数あっても、とても簡単に設定を行うことができます。ぜひ活用してみてください。