Go to top Go to bottom

一旦終了したWordPressループを巻き戻すには、rewind_posts()関数を使用します。たとえば、投稿の一覧を出力する前にタイトルだけの目次を作成したり、あるいはおすすめの記事を先に表示し、それ以外を後から表示したりというような用途に使えます。

用例
  • 記事一覧の目次を作成する
  • 特定の投稿を先に出力した後に、残りの投稿を出力する
関連
Codex

ループを巻き戻す

基本的なWordPressループは次のようになっています。

<?php if ( have_posts() ) : ?>
  <?php while( have_posts() ) : the_post(); ?>
    <!-- 1つの投稿に対する処理 -->
  <?php endwhile; ?>
<?php endif; ?>

the_post()によって投稿を1つずつ取り出して処理を行い、投稿がなくなったらwhile文を抜け、終了します。ループ終了後は、クエリによって取得した投稿がthe_post()によってすべて取り出されているので、このままでは同じループをもう一度繰り返すことはできません。

そこで、rewind_posts()を実行することで、一度終了したループを巻き戻します。

<!-- 1度目のループ -->
<?php if ( have_posts() ) : ?>
  <?php while( have_posts() ) : the_post(); ?>
    <!-- 1つの投稿に対する処理 -->
  <?php endwhile; ?>
<?php endif; ?>

<?php rewind_posts(); ?>

<!-- 2度目のループ -->
<?php if ( have_posts() ) : ?>
  <?php while( have_posts() ) : the_post(); ?>
    <!-- 1つの投稿に対する処理 -->
  <?php endwhile; ?>
<?php endif; ?>

rewind_posts()が実行されていない場合、2度目のループは何も出力しません。これはhave_posts()がfalseのままなので、if文の中に入らないためです。

特定のカテゴリーに含まれる投稿を先に出力する

投稿の一覧を出力する際、あるカテゴリーに含まれる投稿を先に表示することを考えてみます。

投稿が特定のカテゴリーに含まれるかどうかを判定するには、in_category()を使用して判定します。

WordPress関数

in_category( $category, $post )

第2引数に与えられる投稿が、第1引数のカテゴリに含まれるかどうかを判定する。

$category カテゴリーを指定。ID、名前、スラッグ、またはそれらの配列を渡す
$post 調べる対象となる投稿。指定しない場合は現在の投稿が自動的に使用される

管理画面の[投稿]にある[カテゴリー]を開けば、正確な名前やスラッグを調べることができます(URLを見ればIDもわかります)。

このin_category()関数を使って次のように処理すれば、今回の目的を達成することができます。

  1. 1度目のループで、投稿が特定のカテゴリーに含まれていれば出力
  2. ループを巻き戻す
  3. 2度目のループで、投稿が特定のカテゴリーに含まれない場合のみ出力

この処理を簡単にコードで書くと、次のようになります。ここでは、カテゴリーのIDを9とします。

<?php 
  if ( have_posts() ) {
    while( have_posts() ) {
      the_post();
      if( in_category( 9 ) ) {
        ?>
          <!-- 9番のカテゴリーに含まれる記事に対する処理 -->
          <div class="entry-in-9-category">
            <header class="entry-header">
              <?php the_title( '<h2><a href="' . get_the_permalink() . '">', '</a></h2>' ); ?>
            </header>
            <div class="entry-content">
              <?php the_content(); ?>
            </div>
          </div>
        <?php
      }
    }
  }

  rewind_posts();

  if ( have_posts() ) {
    while( have_posts() ) {
      the_post();
      if( ! in_category( 9 ) ) {
        ?>
          <!-- 9番のカテゴリーに含まれない記事に対する処理 -->
          <div class="entry-standard">
            <header class="entry-header">
              <?php the_title( '<h2><a href="' . get_the_permalink() . '">', '</a></h2>' ); ?>
            </header>
            <div class="entry-content">
              <?php the_content(); ?>
            </div>
          </div>
        <?php
      }
    }
  }
?>

最初のループでは5行目のif( in_category( 9 ) )により、IDが9のカテゴリーに属する投稿だけが出力されます。スタイルを分けたければ特別なクラス名を付けたWrapperで囲むこともできますね。

次に、22行目のrewind_posts()によってループを巻き戻し、再度ループを開始します。今度は27行目のif( ! in_category( 9 ) )によって、9番のカテゴリーに含まれない投稿のみが順次出力されていきます。

in_category()はあるのにin_tag()は存在しない

in_category()という関数があるのなら、in_tag()という関数があってもおかしくないような気もするのですが、存在しません。「カテゴリーの中に投稿が含まれている」という考え方は一般的ですが、「タグの中に投稿が含まれている」という考え方は違和感がありますね。タグの場合は投稿につけるもので、「投稿」が主体となります。実際has_tag()という関数が存在し、in_category()と似たような働きをします。実はhas_category()という関数も存在し、in_category()は中でhas_category()を呼んでいるだけですので、’in’のほうが特殊であることがわかります。また、has_category()has_tag()も、has_term()というより原始的な関数から派生しています。