WordPressのループ内コンテキストを理解する

WordPress

その場しのぎでなんとかなってしまうのがWordPressの良いところ? だったりもしますが、WPについてもう少し深いところも知っておこうと思い、「エンジニアのためのWordPress開発入門」を読みました。WPアーキテクチャの基本から実践的な部分まで抑えられており、勉強になるところが多かったです。

ただこの本のループの解説で登場する「コンテキスト」については、コンテキストそのものの説明が省かれ気味な上、私の中でも理解が曖昧だったため、少し読み進めるのに苦労しました。

そういうわけで、本の中で説明されている「コンテキスト」が具体的に何を指しているのかを自分なりに整理してみました。

WordPressの処理の流れおさらい

リクエスト内容からパラメータを取り出し、メインクエリを生成、取り出したデータをテンプレートなどで処理/出力の流れです。

この記事で述べるコンテキストとは、主にテンプレート内処理におけるものです。

ループ内の「コンテキスト」とは具体的に何か

本の中でコンテキストとして扱われているものは、主に以下の2つのグローバル変数が関係しています。

  • $wp_query
  • $post

$wp_queryは投稿のまとまりを保持するオブジェクト、$postは個々の投稿のオブジェクトにあたります。これらの状態によりテンプレートタグの出力内容が変わるため、ループ内における「コンテキスト」となります。

細工を加えずにWordPressのページを表示すると、グローバルの$wp_queryには、リクエストに基づく投稿一覧のデータ(メインクエリ)が入ります。

コンテキストを操作する

コンテキスト(≒グローバル変数)を操作する方法には主に以下のようなものがあります。

query_posts関数

query_posts関数は新たにクエリを発行し、グローバルの$wp_queryを置き換える処理をします。

<?php
// global $wp_queryがfooカテゴリの内容に置き換わる
query_posts( 'category_name=foo' );
if ( have_posts()) : while ( have_posts() ) :
    // global $postを差し替えてコンテキストを切り替える
    the_post(); ?>
    <!-- ループ処理 ... -->
<?php
endwhile; endif;
// global $wp_queryを元に戻す
wp_reset_query();

グローバルのthe_post関数は、グローバルの$wp_queryを元にグローバルの$post変数の内容を差し替えます。

メインクエリ自体を操作する用途であればフックを使ってクエリ発行を抑えるほうが望ましく、サブループとして使用する場合にはメインクエリの置き換えによる悪影響が懸念される、などの理由で推奨されない方法です。

WP_Queryクラス

サブループとして使うWP_Queryのインスタンスでもコンテキストを扱います。

<?php
// fooカテゴリのサブループ用WP_Queryインスタンスを生成
$result = new WP_Query( [ 'category_name' => 'foo' ] );
while ( $result->have_posts() ) :
    // global $postを差し替えてコンテキストを切り替える
    $result->the_post(); ?>
    <!-- サブループ処理 ... -->
<?php
endwhile;
// global $postを元に戻す
wp_reset_postdata();
?>

WP_Queryインスタンスのthe_postメソッドは、そのインスタンスを元にグローバルの$postの内容を差し替えます。

get_posts関数とsetup_postdata関数

サブループ用の投稿取得にはget_posts関数を使う方法もあります。ただしこれがちょっと曲者だったり。

コンテキスト切り替えのためにループ内でsetup_postdata関数に投稿データを渡しますが、単に投稿データをsetup_postdata関数にわたすだけでは駄目。

<?php
// 駄目な例
// fooカテゴリのサブループ用投稿データを取得(配列が返る)
$sub_posts = get_posts( [ 'category_name' => 'foo' ] );
foreach ( $sub_posts as $p ) :
    setup_postdata( $p ); ?>
    <!-- サブループ処理 -->
    <!-- タイトルが切り替わらない!!! -->
    <h2><?php the_title(); ?></h2>
    <!-- 記事本文は出力される -->
    <div><?php the_content(); ?></div>

グローバルの$postを差し替えてから、setup_postdata関数を呼ぶ必要があります。

<?php
// fooカテゴリのサブループ用投稿データを取得(配列が返る)
$sub_posts = get_posts( [ 'category_name' => 'foo' ] );
// 念のため
global $post;
// 投稿データをグローバルの$postに代入してループ
foreach ( $sub_posts as $post ) :
    setup_postdata( $post ); ?>
    <!-- サブループ処理 -->
    <h2><?php the_title(); ?></h2>
    <div><?php the_content(); ?></div>
<?php
endforeach;
// global $postを元に戻す
wp_reset_postdata();
?>

先のquery_posts関数やWP_Queryクラスを使う方法でも、the_post関数(メソッド)内でsetup_postdata関数の呼び出しが行われています。

まとめ

query_posts関数やWP_Queryインスタンスを使った処理は、コンテキスト切り替えが直感的で比較的わかりやすく感じます。一方、get_posts関数では、少し内部の処理に踏み込むような手続きが必要で、WordPress自体のソースを当たるまで処理内容がいまいち理解できませんでした。

本の中では(おそらく章により担当著者が違うため)get_posts関数を薦める箇所があったかと思うと、get_postsは使わないほうが良いとする箇所もあったりして、どっちやねんと思ったりしましたが、個人的にはWP_Queryクラスを使う方法がしっくりくるように思いました。

コメント