WordPress RSS表示の高速化(LazyLoad対応) | OFFのパソコン日記

WordPress RSS表示の高速化(LazyLoad対応)

ある団体のホームページ(Cocoonテーマを使用したWordPressサイト)を運営しています。

このサイトでは、複数のRSS情報を統合表示しています。
従来はページ表示時にRSS取得処理を同時実行していたため、WordPressのRSSキャッシュ更新タイミングでは、表示まで約15秒程度かかり、その間はなにも表示されない画面となっていました。

この問題を改善するため、RSS表示を「LazyLoad(遅延読み込み)」方式へ変更しました。

■ 変更前の動作

  1. ページ表示開始
  2. WordPressがRSS取得
  3. RSS生成完了後にページ表示

この方式では、RSS取得中にページ全体の表示が待たされる場合がありました。

■ 変更後(LazyLoad)の動作

  1. 先にページ本体を表示
  2. JavaScript が実行
  3. admin-ajax.php 経由でRSSを非同期取得
  4. RSS取得後に該当部分へ表示

これにより、

  • ページの初期表示速度向上
  • RSS更新時の無表示時間を軽減
  • ユーザー体感速度の改善

を実現しています。

■ 処理イメージ
ページ表示

JavaScript 実行

admin-ajax.php にRSS取得要求

WordPress がRSS HTML生成

ページへ差し込み表示

■ LazyLoad 対応コード

① ショートコード:HTML を作らず、プレースホルダーだけ返す(functions.php)

// ------------------------------------------------------------
// LazyLoad 用ショートコード
// ここでは RSS の HTML を作らず、空の div(プレースホルダー)だけ返す
// ------------------------------------------------------------

    add_shortcode('rss_merge', function($atts) {
    // ショートコードの初期値
    $atts = shortcode_atts([
    'url'   => '',
    'count' => 5,
    'cache_minute' => 60,
    ], $atts, 'rss_merge');

    // URL が無ければ何も表示しない
    if (empty($atts['url'])) {
    return '';
    }
    // Ajax で識別するための一意 ID を生成
    $id = 'rss_merge_' . md5(json_encode($atts));
    // Ajax 側で使うため、ショートコードの属性を一時保存
    set_transient($id . '_atts', $atts, 60 * 60);
    // ページには RSS の HTML を出さず、空の div だけ返す
    return '<div class="rss-merge-lazy" data-id="' . esc_attr($id) . '">読み込み中...</div>';
});

② Ajax フック:RSS を取得して HTML を返す(functions.php)

// ------------------------------------------------------------
// Ajax フック登録(ログイン・非ログイン両方対応)
// admin-ajax.php?action=rss_merge_load が呼ばれると実行される
// ------------------------------------------------------------

    add_action('wp_ajax_rss_merge_load', 'rss_merge_load');
    add_action('wp_ajax_nopriv_rss_merge_load', 'rss_merge_load');

    function rss_merge_load() {

    // JavaScript から送られた ID を取得
    $id = sanitize_text_field($_GET['id'] ?? '');
    if (!$id) wp_die();

    // ショートコードで保存した属性を取得
    $atts = get_transient($id . '_atts');
    if (!$atts) wp_die('No data');

// ------------------------------------------------------------
// ここに元の RSS 取得処理をそのまま移植
// (fetch_feed → items → ソート → HTML生成)
// ------------------------------------------------------------

echo $feed_contents; // 生成した HTML を返す
wp_die(); // Ajax 終了
}

③ JavaScript に admin-ajax.php の URL を渡す(functions.php)

// ------------------------------------------------------------
// javascript.js を読み込み、admin-ajax.php の URL を JS に渡す
// ------------------------------------------------------------

    function rss_merge_enqueue_js() {

    // javascript.js を読み込む
    wp_enqueue_script(
    'rss-merge-js',
    get_stylesheet_directory_uri() . '/javascript.js',
    [],
    null,
    true // フッターで読み込む
  );

    // admin-ajax.php の URL を JS に渡す
    wp_localize_script('rss-merge-js', 'rssMergeAjax', [
    'url' => admin_url('admin-ajax.php'),
  ]);
}
add_action('wp_enqueue_scripts', 'rss_merge_enqueue_js');

④ JavaScript:ページ読み込み後に Ajax を実行(javascript.js)

// ------------------------------------------------------------
// ページ読み込み後に実行
// プレースホルダー(.rss-merge-lazy)を探し、Ajax で RSS を取得する
// ------------------------------------------------------------

    document.addEventListener("DOMContentLoaded", function() {

    // すべてのプレースホルダーを取得
    document.querySelectorAll(".rss-merge-lazy").forEach(function(box) {

    // data-id 属性から Ajax 用の ID を取得
    const id = box.dataset.id;

    // WordPress の admin-ajax.php に RSS を要求
    fetch(rssMergeAjax.url + "?action=rss_merge_load&id=" + id)

    // WordPress が返した HTML をテキストとして受け取る
    .then(res => res.text())

    // プレースホルダーの中身を RSS の HTML に置き換える
    .then(html => {
      box.innerHTML = html;
    });
  });
});