ループ

ループとは

テンプレートをカスタマイズしていくわけですが、その際知っておかなければならない必須のものにループがあります。

WordPressは、投稿されたコンテンツを MySql のデータベースに保存していますが、それを取り出す際の繰り返し処理です。
言い換えれば、複数の投稿記事を順番に処理する仕組みです。

基本的なループ

下はhome.php にあるループの例です。gush2では、投稿記事のサムネイルの処理が入っているので、・・・記事の処理・・・のところが少し長くなっていますが、骨格だけを見るとこのようになっています。

1行目で、投稿記事はありますか?とたずねて、
あるならば2行目から4行目の while ループを記事がある間まわします。
なければ4行目の else で、5行目のなかった場合の処理をおこないます。

have_posts() という関数は、クエリーにループできる結果があるかどうかをチェックする関数で、結果として TRUE または FALSE を返します。引数はありません。

念のために言っておくと、クエリーというのはデータベースへの検索リクエストのことです。
すなわち「データベースに問い合わせした結果があるか?」と聞いていることになり、あったら TRUE、無ければ FALSE が返ってきます。

ということは、have_posts() を使う前に、クエリーの結果を用意しておかなければならないことになりますが、home.php を見る限りそのような処理の記述はありません。
ある方の説明によると、

WordPress ループ(メインループ)の処理をいきなり書けるのは、テンプレートファイルが実行される時点ですでに「サイトにアクセスされた URL からクエリ変数を抽出し、それらの条件に一致する記事オブジェクトを取得している」からです。

とありますが、それでは“クエリ変数を抽出”というのはどこでやっているのでしょうか?

WordPress Codex 日本語版によると、

wp-blog-header.php (バージョン 2.0 では WP クラス) が $wp_query オブジェクトに現在のリクエストを定義する情報を与えることで、$wp_query はどのタイプのクエリを扱っているのか (カテゴリーアーカイブ、年月別アーカイブ、フィード、検索など) を確定し、要求された投稿を取り出します。

※ wp-blog-header.php というのは、WordPressをインストールしたフォルダーにあるファイルです。

ということです。

$wp_query とかまた聞きなれないのが出てきました。
このあたりはあまりいじらないところですし混乱するといけないので、今はこれ以上深入りしないことにします。
要は、ページが表示される際に wp-blog-header.php というのが実行されて、グローバル変数 $wp_query がセットされるということにしておきます。

メインループとサブループ

で、この暗黙のうちにセットアップされるクエリーをメインクエリーといい、それとは別に明示的にクエリーを実行して得られるものをサブクエリーといいます。
そしてメインクエリーに基づくループをメインループ、サブクエリーに基づくループをサブループと呼びます。Codexでは、メインクループ以外にループを作成することを複数ループと呼んでいます。

既にした説明から解るように、メインループは原則として1ページに1つしかありません。

そのメインクエリーの検索条件を変更したい場合は、query_posts() を呼び出すことで再設定することもできますが、テンプレートの中で query_posts() を使うことは非推奨とされています。またどうしても使う場合は、その前に wp_reset_query() で前のクエリーをリセットする必要があります。

それでは複数ループを実現するにはどうすればいいかというと、get_post() を使う方法があります。この他に、WP_Query を使う方法もありますが、ここでは get_post() で話をすすめることにします。

下は get_post() を使ったループの例です。

例では $args に ‘post_type’ => ‘post’ をセットして、これをパラメータとして get_post()に渡しています。

実は、get_posts()も query_posts() と同じようにデータベースから投稿記事を持って来るのですが、query_posts() が読み込んだ $wp_query というグローバル変数とは別の場所に読み込むことができるのでメインループの中で使ってもメインループに影響を与えないのだと考えておけばいいでしょう。
上の例では、$my_posts という変数に読み込んでいます。これは $wp_query と同じようにオブジェクトの配列ですが、global 宣言されていないのでモジュールの中でだけ有効なローカル変数です。

最初に出てきたメインループの例をもう一度見てみましょう。

$wp_query 変数がセットアップされるところは、このコードにはありませんが、見えないところでされているという話はしました。そしてクエリーに投稿記事があった場合ループが開始されるのですが、その冒頭に the_post() という関数を呼び出しています。
これは、配列である $wp_query の要素、すなわち個別投稿記事をループ内でタイトルやら本文やらを取得したり画面に表示したりするための準備、現在の投稿記事のオブジェクトをグローバル変数 $post にセットアップしています。
これにより、the_title() とか the_content() といった関数が使えるようになります。
また、the_post() はもう一つ $wp_query の中で現在の投稿がどれかをさし示すポインターを進めるという大きな役割を持っています。もしこの関数を呼び出さなかったとすると、メインループは無限に繰り返されてしまうことになります。

get_posts() を使った例では、
global $post; と setup_postdata( $post ); がミソになります。

global $post; という文は、$post がグローバル変数であることを宣言しています。

グローバル変数とそのスコープについてわからない方は、PHP の解説書をご覧ください。

setup_postdata()というのはCodex日本語版によると次のように説明されています。

投稿情報を各種のグローバル変数へセットします。その変数は、テンプレートタグを使ってカスタムクエリの結果を表示するときに使われます。
setup_postdata() は下記のグローバル変数をセットします:

$id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages

これらは現在の投稿を参照する多くのテンプレートタグによって使われます。

この関数は $post グローバル変数をセットしませんが、それへのリファレンスを引数とするつもりで設計されています。

これらにより、foreach ( $my_posts as $post ) のループで、$my_posts に読み込まれたクエリー結果の中の各投稿記事が、グロ-バル変数 $post として使えることになり、テンプレートタグと呼ばれる関数群が利用できることになります。

わざわざグローバル変数にセットアップしているということは、そのグローバル変数を参照している他の関数を使いたいからです。

例えば、the_title() という関数は、投稿のタイトルを表示または取得するものですが、この関数は、$post というオブジェクト型のグローバル変数から投稿タイトルを取得しています。
他にもthe_permalink()やthe_category()といった関数が $postグローバル変数を参照しています。これらは皆ループ内でしか使えない関数に含まれます。

メインループの説明で、the_post() によって the_title() とか the_content() といったループ内で使える関数が使えるようになると書きましたが、これらの関数はメインループ内でしか使えないというわけではありません。the_post() が、$post などのグローバル変数をセットアップしたので使えるようになったと考えればいいでしょう。

下は固定ページを表示する page.php に手を加えてみたものからのループ部分の抜粋です。

メインループの中にサブループがあります。
page.php が元なので、メインループには固定ページのクエリーがセットされています。
サブクエリーではget_posts()で投稿のクエリーを作成しています。
メインループの中で、サブループの前と後、そしてサブループの中の計3ヶ所で、the_title() でタイトルを表示しています。

結果は、まず固定ページのタイトルが表示されて、その下に投稿記事タイトルの一覧が表示され、そして最後にもう一度固定ページのタイトルが表示されます。
もし、サブループの最後の wp_reset_postdata() でリセットしていなければ、22行目にある最後の the_title() は、固定ページのタイトルではなくサブループの最後の投稿記事のタイトルを表示することになります。

スポンサーリンク