WordPressのループの仕組みを深く知る query_posts() と get_posts() の違い

WordPressループの基本

1
2
3
4
5
6
7
8
9
<?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 を表示させてみましょう。

1
<?php print_r($wp_query); ?>

じゃんッ!↓

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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] です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
    [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ループの基本構文を見てください。

1
2
3
4
5
6
7
8
9
<?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 の値を変更することを意味します。

1
2
3
4
5
6
7
8
9
<?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() は、マルチループを生成するための関数です。

1
2
3
4
<?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() は正常に動作します。

1
2
3
4
5
6
7
8
<?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() ではシングルページと判定されません。

1
2
3
4
5
6
7
8
9
10
11
<?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 は、アクセスしたURLに応じて、必要なデータを自動的に取得してくれる。これを「WordPressループ」と呼ぶ。
・WordPress が自動的に取得したデータは、グローバル変数 $wp_query に格納される。
・WordPressループの表示条件を変更したい場合は query_posts() を使う。
・WordPressループとは別に、新しいマルチループを生成する場合は get_posts() を使う。

Comments

Mayuu Sousi へ返信するコメントをキャンセル