はじめに
「先頭固定表示」を有効にすると、その投稿は通常の並び順から独立して先頭に表示されます。
この挙動は、以下のような問題を引き起こすことがあり、これらの問題を対策します。
- カテゴリーなどの一覧ページで標準では機能しない・クラスも付かない
先頭固定表示はトップページ(ホームページ)でのみ適用され、カテゴリーやタグなどのアーカイブページでは固定投稿が先頭に反映されません。
また、HTMLのクラスにもstickyが付与されません。
- 表示件数が意図せず増える
例えば「1ページに10件の記事を表示する」設定の場合、先頭固定表示とした投稿が1件あると、先頭固定表示1件+通常投稿10件=合計11件が表示されてしまいます。
この結果、ページあたりの表示数が変動し、デザインや読みやすさに影響が出る可能性があります。
- 同じ投稿が重複して表示される
先頭固定投稿は先頭に複写されるように表示され、本来の投稿日順の位置にも再表示されてしまいます。
これにより、同じ投稿が1ページ内で2回表示されるという重複表示が発生します。
この記事では、この方法について説明します。
完成イメージ

実装手順
以下の手順で実装します。
- ラベルCocoon設定
表1に示す項目を設定をします。
Cocoon設定 設定 大項目 項目 設定値 インデックス リスト設定 並び順 投稿日(降順) - ラベルPHPを追加
以下のコードをfunctions.phpに追加します。
// 投稿クエリの取得条件を変更 add_action('pre_get_posts', function ($query) { if (is_admin() || !$query->is_main_query()) { return; } $args = []; // ページ種別に応じて取得条件を設定 switch (true) { case is_category(): $args['category__in'] = [get_queried_object_id()]; break; case is_tag(): $args['tag__in'] = [get_queried_object_id()]; break; case is_date(): if (get_query_var('year')) { $args['year'] = get_query_var('year'); } if (get_query_var('monthnum')) { $args['monthnum'] = get_query_var('monthnum'); } if (get_query_var('day')) { $args['day'] = get_query_var('day'); } break; default: break; } // 並び替え済みの投稿IDを取得 $post_ids = my_get_sticky_posts($args); if ($post_ids) { $query->set('post__in', $post_ids); $query->set('orderby', 'post__in'); $query->set('ignore_sticky_posts', 1); } }); /** * 先頭固定投稿を優先的に並べ、指定された条件に基づいて投稿IDの配列を取得 * * 先頭固定投稿がある場合、それらを最初に並べた投稿IDの配列を返す。 * 固定投稿以外は、通常の投稿IDをその後に並べる。 * * @param array $args WP_Queryに渡す引数の配列 * @return array 投稿IDの配列(先頭固定投稿が先頭に並ぶ) */ if (!function_exists('my_get_sticky_posts')): function my_get_sticky_posts($args) { // 先頭固定投稿のIDを取得 $sticky_ids = array_map('intval', (array) get_option('sticky_posts', [])); $valid_sticky_ids = []; // 先頭固定投稿の取得条件を設定 $sticky_query_args = array_merge($args, [ 'fields' => 'ids', 'ignore_sticky_posts' => 1, 'post__in' => $sticky_ids, 'orderby' => 'post__in', 'posts_per_page' => -1, ]); // 通常投稿の取得条件を設定 $normal_query_args = array_merge($args, [ 'fields' => 'ids', 'ignore_sticky_posts' => 1, 'posts_per_page' => -1, ]); // 先頭固定投稿を取得 if (!empty($sticky_ids)) { $sticky_query = new WP_Query($sticky_query_args); $valid_sticky_ids = $sticky_query->posts; // 先頭固定投稿を通常投稿から除外 $normal_query_args['post__not_in'] = $valid_sticky_ids; } // 通常投稿のIDを取得 $normal_query = new WP_Query($normal_query_args); $normal_ids = $normal_query->posts; // 先頭固定投稿と通常投稿を結合 return array_merge($valid_sticky_ids, $normal_ids); } endif; // 投稿にクラスを追加 add_filter('post_class', function ($classes, $class, $post_id) { if (!in_array('sticky', $classes, true) && is_sticky($post_id)) { $classes[] = 'sticky'; } return $classes; }, 10, 3); // タブ一覧のクリエリを変更 add_filter('list_category_tab_args', function ($args, $cat_id) { // 並び替え済みの投稿IDを取得 $ordered_post_ids = my_get_sticky_posts([ 'category__in' => [$cat_id], ]); // クエリの並び順を設定 $args['ignore_sticky_posts'] = 1; $args['orderby'] = 'post__in'; // 投稿IDをクエリに設定 if (!empty($ordered_post_ids)) { $args['post__in'] = $ordered_post_ids; } return $args; }, 10, 2); // カテゴリーごとのクリエリを変更 add_filter('get_category_index_list_entry_card_args', function ($args, $categories) { // 並び替え済みの投稿IDを取得 $ordered_post_ids = my_get_sticky_posts([ 'cat' => $categories, ]); // 投稿IDをクエリに設定 if (!empty($ordered_post_ids)) { $args['post__in'] = $ordered_post_ids; $args['orderby'] = 'post__in'; } return $args; }, 10, 2); // カテゴリーごと(2、3カラム)のクリエリを変更 add_filter('list_category_column_atts', function ($atts, $cat_id) { // 並び替え済みの投稿IDを取得 $ordered_post_ids = my_get_sticky_posts([ 'category__in' => [$cat_id], ]); // 表示する投稿IDを設定 if (!empty($ordered_post_ids)) { $atts['ordered_posts'] = array_slice($ordered_post_ids, 0, $atts['entry_count']); } return $atts; }, 10, 2);
補足
以下の記事で説明している適用範囲をさらに拡張し、全ての条件に対応できるように改善しています。
| フロントページタイプ | 新着記事 | カテゴリー |
|---|---|---|
| 一覧 | ● | – |
| タブ一覧 | ● | ✕ |
| カテゴリーごと | ✕ | ✕ |
| カテゴリーごと(2カラム) | ✕ | ✕ |
| カテゴリーごと(3カラム) | ✕ | ✕ |
さいごに
今回紹介した方法を使えば、先頭固定表示によるページあたりの表示件数のズレや、同一投稿の重複表示といった問題を回避することができます。
デザインの一貫性やユーザー体験が重要な場合には有効な手法です。

