• 赤色のリンクは、まだ日本語Codexに存在しないページ・画像です。英語版と併せてご覧ください。(詳細

このWikiはいつでも誰でも編集できます

ループ

提供: WordPress Codex 日本語版
2013年6月23日 (日) 12:42時点におけるDjkaz (トーク | 投稿記録)による版 (「複数ループの例 2」まで翻訳完了。「複数ループの使い方」以下を最新英語版と置き換え。)

移動先: 案内検索

このページ「ループ」は未翻訳です。和訳や日本語情報を加筆してくださる協力者を求めています

ループ」は、WordPress の投稿を表示するために使われるPHPコードです。このループを使えば、現在のページに表示される各投稿を処理したり、ループタグ内で指定された条件に沿って投稿の形式を整えたりできます。ループの開始部分と終了部分の間に書きこんだ HTMLPHP のコードは、各投稿の表示に使われます。

テンプレートタグプラグインの説明内に「このタグ(プラグイン)はループ内で使います」とある場合、タグが各投稿で繰り返して表示されます。例として、以下が各投稿にデフォルトでループ内に含まれます。

さらに他のテンプレートタグを使ったり、詳しい人ならば $post 変数にアクセスしたりして、投稿に関する様々な情報を表示することもできます。

ループに始めて触れる人は、ループの使用例/en ページも参照してください。

ループの使い方

ループは index.php などのテンプレートファイルに含め、投稿の情報を表示するために使います。

テーマのテンプレートの最初で、ヘッダーテンプレートを必ず呼び出すようにしてください。もしループをテンプレート以外の自分のデザインで使っている場合、WP_USE_THEMESfalse に設定します。

<?php define('WP_USE_THEMES', false); get_header(); ?>

ループはここから始まり、

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>

ここで終わります。

<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>

PHPの制御構造を用いることで、このような表現も可能です。

<?php 
	if ( have_posts() ) {
		while ( have_posts() ) {
			the_post(); 
			//
			// 投稿がここに表示される
			//
		} // end while
	} // end if
?>

ループの例

特定のカテゴリーにある投稿のスタイルを変更する

以下のコードは各投稿をのタイトル (パーマリンクとして用いられるもの)、カテゴリー、内容を表示するものです。これはまた、in_category() テンプレートタグを使ってカテゴリー番号が3の投稿に他とは別のCSSクラス名を割り当てています。CSS(style.css)内でこのクラスの宣言を追加・編集することにより、カテゴリー3の投稿にのみ特別なスタイルを加えることができます。

<!-- --> というHTMLコメントで囲まれた部分は、実際にブラウザでは表示されません。ここではコードを分かりやすくするためにHTMLコメントで囲んだ説明を挿入していますが、実際にはテンプレート内に書き込まなくてもかまいません。

 <!-- ループ開始 -->
 <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>

 <!-- 以下で、投稿がカテゴリー3に属しているかテスト -->
 <!-- もし属している場合、"post-cat-three"というCSSクラスのdivボックスを表示 -->
 <!-- それ以外の場合、"post"というCSSクラスのdivボックスを表示 -->
 <?php if ( in_category('3') ) { ?>
           <div class="post-cat-three">
 <?php } else { ?>
           <div class="post">
 <?php } ?>

 <!-- 投稿のタイトルとパーマリンクを表示 -->
 <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>

 <!-- 日時を表示 -->
 <small><?php the_time('F jS, Y'); ?></small>

 <!-- 投稿の本文をdiv内に表示 -->
 <div class="entry">
  <?php the_content(); ?>
 </div>

 <!-- 投稿のカテゴリーをコンマ区切りで表示 -->
 <p class="postmetadata">Posted in <?php the_category(', '); ?></p>
 </div> <!-- 最初の div ボックスを閉じる -->

 <!-- “else”部分を除いたループ終了 -->
 <?php endwhile; else: ?>

 <!-- 最初の“if”にて表示する投稿があるかどうかをテストしたため、“else”では投稿がない場合に実行 -->
 <!-- つまり、投稿がなければ以下を表示 -->
 <p>Sorry, no posts matched your criteria.</p>

 <!-- ループを「完全に」終了 -->
 <?php endif; ?>

注: HTMLコードをテンプレート内に書く場合は、必ず <?php  ?> というPHP開始・終了タグの外側に書かなければなりません。逆に、PHPコードは、必ず <?php  ?> タグの内側に書きます。上記のように、ifelse ステートメント内でもPHPコードを一時的に閉じ、HTMLコードを書くことができます。

特定カテゴリーの投稿を除外する

この例は特定のカテゴリーを表示させない場合を示します。この場合、カテゴリー3と8の投稿を除外します。この例は上記の例とは異なり、クエリー自身を変更しています。

<?php query_posts($query_string . '&cat=-3,-8'); ?>
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>

<div class="post">

<!-- Display the Title as a link to the Post's permalink. -->
<h2><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>

<!-- Display the date (November 16th, 2009 format) and a link to other posts by this posts author. -->
<small><?php the_time('F jS, Y') ?> by <?php the_author_posts_link() ?></small>

 <div class="entry">
   <?php the_content(); ?>
 </div>

 <p class="postmetadata">Posted in <?php the_category(', '); ?></p>
</div> <!-- closes the first div box -->

<?php endwhile; else: ?>
<p>Sorry, no posts matched your criteria.</p>
<?php endif; ?>

: この例をメインページに用いる場合、違うテンプレートカテゴリーページに適用させる必要があります。さもなくば、WordPressは、カテゴリーアーカイブを含めた全てのページから、カテゴリー3の投稿を除外してしまいます。しかし、同じテンプレートファイルを使いたい場合、is_home() タグを用いることで、カテゴリー3の投稿がメインページからのみ除外されるようにすることができます。

...
<?php if ( is_home() ) {
query_posts($query_string . '&cat=-3');
}
?>
...

他にも条件分岐タグを用いることで、ページに対する特定の条件がtrueであるか否かで出力をコントロールすることができます。

複数のループ

この章ではループの発展的用途について解説します。少々技術的な内容ですが、怖がらずに読んでください。簡単なところから徐々に発展した内容に入っていきます。ほんの少しの常識や我慢、そして熱意があれば、あなたも複数のループを使うことが出来るでしょう。

はじめに、「なぜ複数のループが必要なのか?」という点について考えてみましょう。おそらくあなたは何かをある投稿のグループに対して行い、別の何かを他の投稿のグループに対して行ったものの、同じページが両方のグループに表示されてしまったのでしょう。「何か」というのは「何にでも」という事になり得ます。あなたは今、PHPのスキルと想像に縛られています。

では、例に入りましょう。まずは普通のループから。

     <?php if (have_posts()) : ?>
               <?php while (have_posts()) : the_post(); ?>    
               <!-- 何かの処理 ... -->
     <?php endwhile; ?>

(ソースコードを読むのに慣れている人は飛ばして下さい)。 これを日本語で言えば、以下の様になります。

もし投稿を表示できれば、次へと進む。
          そして一覧に存在している投稿ごそれぞれに、
          <!-- 何かの処理 ... -->を行う。
最後の投稿にたどり着いたら、終了する。

ここでの<!-- 何かの処理 ... -->はテンプレートに依ります。

何かの処理について: この例ではページの各投稿をどうフォーマットし、どう表示させるかというコード一式を表しています。このコードはWordPressでどう表現したいかに依って異なります。Kubrickのテーマの index.php を見た場合、

     <?php while (have_posts()) : the_post(); ?>

に続いて、この行が入ります。

     <?php comments_popup_link('No Comments »', '1 Comment »', '% Comments »'); ?>

コーダー向けの説明: have_posts()the_post() は、全てのアクションであるグローバルな $wp_query オブジェクトを用いるのに便利なラッパーです。$wp_query はブログのヘッダーで呼び出され、GETPATH_INFO を通して来たクエリー引数が入力されます。$wp_query は引数を受け、ビルドし、データベースクエリーを実行し、投稿の配列を作成します。この配列はオブジェクト内に格納され、またグローバルの$posts 配列の中に (古い投稿ループとの後方互換性のために) 入っているブログのヘッダーに返されます。

WordPressがブログのヘッダーを読み込み終わり、テンプレートまでたどり着くと、投稿のループに到達します。ここで have_posts()$wp_query->have_posts()を呼び出し、ループカウンターと投稿配列に残った投稿の有無をチェックします。そしてthe_post()$wp_query->the_post() を呼びだし、ループカウンターを進め、グローバルの $post 変数と、全てのグローバル投稿データをセットアップします。ループが完了したら、have_posts() がfalseを返し、終了します。

ループの例

以下に複数ループの使用例を2つ示します。複数ループを使うための鍵は $wp_query が一度しか呼び出されないところにあります。これを回避するために、 rewind_posts() を呼び出してクエリーを再利用するか、新しいクエリーオブジェクトを生成します。これは複数ループの例 1の内容です。複数ループの例 2ではクエリーの結果を格納する変数を使うケースがを挙げています。最後に複数ループの使い方では、ブログのホームページに特定のカテゴリーの投稿を優先的に載せるために様々なアイディアを駆使した複数ループの使用方法の1つを記載しています。

複数ループの例 1

二度目のループでも同じ様に処理を行うにはrewind_posts()を呼び出して下さい。 この関数はループのカウンタをリセットし、別のループを実行出来るようにします。

  <?php rewind_posts(); ?>
 
  <?php while (have_posts()) : the_post(); ?>
    <!-- 何かの処理 ... -->
  <?php endwhile; ?>

もし既に標準のクエリに関するループを終了したあと、別のクエリを使いたくなったら、$wp_queryオブジェクトをquery_posts()から呼び出すことが可能です。query_posts()は新しいクエリ、投稿リストを作り、ループをリセットします。

  // special_cat カテゴリーから10件の投稿を取り出します。
  <?php query_posts('category_name=special_cat&showposts=10'); ?>

  <?php while (have_posts()) : the_post(); ?>
    <!-- special_cat についての処理... -->
  <?php endwhile;?>

もし標準のクエリを保持しておきたければ、新しいクエリオブジェクトを生成するという方法があります。

<?php $my_query = new WP_Query('category_name=special_cat&showposts=10'); ?>

<?php while ($my_query->have_posts()) : $my_query->the_post(); ?>
  <!-- special_cat についての処理... -->
<?php endwhile; ?>

$wp_query用のhave_posts()the_post() が使えないので、新たなオブジェクト my_query を生成します。 (訳注: ただの have_posts()the_posts() ではなく、事前に生成した $my_query のメソッドであることに注意して下さい。)

複数ループの例 2

複数ループを使うもう一つの方法は、have_posts()the_post() が使えないことに対する別の回避策を必要とします。これを解決するために、オリジナルのクエリー結果を変数に格納し、もう一方のループで再度割り当てる必要があります。これにより、全てのグローバルに依存する全ての標準機能を使うことができます。

例:

// ここで脇にそれる
<?php $temp_query = $wp_query; ?>
<!-- 何かの処理 ... -->

<?php query_posts('category_name=special_cat&posts_per_page=10'); ?>

<?php while (have_posts()) : the_post(); ?>
  <!-- special_cat についての処理... -->
<?php endwhile; ?>

// ここで通常のプログラミングに戻る
<?php $wp_query = $temp_query; ?>

注: PHP 4では "=" オペレーターでオブジェクトが参照されていましたが、PHP 5では "= clone" オペレーターで参照されます。例 2をPHP 5で動くようにするためには、以下のコードを用いる必要があります。

 // ここで脇にそれる
 <?php $temp_query = clone $wp_query; ?>
 <!-- 何かの処理 ... -->
 
 <?php query_posts('category_name=special_cat&posts_per_page=10'); ?>
 
 <?php while (have_posts()) : the_post(); ?>
   <!-- special_cat についての処理... -->
 <?php endwhile; ?>
 <?php endif; ?>
 
 // ここで通常のプログラミングに戻る
 <?php $wp_query = clone $temp_query; ?>

しかし、2つ目の例はWordPress 2.1では使うことはできません。

複数ループの使い方

The best way to understand how to use multiple loops is to actually show an example of its use. Perhaps the most common use of multiple loops is to show two (or more) lists of posts on one page. This is often done when a webmaster wants to feature not only the very latest post written, but also posts from a certain category.

Leaving all formatting and CSS issues aside, let us assume we want to have two lists of posts. One which would list the most recent posts (the standard 10 posts most recently added), and another which would contain only one post from the category ‘featured’. Posts in the ‘featured’ category should be shown first, followed by the second listing of posts (the standard). The catch is that no post should appear in both categories.

Step 1. Get only one post from the ‘featured’ category.

  <?php $my_query = new WP_Query('category_name=featured&posts_per_page=1');
  while ($my_query->have_posts()) : $my_query->the_post();
  $do_not_duplicate = $post->ID; ?>
    <!-- Do stuff... -->
  <?php endwhile; ?>

In English the above code would read:

Set $my_query equal to the result of querying all posts where the category is named featured and by the way, get me one post only. Also, set the variable $do_not_duplicate equal to the ID number of the single post returned. Recall that the Do stuff line represents all the formatting options associated for the post retrieved.

Note that we will need the value of $do_not_duplicate in the next step to ensure that the same post doesn't appear in both lists.

Step 2. The second loop, get the X latest posts (except one).

The following code gets X recent posts (as defined in WordPress preferences) save the one already displayed from the first loop and displays them according to Do stuff.

  <?php if (have_posts()) : while (have_posts()) : the_post(); 
  if( $post->ID == $do_not_duplicate ) continue;?>
   <!-- Do stuff... -->
  <?php endwhile; endif; ?>

In English the above code would read:

Get all posts, where a post equals $do_not_duplicate then just do nothing (continue), otherwise display all the other the posts according to Do stuff. Also, update the cache so the tagging and keyword plugins play nice. Recall, $do_not_duplicate variable contains the ID of the post already displayed.

The End Result

Here is what the final piece of code looks like without any formatting:

  <?php $my_query = new WP_Query('category_name=featured&posts_per_page=1');
  while ($my_query->have_posts()) : $my_query->the_post();
  $do_not_duplicate = $post->ID;?>
    <!-- Do stuff... -->
  <?php endwhile; ?>
    <!-- Do other stuff... -->
  <?php if (have_posts()) : while (have_posts()) : the_post(); 
  if( $post->ID == $do_not_duplicate ) continue; ?>
   <!-- Do stuff... -->
  <?php endwhile; endif; ?>

The end result would be a page with two lists. The first list contains only one post -- the most recent post from the 'feature' category. The second list will contain X recent posts (as defined in WordPress preferences) except the post that is already shown in the first list. So, once the feature post is replaced with a new one, the previous feature will show up in standard post list section below (depending on how many posts you choose to display and on the post frequency). This technique (or similar) has been used by many in conjunction with knowledge of the Template Hierarchy to create a different look for home.php and index.php. See associated resources at the bottom of this page.

Note for Multiple Posts in the First Category

If posts_per_page=2 or more, you will need to alter the code a bit. The variable $do_not_duplicate needs to be changed into an array as opposed to a single value. Otherwise, the first loop will finish and the variable $do_not_duplicate will equal only the id of the latest post. This will result in duplicated posts in the second loop. To fix the problem replace

<?php $my_query = new WP_Query('category_name=featured&posts_per_page=1');
 while ($my_query->have_posts()) : $my_query->the_post();
 $do_not_duplicate = $post->ID;?>

with

<?php $my_query = new WP_Query('category_name=featured&posts_per_page=2');
  while ($my_query->have_posts()) : $my_query->the_post();
  $do_not_duplicate[] = $post->ID ?>

Note that "posts_per_page" can be any number. This changes $do_not_duplicate into an array. Then replace

<?php if (have_posts()) : while (have_posts()) : the_post(); if( $post->ID ==
  $do_not_duplicate ) continue; ?>

with

<?php if (have_posts()) : while (have_posts()) : the_post(); 
 if (in_array($post->ID, $do_not_duplicate)) continue;
 ?>

Where you continue the pattern for whatever posts_per_page is set equal to (2 in this case).

Alternatively you can pass the entire $do_not_duplicate array to $wp_query and only entries that match your criteria will be returned:

<?php query_posts(array('post__not_in'=>$do_not_duplicate));
 if (have_posts()) : while (have_posts()) : the_post();
 ?> 

Note that instead a string, the query parameter was an associative array, with post__not_in option.

Nested Loops

Nesting loops means that you are running a second loop before finishing the first one. This can be useful to display a post list with a shortcode for example.

   $my_query = new WP_Query( "cat=3" );
   if ( $my_query->have_posts() ) { 
       while ( $my_query->have_posts() ) { 
           $my_query->the_post();
           the_content();
       }
   }
   wp_reset_postdata();

It is necessary to reset the main loop data after a nested loop so that some global variables hold the correct values again.

ソース

The section on multiple loops is a combination of Ryan Boren and Alex King's discussion about the Loop on the Hackers Mailing List. The nested loops example was inspired by another discussion on the mailing list and a post by Nicolas Kuttler.

その他のループ関連リソース

WordPressループについて、またループ内で使える様々なテンプレートタグについて更に詳しくは、下記のリソースを参照してください。

リソース

日本語

英語

最新英語版: WordPress Codex » The Loop最新版との差分