WordPressで投稿を表示。正しいループの書き方徹底まとめ。

最終更新:2017-07-16 by Joe

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は、詳しいですが、ちょっと情報量が多くて読みにくいかもしれません。