本文へスキップ
Build

Column

コラム

ignore_sticky_posts の役割とサブループへの書き方

この記事には広告リンクを含みます。紹介している商品・サービスの一部はアフィリエイトプログラムを利用しています。 商品・サービスの選定はご自身の判断でお願いいたします。

ignore_sticky_posts の役割とサブループへの書き方 のアイキャッチ

サブループを書いたとき、orderby => 'date' で新着順にしているはずなのに、先頭固定の投稿が常に1番目に表示される——。
設定を何度見直しても直らず、自分も最初は orderby の設定ミスを疑いました。
WP_Query のサブループには ignore_sticky_posts => 1 が必須です。
WordPress のデフォルト動作として、メインループ以外のサブループにも先頭固定投稿を先頭に差し込む処理が走ります。
この引数はコードの「お作法」ではなく、サブループとページネーション計算を守るための防御的な必須引数です。
なぜそうなるのか、実案件での経験も交えて解説します。

ignore_sticky_posts を指定するとWordPressのループ動作がどう変わるか

WordPressのサブループ実装と先頭固定投稿の検証を行う作業環境

先頭固定に設定した投稿を WP_Query が処理するとき、ignore_sticky_posts の指定がなければ orderby の並び順を無視して先頭に差し込みます。
この動作はメインクエリだけでなく、サイドバー・新着一覧・関連記事など new WP_Query() で組むすべてのサブループでも発生します。
先頭固定はメインの記事一覧に「お知らせ」や「代表的な事例」を常に上部表示させる機能ですが、サブループにも同じ動作が及ぶ点は見落とされやすいです。

ignore_sticky_posts => 1 を追加するとこの挿入処理がスキップされます。
言い換えると、このオプションなしの WP_Query はすべて sticky 処理が「有効」な状態。
orderbymeta_query など引数で指定した条件のみでクエリが実行され、sticky かどうかは考慮されません。

$args = [
    'post_type'           => 'post',
    'posts_per_page'      => 5,
    'orderby'             => 'date',
    'order'               => 'DESC',
    'ignore_sticky_posts' => 1,
];
$query = new WP_Query( $args );

過去のWordPressリニューアル案件で、サイドバーに新着投稿リストのサブループを追加した際に同じ問題が起きました。
先頭固定に設定した告知投稿が新着リストに常に割り込み続け、orderby => 'date' を確認しても改善しませんでした。
ignore_sticky_posts => 1 を引数に追加したことで即座に解消しました。
仕組みを知らなければ、orderby の設定ミスと誤認して時間を溶かしやすいポイントです。

先頭固定投稿をあえて取得・表示したい場合は 【WordPress】「この投稿を先頭に固定表示」を出力する方法 も参照してください。

ignore_sticky_posts を省くとページネーションがずれる仕組み

先頭固定混入と同時に発生しやすいのが、ページネーションのずれです。
WordPress は sticky 投稿を posts_per_page の設定数とは別に1件追加挿入する仕様になっています。
posts_per_page => 10 のループで sticky 投稿が1件あると、実際の取得件数は11件になります。

ページ総数は posts_per_pagefound_posts をもとに計算されるため、ここで計算がずれます。
1ページあたり実際には11件取得されるため、ページ2以降に同じ投稿が重複表示されたり、最終ページの件数がおかしくなったりします。

自分の保守案件でページ2に同じ投稿が重複表示されるという問い合わせを受けました。
管理画面の設定ミスかと思いましたが、sticky 投稿の二重カウントが原因で、ignore_sticky_posts => 1 の追加で解消しました。

症状が出たときは次の順で確認してください:

  1. 管理画面 → 投稿一覧で「先頭固定」に設定された投稿があるか確認する
  2. $query->post_countposts_per_page の設定値より多いか確認する
  3. WP_Query の引数に ignore_sticky_posts => 1 を追加。これで先頭固定の割り込みが止まれば原因確定

ignore_sticky_posts と post__not_in の動作の違いと使い分け

先頭固定投稿の扱いには2通りの方法があり、目的に応じて使い分けます。

方法

動作

使う場面

ignore_sticky_posts => 1

先頭挿入をスキップ。sticky 投稿は通常順で取得される

新着一覧・サイドバー・関連記事など大半のサブループ

post__not_in => get_option('sticky_posts')

sticky 投稿をクエリ結果から完全除外する

sticky 投稿を一切表示させたくないケース

ignore_sticky_posts => 1 は先頭への挿入を止めるだけで、sticky 投稿が日付順で上位に来る場合はそのまま取得されます。
完全に非表示にしたい場合は post__not_in => get_option('sticky_posts') を使います。
サイドバーの「最近の投稿」など、sticky 投稿を一切出したくないケースで有効です。

pre_get_posts フックでサイト全体に適用するときは、is_main_query() チェックが必要です。
チェックを省くとアーカイブページのメインクエリにも影響し、本来表示されるべき先頭固定投稿が消えます。

add_action( 'pre_get_posts', function( $query ) {
    if ( ! is_admin() && ! $query->is_main_query() ) {
        $query->set( 'ignore_sticky_posts', 1 );
    }
} );

カスタム投稿タイプや taxonomy ループには先頭固定投稿の概念がないため、ignore_sticky_posts を書いても実質無効です。
ただし引数に書いておくとコードの意図が伝わり、後からメンテナンスする人が混乱しません。

コーディング代行・実装判断で詰まったら Build に振ってください。