WordPress ページングはやめてAjaxローディングにする

Ajaxを使う方法はこちらが最新です: WordPressでAjaxを使う方法の解説

ページングはやめて、Ajaxによる非同期ローディングにしてみましょう。

最初は5件の記事が表示されています。
「もっと見る」ボタンをクリックするとAjaxにより次の5件が非同期で読み込まれます。
以後、記事がなくなるまで同じ動作です。

テンプレート

<section id="content">

	<?php query_posts('posts_per_page=5'); ?>
	<?php if (have_posts()) : ?>
		<?php while (have_posts()) : the_post(); ?>
			<article>
				<h2><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></h2>
				<div class="excerpt"><?php the_excerpt(); ?></div>
			</article>
		<?php endwhile; ?>
	<?php else : ?>
		Not Found.
	<?php endif; ?>
	<?php wp_reset_query(); ?>
	
	<div id="more_disp"><a href="#">もっと表示</a></div>
	
</section>

基本的なWordPressループに、「もっと表示」ボタンを設置します。

query_posts()で、最初に表示しておく件数を指定しておきましょう。
指定しない場合は、管理画面 > 設定 > 表示設定 の「1ページに表示する最大投稿数」が反映されます。

PHPファイル

Ajaxで通信するPHPファイルを作成します。
テーマフォルダの中に more-disp.php を作ります。
テーマフォルダ名は「ajax_loading」とします。

> テーマフォルダ/more-disp.php

<?php

require_once("../../../wp-config.php");

$now_post_num = $_POST['now_post_num'];
$get_post_num = $_POST['get_post_num'];

$sql = "SELECT
		$wpdb->posts.ID, 
		$wpdb->posts.post_title, 
		$wpdb->posts.post_excerpt 
	FROM 
		$wpdb->posts  
	WHERE 
		$wpdb->posts.post_type = 'post' AND $wpdb->posts.post_status = 'publish' 
	ORDER BY 
		$wpdb->posts.post_date DESC 
	LIMIT $now_post_num, $get_post_num";
		
$results = $wpdb->get_results($sql);

$html = "";

foreach ($results as $result) {
	$html .= '<article>';
	$html .= '<h2><a href="'.get_permalink($result->ID).'">'.apply_filters('the_title', $result->post_title).'</a></h2>';
	$html .= '<div class="excerpt">'.apply_filters('the_excerpt', $result->post_excerpt).'</div>';
	$html .= '</article>';
}
echo $html;

?>

wp-config.phpの読み込み

データベースの接続設定が記述されている wp-config.php を読み込むことで、グローバル変数 $wpdb が使えるようになります。
テーマフォルダからの相対パスで記述します。

関数リファレンス/wpdb Class
wpdb クラスのメソッドは、直接呼び出さず、必ずグローバル変数 $wpdb を使いましょう。

SQLの発行

必要なデータを取得する為のSQLを発行します。
タイトル(posts.post_title)と抜粋(posts.post_excerpt)以外に必要なデータがあれば適宜追加します。
ID(posts.ID)は、JavaScriptに返すHTMLを組み立てるのに使います。

データを組み立てる

必要なデータを組み立ててJavaScriptに返すHTMLを組み立てます。
get_permalink($result->ID)を使っていることからもわかる通り、get系のテンプレートタグを用いればどんなデータでも取得できます。

フィルターを通す

テンプレートで抜粋を表示するテンプレートタグは the_excerpt() です。
これは posts.post_excerpt という生のデータが the_excerpt フィルターを通ることを意味します。
よって、the_excerpt フィルターを通して返します。

JavaScript

var now_post_num = 5; // 現在表示されている数
var get_post_num = 5; // 一度に取得する数

$(function() {
	$("#more_disp a").live("click", function() {
		
		$("#more_disp").html('<img class="ajax_loading" src="http://localhost/wordpress/wp-content/themes/ajax_loading/images/ajax_loader.gif" />');
		
		$.ajax({
			type: 'post',
			url: 'http://localhost/wordpress/wp-content/themes/ajax_loading/more-disp.php',
			data: {
				'now_post_num': now_post_num,
				'get_post_num': get_post_num
			},
			success: function(data) {
				now_post_num = now_post_num + get_post_num;
				$("#content").append(data);
				$("#more_disp").remove();
				$("#content").append('<div id="more_disp"><a href="#">もっと表示</a></div>');
			}
		});
		return false;
	});
});

事前にjQueryを読み込んでおきます。

ローディング画像

ajax_loader.gif は、Ajax通信中のローディング画像です。
なくても動作しますが、あった方がいいですね。

POSTするPHPファイルのパス

JavaScriptではWordPressのテンプレートタグは使えないので、絶対パスで記述します。

あとがき

サイトや記事の内容にもよりますが、ページングを設置してもクリックされる可能性はかなり低いと思います。
特にスマホで閲覧されることを考えると、ページ遷移を伴うページングはユーザビリティが低いと言わざるを得ません。
ということで、ページングをやめてAjaxによる非同期ローディングにするのは、非常に意味のあることだと思います。

読み込むデータがなくなったら「もっと表示」を非表示にする

※2013/10/11追記 あとでちゃんとコード整理します。。

> script.js

var now_post_num = 5; // 現在表示されている数
var get_post_num = 5; // 一度に取得する数

$(function() {
	$("#more_disp a").live("click", function() {
		
		$("#more_disp").html('<img class="ajax_loading" src="http://localhost/wordpress/wp-content/themes/ajax_loading/images/ajax_loader.gif" />');
		
		$.ajax({
			type: 'post',
			url: 'http://localhost/wordpress/wp-content/themes/ajax_loading/more-disp.php',
			data: {
				'now_post_num': now_post_num,
				'get_post_num': get_post_num
			},
			success: function(data) {
				now_post_num = now_post_num + get_post_num;
				data = JSON.parse(data);
				$("#content").append(data['html']);
				$("#more_disp").remove();
				if (!data['noDataFlg']) {
					$("#content").append('<div id="more_disp"><a href="#">もっと表示</a></div>');
				}
			}
		});
		return false;
	});
});

・戻り値をJSONで受け取る。
・第一引数は最後まで読み込んだかどうかフラグ、第二引数はHTMLデータ。

> more-disp.php

require_once("../../../wp-config.php");

$now_post_num = $_POST['now_post_num'];
$get_post_num = $_POST['get_post_num'];

$next_now_post_num = $now_post_num + $get_post_num;
$next_get_post_num = $get_post_num + $get_post_num; 

$sql = "SELECT
		$wpdb->posts.ID, 
		$wpdb->posts.post_title, 
		$wpdb->posts.post_excerpt 
	FROM 
		$wpdb->posts  
	WHERE 
		$wpdb->posts.post_type = 'post' AND $wpdb->posts.post_status = 'publish' 
	ORDER BY 
		$wpdb->posts.post_date DESC 
	LIMIT $now_post_num, $get_post_num";
		
$results = $wpdb->get_results($sql);

$sql = "SELECT
		$wpdb->posts.ID, 
		$wpdb->posts.post_title, 
		$wpdb->posts.post_content 
	FROM 
		$wpdb->posts  
	WHERE 
		$wpdb->posts.post_type = 'post' AND $wpdb->posts.post_status = 'publish' 
	ORDER BY 
		$wpdb->posts.post_date DESC 
	LIMIT $next_now_post_num, $next_get_post_num";

$next_results = $wpdb->get_results($sql);

$noDataFlg = 0;
if ( count($results) < $get_post_num || !count($next_results) ) {
	$noDataFlg = 1;
}

$html = "";

foreach ($results as $result) {
	$html .= '<article>';
	$html .= '<h2><a href="'.get_permalink($result->ID).'">'.apply_filters('the_title', $result->post_title).'</a></h2>';
	$html .= '<div class="excerpt">'.apply_filters('the_excerpt', $result->post_excerpt).'</div>';
	$html .= '</article>';
}

$returnObj = array();
$returnObj = array(
	'noDataFlg' => $noDataFlg,
	'html' => $html,
);
$returnObj = json_encode($returnObj);

echo $returnObj;

・いま取得したデータ数が取得件数より少ない、もしくは、次に取得されるデータ数がゼロ(ちょうどいま最後まで取得)の場合はフラグを立てる。
・第一引数をフラグ、第二引数をHTMLデータとしてJSON形式で戻す。