当社は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がクエリを実行する前に呼び出されるため、データベースへのリクエストが減るメリットもあります。