WordPressで無限スクロールで記事を読み込む方法!【プラグインなし編】

WordPressで無限スクロールを実装する方法です!無限スクロールの実装を理解できているとカスタマイズもしやく、かつWordPressの動きもちょっとだけ深く理解できるようになります。

前提として、WP_QueryなどWordPress特有のループ処理方法が当たり前のように出てきますが、その辺りの説明はしないのでWordPressの基本は理解している前提で記事が書かれていることをご理解いただけますと幸いです…。

一応、サブループについては以下で解説しています。

WordPressの任意のループ(サブループ)を作る方法と覚えておきたい指定方法

動きのサンプル例

実際の動きはこんな感じです。スクロールが最後まで行くと、ローディングが開始して記事を取得して表示するという動きになっています。

自作できるようになっていると、ローディング時の動きなど柔軟に対応できるようになるはずです。

WordPressで無限スクロールを実装する方法!

大きな流れとしては以下の2つです。

  • 追加で表示する用のPHPファイルの作成
  • Ajaxで表示するためのJavaScriptの記述

追加で表示するようのPHPファイルの作成

では早速、追加で表示する用のPHPファイルを作っていきましょう。

何を書くかというと、一覧のループの中で回している部分になります。archive.phphome.phpでループ処理をしているかと思いますが、ループ部分だけを抜き出すようなイメージです。以下のような書き方がされていたとすると<div class="entry-items"></div><!-- /entry-items -->以外の部分ですね。

home.phpコピー<div class="entry-items">
<?php
while ( $hoge_query->have_posts() ) :
$hoge_query->the_post();
?>

<!-- 一覧のアイテム -->

	<?php
endwhile;
?>
</div><!-- /entry-items -->
wp_reset_postdata();

ajax-item.phpのような名前で新しいファイルを用意します。ここに上記の<div class="entry-items"></div><!-- /entry-items -->以外の部分をコピーしてあげて、WP_Queryの条件を変えてあげます。

そして必要なものを色々足して書き直したのが以下のようなコードですね(3分クッキングのような手際…)。

ajax-item.phpコピーrequire_once '../../../../wp-load.php';

$offset         = isset( $_POST['post_num_now'] ) ? $_POST['post_num_now'] : 1;
$posts_per_page = isset( $_POST['post_num_add'] ) ? $_POST['post_num_add'] : 0;

$ajax_query = new WP_Query(
	array(
		'post_type'      => 'post',
		'posts_per_page' => $posts_per_page,
		'offset'         => $offset,
	)
);
?>
<?php if ( $ajax_query->have_posts() ) : ?>
	<?php while ( $ajax_query->have_posts() ) : ?>
		<?php $ajax_query->the_post(); ?>

		<!-- 一覧のアイテム -->

	<?php endwhile; ?>
<?php endif; ?>
<?php
wp_reset_postdata();

ポイントとしては以下の3点です。

1、WordPress関数を使えるようにする

次のコードを追加しています。require_once '../../../../wp-load.php';

wp-load.phpとは、WordPressの関数を読み込ませるために必要なファイルとなります。Ajaxで通信したファイルはWordPressのファイルの関数を使うことができないので、最初にwp-load.phpを読み込んでWordPressの書き方ができるようにしておく必要があります。

2、Ajaxで値を受け取る

無限スクロールで記事を読み込む上で大事なのは、何件目から何件目までを読み込むかという情報です。これはJavaScript側で持たせて、PHPに情報を連携してあげます。

最初の何件目からというところは、今表示されている件数を都度取得してPHPに送ってあげる必要がります。値は何でもいいですが、今回はpost_num_nowという値にしてPOSTで送っているので、$_POST['post_num_now']で取得するという書き方をしています。

何件目までという部分も同様に$_POST['post_num_add']で取得しています。

3、WP_Queryで追加分を取得

そしてWP_Queryによって追加分を取得しています。パラメーターとして重要なのは以下の2つです。

  • offset・・・何件目からの情報を取得するか
  • posts_per_page・・・何件分の情報を取得するか

offsetに、今表示されている件数 + 1の値を入れてあげることで、どんどん新しい情報を取得できるといった仕組みですね。

Ajaxで表示するためのJavaScriptの記述

続いてはJavaScript側での記述内容です。こちらもまずは一気に書いてみます。

ざっくりとした処理内容としては、一番下までスクロールされたらAjax通信して先ほど作成したajax-item.phpによって記事を取得し読み込むといったものになります。

jQueryのスクロール処理についても詳しくは解説しないので、以下の記事を参考にしてください…。

コピーjQuery(function() {
	let documentHeight = jQuery(document).height();
	let windowsHeight = jQuery(window).height();
	let url = "http://example.com/wp-content/themes/theme-name/ajax-item.php"; /* ご自身のURL */
	let postNumNow = 4; /* 最初に表示されている記事数 */
	let postNumAdd = 4; /* 追加する記事数 */
	let flag = false;
	jQuery(window).on("scroll", function() {
		let scrollPosition = windowsHeight + jQuery(window).scrollTop();
		if (scrollPosition >= documentHeight) {
			if (!flag) {
				flag = true;
				jQuery.ajax({
					type: "POST",
					url: url,
					data: {
						post_num_now: postNumNow,
						post_num_add: postNumAdd
					},
					success: function(response) {
						jQuery(".entry-items").append(response);
						documentHeight = jQuery(document).height();
						postNumNow += postNumAdd;
						flag = false;
					}
				});
			}
		}
	});
});

ajax-item.phpへのURL

urlに入れるのは、先ほど作成したajax-item.phpまでの絶対パスになります。

今の記事数と追加する記事数

postNumNowは、最初(今)に表示されている記事数です。それぞのれサイトで違う値になるかと思います。postNumAddはスクロール時に何件取得するかという値です。こちらもサイトの設計によって変わってくるはずです。

読み込み中か否か

flagは、処理中かどうかを判定するためのものです。AJAX通信中は読み込み処理を中止するという動きになります。

成功するとsuccessの関数に移ります。ここで行うのは、取得した記事を画面に表示させる処理です。jQuery(".entry-items")は一覧を囲っている親要素となる部分で、この最後にajax-item.phpの内容を追加します。

高さの再取得

要素が追加されて画面が高さが変わったので、jQuery(document).height()の値を再度取得しなおします。そして、現在の記事数を持っているpostNumも追加した分を足して更新し、Ajax通信中かどうかを判断していたflagを解除してあげるといった動きをしています。

どこまでスクロールしたら読み込むかといった部分はサイトの設計や一覧の表示場所によって各々指定を考えてもらえたらと思います。

ローディング要素を追加する

記事を読込中であることが分かるように、ローディング表示用の要素を追加して、ローディング処理を追加してみます。要素の中身やデザインは好きなように変更してもらえたらと思います。

以下のように一覧を囲っている要素である</div><!-- /entry-items -->の後に追加して、常に一覧の最後に表示されるようにしました。<div class="entry-loading">loading...</div>の部分です。

コピー<div class="entry-items">
<?php
while ( $hoge_query->have_posts() ) :
$hoge_query->the_post();
?>

<!-- 一覧のアイテム -->

  <?php
endwhile;
?>
</div><!-- /entry-items -->
<div class="entry-loading">loading...</div>
wp_reset_postdata();

続いてJavaScriptですが、Ajaxの通信開始時(記事を取得しにいくタイミング)でjQuery(".entry-loading").addClass("is-show");.is-showというクラスを付与して、記事の取得が完了したら、removeClassしているというシンプルな処理です。動きはCSSで作っていきます。
Ajaxの部分だけ抜粋

コピーif (!flag) {
	jQuery(".entry-loading").addClass("is-show");
	flag = true;
	jQuery.ajax({
		type: "POST",
		url: url,
		data: {
			post_num_now: postNumNow,
			post_num_add: postNumAdd
		},
		success: function(response) {
			jQuery(".works-items").append(response);
			jQuery(".entry-loading").removeClass("is-show");
			documentHeight = jQuery(document).height();
			postNumNow += postNumAdd;
			flag = false;
		}
	});
}

今回のローディング要素のCSSはめっちゃシンプルですが、ここを好きなような変更することで、画面を覆う半透明のローディング画面にしたり、アニメーション付けたりなど色んな表現ができるようになるはずです。

コピー.entry-loading {
	text-align: center;
	margin: 3em 0;
	font-weight: 700;
	width: 100%;
	display: none;
}

.entry-loading.is-show {
	display: block;
}

おさらいすると、ローディング用の要素を一覧の最後につけて、Ajaxの処理と連動してクラスを外したり付けたりして、実際の動きはCSSに書いていく、といった流れになります。

CSSで動きつけるのが面倒な人は、Gif動画などを用意してローディング用の要素のところで画像を差し込めば楽かもしれません。

ボタンによる読み込みに変更

スクロールではなくボタンを押した時に読み込むという処理もよく見ます。スクロールと違うのは、jQueryでのイベント取得の方法と判定の部分だけですね。Ajaxとかの考え方は特に変わりません。

変わる部分はクリックイベントでの発動になる点と、ボタン要素へのクラスの付与があるという点だけです。

ボタン用の要素を一覧の下に追加

ローディングと同様にボタン用の要素を一覧の下に追加します。こちらは標準で表示させておくようにします。<div class="entry-more">もっと読み込む</div>の部分。

コピー<div class="entry-items">
<?php
while ( $hoge_query->have_posts() ) :
$hoge_query->the_post();
?>

<!-- 一覧のアイテム -->

  <?php
endwhile;
?>
</div><!-- /entry-items -->
<div class="entry-more">もっと読み込む</div>
<div class="entry-loading">loading...</div>
wp_reset_postdata();

Ajaxと連動してボタンにクラスを付与

Ajax通信中(追加の記事を取得中)はボタンを非表示にするように、クラスを付与したり外したりしています。

コピーlet url = "http://example.com/wp-content/themes/theme-name/ajax-item.php"; /* ご自身のURL */
let postNumNow = 4;
let postNumAdd = 4;
let flag = false;
jQuery(document).on("click", ".entry-more", function() {
	if (!flag) {
		jQuery(".entry-more").addClass("is-hide");
		jQuery(".entry-loading").addClass("is-show");
		flag = true;
		jQuery.ajax({
			type: "POST",
			url: url,
			data: {
				post_num_now: postNumNow,
				post_num_add: postNumAdd
			},
			success: function(response) {
				jQuery(".works-items").append(response);
				jQuery(".entry-loading").removeClass("is-show");
				jQuery(".entry-more").removeClass("is-hide");
				documentHeight = jQuery(document).height();
				postNumNow += postNumAdd;
				flag = false;
			}
		});
	}
});

ボタンのCSSも自由ですが、今回は単純に表示・非表示のCSSとしています。

コピー.entry-more {
	text-align: center;
	width: 280px;
	padding: 12px 16px;
	text-align: center;
	background: #7e7e7e;
	color: #fff;
	margin: 3em auto 0;
	cursor: pointer;
}

.entry-more.is-hide {
	display: none;
}

記事の終わりはボタンを非表示

今のままだと、終了時にボタンが常に表示されてしまいます。読み込む記事がなくなったら非表示にする処理に変更してみましょう。記事を表示するHTMLタグと、これ以上記事があるかどうかを判定する値をAjaxに受け取らせる必要があって、ちょっとだけ面倒です…。

Ajax通信した時に表示対象のPHP(今回だとajax-item.php)を書き換えます。

まずは、全件読み込んだ時の最大件数を取得

コピー$all_query = new WP_Query(
	array(
		'post_type'      => 'post',
		'posts_per_page' => -1,
	)
);
$all_post_count = $all_query->post_count;

一覧取得時に表示させることなく、出力される値を変数として格納

ob_start()等の出力させずに変数に格納します。

コピー<?php if ( $ajax_query->have_posts() ) : ?>
	<?php $entry_item = ''; ?>
	<?php ob_start(); ?>
  <?php while ( $ajax_query->have_posts() ) : ?>
    <?php $ajax_query->the_post(); ?>

    <!-- 一覧のアイテム → --><?php get_template_part( 'parts/works-item' ); ?>

  <?php endwhile; ?>
	<?php $entry_item .= ob_get_contents(); ?>
	<?php ob_end_clean(); ?>
<?php endif; ?>
<?php
wp_reset_postdata();

追加するHTMLタグと残りの件数を配列で返却

上記で取得できる2つの値を配列にしてからJSONに返却します。

コピーecho json_encode( array( $entry_item, $all_post_count - ( $offset + $ajax_query->post_count ) ) );

JSON形式の値をAjaxで受け取る

Ajaxの処理が成功した時にJSONを受け取るうようにします。JSON.parse()で変換して配列のように使えるようになりました。if (data[1] > 0)として、「まだ記事があるときだけボタンを表示させる」という処理にできました。

コピーsuccess: function(response) {
	data = JSON.parse(response);
	jQuery(".works-items").append(data[0]);
	jQuery(".entry-loading").removeClass("is-show");
	if (data[1] > 0) {
		jQuery(".entry-more").removeClass("is-hide");
	}
	documentHeight = jQuery(document).height();
	postNumNow += postNumAdd;
	flag = false;
}

おわり

WordPressでのJavaScriptの読み込み、WP_Query()やテンプレート階層などのWordPressのお作法のお話や、そもそものAjaxの使い方など、前提となる知識が多すぎるので、まだ理解できていない方はまずはそれらの知識をインターネット等で検索して保管しながらこの記事を見てもらえたらと思います…。

自分で実装するとカスタマイズもしやすく、より知識も深まります。プラグインやライブラリでは不十分、、、という方は自作してゴリゴリカスタマイズできるように自作してみてくださいー!

このページが役に立ったら
いいね!お願いします

運営の励みになります...。

関連の記事