Ajaxページネーション
例えばこんなケースがある!
CPT一覧でターム別にタブ切り替えで表示したい
ここで問題なのはページネーションをどうするか?


<DEMO>
<解説>
通常WordPressでのページネーションはリンクで行い、URLが「wp1stop.ne/blog/page/2/」のように変更される。
CPT一覧が1つの場合は何も問題はないが、ターム別にタブ切り替えで表示する場合はURL(/page/2/)を共有することになるので思うような動作にならない。
この場合リンクではなくAjaxを使ったページネーションを実装することで解決出来る!
<実装方法>
WordPressにはajaxを扱うアクションフックが2つがある。「wp_ajax_action(+name)」「wp_ajax_nopriv_action(+name)」
PHPはこのアクションフック使ってAjaxコールバックコードを書く。
またAjaxページネーション生成用のコードも必要である。
JSはAjaxコードが必要である。
Ajaxコールバック、Ajaxページネーション生成コードをfunctions.phpなどに追加する
functions.php
//Ajax callback
add_action('wp_ajax_load_more_posts', 'load_more_posts_callback');
add_action('wp_ajax_nopriv_load_more_posts', 'load_more_posts_callback');
function load_more_posts_callback() {
$post_type = $_POST['post_type'];
$posts_per_page = $_POST['posts_per_page'];
$paged = $_POST['page'];
$taxonomy = $_POST['taxonomy'];
$terms = $_POST['terms'];
$html = "";
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => $posts_per_page,
'paged' => $paged,
);
if( $taxonomy != '' && $terms != '' ){
$args['tax_query'] = array(
array(
'taxonomy' => $taxonomy,
'field' => 'slug',
'terms' => $terms,
)
);
}
$query = new WP_Query($args);
$total_posts = $query->found_posts;
if ($query->have_posts()) {
while ( $query->have_posts() ) : $query->the_post();
$term_slug = $term_name = '';
$get_terms = get_the_terms(get_the_ID(), $taxonomy);
if ( ! empty( $get_terms ) ) {
if ( ! is_wp_error( $get_terms ) ) {
$term_name = $get_terms[0]->name;
$term_slug = $get_terms[0]->slug;
}
}
$html .= '<ul class="col2blog"><li class="l">';
$permalink = get_permalink();
$time = get_the_time("Y/m/d");
$title = the_title('','',false);
$content = do_shortcode( get_the_content() );
$url = get_post_meta(get_the_ID(), 'proresults_url', true);
if ( has_post_thumbnail() ) {
$html .= get_the_post_thumbnail( get_the_ID(), 'thumb300_200', array('class' => 'newsimg') );
}else{
$html .= '<img src="' . get_template_directory_uri(). '/img/noimg.gif" alt="No image" class="newsimg">' . PHP_EOL;
}
$html .= '</a></li>';
$html .= '<li class="spa"></li>';
$html .= '<li class="r">';
$html .= '<p class="ti"><i class="fa fa-clock-o"></i>';
$html .= '<a href="' . $permalink .'" class="link">';
$html .= $time . ' ';
if( $terms != '' ){
$html .= '<span class="cate '.$term_slug.'">' . $term_name . '</span><br>';
}
$html .= $title . '</p>' . PHP_EOL;
$html .= '<a href="' . $url . '" target="_blank">' . $url . '</a>';
$html .= '<p class="excerpt">' . $content . '</p>' . PHP_EOL;
$html .= '</li></ul>';
endwhile;
wp_reset_postdata();
$response = array(
'html' => $html,
'show_button' => true,
'total_posts' => $total_posts,
);
} else {
$response = array(
'show_button' => false,
);
}
$response = json_encode($response);
echo $response;
wp_die();
}
//Ajaxページネーション
function ajax_pagination($max_page = 1, $posts_per_page = 3, $post_type = '', $taxonomy = '', $terms = '', $showitems = 5, $cuurent_maxpage = false){
//$showitems = ($range * 2)+1;
$paged = 1;
$admin_url = admin_url() . 'admin-ajax.php';
if(1 != $max_page && $posts_per_page != '' && $post_type != '' ) {
if( $taxonomy != '' && $terms != '' ) {
echo '<div class="pagingBox" data-maxpage="'.$max_page.'" data-post_type="'.$post_type.'" data-admin_url="'.$admin_url.'" data-terms="'.$terms.'" data-taxonomy="'.$taxonomy.'" data-posts_per_page="'.$posts_per_page.'" data-showitems="'.$showitems.'" data-cuurent_maxpage="'.$cuurent_maxpage.'">';
} else {
echo '<div class="pagingBox" data-maxpage="'.$max_page.'" data-post_type="'.$post_type.'" data-admin_url="'.$admin_url.'" data-terms="" data-taxonomy="" data-posts_per_page="'.$posts_per_page.'" data-showitems="'.$showitems.'" data-cuurent_maxpage="'.$cuurent_maxpage.'">';
}
//先頭へ
echo '<button data-page="1" class="pagingBut noNum top"><i class="fas fa-angle-double-left"></i></button>';
//1つ戻るGo back one
//$backOne = ($paged == 1) ? 1 : $paged;
echo '<button data-page="" class="pagingBut noNum backOne"><i class="fas fa-angle-left"></i></button>';
echo '<div class="numBox">';
//番号つきページ送りボタン
for ( $i=1; $i <= $showitems; $i++ ) {
if ( $i <= $max_page ) {
$class = ($paged == $i) ? ' active' : '';
echo '<button data-page="'.$i.'" class="pagingBut'.$class.'">'.$i.'</button>';
}
}
echo '</div>';
//1つ進むadvance one step
echo '<button data-page="2" class="pagingBut noNum oneStep"><i class="fas fa-angle-right"></i></button>';
//最後尾へ
echo '<button data-page="'.$max_page.'" class="pagingBut noNum end"><i class="fas fa-angle-double-right"></i></button>';
echo '</div><!--.pagingBox-->';
if($cuurent_maxpage) {
echo '<div class="cuurent_maxpage"><span>1</span> / '.$max_page.'</div>';
}
}
}
CPT一覧ページなどにAjaxページネーションを埋め込む
//pagination
ajax_pagination( $wp_query->max_num_pages, $posts_per_page, $post_type, $taxonomy, $terms );
AjaxコードをJSファイルに
//ajax.js
jQuery(function ($) {
$(document).on('click', '.pagingBut', function(){
var $pagingBox = $(this).closest('.pagingBox');
$pagingBox.find('.pagingBut').removeClass('active');
const post_type = $pagingBox.data('post_type');
const admin_url = $pagingBox.data('admin_url');
let page = $(this).attr('data-page');
let maxpage = $pagingBox.data('maxpage');
let showitems = $pagingBox.data('showitems');
const terms = $pagingBox.data('terms');
const taxonomy = $pagingBox.data('taxonomy');
const posts_per_page = $pagingBox.data('posts_per_page');
const cuurent_maxpage = $pagingBox.data('cuurent_maxpage');
const $thisEle = $(this);
$.ajax({
url: admin_url,
type: 'POST',
data: {
action: 'load_more_posts',
post_type: post_type,
posts_per_page: posts_per_page,
page: page,
terms: terms,
taxonomy: taxonomy,
showitems: showitems,
}, success: function(response) {
var result = JSON.parse(response);
$pagingBox.closest('.tab_content_description').children('.text_flex').html(result.html);
page = Number(page);
maxpage = Number(maxpage);
showitems = Number(showitems)
if (page >= 2) {$pagingBox.children('.pagingBut.backOne').attr('data-page', (page - 1));
} else {$pagingBox.children('.pagingBut.backOne').attr('data-page', page);}
if (page < maxpage) {$pagingBox.children('.pagingBut.oneStep').attr('data-page', (page + 1));
} else {$pagingBox.children('.pagingBut.oneStep').attr('data-page', page);}
//番号つきページ送りボタン
let numBox = '';
let classN = '';
let startN = 0;
let cou = 0;
let maxdiffer = 0;
let pagediffer = 0;
let show = (showitems-1);//case 5 -> 4
let show2 = ((showitems-1)/2);//case 5 -> 2
let cuurentmaxpage = '';
if (cuurent_maxpage) {
cuurentmaxpage = ''+page+' / '+maxpage;
}
$pagingBox.closest('.tab_content_description').find('.cuurent_maxpage').html(cuurentmaxpage);
if (maxpage <= showitems) {
startN = 1;
} else {
maxdiffer = maxpage - show;
pagediffer = page - show2;
if (pagediffer >= maxdiffer) {
startN = maxdiffer;
} else if (pagediffer < 1) {
startN = 1;
} else {
startN = pagediffer;
}
}
for (let i = startN; i <= maxpage; i++) {
if (cou < showitems) {
classN = (page == i) ? ' active' : '';
numBox += '\n';
}
cou++;
}
$pagingBox.closest('.tab_content_description').find('.numBox').html(numBox);
}, error: function(xhr, status, error) {
console.error(xhr);
}
});
});
});
<まとめ>
WordPressでajaxの実装は簡単なのでページネーション以外にもトライしてみたいと思う。
今後、機会があればタブ切替(Ajaxページネーション付き)のプラグイン化を検討中。