WordPressループの基本
<?php if (have_posts()) : ?> <?php while (have_posts()) : the_post(); ?> <!-- 表示内容を記述 --> <h2><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></h2> <div <?php post_class(); ?> id="post-<?php the_ID(); ?>"> <?php the_content(); ?> </div> <?php endwhile; ?> <?php endif; ?>
これは WordPressループの基本構文ですね。
このループ構文を記述すれば、投稿記事一覧、個別記事、固定ページ、カテゴリーアーカイブ、年月別アーカイブ、フィード、検索、などなど、それぞれのページに必要なデータが表示されます。
これって不思議だと思いませんか?
「○○のデータを取得する」とかいう条件がどこにもありません。
これを紐解いていくと WordPress のループの仕組みを深く理解することができるようになります。
WP Query オブジェクト
WP_Query
WP_Query は wp-includes/query.php に定義されているクラスで、WordPress への複雑なリクエストを取り扱います。
グローバル変数 $wp_query に、現在のリクエストを定義する情報を与えることで、どのタイプのクエリを扱っているのかを確定し、要求されたデータを取り出します。
つまり、特定のURLにアクセスするだけで、そのページに必要なデータを自動的に取得して、グローバル変数 $wp_query に格納してくれる のです。
では、グローバル変数 $wp_query とはどのようなものでしょうか?
投稿記事一覧ページのテンプレートの一番はじめに以下のコードを記述して、$wp_query を表示させてみましょう。
<?php print_r($wp_query); ?>
じゃんッ!↓
WP_Query Object
(
    [query_vars] => Array
        (
            [error] => 
            [m] => 0
            [p] => 0
            [post_parent] => 
            [subpost] => 
            [subpost_id] => 
            [attachment] => 
            [attachment_id] => 0
            [name] => 
            [static] => 
            [pagename] => 
            [page_id] => 0
            [second] => 
            [minute] => 
            [hour] => 
            [day] => 0
            [monthnum] => 0
            [year] => 0
            [w] => 0
            [category_name] => 
            [tag] => 
            [cat] => 
            [tag_id] => 
            [author_name] => 
            [feed] => 
            [tb] => 
            [paged] => 0
            [comments_popup] => 
            [meta_key] => 
            [meta_value] => 
            [preview] => 
            [s] => 
            [sentence] => 
            [fields] => 
        // 省略
        )
)
たくさん出てきましたね〜。
最初の方には関連するグローバル変数がずらっと並びます。
注目すべきは、このずーっと下の方にある、[request] と [posts] です。
    [request] =>  SELECT SQL_CALC_FOUND_ROWS  wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')  ORDER BY wp_posts.post_date DESC LIMIT 0, 10
   [posts] => Array
        (
            [0] => stdClass Object
                (
                    [ID] => 187
                    [post_author] => 1
                    [post_date] => 2012-02-13 15:22:35
                    [post_date_gmt] => 2012-02-13 06:22:35
                    [post_content] => 投稿3の内容
                    [post_title] => 投稿3
                    [post_excerpt] => 
                    [post_status] => publish
                    [comment_status] => closed
                    [ping_status] => open
                    [post_password] => 
                    [post_name] => %e6%8a%95%e7%a8%bf3
                    [to_ping] => 
                    [pinged] => 
                    [post_modified] => 2012-02-13 15:22:35
                    [post_modified_gmt] => 2012-02-13 06:22:35
                    [post_content_filtered] => 
                    [post_parent] => 0
                    [guid] => http://localhost/wordpress/dev/?p=187
                    [menu_order] => 0
                    [post_type] => post
                    [post_mime_type] => 
                    [comment_count] => 0
                    [filter] => raw
                )
            [1] => stdClass Object
                (
                    [ID] => 185
                    [post_author] => 1
                    [post_date] => 2012-02-13 15:22:03
                    [post_date_gmt] => 2012-02-13 06:22:03
                    [post_content] => 投稿2の内容
                    [post_title] => 投稿2
                    [post_excerpt] => 
                    [post_status] => publish
                    [comment_status] => closed
                    [ping_status] => open
                    [post_password] => 
                    [post_name] => %e6%8a%95%e7%a8%bf2
                    [to_ping] => 
                    [pinged] => 
                    [post_modified] => 2012-02-13 15:22:03
                    [post_modified_gmt] => 2012-02-13 06:22:03
                    [post_content_filtered] => 
                    [post_parent] => 0
                    [guid] => http://localhost/wordpress/dev/?p=185
                    [menu_order] => 0
                    [post_type] => post
                    [post_mime_type] => 
                    [comment_count] => 0
                    [filter] => raw
                )
                // 省略
        )
    [post] => stdClass Object
        (
            [ID] => 187
            [post_author] => 1
            [post_date] => 2012-02-13 15:22:35
            [post_date_gmt] => 2012-02-13 06:22:35
            [post_content] => 投稿3の内容
            [post_title] => 投稿3
            [post_excerpt] => 
            [post_status] => publish
            [comment_status] => closed
            [ping_status] => open
            [post_password] => 
            [post_name] => %e6%8a%95%e7%a8%bf3
            [to_ping] => 
            [pinged] => 
            [post_modified] => 2012-02-13 15:22:35
            [post_modified_gmt] => 2012-02-13 06:22:35
            [post_content_filtered] => 
            [post_parent] => 0
            [guid] => http://localhost/wordpress/dev/?p=187
            [menu_order] => 0
            [post_type] => post
            [post_mime_type] => 
            [comment_count] => 0
            [filter] => raw
        )
)
必要なデータを取得するクエリが [request] で、取得されたデータが [posts] だということが分かるでしょう。
さらに、[post] には、[posts] のデータが順番にセットされていきます。
もう一度、WordPressループの基本構文を見てください。
<?php if (have_posts()) : ?> <?php while (have_posts()) : the_post(); ?> <!-- 表示内容を記述 --> <h2><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></h2> <div <?php post_class(); ?> id="post-<?php the_ID(); ?>"> <?php the_content(); ?> </div> <?php endwhile; ?> <?php endif; ?>
the_posts() 関数というのがあります。
この関数こそが、 取得したデータを順番にグローバル変数 $post に読み込んでいるのです。
もしこの関数を記述しなければ、 $post は永遠に最初のデータから動かないので、無限ループになります。
WordPressのテンプレートはクエリベースである
ここで重要なことが判明してきます。
最初に「特定のURLにアクセスするだけで、そのページに必要なデータを自動的に取得して、グローバル変数 $wp_query に格納してくれる」と書きましたが、正確には「URLから必要なデータのクエリを発行し、グローバル変数 $wp_query に格納した後、テンプレート階層に従ってデータを表示する。」となります。
この流れをよーく覚えておきましょう。
WordPressループを変更する query_posts()
WordPressループを変更するには、query_posts() を使います。
これは、取得するデータのクエリを動的に発行して $wp_query の値を変更することを意味します。
<?php query_posts(引数); ?> <?php if (have_posts()) : ?> <?php while (have_posts()) : the_post(); ?> <!-- 表示内容を記述 --> <?php endwhile; ?> <?php endif; ?> <?php wp_reset_query(); ?>
引数として条件を与えることで、データを取得するクエリを変更します。
条件の指定方法はこちら→ query_posts()
最後に wp_reset_query() で、動的に変更した $wp_query をリセットすることを忘れないでください。
マルチループを生成する get_posts
ループを生成する関数には、他に get_posts() があります。
get_posts() は、マルチループを生成するための関数です。
<?php $myposts = get_posts(引数); ?> <?php foreach($myposts as $post) : setup_postdata($post); ?> <!-- 表示内容を記述 --> <?php endforeach; ?>
query_posts() と同様に、引数で条件を指定することで、マルチループを生成することができます。
生成できるループは query_posts() とほぼ同じですが、両者には決定的な違いがあります。
query_posts と get_posts の違い
query_posts と get_posts の違い
get_posts() は、単にデータを取得するだけで、グローバル変数 $wp_query には影響を与えません。
query_posts() は、グローバル変数 $wp_query を変更します。
この違いは重要です。
個別記事ページ(シングルページ)を表示させてみましょう。
一番最初にグローバル変数 $wp_query の内容を表示させてみると、[is_single] => 1 となっており、シングルページのフラグが立っています。シングルページなのですから当然です。
ここで、個別記事ページの一部に、固定ページの一覧を表示させたいとします。
query_posts() でも get_posts() でも、どちらでも固定ページ一覧のループは生成可能です。
しかし、この時は、get_posts() を使うべきです。
query_posts() は使ってはいけません。
それはなぜか?
ループ内に is_single() という条件分岐タグを入れてみれば分かります。
get_posts() を使えば、グローバル変数 $wp_query には影響を与えませんので、is_single() は正常に動作します。
<?php $myposts = get_posts('post_type=page'); ?>
<?php foreach($myposts as $post) : setup_postdata($post); ?>
<?php if (is_single()) : ?>
<?php the_title(); ?>
<?php endif; ?>
<?php endforeach; ?>
一方、query_posts() では、グローバル変数 $wp_query が上書きされる、つまり [is_single] => となり、is_single() ではシングルページと判定されません。
<?php query_posts('post_type=page'); ?>
<?php if (have_posts()) : ?>
	<?php while (have_posts()) : the_post(); ?>
		<?php if (is_single()) : ?>
		<?php the_title(); ?>
		<?php endif; ?>
	<?php endwhile; ?>
<?php endif; ?>
<?php wp_reset_query(); ?>
“query_posts() は WordPressループ内で使うべき” と言われるのはこういうことです。
まとめ
・WordPress が自動的に取得したデータは、グローバル変数 $wp_query に格納される。
・WordPressループの表示条件を変更したい場合は query_posts() を使う。
・WordPressループとは別に、新しいマルチループを生成する場合は get_posts() を使う。
Comments
「manablog」さんの「『プラグインなし』で人気記事一覧を出力する方法」で分からなかったところがすっきりしました。ありがとうございました。
[…] http://hijiriworld.com/web/wordpress-loop/ […]
[…] WordPress ループの仕組み query_posts() と get_posts() の違い | hijiriworld Web […]
[…] WordPressのループの仕組みを深く知る query_posts() と get_posts() の違い http://hijiriworld.com/web/wordpress-loop/ […]
[…] WordPress ループの仕組み query_posts() と get_posts() の違い | hijiriworld Web http://hijiriworld.com/web/wordpress-loop/ posted at 19:37:44 […]
[…] !?なんでー!!ということで、またもググったところ、query_postsを変更してしまうと、条件分岐は使えないとのこと。 WordPress ループの仕組み query_posts() と get_posts() の違い | hijiriworld Web […]
勉強になります
参考にしていただけたようで良かったです^^
[…] 「Webデザインレシピ:WordPressでブログじゃないWebサイトを作るときのいろいろ(サンプル付き)」 […]
[…] WordPressループの基本 では新着情報でよく見る、下記をつくってみましょう。 […]