はじめに
以前の記事では、ボタンをクリックする度にAjax通信を行って表示件数を動的に増やす方法を紹介しました。
今回はこの方法をさらに発展させ、スクロール操作と連動させて自動で表示件数を増やす(無限スクロール化)カスタマイズを行います。
ユーザーがボタンを押す手間を無くし、よりシームレスにコンテンツを閲覧できるようになります。
この記事では、この方法について説明します。
完成イメージ
実装手順
以下の手順で実装します。
- ラベルGutenbergエディターでの設定
「新着記事」ブロックを配置し、表示する記事の数を3とします。
- ラベルPHPを追加
以下のコードをfunctions.phpに追加します。
/** * Ajaxコールバック関数 * * @return void */ if (!function_exists('update_shortcode_callback')): function update_shortcode_callback() { if (!session_id() && !headers_sent()) { session_start(); } // セッションから保存済みの属性配列を取得 $saved_atts = isset($_SESSION['new_list_atts']) && is_array($_SESSION['new_list_atts']) ? $_SESSION['new_list_atts'] : array(); // 追加件数を設定 $add_count = 3; // 現在の件数を取得して加算 $new_count = intval(isset($saved_atts['entry_count']) ? $saved_atts['entry_count'] : 0) + $add_count; // セッションの保持件数を変更 $_SESSION['new_list_atts']['entry_count'] = $new_count; // ショートコード属性用の配列を設定 $shortcode_atts = $saved_atts; // 属性名を変更 $shortcode_atts['count'] = $new_count; unset($shortcode_atts['entry_count']); // パラメータ文字列を構築 $attr_str = ''; foreach ($shortcode_atts as $key => $value) { if (is_array($value)) { // 配列をカンマ区切り文字列へ置換 $value = implode(',', $value); } elseif (is_object($value) || is_null($value)) { // オブジェクトまたはNULLを処理対象外 continue; } $attr_str .= ' ' . sanitize_key($key) . '="' . esc_attr($value) . '"'; } // Ajax実行時の予約記事の混入を防止 $force_publish_status = function ($query) { if (wp_doing_ajax()) { $query->set('post_status', 'publish'); } }; add_action('pre_get_posts', $force_publish_status, 999); // ショートコードを実行して出力 $shortcode = '[new_list' . $attr_str . ']'; echo do_shortcode($shortcode); // 処理後にフィルターを解除 remove_action('pre_get_posts', $force_publish_status, 999); wp_die(); } endif; // 新着記事の属性を設定 add_filter('shortcode_atts_generate_widget_entries_tag', function ($out, $pairs, $atts) { if (!session_id() && !headers_sent()) { session_start(); } // 設定値をセッションへ記録 if (!wp_doing_ajax()) { $_SESSION['new_list_atts'] = is_array($out) ? $out : array(); } return $out; }, 10, 3); // フロント用JS・CSSを追加 add_action('wp_enqueue_scripts', function () { $url = admin_url('admin-ajax.php'); ob_start(); ?> jQuery(function ($) { // 新着記事一覧の要素を取得 var container = $('.new-list-box'); // 新着記事一覧が存在しない場合は処理を終了 if (!container.length) { return; } // Ajax通信中かどうかを設定 var isLoading = false; // これ以上読み込む記事がないかどうかを設定 var finished = false; // 読み込みを開始する画面上端からの距離を設定 var triggerOffset = 200; // 次回の読み込みを許可する状態を設定 var canTrigger = true; // スクロール処理の実行待ち状態を設定 var ticking = false; /** * 追加データの読み込みを実行 * * @returns {void} */ function loadMore() { // Ajax通信中、読み込み完了済み、または再発火禁止中の場合は処理を終了 if (isLoading || finished || !canTrigger) { return; } // 次回の読み込みを禁止 canTrigger = false; // Ajax通信中の状態を設定 isLoading = true; $.ajax({ type: 'POST', url: '<?php echo esc_url($url); ?>', data: { action: 'update_shortcode' }, success: function (response) { // 取得結果が空かどうかを確認 if ($.trim(response) === '') { // これ以上データが無いため処理を終了 finished = true; } else { // 新着記事一覧を取得結果へ置換 container.html(response); } }, // Ajax通信完了後の処理を設定 complete: function () { // Ajax通信中の状態を解除 isLoading = false; // Ajax完了後の位置を確認 checkPosition(); } }); } /** * リストの位置を確認 * * @returns {void} */ function checkPosition() { // 読み込み完了済みの場合は処理を終了 if (finished) { return; } // 新着記事一覧の位置とサイズを取得 var rect = container[0].getBoundingClientRect(); // 最下部が200pxより下側に戻ったことを確認 if (rect.bottom > triggerOffset) { // 次回の読み込みを許可 canTrigger = true; } // Ajax通信中または次回の読み込みが禁止されている場合は処理を終了 if (isLoading || !canTrigger) { return; } // 新着記事一覧の最下部が画面上端から200px以内か確認 if (rect.bottom <= triggerOffset) { // 追加データの読み込みを実行 loadMore(); } } /** * スクロールイベントを処理 * * @returns {void} */ function onScroll() { // 前回のスクロール処理が実行待ちの場合は処理を終了 if (ticking) { return; } // スクロール処理の実行待ち状態を設定 ticking = true; // 次の描画タイミングで位置を確認 window.requestAnimationFrame(function () { // 新着記事一覧の位置を確認 checkPosition(); // スクロール処理の実行待ち状態を解除 ticking = false; }); } // スクロールイベントを登録 $(window).on('scroll', onScroll); // 初期表示時にも位置を確認 checkPosition(); }); <?php wp_add_inline_script('jquery', ob_get_clean(), 'after'); }); // Ajaxアクションを追加 add_action('wp_ajax_update_shortcode', 'update_shortcode_callback'); add_action('wp_ajax_nopriv_update_shortcode', 'update_shortcode_callback');
さいごに
今回紹介した方法を使えば、「新着記事」ブロックにシームレスな無限スクロール機能を簡単に導入できます。
ユーザーがボタンをクリックする手間を抑え、ストレスのないスムーズな記事閲覧体験を提供できるようになりますので、サイトの回遊率アップや利便性向上にぜひ役立ててみてください。


