2026年9月26日
2026年9月26日
WordPressの遅延読み込みエラーを解決する方法
はじめに
WordPressサイトで画像にloading="lazy"が付いているのにスクロールしても読み込まれない・サードパーティの遅延読み込みプラグインを入れたら特定のスライダーで画像が表示されなくなった・JavaScriptコンソールにIntersectionObserver is not definedというエラーが出ている・iOSのSafariで遅延読み込みが動作せずページが真っ白になるといった問題は、ブラウザのネイティブlazy loadとJavaScriptベースの遅延読み込みの競合・古いブラウザ対応漏れ・above-the-fold(ファーストビュー)への誤適用が原因です。
症状・原因
- ファーストビュー(スクロールなしで見える範囲)の画像にも
loading="lazy"が付いてLCPが悪化している - JavaScriptの遅延読み込みプラグインとWordPressネイティブのlazy loadが二重に動作して競合している
- スライダープラグイン(Swiper、Slick)が初期化前に遅延読み込みで画像を隠してしまい表示されない
data-srcを使った遅延読み込みがCSSでdisplay:noneのタブ内の画像を読み込まない
解決手順
ステップ1:遅延読み込みの現状を診断する
# WP-CLIで遅延読み込み設定を確認
wp eval "
// ネイティブlazy loadの設定確認
echo 'wp_lazy_loading_enabled: ' . (apply_filters('wp_lazy_loading_enabled', true, 'img', 'the_content') ? 'true' : 'false') . PHP_EOL;
// アイキャッチ画像のloading属性確認
\$posts = get_posts(['posts_per_page' => 3]);
foreach (\$posts as \$post) {
\$thumb_id = get_post_thumbnail_id(\$post->ID);
if (\$thumb_id) {
\$img = wp_get_attachment_image(\$thumb_id, 'medium');
preg_match('/loading=[\"\'](.*?)[\"\']/', \$img, \$m);
echo \$post->post_title . ': loading=' . (\$m[1] ?? 'none') . PHP_EOL;
}
}
"
# アクティブな遅延読み込み関連プラグイン確認
wp plugin list --status=active --format=table | grep -i lazy
ステップ2:ネイティブlazy loadを正しく設定する
// functions.php: ネイティブlazy loadの最適化
// ① ファーストビューの画像にはeager(即時読み込み)を設定
add_filter('wp_get_attachment_image_attributes', function(array $attr, WP_Post $attachment, $size): array {
// アイキャッチ画像は通常ファーストビューにあるのでeagerに
if (is_singular() && $attachment->ID === get_post_thumbnail_id()) {
$attr['loading'] = 'eager';
$attr['fetchpriority'] = 'high';
} else {
$attr['loading'] = 'lazy';
$attr['decoding'] = 'async';
}
return $attr;
}, 10, 3);
// ② コンテンツ内の最初の画像はeagerに
add_filter('the_content', function(string $content): string {
static $first_image_found = false;
if ($first_image_found) {
return $content;
}
// 最初のimgタグのloading=lazyをeagerに変更
$content = preg_replace_callback(
'/<img([^>]*loading=["\']lazy["\'][^>]*)>/i',
function(array $m) use (&$first_image_found): string {
if ($first_image_found) {
return $m[0];
}
$first_image_found = true;
return '<img' . str_replace('loading="lazy"', 'loading="eager"', $m[1]) . '>';
},
$content
);
return $content;
});
// ③ 管理画面では無効化
add_filter('wp_lazy_loading_enabled', function(bool $default, string $tag_name, string $context): bool {
if (is_admin()) {
return false;
}
return $default;
}, 10, 3);
ステップ3:JavaScriptベースの遅延読み込みを実装する
// assets/js/lazy-load.js: IntersectionObserver を使った安全な遅延読み込み
(function() {
'use strict';
// IntersectionObserver非対応ブラウザへのフォールバック
if (!('IntersectionObserver' in window)) {
// 全画像を即座に読み込む
document.querySelectorAll('img[data-src]').forEach(function(img) {
img.src = img.dataset.src;
if (img.dataset.srcset) {
img.srcset = img.dataset.srcset;
}
});
return;
}
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (!entry.isIntersecting) return;
var img = entry.target;
// data-srcからsrcに切り替え
if (img.dataset.src) {
img.src = img.dataset.src;
delete img.dataset.src;
}
if (img.dataset.srcset) {
img.srcset = img.dataset.srcset;
delete img.dataset.srcset;
}
img.classList.add('loaded');
observer.unobserve(img);
});
}, {
rootMargin: '200px 0px', // 200px手前から読み込み開始
threshold: 0
});
// 遅延読み込み対象の画像を監視
document.querySelectorAll('img[data-src]').forEach(function(img) {
observer.observe(img);
});
})();
// functions.php: 遅延読み込みJSを登録
add_action('wp_enqueue_scripts', function(): void {
wp_enqueue_script(
'lazy-load',
get_theme_file_uri('assets/js/lazy-load.js'),
[],
'1.0.0',
true // フッターに出力
);
});
// コンテンツのimgをdata-src形式に変換(JSベースの場合)
add_filter('the_content', function(string $content): string {
return preg_replace_callback(
'/<img([^>]*)src=["\']([^"\']+)["\']([^>]*)>/i',
function(array $m): string {
// ファーストビュー画像はスキップ
if (str_contains($m[1] . $m[3], 'fetchpriority="high"')) {
return $m[0];
}
$attrs = $m[1] . ' data-src="' . $m[2] . '"' . $m[3];
return '<img' . $attrs . '>';
},
$content
);
});
ステップ4:スライダーとタブの競合を解決する
// functions.php: スライダー・タブ内の画像を除外
// ① スライダープラグインの画像は遅延読み込みから除外
add_filter('wp_lazy_loading_enabled', function(bool $enabled, string $tag): bool {
// スライダーのコンテキストでは無効化
if (doing_filter('the_content') && isset($GLOBALS['_wp_lazy_load_skip'])) {
return false;
}
return $enabled;
}, 10, 2);
// ② タブ・アコーディオン内の画像はロード後に監視を再実行
add_action('wp_footer', function(): void {
?>
<script>
// タブ切り替え時に遅延読み込みを再トリガー
document.addEventListener('tab-changed', function(e) {
var panel = e.detail && e.detail.panel;
if (!panel) return;
panel.querySelectorAll('img[data-src]').forEach(function(img) {
img.src = img.dataset.src;
img.removeAttribute('data-src');
});
});
// display:none から表示されたときのCSSアニメーション
var style = document.createElement('style');
style.textContent = 'img.loaded { animation: fadeIn 0.3s ease; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }';
document.head.appendChild(style);
</script>
<?php
});
ステップ5:背景画像とiframeの遅延読み込みを実装する
// functions.php: 背景画像とiframeの遅延読み込み
// ① iframe(YouTube埋め込み)を遅延読み込み
add_filter('the_content', function(string $content): string {
return preg_replace_callback(
'/<iframe([^>]*src=["\'][^"\']*youtube[^"\']*["\'][^>]*)>/i',
function(array $m): string {
// loading="lazy"がなければ追加
if (!str_contains($m[1], 'loading=')) {
return '<iframe' . $m[1] . ' loading="lazy">';
}
return $m[0];
},
$content
);
});
// ② CSS背景画像を遅延読み込み(data-bg属性を使用)
add_action('wp_footer', function(): void {
?>
<script>
if ('IntersectionObserver' in window) {
var bgObserver = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (!entry.isIntersecting) return;
var el = entry.target;
if (el.dataset.bg) {
el.style.backgroundImage = 'url(' + el.dataset.bg + ')';
el.removeAttribute('data-bg');
bgObserver.unobserve(el);
}
});
}, { rootMargin: '100px' });
document.querySelectorAll('[data-bg]').forEach(function(el) {
bgObserver.observe(el);
});
}
</script>
<?php
});
# Chrome DevToolsでlazy loadの動作確認
# Network タブ → Img フィルター → スクロール時に読み込まれることを確認
# Lighthouse でLCPのlazy load誤適用を検出
# "Largest Contentful Paint image was lazily loaded" 警告が出ていないか確認
wp eval "
// ファーストビューの画像リスト(参考用)
\$thumb_ids = [];
\$posts = get_posts(['posts_per_page' => 5]);
foreach (\$posts as \$p) {
\$id = get_post_thumbnail_id(\$p->ID);
if (\$id) echo wp_get_attachment_url(\$id) . PHP_EOL;
}
"
注意事項
- ファーストビュー(above-the-fold)に表示される画像に
loading="lazy"を設定するとLCPスコアが悪化します。Lighthouseの「Largest Contentful Paint element」で特定してeagerまたはfetchpriority="high"を設定してください IntersectionObserverはIE11で未対応です。必要に応じてpolyfillを追加するか、未対応ブラウザでは全画像を即時読み込みするフォールバックを実装してください- WordPressのネイティブlazy loadとJavaScriptベースの遅延読み込みプラグインを同時に使うと二重処理になります。どちらかに統一することをお勧めします
まとめ
WordPress遅延読み込みエラーの解決は①wp_lazy_loading_enabledフィルターで設定確認・アクティブプラグインの競合チェック・ファーストビュー画像のloading属性確認、②アイキャッチ画像をloading=eager+fetchpriority=highに・コンテンツ内最初の画像をeagerに変更・管理画面では無効化、③IntersectionObserverでdata-src→srcの切り替えを実装・非対応ブラウザは全画像即時読み込み・rootMargin:200pxで早めに読み込み開始、④スライダー・タブ内の画像はlazy load除外・tab-changedイベントで表示時に読み込みを再実行・fadeInアニメーションで自然な表示、⑤YouTubeなどiframeにloading=lazy追加・CSS背景画像はdata-bg属性+IntersectionObserverで遅延読み込みの手順で解決します。