メインクエリ – main query
WordPressのコアAPIでは、URLリクエストに応じて必要な記事データを取得するクエリが発行されて、取得されたデータが $wp_query というグローバル変数に格納されます。ここまでを自動的に行ってくれます。
この自動的に発行されるクエリを、メインクエリと呼びます。
素直にメインクエリを出力する場合は、すべてのテンプレートで共通のループ構文を記述すればいいことになります。
<?php if (have_posts() ) : ?> <?php while (have_posts()) : the_post(); ?> <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2> <?php endwhile; ?> <?php else : ?> Not Found. <?php endif; ?>
advanced
$wp_query オブジェクトは以下のような構造になっています。
WP_Query Object
(
[query] => Array
[query_vars] => Array
[tax_query] => WP_Tax_Query Object
[meta_query] => WP_Meta_Query Object
[request] => SELECT SQL_CALC_FOUND_ROWS wp_posts.ID 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.menu_order ASC LIMIT 0, 10
[posts] => Array(
[0] => WP_Post Object (
)
…
)
…
[is_home] =>
[is_paged] =>
[is_admin] =>
[is_singular] =>
[is_post_type_archive] =>
…
)
request: メインクエリのSQL文
posts: 記事データ
is_home からの部分にも注目。
これは is_home() などの条件分岐タグに対するフラグです。
つまり条件分岐タグは $wp_query オブジェクトの値をみているということがわかります。
サブクエリ – sub query
メインクエリで取得される記事データとは別のデータを取得したい場合、自前でクエリを発行します。
この自前で発行するクエリを、サブクエリと呼びます。
サイドバーに記事一覧を表示したり、トップページに post_type=news の記事一覧を表示したいときなどに使います。
サブクエリの発行方法は2種類あります。
いずれも引数はほぼ同じなので、単純に記事データ(メタデータも含む)だけが必要であればどちらを使っても問題はないでしょう。
1. WP_Queryクラスを使う
<?php $args = array( 'post_type' => 'hoge', ); ?> <?php $query = new WP_Query( $args ); ?> <?php if( $query->have_posts() ) : ?> <?php while ( $query->have_posts() ) : $query->the_post(); ?> <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2> <?php endwhile; wp_reset_postdata(); ?> <?php else : ?> Not Found. <?php endif; ?>
2. get_posts関数を使う
<?php $args = array( 'post_type' => 'hoge', ); ?> <?php $hoge_posts = get_posts( $args ); ?> <?php if( !empty( $hoge_posts ) ) : ?> <?php foreach( $hoge_posts as $post ) : setup_postdata( $post ); ?> <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2> <?php endforeach; wp_reset_postdata(); ?> <?php else : ?> Not Found. <?php endif; ?>
Advanced
1 と 2 の違い
WP_Queryクラスを使う場合は、その名の通り WP_Queryクラスでクエリを発行するわけですが、これはメインクエリを発行する時に使われるクラスと同じです。
取得されたデータを格納した $query 変数を出力してみると、$wp_query と同じ構造のオブジェクトであることがわかります。
一方 get_postsで取得されるデータは、記事データ $wp_query->posts 限定になっています。
以上のことから、記事データのみを扱う場合は WP_Queryクラスでも get_posts でもどちらを使ってもいいですが、条件分岐タグや、その他のパラメーターを扱う場合は WP_Query を使った方がいろいろ高度なことができるということです。
メインクエリの改変
query_posts() はもう使うべきではありません。
その理由について WordPress Codex ではパフォーマンスの問題によって説明されおり、今後は query_posts() ではなく pre_get_posts にフックすべし、と言っています。
pre_get_posts に移行するメリットは他にもあります。
メインクエリの改変はテンプレート側ではなく、関数ファイル(functions.php)で一元的に行う、ということなので、MVCモデルに基づくビューテンプレートとコントローラーの分離が明確になります。
また、テンプレート数の削減にもつながるかもしれません。
news と evnet という2つのカスタム投稿タイプのアーカイブページがあったとして、いずれもループ出力の内容は同じ、唯一取得件数だけ違う場合、query_posts() を使うと、archive-news.php と archive-event.php という2つのテンプレートを用意しなければなりません。
一方、pre_get_posts を使うと、archive.php の1つのテンプレートだけでまかなえます。
つまり、メンテナブルなテーマ作成になるということです。
> functions.php
function custom_main_query( $query ) { if ( is_admin() || !$query->is_main_query() ) return; if ( $query->is_home() ) { $query->set( 'posts_per_page' , '1' ); } if ( $query->is_post_type_archive( 'hoge' ) ) { $query->set( 'order' , 'ASC' ); } } add_action( 'pre_get_posts', 'custom_main_query' );