2026年9月28日
2026年9月28日
WordPressテーマでWebPのフォールバックを実装する方法|picture要素とCore Web Vitals
WebP に対応していないブラウザには JPEG や PNG を渡し、対応しているブラウザには WebP を渡す仕組みは、テーマ側では <picture> 要素で実装するのが分かりやすい方法です。この記事では、WebP が Core Web Vitals のどこに効くのかを整理したうえで、テーマのテンプレートで使える <picture> 出力関数、CSS 背景画像のフォールバック、サーバー側で切り替える方法の注意点、効果の確かめ方までを説明します。
先に前提を確認しておきます。WordPress は 5.8 で WebP 画像のアップロードに対応し、主要なブラウザも現在は WebP を表示できます(2026年10月時点)。そのためフォールバックが必要になるのは、古い Safari や更新されていない端末など一部の環境です。「フォールバックを入れたからスコアが上がる」のではなく、「WebP で軽くした画像を、表示できない環境でも壊さずに配信する」ための仕組みだと考えてください。
WebP が Core Web Vitals に効く場所
Core Web Vitals の3指標のうち、画像形式の変更が直接関わるのは主に LCP(Largest Contentful Paint)です。ファーストビューの大きな画像が LCP 要素になっているページでは、画像のファイルサイズが小さくなるほどダウンロードが早く終わり、LCP が短くなる可能性があります。
CLS(レイアウトのずれ)は画像形式ではなく、width と height 属性の有無で決まります。INP(操作への応答性)は主に JavaScript の問題で、画像形式とはほぼ関係ありません。WebP 化と同時に、幅・高さの指定と LCP 画像の読み込み方も見直すと、効果が出やすくなります。
なお、Core Web Vitals の数値を改善しても、検索順位が上がることを約束するものではありません。表示が速くなることで訪問者が快適に読めるようにする、という目的で取り組むのが現実的です。
WebP ファイルを用意する方法を決める
フォールバックを組むには、同じ画像の JPEG(または PNG)版と WebP 版の両方がサーバー上に必要です。用意の方法によって、WebP のファイル名と、JPEG 版が残るかどうかが変わります。
| 方法 | WebP のファイル名の例 | JPEG 版の生成サイズ |
|---|---|---|
EWWW Image Optimizer など(元の名前に .webp を付け足す方式) |
photo-800x600.jpg.webp |
残る |
| 拡張子を置き換える方式のツール | photo-800x600.webp |
残る |
| Modern Image Formats(WordPress のパフォーマンスチームのプラグイン) | プラグインが決めた名前を添付ファイルのメタデータに記録 | 既定では作られない(設定で作れる) |
image_editor_output_format フィルター |
生成サイズそのものが WebP になる | 作られない |
Modern Image Formats を使う場合
「Modern Image Formats」は、アップロード時に WebP や AVIF の画像を生成するプラグインです(2026年10月時点のバージョン 2.7.1 は WordPress 6.9 以上が必要)。サーバーが AVIF に対応していれば AVIF、そうでなければ WebP が既定の形式になり、「設定」→「メディア」の「Modern Image Formats」の項目で形式を選べます。
既定では、元のファイルだけが JPEG/PNG のまま残り、サムネイルなどの生成サイズは WebP/AVIF だけになります。同じ画面の Output fallback images をオンにすると、生成サイズも元の形式と両方作られます(設定変更後にアップロードした画像から)。また、このプラグインにはバージョン 2.0.0 から <picture> 要素で出力する機能もあります。このプラグインを使う場合は、次の自作の関数ではなく、プラグインの設定で <picture> 出力とフォールバックを有効にするほうが、ファイル名やメタデータとの食い違いが起きません。
WordPress の生成サイズを WebP にする場合
WordPress 5.8 以降には image_editor_output_format フィルターがあり、サムネイルなど自動生成されるサイズの出力形式を変えられます。
<?php
// 子テーマの functions.php:JPEG をアップロードしたとき、生成サイズを WebP で作る
add_filter( 'image_editor_output_format', function ( $formats ) {
$formats['image/jpeg'] = 'image/webp';
return $formats;
} );
この方法では生成サイズが WebP に置き換わり、JPEG 版の生成サイズは作られません。つまりフォールバック用のファイルが残らないため、古い環境への配慮が必要なサイトでは、両方を残せる方法のほうが向いています。
どの方法でも、サーバーの画像処理ライブラリ(GD または Imagick)が WebP に対応していないと生成できません。「ツール」→「サイトヘルス」→「情報」の「メディア処理」の項目で対応状況を確認できます。
テーマで <picture> を出力する関数
ここでは、WebP 版が元画像と同じフォルダーにあり、ファイル名が「元の名前に .webp を付け足す方式」(photo-800x600.jpg.webp)か「拡張子を置き換える方式」(photo-800x600.webp)のどちらかである場合に使える関数を作ります。srcset のすべての候補に WebP 版がそろっているときだけ <source> を付け、1つでも欠けていれば従来の <img> だけを返します。
拡張子を置き換える方式は、同じフォルダーに photo.jpg と photo.png があると、どちらも photo.webp になり区別できません。そのため、付け足す方式を先に調べています。
<?php
// 子テーマの functions.php
/**
* アップロードフォルダー内の JPEG/PNG の URL から、対応する WebP の URL を返す。
* 見つからなければ空文字を返す。
*/
function mytheme_webp_url( $url ) {
$uploads = wp_get_upload_dir();
// http と https の違いを無視して比べる
$base = preg_replace( '#^https?:#i', '', $uploads['baseurl'] );
$rel = preg_replace( '#^https?:#i', '', $url );
if ( 0 !== strpos( $rel, $base ) || ! preg_match( '/\.(jpe?g|png)$/i', $rel ) ) {
return '';
}
$file = $uploads['basedir'] . substr( $rel, strlen( $base ) );
// 1. 付け足す方式: photo.jpg → photo.jpg.webp
if ( file_exists( $file . '.webp' ) ) {
return $url . '.webp';
}
// 2. 置き換える方式: photo.jpg → photo.webp
$replaced_file = preg_replace( '/\.(jpe?g|png)$/i', '.webp', $file );
if ( file_exists( $replaced_file ) ) {
return preg_replace( '/\.(jpe?g|png)$/i', '.webp', $url );
}
return '';
}
/**
* 添付画像を <picture> で出力する。WebP 版がそろわなければ通常の <img> を返す。
*/
function mytheme_picture( $attachment_id, $size = 'large', $attr = array() ) {
$img = wp_get_attachment_image( $attachment_id, $size, false, $attr );
if ( ! $img ) {
return '';
}
$srcset = wp_get_attachment_image_srcset( $attachment_id, $size );
if ( ! $srcset ) {
$srcset = wp_get_attachment_image_url( $attachment_id, $size ) . ' 1x';
}
$webp = array();
foreach ( array_map( 'trim', explode( ',', $srcset ) ) as $candidate ) {
$parts = preg_split( '/\s+/', $candidate, 2 );
$webp_url = mytheme_webp_url( $parts[0] );
if ( '' === $webp_url ) {
return $img; // 1つでも欠けていれば WebP を使わず従来の img だけを返す
}
$webp[] = $webp_url . ( isset( $parts[1] ) ? ' ' . $parts[1] : '' );
}
$sizes = wp_get_attachment_image_sizes( $attachment_id, $size );
return sprintf(
'<picture><source type="image/webp" srcset="%s"%s>%s</picture>',
esc_attr( implode( ', ', $webp ) ),
$sizes ? ' sizes="' . esc_attr( $sizes ) . '"' : '',
$img
);
}
テンプレートでは次のように使います。wp_get_attachment_image() が出力する <img> は、WordPress が組み立てて属性をエスケープ済みの HTML です。
<?php
// single.php などで、アイキャッチを LCP 候補として読み込む例
if ( has_post_thumbnail() ) {
echo mytheme_picture(
get_post_thumbnail_id(),
'large',
array(
'loading' => 'eager',
'fetchpriority' => 'high',
)
);
}
ポイントは次の4つです。
- img 要素を残す:
<picture>に対応していないブラウザや、WebP を表示できないブラウザは<source>を使わず、<img>の JPEG を表示します。代替テキストや幅・高さも<img>側に付くので、CLS 対策もそのまま効きます。 - LCP 画像は遅延読み込みしない: WordPress は画像に自動で
loading="lazy"を付けることがあります。ファーストビューの画像はeagerを指定し、fetchpriority="high"(WordPress 6.3 以降で扱える属性)で優先度を上げます。一覧ページの2枚目以降は通常どおり遅延読み込みでかまいません。 - ファイルの存在確認はコストがかかる:
file_exists()を画像の候補ごとに呼ぶため、1ページに大量の画像を並べるテンプレートでは、結果をキャッシュする工夫も検討してください。 - ファイル名の方式を確かめる: 使っているツールが別の名前の付け方をしている場合は、
mytheme_webp_url()の候補を合わせて書き換えます。アップロードフォルダーで実際のファイル名を確認してから使ってください。
<picture> で包むと、テーマの CSS で .entry-content > img のように直接の子要素を指定していたスタイルが当たらなくなることがあります。導入後は記事ページのレイアウトを確認してください。
本文中の画像と CSS 背景画像
ブロックエディターで挿入した本文の画像は、上の関数ではなく WordPress のコンテンツフィルターで出力されます。本文画像まで <picture> 化したい場合は、自作よりもプラグインの機能に任せるほうが安全です。WordPress 6.0 以降には本文中の img タグを個別に加工できる wp_content_img_tag フィルターもありますが、他のプラグインの加工と衝突しやすいので、導入するならステージングで十分に試してください。
CSS の背景画像は image-set() で形式ごとの候補を指定できます。対応していないブラウザ向けに、先に通常の background-image を書いておくと、そちらが使われます。
.hero {
background-image: url("images/hero.jpg");
background-image: image-set(
url("images/hero.webp") type("image/webp"),
url("images/hero.jpg") type("image/jpeg")
);
}
ただし、背景画像は HTML を読み込んでから CSS を解析するまで取得が始まらないため、表示が遅れがちです。ファーストビューの主役の画像は、背景画像ではなく <img> で置くほうが LCP の面では有利です。
サーバー側で切り替える方法の注意点
.htaccess などで、ブラウザーが送る Accept ヘッダーに image/webp が含まれていれば同じ URL で WebP を返す、という方法もあります。HTML を変えずに済むのが利点ですが、同じ URL で中身が変わるため、レスポンスに Vary: Accept を付けないと、CDN やプロキシのキャッシュが WebP を非対応ブラウザに返してしまうおそれがあります。CDN によっては Vary: Accept を扱えない、またはキャッシュ効率が下がることもあるので、CDN を使っているサイトでは <picture> 方式のほうが扱いやすいと考えてください。
効果を確かめる
導入前後で、次の2種類の数値を見比べます。
- ラボデータ: PageSpeed Insights や Chrome の開発者ツール(Lighthouse)で、LCP 要素が何か、その画像が何 KB で、いつ読み込まれているかを確認します。ネットワークタブで画像の「Type」が webp になっているかも見ておきます。
- フィールドデータ: PageSpeed Insights の実ユーザーのデータや、Search Console の「ウェブに関する主な指標」レポートです。実際の訪問者のデータが反映されるまでには時間がかかります。
あわせて、開発者ツールで <source> を削除して表示を確かめるなどの方法で、WebP を使わない場合に JPEG が表示されることも確認しておくと安心です。
まとめ
- WebP 化が主に効くのは LCP で、CLS は幅・高さ指定、INP は JavaScript の問題です。
- フォールバックには JPEG 版と WebP 版の両方が要ります。ツールによって WebP のファイル名(
photo.jpg.webpかphoto.webpか)や JPEG 版が残るかが違うので、先に確認します。 - Modern Image Formats を使うなら、プラグインの
<picture>出力とOutput fallback imagesの設定を使います。 - テーマで自作する場合は、
<picture>と<source type="image/webp">に、WordPress が出力する<img>を組み合わせます。 - LCP 画像は遅延読み込みを外し、
fetchpriority="high"を付けます。サーバー側の切り替えはVary: Acceptと CDN の扱いに注意します。
関連記事: