WordPressのサブループでWP_Queryのオブジェクトを使いつつ、ページネーションするハック

WordPressのtemplate内でquery_posts()は非推奨というのは、割と浸透してきたようなのですが、それでも、query_posts()を使う人がいるのは、ページネーション(ページング)をしたいとか、いろいろと一見便利な「副作用」があるからですよね。

メインループの時には、the_posts_pagination()で、手軽にページネーションが表示されるのに、サブループだとうまくいかない。そんなとき、query_posts()を使うとうまくいく……というわけです。

なんで、query_posts()を使うとうまくいくかというと、query_posts()が、$GLOBALS['wp_query']を書き換えるからです。

WordPressは、スーパーグローバル変数のお祭り状態なので、たいへん「らしい」といえば「らしい」です。

短いんで、ちらと、query_posts()をのぞいてみましょう。

function query_posts($query) {
	$GLOBALS['wp_query'] = new WP_Query();
	return $GLOBALS['wp_query']->query($query);
}

これだけです。

で、ページネーションを出力しているget_the_posts_pagination()は、$GLOBALS['wp_query']に依存しているので、当然、$GLOBALS['wp_query']に代入されているオブジェクトを相手にしかしてくれません。

というわけで、サブループで、WP_Query()をnewしつつ、ページネーションするための関数を書いてみます。

これはfunctions.phpに記述します。

/**
 * wrapper get_the_posts_pagination and the_posts_pagination
 */
if (
	! function_exists('my_get_the_posts_pagination') &&
	! function_exists('my_the_posts_pagination')
)
{
	function my_get_the_posts_pagination (WP_Query $wp_query_obj, $args = array())
	{
		$tmp_obj = $GLOBALS['wp_query'];
		$GLOBALS['wp_query'] = $wp_query_obj;
		$navigation = get_the_posts_pagination($args);
		$GLOBALS['wp_query'] = $tmp_obj;
		return $navigation;
	}

	function my_the_posts_pagination (WP_Query $wp_query_obj, $args = array())
	{
		echo my_get_the_posts_pagination($wp_query_obj, $args);
	}
}

で、

$my_query = WP_Query($args);

とかしたら、

my_the_posts_pagination($query);

で、当該ループのページネーションを取得できます。

原理的にはメインクエリを汚していないので、wp_reset_query()wp_reset_postdata()も不要です。

余談

WordPressでは、$posts$post$wp_queryが、スーパーグローバルなんですが、うっかり、

foreach ($posts as $post):
endforeach;

みたいなコードを書いちゃうと、スーパーグローバルを壊しちゃうんですね。

気をつけましょう。

ジャンル: Web