WordPress
カスタマイズ事例

WORDPRESS CUSTOMIZATION

Ajaxでページネーションなしのターム(カテゴリ)別投稿記事一覧ローディングをつくる テーマ販売あり

投稿記事が増えてくると、投稿記事一覧ページ1ページ内ですべての記事を表示させるようなことはせず、たいていの場合、一覧ページにページネーションをつけてページを分割して2ページ目以降で表示するか、Ajaxなどで同一ページ内で次以降の記事をロードする機能などをつけますよね。
今回は後者の「Ajaxで次以降の記事をロードする機能」の実装について詳しく説明していきます。
とはいえ、投稿(Post)の一覧をAjaxローディングにするのも普通すぎておもしろくない(プラグインでできちゃうし)ので、今回は下の事例で紹介した、ターム(カテゴリ)ごとに分けた記事一覧の取得のAjaxローディングについて説明していくことにします。
アーカイブページで、ターム(カテゴリ)ごとに分けて記事一覧を表示する
※ この記事中にはBootstrap版と通常版ありますが、Bootstrap版のほうを対象とします。
 
作る(あるいは編集する)ファイルは4つ。

  • HTMLテンプレート: archive-items.php
  • Ajaxから呼ばれるテンプレート: page-templates/ajax-search.php
  • テーマの機能を管理するプログラム用ファイル: functions.php
  • フォームの内容をAjaxでサーバーに送るjavascript: search.js

それではひとつひとつ見ていきましょう。

archive-items.php

<?php get_header(); ?>

<h2>Bootstrapタブバージョン</h2>
<?php
// カスタム投稿タイプ
$post_type = 'items';
// カスタム分類名
$taxonomy = 'items_cat';

// パラメータ
$args = array(
	// 親タームのみ取得
	'parent' => 0,
	// 子タームの投稿数を親タームに含める
	'pad_counts' => false,
	// 投稿記事がないタームは取得しない
	'hide_empty' => true
);

// カスタム分類のタームのリストを取得
$terms = get_terms( $taxonomy , $args );

if (count($terms) != 0) {
	$tab_html = '<ul class="nav nav-tabs" id="itemTab" role="tablist">';
	$content_html = '<div class="tab-content" id="itemTabContent">';

	$i = 0;
	// 親タームのリスト $terms を $term に格納してループ
	foreach ($terms as $term) {
		$term_slug = $term->slug;
		$term_name = $term->name;
		$tab_active_html = '';
		$content_active_html = '';
		if ($i == 0) {
			$tab_active_html = 'active';
			$content_active_html = 'show active';
		}
		$tab_html .= '<li class="nav-item">
      <a class="nav-link ' . $tab_active_html . '" id="' . $term_slug . '-tab" data-toggle="tab" href="#' . $term_slug . '" role="tab"
      aria-controls="' . $term_slug . '" aria-selected="true">' . $term_name . '</a>
    </li>';
		$content_html .= '<div class="tab-pane fade ' . $content_active_html . '" id="' . $term_slug . '" role="tabpanel" aria-labelledby="' .
		                 $term_slug . '-tab">';

    $content_html .= func_search($post_type, $taxonomy, $term_slug, 1);
    $content_html .= '<button class="btn ajax-btn" id="tab' . $i . '-btn" data-paged="2" data-cat="' . $term_slug . '">MORE</button>';
		$content_html .= '</div>';
		$i++;
	}
	$tab_html .= '</ul>';
  $content_html .= '</div>';

	echo $tab_html;
	echo $content_html;
}
?>
<script>
  $('#itemTab a').on('click', function (e) {
    e.preventDefault()
    $(this).tab('show')
  })
</script>

<?php get_footer(); ?>

45行目で、後述する functions.php 内につくる func_search という関数を使って、記事一覧を出力。
46行目では、タームごとに記事をロードするため、タブごとに「MORE」ボタンを用意。それぞれのボタンのIDは簡単のため、#tab0-btn, #tab1-btn, #tab2-btn・・・といった具合に番号を振るようにしてます。
 
次は、Ajaxから呼ばれるテンプレート: page-templates/ajax-search.php

<?php
$post_type = 'items';
$taxonomy = 'items_cat';
$term_slug = isset($_GET['cat']) ? $_GET['cat'] : '';
$ajax_paged = isset($_GET['paged']) ? $_GET['paged'] : 1;

echo func_search($post_type, $taxonomy, $term_slug, $ajax_paged);

このプログラムでは、Ajaxから受け取った引数を functions.php につくる func_search という関数に渡しています。
 
その functions.php

function func_search($post_type, $taxonomy, $term_slug, $ajax_paged)
{
  global $post;

  if ($ajax_paged) {
    $paged = $ajax_paged;
  } else {
    $paged = 1;
  }

  $the_query = new WP_Query(array(
    'post_status' => 'publish',
    'post_type' => $post_type,
    'tax_query' => array(
      array(
        'taxonomy' => $taxonomy,
        'field' => 'slug',
        'terms' => $term_slug
      )
    ),
    'paged' => $paged,
    'posts_per_page' => 10,
    'orderby' => 'date',
    'order' => 'DESC'
  ));

  if ($the_query->have_posts()) {
    $html = '';

    while ($the_query->have_posts()) : $the_query->the_post();
      $image_url = wp_get_attachment_image_src(get_post_thumbnail_id($post->ID), 'medium');
      $image_url_hon = '';
      if ($image_url) {
        $image_url_hon = $image_url[0];
      }
      $html .= '<a href="' . get_permalink() . '">';
      if ($image_url_hon) {
        $html .= '<img src="' . $image_url_hon . '"/>';
      }
      $html .= get_the_title() . '</a>';

      wp_reset_postdata();
    endwhile;

    return $html;
  }
}

/* フォームの内容を取得してAjaxに送信するプログラムが記述されたJavascriptをheadタグにキュー */
add_action('wp_enqueue_scripts', function () {
  $handle = 'search';
  $file = get_stylesheet_directory_uri() . '/assets/js/' . $handle . '.js';
  wp_register_script($handle, $file, array('jquery'), '3.6.0', true);

  $localize = [
    'ajax_url' => admin_url('admin-ajax.php'),
    'action' => 'view_search_results',
    'nonce' => wp_create_nonce('view_search_results')
  ];
  wp_localize_script($handle, 'localize', $localize);
  wp_enqueue_script($handle);
});

function view_search_results()
{
  $nonce = $_REQUEST['nonce'];
  if (wp_verify_nonce($nonce, 'view_search_results')) {
    get_template_part('page-templates/ajax-search');
  }
  die();
}
add_action('wp_ajax_view_search_results', 'view_search_results');
add_action('wp_ajax_nopriv_view_search_results', 'view_search_results');

add_action('wp_enqueue_scripts', 'my_init');
function my_init()
{
  wp_deregister_script('jquery');
  wp_enqueue_script('jquery', 'https://code.jquery.com/jquery-3.6.0.min.js', array(), '3.6.0');
}

func_search が、ajax-search.php経由でAjaxから引数を受け取りHTMLを生成する関数。
そして、後半のほうの記述がAjaxのファイルや挙動を定義する部分になるのですが、
Ajaxでページ遷移なしの絞り込み検索をつくる
に詳しい説明を載せていますので、ここでは省略させてください。
 
最後にAjax(javascript):search.js

$('#tab0-btn, #tab1-btn, #tab2-btn, #tab3-btn, #tab4-btn, #tab5-btn, #tab6-btn, #tab7-btn').on('click', function() {
  dispLoading();
  let btn = $(this)
  let cat = btn.data('cat');
  let paged = btn.data('paged');
  let next_paged = Number(paged) + 1;
  btn.attr('data-paged', next_paged);
  btn.data('paged', next_paged);

  $.ajax({
    type: 'GET',
    cache: false,
    url: localize.ajax_url,
    data: {
      'action': 'view_search_results',
      'cat': cat,
      'paged': paged,
      'nonce': localize.nonce
    },
    success: function (response) {
      if (response.length > 0) {
        btn.before(response);
      } else {
        btn.remove();
      }
      console.log(response)
    }
  })
    // 処理終了時
    .always(function (response) {
      removeLoading();
    });

  return false;
});

/* ------------------------------
 Loading
 ------------------------------ */
function dispLoading(msg) {
  if (msg == undefined) {
    msg = "";
  }
  var dispMsg = "<div class='loadingMsg'>" + msg + "</div>";
  if ($("#loading").length == 0) {
    $("body").append("<div id='loading'>" + dispMsg + "</div>");
  }
}

function removeLoading() {
  $("#loading").fadeOut('fast').queue(function () {
    $("#loading").remove();
    $('body').removeClass('open-menu');
  })
}

MOREボタンが押されたら起動するAjaxです。
ボタンのIDは、archive-items.php で生成されたボタンを #tab0-btn, #tab1-btn, #tab2-btn・・・といった具合に直接指定しています。本来、動的に生成するのがスマートではありますが、今回は独立したJavascriptファイルにした関係で簡単のためそうさせてもらいました。
 
なお、ローディング画面の装飾(クルクルまわるローディングアイコンなど)については
Ajaxでページ遷移なしの絞り込み検索をつくる
にて説明をしていますので、ここでは省略します。
 
以上、完成です。

いかがでしたでしょうか?
全カテゴリ対象のアーカイブ(記事一覧)のAjaxローディングならプラグインもありますし、参考文献もネットに転がっているんですが、ターム(カテゴリ)別の記事一覧のAjaxローディングとなると参考文献がネット上には見当たりません。
探していた方はこの事例を参考にがんばって実装してみてください。
 
 
それから、文中に参考として何回か貼り付けていた事例リンク
Ajaxでページ遷移なしの絞り込み検索をつくる
も、Ajaxがらみでかなり使える事例ですので、興味のある方はぜひご覧ください。

【この事例を解決するためのWordPressテーマを購入できます】

現在あなたが利用されているWordPressテーマを活かしたまま、このページの事例を解決できるWordPressテーマを、子テーマとして購入できます。
この子テーマを有効化するだけで、現在お使いのデザインテーマにこの事例解決の機能が自動付与されます。
デザインが入っていないため、一般より格段に低い価格(事例の難易度により200円~1.3万円)です。
※ テーマは買い切りです
※ 自由に改変してお使いいただいて構いません
※ すでに子テーマでサイト運用されている方は、当該子テーマをマージしてください

【100ウェブ新着情報メルマガ】

WordPressカスタマイズ事例やウェブ制作ノウハウの新着情報、お役立ち情報を
リアルタイムにメルマガ配信!