2026年5月20日

2026年5月20日

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

はじめに

無限スクロールは、ページ下部に到達したときに自動で次の記事を追加読み込みする機能です。ページネーションなしに記事を連続して閲覧できます。WordPress REST APIとIntersection Observerを組み合わせることでパフォーマンス良く実装できます。

症状・原因

  • 記事一覧で「次のページへ」ボタンをなくして自動読み込みしたい
  • スクロールしたら続きの記事が自動で表示されるようにしたい
  • REST APIを使って非同期で記事を追加したい
  • 無限スクロールとSEOを両立したい

解決手順

ステップ1:REST APIエンドポイントの確認

# WordPress REST API で記事を取得(ページネーション対応)
# https://example.com/wp-json/wp/v2/posts?per_page=10&page=2&_embed

wp eval "echo rest_url('wp/v2/posts');"
# → https://example.com/wp-json/wp/v2/posts

ステップ2:JavaScriptで無限スクロール実装

// functions.php — スクリプトにデータを渡す
add_action('wp_enqueue_scripts', function(): void {
    if (!is_home() && !is_archive()) return;

    wp_enqueue_script(
        'infinite-scroll',
        get_template_directory_uri() . '/js/infinite-scroll.js',
        [],
        filemtime(get_template_directory() . '/js/infinite-scroll.js'),
        true
    );

    global $wp_query;
    wp_localize_script('infinite-scroll', 'InfiniteScrollData', [
        'restUrl'   => esc_url_raw(rest_url('wp/v2/posts')),
        'nonce'     => wp_create_nonce('wp_rest'),
        'perPage'   => (int) get_option('posts_per_page'),
        'maxPages'  => (int) $wp_query->max_num_pages,
        'currentPage' => 1,
    ]);
});
// js/infinite-scroll.js
(function() {
    const container = document.querySelector('.posts-container');
    const sentinel  = document.querySelector('.infinite-scroll-sentinel');
    if (!container || !sentinel) return;

    let page     = parseInt(InfiniteScrollData.currentPage);
    let loading  = false;
    const maxPages = parseInt(InfiniteScrollData.maxPages);

    async function loadMore() {
        if (loading || page >= maxPages) return;
        loading = true;
        page++;

        try {
            const res = await fetch(
                `${InfiniteScrollData.restUrl}?per_page=${InfiniteScrollData.perPage}&page=${page}&_embed`,
                { headers: { 'X-WP-Nonce': InfiniteScrollData.nonce } }
            );
            const posts = await res.json();

            posts.forEach(function(post) {
                const article = document.createElement('article');
                article.className = 'post-card';
                const img = post._embedded?.['wp:featuredmedia']?.[0]?.source_url ?? '';
                article.innerHTML = `
                    ${img ? `<img src="${img}" alt="${post.title.rendered}">` : ''}
                    <h2><a href="${post.link}">${post.title.rendered}</a></h2>
                    <div>${post.excerpt.rendered}</div>
                `;
                container.appendChild(article);
            });

            if (page >= maxPages) observer.disconnect();
        } catch(e) {
            page--;
        } finally {
            loading = false;
        }
    }

    // ページ最下部(センチネル要素)を監視
    const observer = new IntersectionObserver(function(entries) {
        if (entries[0].isIntersecting) loadMore();
    }, { rootMargin: '200px' });

    observer.observe(sentinel);
})();

ステップ3:テンプレートにセンチネル要素を追加

// index.php または archive.php
<div class="posts-container">
    <?php while (have_posts()): the_post(); ?>
    <article class="post-card">
        <?php the_post_thumbnail('medium'); ?>
        <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
        <?php the_excerpt(); ?>
    </article>
    <?php endwhile; ?>
</div>

<!-- 画面外に置く番兵要素(IntersectionObserverのターゲット) -->
<div class="infinite-scroll-sentinel" aria-hidden="true"></div>

ステップ4:プラグインで手軽に実装する

# Jetpack の無限スクロールを有効化
wp plugin install jetpack --activate
# 設定 → パフォーマンス → 無限スクロール を有効化
// functions.php — テーマでJetpack無限スクロールをサポート
add_theme_support('infinite-scroll', [
    'container' => 'main',
    'render'    => function(): void {
        while (have_posts()): the_post();
            get_template_part('template-parts/content', get_post_type());
        endwhile;
    },
    'footer'    => 'page',
]);

注意事項

  • 無限スクロールはSEOに不利になる場合があります。Googlebotは自動スクロールしないため、後から追加される記事がインデックスされにくい場合があります。SEOを重視する場合はページネーションと共存させるか、rel="next" リンクを維持してください
  • REST APIへのリクエストには wp_create_nonce('wp_rest') を使ってnonceを付与し、CSRF攻撃を防いでください
  • rootMargin: '200px' で画面下200px手前から先読みを開始することで、ユーザーが下端に到達する前にコンテンツを表示できます

まとめ

無限スクロールはIntersection Observerで .infinite-scroll-sentinel 要素を監視し、ビューポートに入ったらREST API (/wp/v2/posts?page=N) でJSONを取得してDOMに追加します。wp_localize_scriptmaxPagesrestUrl をPHPからJSに渡します。

お気軽にご相談ください

お見積りへ お問い合わせへ