WordPressの投稿を表示するループの記述方法についてです。
WordPressで「loop(ループ)」と呼ばれる投稿の表示方法には、いくつかの選択肢があります。その中でも最適な方法を選び、効率のよく、整然としたテンプレートでテーマを開発をしましょう。
目次
Loop(ループ)とは?
WordPressにおいて、「Loop(ループ)」とは、正確には「WordPressのメインクエリを、forループを利用して繰り返す事で、個々の投稿に関する情報を表示する処理」を指します。
初学者にはいったん何の事を言っているか、分かりにくいかもしれません。もしよくわからなければ、いったん「投稿をwhileループで回して表示させる処理」くらいに考えておいて、今は大丈夫です。
ループの書き方
具体的な選択肢について、見ていきます。
1メインループの書き方
メインループとは、メインクエリから得られた投稿群をループさせる処理の記述方法です。すなわち、以下のような処理を指します。
if ( have_posts() ) { // ループの開始 while ( have_posts() ) { the_post(); } ?> <h1><?php the_title(); ?></h1> <div><?php the_content(); ?></div> <?php } } else { // 対象の投稿が見つからない時の処理 }
上記の例で、while ループの外側の if 文は、必ずしも必要なものではありません。もしあなたのテーマが、「対象の投稿が見つからない場合のレイアウト」を想定しておく必要があるのであれば、これを記載しましょう。
2WP_Query を利用したサブループの書き方
さて、上記は、いわゆる「メインループ」を利用して、レイアウトを実装する時の方法です。そうではなく「サブループ」などと呼ばれる、メインクエリとは異なる投稿群をループさせる処理を考えます。
最も主要な方法は、WP_Query クラスから作られる、queryオブジェクトを利用すれば、上記のメインクエリとよく似た記法でループ処理を行う事ができます。メインクエリもまた、WP_Queryオブジェクトを利用しますが、それとは別にWP_Queryオブジェクトを生成する事になります。
page-staff.php
<?php // ・・・ 略 ・・・ $args = array( 'post_type' => 'staff', 'posts_per_page' => 9, 'no_found_rows' => true; ); // クエリオブジェクト取得 $staff = new WP_Query( $args ); // ループの開始 while ( $staff->have_posts() ) { $staff->the_post(); } ?> <h1><?php the_title(); ?></h1> <div><?php the_content(); ?></div> <?php } // グローバルの$postの値を、メインクエリの値に戻す wp_reset_post_data(); // ・・・ 略 ・・・
WP_Queryを使って、クエリオブジェクトを自分で生成する、そして、生成したクエリオブジェクトのメソッドのループ関数(have_posts(), the_post())を利用する以外は、ほぼメインループと同じ記法が利用できます。
また、この方法の最大の特徴は「グローバルの$post オブジェクトを書き換える」という点にあります。
これは「the_title() 」などのメイン関数を呼べば、サブループ内でも、関数の呼び出しによって、対象の投稿のフィールドにアクセスしてそれを出力できる事を意味します。
最後に「wp_reset_post_data()」を実行しているのは、その書き換えられた$post の値を を元に戻す処理です。(もし、この行のあと、メインクエリの投稿オブジェクトにアクセスしないのであれば、これは不要です)
すなわち、サブループ内の出力処理は、このように、テンプレート部品化できます。
page-staff.php
<?php // ・・・ 略 ・・・ while ( $staff->have_posts() ) { $staff->the_post(); get_tempalate_part( 'content', 'staff' ); }
content-staff.php
<h1><?php the_title(); ?></h1> <div><?php the_content(); ?></div>
content-staff.php のような「テンプレート部品ファイル」内において、投稿のフィールドへのアクセスは、すべて、投稿関数経由で行うことができます。
これが、WordPressが想定するテンプレート構造に、完全に乗っ取ったループの記述方法となります。
しばしば、get_tempalate_part関数から呼び出したテンプレート部品内に、投稿の値を持ち込めないことが問題になりますが、この設計思想を尊重していないために、発生する問題とも言えるかもしれません。
3get_posts() 関数を使ったサブループ
クエリにマッチした投稿の配列を返す、get_posts() という関数があります。
get_post()関数の内部ではWP_Queryを利用して投稿を取得しています。ただし、get_postsは、配列のみの、よりシンプルな値を返す、より単純な低レベルな処理に向いているといえます。
page-staff.php
<?php // ・・・ 略 ・・・ $args = array( 'post_type' => 'staff', 'posts_per_page' => 9, 'no_found_rows' => true; ); // クエリオブジェクト取得 $staff = get_posts( $args ); // ループの開始 foreach ( $staff as $s ) { $title = $s->post_title; $content = $s->post_content; // apply_filter( 'the_content', $s->post_content ); } ?> <h1><?php echo $title; ?></h1> <div><?php echo $content; ?></div> <?php } // ・・・ 略 ・・・
このケースで、注意が必要なのは、上記の「post_content」の値です。通常、get_the_content()で得られる値は、テキストのフォーマットや、ショートコードなど、多くのフィルターを通した後の値を返していました。
the_content() と、同じような出力を得るには、手動でそのフィルタを通してやる必要があります。
$content = $s->post_content; // でなく、 $content = apply_filter( 'the_content', $s->post_content );
また、get_posts()でも、setup_postdataを利用すると、グローバルの$postを書き換えて、WP_Queryのメソッドを利用できるようになります。
// ループの開始 foreach ( $staff as $s ) { global $post; // グローバル$psot を上書きしてから、関数に渡す $post = $s; setup_postdata( $post ); // テンプレート部品内で、WP_Queryのメソッドが利用できる get_template_part( 'content', 'staff' ); }
あえて、この方法を取るくらいなら、前述のようにWP_Queryオブジェクトを生成して、have_posts()や、the_post()を利用したほうがスッキリかけるでしょう。
参考:
悪い例:query_posts() を呼んでしまう
初学者は注意が必要ですが、よく似た名前の関数に、「query_posts() 」があります。この関数は、メインクエリを変更するためのもので、基本的にはWordPressコアコードの中でだけ利用される関数です。query_postsを、テーマから読んでしまうと、メインクエリが壊れて、意図しない動作が発生する可能性が高いです。
メインクエリをカスタマイズしたいのであれば、pre_get_posts という、メインクエリ実行前に差し込める、メインクエリのクエリ変数を上書きできるフックがありますので、これを利用しましょう。
参考:
ループの作成時の注意点まとめ
最後に、まとめます。
- メインループは、WP_Queryのメソッドを利用するなど、WordPress作法に従いましょう。
- メインループのカスタマイズは、pre_get_postフックを利用し、クエリ変数を上書きしましょう。
- query_posts() は絶対に呼ばないようにしましょう。
- サブループを作るには、基本的には、WP_Queryから、クエリオブジェクトを生成しましょう。
- テンプレート部品を必要としない、小さなサブループであれば、get_posts() から得た配列をforeachで回しましょう。
- サブループ後は(必要に応じて)、wp_reset_postdata() でグローバル$postを復元しましょう。
参考
日本語Codexは、詳しいですが、ちょっと情報量が多くて読みにくいかもしれません。