先頭固定投稿による表示件数のズレを防ぐ方法

Cocoonカスタマイズ集
この記事は約8分で読めます。
記事内に広告が含まれています。

はじめに

「先頭固定表示」を有効にすると、その投稿は通常の並び順から独立して先頭に表示されます。
この挙動は、以下のような問題を引き起こすことがあり、これらの問題を対策します。

  • カテゴリーなどの一覧ページで標準では機能しない・クラスも付かない
    先頭固定表示はトップページ(ホームページ)でのみ適用され、カテゴリーやタグなどのアーカイブページでは固定投稿が先頭に反映されません。
    また、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カラム)✕✕

さいごに

今回紹介した方法を使えば、先頭固定表示によるページあたりの表示件数のズレや、同一投稿の重複表示といった問題を回避することができます。
デザインの一貫性やユーザー体験が重要な場合には有効な手法です。

タイトルとURLをコピーしました