2026年5月20日

2026年5月20日

WordPressのCore Web Vitalsを改善する方法

はじめに

Core Web Vitals(CWV)はGoogleが定めるユーザー体験の品質指標で、2021年以降Googleの検索ランキング要因の一つです。LCP(最大コンテンツフル描画)・CLS(累積レイアウトシフト)・INP(次のペイントまでのインタラクション)の3指標すべてを「良好」にすることが目標です。

症状・原因

  • Google Search ConsoleのCore Web Vitalsレポートで「不良」「改善が必要」が表示される
  • LCPが2.5秒を超えている(主な原因:画像の遅延読み込み、サーバーレスポンス遅延)
  • CLSが0.1を超えている(主な原因:画像のサイズ未指定、広告の動的挿入)
  • INPが200msを超えている(主な原因:重いJavaScript処理、サードパーティスクリプト)

解決手順

ステップ1:現状をSearch Consoleで確認する

確認手順:
1. Search Console → 「エクスペリエンス」→「ウェブに関する主な指標」
2. 「不良なURL」「改善が必要なURL」をクリックして対象ページを特定
3. 「URLの詳細を開く」でPageSpeed Insightsの詳細レポートを確認

指標の基準:
  LCP: 良好 ≤ 2.5秒 / 要改善 ≤ 4.0秒 / 不良 > 4.0秒
  CLS: 良好 ≤ 0.1  / 要改善 ≤ 0.25  / 不良 > 0.25
  INP: 良好 ≤ 200ms / 要改善 ≤ 500ms / 不良 > 500ms

ステップ2:LCPを改善する

// functions.php: LCP要素(アイキャッチ)の優先読み込み

add_action('wp_head', function (): void {
    if (!is_singular() || !has_post_thumbnail()) {
        return;
    }
    // srcset対応のpreload(レスポンシブ画像)
    $id   = get_post_thumbnail_id();
    $meta = wp_get_attachment_metadata($id);
    $src  = wp_get_attachment_image_src($id, 'large');
    if (!$src) {
        return;
    }
    $srcset = wp_get_attachment_image_srcset($id, 'large');
    $sizes  = wp_get_attachment_image_sizes($id, 'large');

    $tag = '<link rel="preload" as="image" href="' . esc_url($src[0]) . '"';
    if ($srcset) {
        $tag .= ' imagesrcset="' . esc_attr($srcset) . '"';
    }
    if ($sizes) {
        $tag .= ' imagesizes="' . esc_attr($sizes) . '"';
    }
    $tag .= ">\n";
    echo $tag;
}, 1);

// TTFBを改善: wp-config.phpでオブジェクトキャッシュを有効化
// define('WP_CACHE', true); // キャッシュプラグイン必須

ステップ3:CLSを改善する

// functions.php: 画像に width/height を必ず付与する

// WordPressはwp_get_attachment_image()で自動付与するが、
// the_content内の画像はフィルターで確認
add_filter('the_content', function (string $content): string {
    // wp_filter_content_tags() がWP5.5+で自動的にwidth/heightを付与
    // 手動img要素への対処
    $content = preg_replace_callback(
        '/<img([^>]+)>/i',
        function (array $matches): string {
            $img = $matches[0];
            // すでに width/height がある場合はスキップ
            if (preg_match('/width=/i', $img) && preg_match('/height=/i', $img)) {
                return $img;
            }
            // srcからIDを取得してメタデータで補完
            if (preg_match('/class="[^"]*wp-image-(\d+)[^"]*"/i', $img, $m)) {
                $meta = wp_get_attachment_metadata((int) $m[1]);
                if ($meta && !empty($meta['width']) && !empty($meta['height'])) {
                    $img = str_replace('<img', '<img width="' . $meta['width'] . '" height="' . $meta['height'] . '"', $img);
                }
            }
            return $img;
        },
        $content
    );
    return $content;
});
/* style.css: CLS防止CSS */

/* 動的コンテンツ(広告・埋め込み)の領域確保 */
.ad-slot {
    min-height: 90px;  /* バナー広告の最小高さ */
    contain: layout;   /* レイアウト計算をコンテナ内に閉じ込める */
}

/* iframe(YouTube等)のアスペクト比 */
.embed-container {
    position: relative;
    aspect-ratio: 16 / 9;
}
.embed-container iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

/* Webフォントの切替によるCLS防止 */
@font-face {
    font-family: 'MyFont';
    src: url('/fonts/myfont.woff2') format('woff2');
    font-display: optional; /* フォントが遅い場合はフォールバックフォントを維持 */
    size-adjust: 105%;      /* フォントサイズを調整してCLSを最小化 */
}

ステップ4:INPを改善する

// functions.php: 重いサードパーティスクリプトを遅延読み込み

// GTM(Googleタグマネージャー)をユーザー操作後に遅延読み込み
add_action('wp_footer', function (): void {
    $gtm_id = 'GTM-XXXXXXX';
    ?>
    <script>
    // ユーザーが操作するまでGTMの読み込みを遅延
    (function() {
        var loaded = false;
        function loadGTM() {
            if (loaded) return;
            loaded = true;
            (function(w,d,s,l,i){
                w[l]=w[l]||[];
                w[l].push({'gtm.start': new Date().getTime(), event:'gtm.js'});
                var f=d.getElementsByTagName(s)[0],
                    j=d.createElement(s), dl=l!='dataLayer'?'&l='+l:'';
                j.async=true;
                j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
                f.parentNode.insertBefore(j,f);
            })(window,document,'script','dataLayer','<?php echo esc_js($gtm_id); ?>');
        }
        // スクロール・マウス移動・タッチで読み込み
        ['scroll','mousemove','touchstart','keydown'].forEach(function(e) {
            window.addEventListener(e, loadGTM, {once: true, passive: true});
        });
        // 5秒後に強制読み込み
        setTimeout(loadGTM, 5000);
    })();
    </script>
    <?php
});

ステップ5:Web Vitals APIでリアルユーザー計測する

// テーマのfooter.phpまたはカスタムJSファイルに追加

// web-vitals ライブラリを使ってリアルユーザーのCWVを計測
import { onLCP, onCLS, onINP } from 'web-vitals';

function sendToAnalytics(metric) {
    // Google Analytics 4 にイベント送信
    gtag('event', metric.name, {
        value: Math.round(metric.name === 'CLS' ? metric.value * 1000 : metric.value),
        metric_id: metric.id,
        metric_value: metric.value,
        metric_delta: metric.delta,
    });
}

onLCP(sendToAnalytics);
onCLS(sendToAnalytics);
onINP(sendToAnalytics);

注意事項

  • CWVのフィールドデータ(実ユーザー計測)は28日間の集計です。改善後のスコア反映には最大28日かかります
  • INP(旧FID)はJavaScriptの実行時間に依存します。プラグインを減らし、不要なJSを削除することが最も効果的です
  • CLSはフォント読み込みでも発生します。font-display: optional を使うとフォント切替によるレイアウトシフトが完全に防止できます

まとめ

LCPはアイキャッチ画像のrel="preload"imagesrcset付きpreloadで改善します。CLSは画像へのwidth/height付与・広告スロットのmin-height確保・font-display: optionalで防ぎます。INPは重いサードパーティスクリプトをユーザー操作後に遅延読み込みすることで改善します。

お気軽にご相談ください

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