paged と offset を同時に使ってクエリを投げると意図したように動かないのを回避

WP_Query に対してページングとオフセットを一緒に利用できない

絞り込みの検索などいろいろな条件で投稿等を取得したい場合に便利な WP_Query。なのですが、  paged と offset のパラメータを一緒に使うことはできません。

  • paged: 何ページ目なのかを指定する。1ページ毎に10個の投稿を取得する設定で、3ページ目なら、21記事目から30記事目までが取得される
  • offset: 最初の4件はいらない、等の場合に使える。いくつか記事を飛ばしたいときに指定する。4を指定すると5記事目から14記事目が取得される

で、Making Custom Queries using Offset and Pagination によれば、このふたつのパラメータは同時に使うことができません。ためしてみるとちゃんと、意図したように動かないのを確認できます。理由は、そもそもページネーションの処理にoffsetを使っているのであって、offset を明示して指定すると、WPがページネーションで使おうとしてた値を、上書きしてしまう、ということだそうです。

上記のページにはそのpre_get_posts を使った回避方法が紹介されています。ただ、今回私がやりたかったのは、ajaxでinfinite scrollっぽい動きをさせるということだったので、WP_Queryに配列を渡すお馴染みのやり方だとこうなるよというのをご紹介したいと思います。

<?php
add_action( 'template_redirect', 'uis_do_api' );

function uis_do_api() {

  // ページ番号取得
  $paged_id = (int)get_query_var( 'infinite' );
  
  if ( ! empty( $paged_id ) ) {
    $response = array();
    $response['html'] = '';
  
    // カテゴリアーカイブで使う場合
    $category = get_query_var( 'cat' );
  
    // posts per page 
    $ppp        = 12; // 1ページに表示するのは12個
    $offset_cnt = 6; // 最初のページで6つ別の形で表示してるので引き算したい
    $offset     = $offset_cnt + ( ( $paged_id -1 ) * $ppp ); // オフセット値 + (現在の表示ページ数−1)* 1ページ毎に表示させる数
  
    $post_args = array( 
      'paged'          => $paged_id,
      'cat'            => $category,
      'posts_per_page' => 12,
      'offset'         => $offset,
    );
  
    $post = new WP_Query( $post_args );
    if ( $post->have_posts() ) {
      $response['html'] .= '<ul>';
      while ( $post->have_posts() ) {
        $post->the_post();
        
        // ループ回す
        ob_start();
        get_template_part( 'template-parts/archive/loop', 'infinite' );
        $response['html'] .= ob_get_contents();
        ob_end_clean();
      }
      $response['html'] .= '</ul>';
  
      // 無限スクロールっぽくするので
      $response['html'] .= '<div class="iscroll-archive-target" data-next-page="' . ++$paged_id . '"></div>';
  
      wp_send_json( $response );
    }
    die();
  }

}

上記でのポイントは、オフセットの値を自分で計算しているところですね。

  • オフセットしたいのは6個
  • 各ページで表示させたいのは12個

今回の場合、最初のページでは18個表示されるのだけど、無限スクロールで追加したいのは12個だけだ、ということです。

下記は、ページングの際に、こうした対処を行った場合に、起きる問題を防ぐためのものです。つまり、

  • 最後から2番めのページにいる際に、最後のページヘのリンクが出力されるが、
  • 実際にはそんなページはなく、オフセット値の分がオフセットされていなくてWPが誤解してしまってる

という状態になってしまうのを防ぐためのものです。

add_filter('found_posts', 'myprefix_adjust_offset_pagination', 1, 2 );
function myprefix_adjust_offset_pagination($found_posts, $query) {

    $offset = 6;

    if ( $query->is_category ) {
        return $found_posts - $offset;
    }
    return $found_posts;
}

↓ プラグインを作る方々への本、書きました。 ↓

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です