WordPressを使うなら知っておきたい!WP_Queryの使い方

カテゴリー:バックエンド

珍しくWordPress系の記事でも書いてみようと思います。

普段Twitterではあまり公言していませんが、僕はWordPress系の開発をやっています。
公言していない理由は単純で、「WordPressはウェブ開発じゃない」みたいに絡んでくる人たちの対応が面倒だからです。

今回はWordPressのカスタマイズでもかなり使用頻度が高いWP Queryについて解説していこうと思います。

WP_Queryとは?

WP_Queryは、公式リファレンスではこのように説明されています。

WP_Query は wp-includes/class-wp-query.php に定義されているクラスで、WordPress ブログへの複雑な投稿やページのリクエストを取り扱います。 wp-blog-header.php (バージョン 2.0 では WP クラス) が $wp_query オブジェクトに現在のリクエストを定義する情報を与えることで、$wp_query はどのタイプのクエリを扱っているのか (カテゴリーアーカイブ、年月別アーカイブ、フィード、検索など) を確定し、要求された投稿を取り出します。
引用:WordPress Codex 日本語版 - OSDN

超簡単に説明すると、WPで定義されているさまざまな投稿(投稿ページ、固定ページ、カスタム投稿)を自由自在に取得できるクラスです。

メインループ(投稿一覧とかカテゴリー一覧とか)とは別にループを作成することが可能なだけではなく、メインループを汚染することがないので、表示する場所も自由に決めることができます。
メインループの中でさらにループを作って、投稿を表示するといった使い方も可能です。

オプションも非常に豊富なので、表示する投稿も自由自在にコントロールすることが可能です。

WP_Queryの基本形

WP_Queryの基本形は以下のような形になります。

<?php
    //$argsの引数にパラメータを指定
    $args = array(
        'post_type' => 'post', 
        'posts_per_page' => 5,
        'order' => 'DESC',
    ); 
    $query_instance = new WP_Query($args);
?>

<?php if ($query_instance->have_posts()): ?>
    <?php while ( $query_instance->have_posts()): $query_instance->the_post(); ?>
    /* ループ内の記述 */
    <?php endwhile ?>
<?php endif ?>
<?php wp_reset_postdata(); ?>

$argsではパラメータ、つまり取得する投稿を指定できます。
今回だったら、投稿タイプが投稿ページである投稿を5件降順で取得するという条件を指定しています。

$query_instance = new WP_Query($args);

最も重要なのはこの部分です。
この部分でWP_Query(引数には取得したい投稿の条件が入っている)のインスタンスを生成することで、$query_instanceには投稿タイプが投稿ページである投稿が5件、降順でセットされた状態のオブジェクトが代入されます。

取得したい投稿のオブジェクトが生成できれば後は簡単です。
$query_instanceに投稿が存在するかチェックして、表示できる投稿がなくなるまでループして表示するだけです。

<?php wp_reset_postdata(); ?>

wp_reset_postdata()では何をしているかというと、サブループのリセットを行なっています。

公式では以下のように説明されています。

この関数は、new WP_Query を使って二番目のクエリを実行した後に、メインクエリの $post グローバル変数を復元するために使用します。つまり $post がメインクエリの現在の投稿になります。
引用:WordPress Codex 日本語版 - OSDN

$postは現在の投稿データ(ループされた時点)が格納されているグローバル変数なので、WP_Queryで生成したサブループをリセットして元のメインループに戻す処理を行わないと、意図しない投稿情報を拾ってしまうから必要なのかという解釈を僕はしています。
→正直この考え方があっているかあまり自信がないので、よくわからない人はおまじない程度に思っておいて問題ないと思います。

WP_Queryで指定可能なパラメータ

WP_Queryで指定可能なパラメータはめちゃくちゃ多いです!
全部説明するのは無理なので、比較的よく使うものに限定して紹介しようかなと思います。

  • post_type(投稿の種類)
  • posts_per_page(投稿を何件取得するか)
  • order(昇順か降順かの指定)
  • orderby(取得した投稿の並べ方)

post_typeでは投稿の種類(投稿ページや固定ページ、カスタム投稿など)を指定することができます。

<?php
    // 投稿ページ
    $query_instance_post = new WP_Query('post_type' => 'post');
    // 固定ページ
    $query_instance_page = new WP_Query('post_type' => 'page');
    // カスタム投稿
    $query_instance_custom = new WP_Query('post_type' => 'movies');

posts_per_pageでは投稿を取得する件数を取得できるのですが、全件取得したい時だけ指定の方法がちょっと特殊で、全件取得したいときは-1を指定します。

<?php
    $query_instance = new WP_Query('posts_per_page' => -1);

orderのパラメータは昇順か降順のみです。

<?php
    // 降順
    $query_instance_desc = new WP_Query('order' => 'DESC');
    // 昇順
    $query_instance_asc = new WP_Query('order' => 'ASC');

orderbyは、降順や昇順以外での並び替えができます。
よく使うのは、ランダムで表示するときでしょうか。

<?php
    // ランダムで表示
    $query_instance = new WP_Query('orderby' => 'rand');

もっと詳しく知りたい人は公式を見てください。

WP_Queryのユースケース

具体的なユースケースとしては、以下のような例が考えられます。

  • 投稿一覧の上部に新着記事一覧を表示する
  • 新着記事を投稿一覧をスライダーで表示する
  • 関連記事を表示する

上記の中で使用頻度が高いのは、投稿一覧をスライダーで表示するとかでしょうか。
SwiperとかSlickとかを使えば、投稿一覧をスライダーで表示することは結構簡単にできるのかなとは思います。

関連記事はちょっと難しいですが、WP_Queryの仕組みが分かれば十分自作可能です。
コード化するとこんな感じでしょうか。

<?php
    function related_posts($post_id) {
        $categories = get_the_category($post_id);
        $category_id = array();
    
        foreach ($categories as $category) {
            array_push($category_id, $category->cat_ID);
        }
    
        $args = array(
            'post_type' => 'post', 
            'post__not_in' => array($post_id),
            'posts_per_page' => 3,
            'category__in' => $category_id,
            'orderby' => 'rand',
        );
    
        $query_instance = new WP_Query($args);
        ?>
            <div class="related-posts">
                <h2 class="related-heading">関連記事</h2>
                <?php if($query_instance->have_posts()): ?>
                    <?php while($query_instance->have_posts()): $query_instance->the_post(); ?>
                        <div class="related-post">
                            <div class="related-thumbnail">
                                <?php if(has_post_thumbnail()): ?>
                                    <?php the_post_thumbnail(array(100, 100)); ?>
                                <?php else: ?>
                                    <?php echo '<img class="no-image" src="'. get_template_directory_uri() .'/images/no-image.png">'; ?>
                                <?php endif ?>
                            </div>
                            <h3 class="related-title">
                                <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
                            </h3>
                        </div>
                    <?php endwhile ?>
                <?php endif ?>
                <?php wp_reset_postdata(); ?>
            </div>
        <?php
    }

get_the_category()で関連記事が属するカテゴリーを取得して、foreach($categories as $category)の部分で関連記事部分の投稿が所属するカテゴリーIDをarray_pushを使ってcategory_idという配列に代入しています。

post__not_inは指定した投稿idの投稿を取得し内容にするために設定しています。
この関数を実行するとどうなるか簡単にまとめると、表示されている投稿以外で自分と同じカテゴリーの投稿を3件ランダムで表示することができます。

カスタムフィールドのキーや値を含む投稿のみを絞り込んで表示するとかも、カスタムフィールドを使いまくってるサイトだと割と使ったりします。
カスタムフィールドのキーや値の絞り込みにはmeta_queryというオプションを使用するのですが、使用するにはSQLの知識(簡単なテーブル操作ができるレベル)が必要なので、ちょっと難しいかもしれないです。

下記のようにパラメータを指定すると、keyの名前がtokyo_areaであるカスタムフィールドの値に世田谷区が含まれている投稿を取得したりもできます。

<?php
    $args = array(
        'meta_query' => array(
            array(
                'key' => 'tokyo_area',
                'value' => '世田谷区',
                'compare' => 'LIKE'
            )
        )
    );


まとめ

WP_Queryとは?
WPで定義されている投稿情報を自由自在に取得して、表示することができるクラスのこと。

主にコーダーさんやウェブ制作者さんが対象になりますが、WP_Queryをある程度使えれば、他の人と一気に差をつけることができると思うので、頑張って使えるようになるといいことがあるかも知れません。

おまけ

個人的になのですが、WP_Queryとカスタムフィールドが使えるかがWord Pressをどの程度使えるのかを知る一つの目安なのかなと思ったりしています。

WP_Queryとカスタムフィールドはループや条件分岐が多少は書けないと使いこなすのが困難なので、「あいつのWP力はどれくらいかなー」っていうのが知りたいときは、「WP_Queryってめっちゃ便利だよね!?」って話を振ってどんな反応が返ってくるかどうかで、相手の力量を推し量ってみるのも面白いかもしれません。