WorePressループによる記事出力(メインクエリとサブクエリ)

WordPressループはWordPressを使いこなすために重要な知識の1つです。今回はWorePressループによる記事の出力についてまとめました。query_postsやWP_Queryを使うと色々な条件のもと記事を取得できるようになります。

WordPressループの基本的な利用

WordPressではURLによって、そのURLに対応する記事をデータベースから取得してます。このURLによって決定されるクエリのことを メインクエリ と呼びます。

WordPressループは、メインクエリで取得した記事の数だけ繰り返されます。

固定ページや投稿ページのURLの場合、1件だけ記事が取得されます。なので、WordPressループの回数も1回だけです。カテゴリーページであればそのカテゴリーに対応する記事の数だけ、WordPressループが繰り返されます。

では、WordPressループの記述を見てみましょう。

if (have_posts()) :
    while (have_posts()) :  // 処理すべき記事があるか判定(WordPressの内部的カウンタをみている)
        the_post();         // 処理すべき記事をセット(同時にWordPressの内部的カウンタを次に進める)
        the_title();        // 記事のタイトルを出力
        the_content();      // 記事の内容を出力
    endwhile;
endif;

the_post() によって記事がセットされて、 the_title() などの記事に紐づく関数を利用できます。また、the_post() を実行することで、 $post という投稿情報を保持する変数も自動更新されます。

サブクエリの発行

トップページでは、
「上部に最新投稿記事を10件だけ表示」
「その下に○○カテゴリーの最新記事を5件だけ表示」
など、複数の条件で記事を取得して表示したいときがあります。

この場合は、WP_Query を利用することでメインクエリとは別に サブクエリ を生成し記事を取得することができます。

次の例では、サブクエリで最新投稿記事を10件取得しています。

// サブクエリをセット
$args = array(
    'post_type' => 'post',  // 投稿タイプ
                            // ・投稿        :post  
                            // ・固定ページ  :page 
                            // ・カスタム投稿:カスタム投稿タイプ名
    'posts_per_page' => 10, // 表示件数。 -1ならすべての投稿を取得
    'orderby' => 'date',    // ソート
                            // ・date  :日付
                            // ・rand  :ランダム
    'order' => 'DESC'));    // 降順(日付の場合、日付が新しい順)
}
$loop = new WP_Query($args);
 
// ループ
if (have_posts()) :
    while (have_posts()) :  
        the_post();
        /* 処理 */
    endwhile;
endif;
 
// リセット(元の投稿データの復元)
wp_reset_postdata();

WP_Queryのパラメータ

WP_Queryのパラメータについては、関数リファレンス/WP Queryにて詳しい情報が書かれています。

下記にて、関数リファレンス/WP Queryに記述されている内容の一部を抜粋してます。詳しい情報は、リンク先にて確認することをお勧めします。

投稿者に関連付けられた投稿を表示

// ユーザー ID を用いて、ある投稿者の投稿を表示する場合: 
$query = new WP_Query( 'author=123' );
 
// 'user_nicename' を用いて、ある投稿者の投稿を表示する場合: 
$query = new WP_Query( 'author_name=rami' );
 
// 特定の複数の投稿者の投稿を表示する場合: 
$query = new WP_Query( 'author=2,6,17,38' );

カテゴリーに関連付けられた投稿を表示

// カテゴリーIDを使用して、そのカテゴリー(さらにそのカテゴリーの子カテゴリー)に属する記事を表示: 
$query = new WP_Query( 'cat=4' );
 
// カテゴリースラッグを使用して、そのカテゴリー(さらにそのカテゴリーの子カテゴリー)に属する記事を表示: 
$query = new WP_Query( 'category_name=staff' );
 
// カテゴリー ID を使って、そのカテゴリー (子カテゴリーではない)に属する記事を表示: 
$query = new WP_Query( 'category__in=4' );
 
// カテゴリー ID を使用して、それらのカテゴリーに属する記事を表示: 
$query = new WP_Query( 'cat=2,6,17,38' );
 
// カテゴリースラッグを使用して、それらのカテゴリーに属する記事を表示: 
$query = new WP_Query( 'category_name=staff,news' );

タグに関連付けられた投稿を表示

// タグのスラッグを使って、このタグを持つ記事を表示: 
$query = new WP_Query( 'tag=cooking' );
 
// タグのIDを使って、このタグを持つ記事を表示: 
$query = new WP_Query( 'tag_id=13' );
 
// これらのいずれかのタグを持つ記事を表示: 
$query = new WP_Query( 'tag=bread,baking' );
 
// これらのすべてのタグを持つ記事を表示: 
$query = new WP_Query( 'tag=bread+baking+recipe' );
 
// タグID 37 と 47 いずれかの記事を表示: 
$query = new WP_Query( array( 'tag__in' => array( 37, 47 ) ) );

タクソノミーに関連付けられた投稿を表示

// カスタム分類 people の bob に関連付けられた投稿(post)を表示します : 
$args = array(
    'post_type' => 'post',
    'tax_query' => array(
        array(
            'taxonomy' => 'people',
            'field'    => 'slug',
            'terms'    => 'bob',
        ),
    ),
);
$query = new WP_Query( $args );
 
// いくつかのカスタム分類から投稿を表示します: 
$args = array(
    'post_type' => 'post',
    'tax_query' => array(
        'relation' => 'AND',
        array(
            'taxonomy' => 'movie_genre',
            'field'    => 'slug',
            'terms'    => array( 'action', 'comedy' ),
        ),
        array(
            'taxonomy' => 'actor',
            'field'    => 'term_id',
            'terms'    => array( 103, 115, 206 ),
            'operator' => 'NOT IN',
        ),
    ),
);
$query = new WP_Query( $args );
 
// カテゴリー quotes に所属するか投稿フォーマットが quote の投稿(post)を表示します: 
$args = array(
    'post_type' => 'post',
    'tax_query' => array(
        'relation' => 'OR',
        array(
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => array( 'quotes' ),
        ),
        array(
            'taxonomy' => 'post_format',
            'field'    => 'slug',
            'terms'    => array( 'post-format-quote' ),
        ),
    ),
);
$query = new WP_Query( $args );

キーワード検索によって投稿を表示

// 「キーワード」という検索語にマッチする投稿を表示します: 
$query = new WP_Query( array( 's' => 'キーワード' ) );

投稿および固定ページに基づいてコンテンツを表示

// 投稿のIDを指定して表示する: 
$query = new WP_Query( 'p=7' );
 
// 固定ページのIDを指定して表示する: 
$query = new WP_Query( 'page_id=7' );
 
// 投稿のスラッグを指定して表示する: 
$query = new WP_Query( 'name=about-my-life' );
 
// 固定ページのスラッグを指定して表示する: 
$query = new WP_Query( 'pagename=contact' );
 
// 親ページの ID を使って子ページを表示する: 
$query = new WP_Query( array( 'post_parent' => 93 ) );
 
// 子ページは除外し、トップレベルのページのみ表示する: 
$query = new WP_Query( array( 'post_parent' => 0 ) );
 
// 配列中の ID で示されたページを親に持つ投稿を表示する: 
$query = new WP_Query( array( 'post_parent__in' => array( 2, 5, 12, 14, 20 ) ) );
 
// 指定された投稿のみ表示: 
$query = new WP_Query( array( 'post__in' => array( 2, 5, 12, 14, 20 ) ) );
 
// 指定された以外の全ての投稿を表示: 
$query = new WP_Query( array( 'post__not_in' => array( 2, 5, 12, 14, 20 ) ) );

パスワード保護の有無に応じて表示

// パスワード保護された投稿のみ表示する: 
$query = new WP_Query( array( 'has_password' => true ) );
 
// パスワード保護されていない投稿のみ表示する: 
$query = new WP_Query( array( 'has_password' => false ) );
 
// パスワード保護の有無に関わらず投稿を表示する: 
$query = new WP_Query( array( 'has_password' => null ) );

投稿タイプに関連付けられた投稿を表示

// 固定ページのみ表示: 
$query = new WP_Query( array( 'post_type' => 'page' ) );
 
// 'any'(すべての)投稿タイプを表示(リビジョンと 'exclude_from_search' が TRUE になっている投稿タイプを除くすべての投稿タイプが含まれます): 
$query = new WP_Query( array( 'post_type' => 'any' ) );
 
// カスタムポストタイプを含む複数のポストタイプを表示: 
$args = array(
    'post_type' => array( 'post', 'page', 'movie', 'book' )
);
$query = new WP_Query( $args );

投稿ステータスに関連付けられた投稿を表示

//下書きのみ表示: 
$query = new WP_Query( array( 'post_status' => 'draft' ) );
 
//すべての添付ファイルを表示: 
$args = array(
    'post_status' => 'any',
    'post_type'   => 'attachment'
);
$query = new WP_Query( $args );

ページ送りパラメータ

// ページあたり3件の投稿を表示する: 
$query = new WP_Query( array( 'posts_per_page' => 3 ) );
 
// 1つのページに全ての投稿を表示する: 
$query = new WP_Query( array( 'posts_per_page' => -1 ) );
 
// ページネーションを無効にして全ての投稿を表示する: 
$query = new WP_Query( array( 'nopaging' => true ) );
 
// 現在のページから投稿を表示する: 
$query = new WP_Query( array( 'paged' => get_query_var( 'paged' ) ) );

投稿の並びを指定

// 投稿をその 'title' で降順に並べ替えて表示します: 
$args = array(
    'orderby' => 'title',
    'order'   => 'DESC',
);
$query = new WP_Query( $args );
 
// 投稿を 'menu_order' の降順でソートして表示します。同じ値なら投稿の 'title' の順にします: 
$args = array(
    'orderby' => 'menu_order title',
    'order'   => 'DESC',
);
$query = new WP_Query( $args );
 
//ランダムに投稿を1件表示する: 
$args = array(
    'orderby'        => 'rand',
    'posts_per_page' => '1',
 
);
$query = new WP_Query( $args );
 
// 投稿をコメント数の順に表示する: 
$args = array(
    'orderby' => 'comment_count'
);
$query = new WP_Query( $args );
 
// 'Product' 投稿タイプをカスタムフィールド 'Price' で並び替えて表示: 
$args = array(
    'post_type' => 'product',
    'orderby'   => 'meta_value_num',
    'meta_key'  => 'price',
);
$query = new WP_Query( $args );
 
// 別々の表示順(昇順/降順)の 'title' と 'menu_order' で並べ替えた固定ページを表示(バージョン 4.0 から利用可能): 
$args = array(
    'orderby' => array( 'title' => 'DESC', 'menu_order' => 'ASC' )
);
$query = new WP_Query( $args );
 
// カスタムフィールドとカスタム投稿タイプを 'orderby' に指定 
// 投稿タイプが 'my_custom_post_type' で 'age' 順、そして 'age' が3か4のものだけを表示(meta_query を使用)。 
$args = array(
    'post_type'  => 'my_custom_post_type',
    'meta_key'   => 'age',
    'orderby'    => 'meta_value_num',
    'order'      => 'ASC',
    'meta_query' => array(
        array(
            'key'     => 'age',
            'value'   => array( 3, 4 ),
            'compare' => 'IN',
        ),
    ),
);
$query = new WP_Query( $args );

期間に関連付けられた投稿を表示

// 2012年12月12日の投稿を返す: 
$query = new WP_Query( 'year=2012&monthnum=12&day=12' );
 
// または: 
$args = array(
    'date_query' => array(
        array(
            'year'  => 2012,
            'month' => 12,
            'day'   => 12,
        ),
    ),
);
$query = new WP_Query( $args );
 
// 今日の投稿を返す: 
$today = getdate();
$query = new WP_Query( 'year=' . $today['year'] . '&monthnum=' . $today['mon'] . '&day=' . $today['mday'] );
 
// または: 
$today = getdate();
$args = array(
    'date_query' => array(
        array(
            'year'  => $today['year'],
            'month' => $today['mon'],
            'day'   => $today['mday'],
        ),
    ),
);
$query = new WP_Query( $args );
 
// 今週の投稿を返す: 
$week = date( 'W' );
$year = date( 'Y' );
$query = new WP_Query( 'year=' . $year . '&w=' . $week );
 
// または: 
$args = array(
    'date_query' => array(
        array(
            'year' => date( 'Y' ),
            'week' => date( 'W' ),
        ),
    ),
);
$query = new WP_Query( $args );
 
// 平日の午前9時から午後5時までの投稿を返す 
$args = array(
    'date_query' => array(
        array(
            'hour'      => 9,
            'compare'   => '>=',
        ),
        array(
            'hour'      => 17,
            'compare'   => '<=',
        ),
        array(
            'dayofweek' => array( 2, 6 ),
            'compare'   => 'BETWEEN',
        ),
    ),
    'posts_per_page' => -1,
);
$query = new WP_Query( $args );
 
// 1月1日から2月28日までの投稿を返す 
$args = array(
    'date_query' => array(
        array(
            'after'     => 'January 1st, 2013',
            'before'    => array(
                'year'  => 2013,
                'month' => 2,
                'day'   => 28,
            ),
            'inclusive' => true,
        ),
    ),
    'posts_per_page' => -1,
);
$query = new WP_Query( $args );
 
// 1年より前の投稿で1ヶ月以内に変更されたものを返す 
$args = array(
    'date_query' => array(
        array(
            'column' => 'post_date_gmt',
            'before' => '1 year ago',
        ),
        array(
            'column' => 'post_modified_gmt',
            'after'  => '1 month ago',
        ),
    ),
    'posts_per_page' => -1,
);
$query = new WP_Query( $args );

カスタムフィールドに関連付けられた投稿を表示

// カスタムフィールドの値に関係なく、カスタムフィールドのキーが 'color' の投稿を表示します: 
$query = new WP_Query( array( 'meta_key' => 'color' ) );
 
// カスタムフィールドのキーに関係なく、カスタムフィールドの値が 'blue' の投稿を表示します: 
$query = new WP_Query( array( 'meta_value' => 'blue' ) );
 
// カスタムフィールドのキーに関係なく、カスタムフィールドの値が 'blue' の固定ページを表示します: 
$args = array(
    'meta_value' => 'blue',
    'post_type'  => 'page'
);
$query = new WP_Query( $args );
 
// カスタムフィールドのキーが 'color'、値が 'blue' の投稿を表示します: 
$args = array(
    'meta_key'   => 'color',
    'meta_value' => 'blue'
);
$query = new WP_Query( $args );
 
// カスタムフィールドのキーが 'color'、値が 'blue' ではない投稿を表示します: 
$args = array(
    'meta_key'     => 'color',
    'meta_value'   => 'blue',
    'meta_compare' => '!='
);
$query = new WP_Query( $args );
 
// イベントの投稿('event' カスタム投稿タイプ)を表示します。開催日のカスタムフィールドのキーが 'event_date'、値が今日以降とします。 
$args = array(
    'post_type'    => 'event',
    'meta_key'     => 'event_date',
    'meta_value'   => date( "Ymd" ), // 'event_date' の保存形式に合わせる
    'meta_compare' => '>',
);
$query = new WP_Query( $args );
 
// 製品('product' カスタム投稿タイプ)のうち、値段('price' カスタムフィールド)が 22 以下 であるものを表示します。
// 値を指定するのに 'meta_value' パラメータを使うと 99 が 100 より大きいと判定されます(数値ではなく文字列として保存されているため)。 
$args = array(
    'meta_key'         => 'price',
    'meta_value_num'   => '22',
    'meta_compare'     => '<=',
    'post_type'        => 'product'
);
$query = new WP_Query( $args );
 
// カスタムフィールドのキーに関係なく、値がゼロ (0) のカスタムフィールドを持つ投稿を表示します: 
$args = array(
    'meta_value' => '_wp_zero_value'
);
$query = new WP_Query( $args );
 
 
// 1つのカスタムフィールドからの記事を表示します: 
$args = array(
    'post_type' => 'product',
    'meta_query' => array(
        array(
            'key' => 'color',
            'value' => 'blue',
            'compare' => 'NOT LIKE'
        )
    )
 );
$query = new WP_Query( $args );
 
// 製品(カスタム投稿タイプ 'product')について、
// 色(カスタムフィールドのキー 'color')が青('blue')ではなく('NOTE LIKE')、
// 値段(キー 'price'、タイプ 'numeric')が20と100の間にある('BETWEEN')ものを表示します。
// 'relation' を省略しているので 'AND' になることに注意してください: 
$args = array(
    'post_type'  => 'product',
    'meta_query' => array(
        array(
            'key'     => 'color',
            'value'   => 'blue',
            'compare' => 'NOT LIKE',
        ),
        array(
            'key' => 'price',
            'value'   => array( 20, 100 ),
            'type'    => 'numeric',
            'compare' => 'BETWEEN',
        ),
    ),
);
$query = new WP_Query( $args );
 
// 製品について、色が青ではないか、または値段が20と100の間にあるものを表示します。
// ひとつ前の例と違って 'relation' を指定しています: 
$args = array(
    'post_type'  => 'product',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key'     => 'color',
            'value'   => 'blue',
            'compare' => 'NOT LIKE',
        ),
        array(
            'key'     => 'price',
            'value'   => array( 20, 100 ),
            'type'    => 'numeric',
            'compare' => 'BETWEEN',
        ),
    ),
);
$query = new WP_Query( $args );

ユーザーが適切な権限を持つ場合に投稿を表示

// ユーザーが適切な権限を持つ場合に、公開済みと非公開の投稿を表示します: 
$args = array(
    'post_status' => array( 'publish', 'private' ),
    'perm'        => 'readable',
);
$query = new WP_Query( $args );

メインクエリの改変

プラグインでページ送りを実装していると、WP_Queryの利用時にページ送りが動作しなくなることがあります。

これはメインクエリの情報をもとにページ送りが実装されているためです。

この場合は、メインクエリを改変することでページ送りが実装されたまま、別条件による記事の取得が可能となります。

メインクエリを改変するには、query_posts() を利用します。

// メインクエリの改変
$args = array(
    'post_type' => 'post',
    'posts_per_page' => 10,
    'paged' => get_query_var('page'),  // ページ数
                                       // get_query_var('page')で現在のページ番号を取得
    'orderby' => 'date',
    'order' => 'DESC'));
}
query_posts( $args );
 
// ループ
if (have_posts()) :
    while (have_posts()) :  
        the_post();
        /* 処理 */
    endwhile;
endif;
 
/* ページ送りの処理 */
 
// リセット
wp_reset_query();
※注意
query_posts()は非推奨なようです。今のところページ送りを実装したいときだけ利用してますが、今後不具合がでるかもしれません。
わくわくBank.
ソフトウェア開発で必要とされる技術、用語、概念を整理しています。