複数のループがある時はWP_Queryを使う

投稿記事を普通にループで取得したい時は下記のように書きますね。

<?php if ( have_posts() ) : ?>
    <?php while ( have_posts() ) : the_post(); ?>
        <div class="col-md-4">
            <?php get_template_part('template-parts/loop', 'news'); ?>
        </div>
    <?php endwhile; ?>
<?php endif; ?>

投稿した記事をループさせるのはWPに用意されているメインクエリを使用しますが、 下記のページのように投稿ページのサイドバーやページ下部に違うループを表示させたい場合があります。 f:id:acots:20220226144231p:plain

メインクエリだけでこれを実現しようとすると、下記のようになります。 f:id:acots:20220226141810p:plain

上記のような時、サイドバー用のクエリを独自に定義する必要があります。

1.WP_Queryを使ってクエリを定義する

例えば、sidebar-latests.phpにサイドバーの新着リストを作りたい場合

<?php
$args = array(
    'post_type' => 'post', //投稿記事だけを指定
    'posts_per_page' => 5, //最新記事を5件表示
);
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) :
?>
<aside class="archive">
    <h2 class="archive_title">最新記事</h2>
    <ul class="archive_list">
        <?php while (  $the_query->have_posts() ) :  $the_query->the_post(); ?>
            <li>
                <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
            </li>
        <?php endwhile; ?>
        <?php wp_reset_postdata(); ?>
    </ul>
</aside>
<?php endif; ?>

1.どのようなクエリを作るか配列で指定する

$args = array(
    'post_type' => 'post', //投稿記事だけを指定
    'posts_per_page' => 5, //最新記事を5件表示
);

2.クエリを作成

new WP_Query(配列)を$the_queryという変数に格納する

$the_query = new WP_Query( $args );

3.have_posts()とthe_post()の前に$the_query->を付け加える

『if ( $the_query->have_posts() ) :』は『もしも、$the_queryの記事があるならば』という意味になります。

if ( $the_query->have_posts() ) :
?>
<aside class="archive">
    <h2 class="archive_title">最新記事</h2>
    <ul class="archive_list">
        <?php while (  $the_query->have_posts() ) :  $the_query->the_post(); ?>
            <li>
                <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
            </li>
        <?php endwhile; ?>
        <?php wp_reset_postdata(); ?>
    </ul>
</aside>
<?php endif; ?>

4.WP_reset_postdata()で投稿データをリセットする

new WP_Query()を使うとWPのループで使用されている投稿データが変わってしまうため、リセットして元に戻す必要があります。 new WP_Queryを使って独自のループを作成した時は、wp_reset_postdata()でリセットします。

        <?php endwhile; ?>
        <?php wp_reset_postdata(); ?>

f:id:acots:20220226144054p:plain

特定のページだけ表示数を変えたいなど、pre_get_postsアクションフックでメインクエリを変更する

例えば、WPのメインクエリの表示件数はダッシュボードの表示設定で設定されています。 f:id:acots:20220226144926p:plain

例えば、TOPページだけ表示件数を変更したい場合には、pre_get_postsアクションフックを使用します。

WPがクエリを取得する前に実行されるpre_get_postsアクションフックをfunctions.phpに記述する

/**
 * メインクエリの内容を変更する
 */
add_action( 'pre_get_posts', 'my_pre_get_posts' );
function my_pre_get_posts($query) {
    // 管理画面、メインクエリ以外には設定しない
    if ( is_admin() || ! $query->is_main_query() ){
        return;
    }

    //トップページの場合
    if ( $query->is_home() ) {
        $query->set( 'posts_per_page', 3 );
        return;
    }
}
1.クエリ取得前に関数を実行

pre_get_postsアクションフックを使い、my_pre_get_postsというユーザ定義の関数を実行

add_action( 'pre_get_posts', 'my_pre_get_posts' );
function my_pre_get_posts($query) {
}
2.実行する関数を定義するmy_pre_get_posts

pre_get_postsは全てのクエリの実行前が対象になるので、管理画面のクエリも対象です。 is_admin()で管理画面かをチェックし、管理画面の場合はreturnで関数を終了します。

   // 管理画面、メインクエリ以外には設定しない
    if ( is_admin() || ! $query->is_main_query() ){
        return;
    }

今回の例は、メインクエリのみを対象にしているので、is_main_query()関数を使ってチェックして、条件分岐を行います。

  • ! $query->is_main_query():メインクエリ以外の時
  • $query->is_home():トップページの時
  • $query->is_category():カテゴリーページの時
    // 管理画面、メインクエリ以外には設定しない
    if ( is_admin() || ! $query->is_main_query() ){
        return;
    }

    //トップページの場合
    if ( $query->is_home() ) {
        $query->set( 'posts_per_page', 3 );
        return;
    }

WP_Queryについて

WPのメインクエリも独自で作成したクエリもWP_Queryを使用しています。WP_QueryはWPがクエリをつくるときに使用されるクラスです。

WP_Queryにはさま様なパラメータがあり、setを使うことで値をセットできます。

$query->set( 'パラメーター', 値 );  //例:$query->set( 'posts_per_page', 3 );

例:TOPページにお知らせカテゴリーに属する記事を表示する

  • category_name:カテゴリーを指定するパラメーター
  • news:指定するカテゴリーのスラッグ名
    if ( $query->is_home() ) {
        $query->set( 'category_name', 'news' );
        return;
    }

例:カテゴリーページではページングを使わず、全て投稿記事を表示する

全ての投稿を表示する場合は、nopagingというパラメータを使用します。

    if ( $query->is_category() ) {
        $query->set( 'nopaging', true );
        return;
    }