blogスタッフブログ
HOME > スタッフブログ > CMS > WordPress >WordPressでページ送りを実装する(プラグイン未使用)

WordPressでページ送りを実装する(プラグイン未使用)

当社はPowerCMSやPowerCMS XでCMSを実装することが多いのですが、WordPressで実装することもあります。 今回はWordPressでお知らせやブログなどのアーカイブ(投稿一覧)を作成する際に必要となるページ送りの実装方法を紹介します。

メインループ

WP_Queryを使って以下のように表示件数を指定します。

<?php if (have_posts()) : ?>
  <ul class="p-blog__items">
    <?php
      $paged = get_query_var('paged') ? get_query_var('paged') : 1;
      $args = array(
        'post_type' => 'blog',
        'posts_per_page' => 20,
        'paged' => $paged
      );
      $the_query = new WP_Query($args);
      while ($the_query->have_posts()) {
        $the_query->the_post();
        get_template_part('template-parts/content', get_post_type());
      }
      wp_reset_postdata();
    ?>
  </ul>

<?php else : ?>
  <?php get_template_part('template-parts/content', 'none'); ?>
<?php endif; ?>

ページ送りのコード

paginate_links関数を使う事でページネーションのリンクを得る事ができます。

<?php if ($the_query->max_num_pages > 1) : ?>
<?php
  $limitnum = 999999999;
  echo '<div class="p-blog__pager">';
  echo paginate_links(array(
    'base'         => str_replace($limitnum, '%#%', esc_url(get_pagenum_link($limitnum))),
    'format'       => '',
    'current'      => max(1, get_query_var('paged')),
    'total'        => $the_query->max_num_pages,
    'prev_next'    => false,
    'type'         => 'list',
    'end_size'     => 3,
    'mid_size'     => 3
  ));
  echo '</div>';
?>
<?php endif; ?>

上記実装の問題点

記事が100件ある場合はWP_Queryでposts_per_pageに20を指定しているため20件ずつ区切られて一覧が表示され、ページネーションのリンクが5ページ目まで出力される事を期待します。

しかし、paginate_linksで得るページネーションのリンクは「設定」->「表示設定」->「1ページに表示する最大投稿数」の設定値を参照しています。 つまり「1ページに表示する最大投稿数」が10に設定されていると10ページ目までのリンクが出力されます。

ブログのアーカイブだけが必要な場合は「1ページに表示する最大投稿数」を20に設定するだけで良いですが、お知らせは10件にしたいと言ったケースでは困ります。

複数アーカイブ実装時の対策

アクションフックpre_get_postsを使ってメインクエリを操作します。functions.phpへ以下のコードを追加します。

function set_pre_get_posts($query) {
  if (is_admin() || !$query->is_main_query()) {
    return;
  }

  if ($query->is_post_type_archive('blog')) {
    $query->set('posts_per_page', '20');
    return;
  }

  if ($query->is_post_type_archive('news')) {
    $query->set('posts_per_page', '10');
    return;
  }
}
add_action('pre_get_posts', 'set_pre_get_posts');

対策後のメインループとページ送り

<?php if (have_posts()) : ?>
  <ul class="p-blog__items">
    <?php
      while (have_posts()) {
        the_post();
        get_template_part('template-parts/content', get_post_type());
      }
      wp_reset_postdata();
    ?>
  </ul>

<?php else : ?>
  <?php get_template_part('template-parts/content', get_post_type()); ?>
<?php endif; ?>

<?php
  global $wp_query;
?>
<?php if ($wp_query->max_num_pages > 1) : ?>
<?php
  $limitnum = 999999999;
  echo '<div class="p-blog__pager">';
  echo paginate_links(array(
    'base'         => str_replace($limitnum, '%#%', esc_url(get_pagenum_link($limitnum))),
    'format'       => '',
    'current'      => max(1, get_query_var('paged')),
    'total'        => $wp_query->max_num_pages,
    'prev_next'    => false,
    'type'         => 'list',
    'end_size'     => 3,
    'mid_size'     => 3
  ));
  echo '</div>';
?>
<?php endif; ?>

まとめ

WP_Queryでループで得る内容を変更するのではなく、アクションフックpre_get_postsでクエリにセットする事で複数アーカイブでのページ送りに対応可能です。

pre_get_postsではWP_Queryと違ってWordpressがクエリを実行する前に呼び出されるため、データベースへのリクエストが減るメリットもあります。

参考