「サイトが遅い」と感じたとき、真っ先に「速くなるプラグイン」を探したくなるかもしれません。しかし、WordPress の表示速度の改善は、何が遅いのかを計測し、原因ごとに手を打つのが近道です。キュレーションメディアでは、アイキャッチなどの画像が大きな割合を占めることが多く、画像の選ばれ方を直すだけで転送量が大きく変わることがあります。
「サイトの表示が遅いと言われた。WordPress の表示速度を改善するには、まず何をすればいい?」
結論から言うと、まず計測し、次に「画像のサイズ」「ブラウザキャッシュ」を整え、ページ全体のキャッシュはホスティング側で用意する、という順番がおすすめです。今回のサンプルでは、テーマに数十行を追加しただけで、パソコン幅で記事ページを表示したときの転送量が、手元の計測で約半分になりました。ただし、速度対策の多くはサーバー(ホスティング)側で決まり、コードだけでできることには限りがあります。
前回の第9回では、OGP と広告・PR表記を作りました。第10回の今回は、画像サイズの整理、ブラウザキャッシュの設定、改善前後の計測を行います。
今回のゴールと、WordPress が最初からやってくれること
改善に入る前に、WordPress 6.8 が最初から行っている画像の最適化を確認しておきます。ここを知らずに同じ処理を追加すると、二重になったり逆効果になったりします。
| 機能 | 内容 | 導入された版 |
|---|---|---|
| srcset と sizes | 画像の複数のサイズを HTML に並べ、ブラウザに画面に合うものを選ばせる | 4.4 |
| 大きな画像の自動縮小 | 幅または高さが 2560px を超える画像をアップロードすると、縮小版(-scaled)を作って表示に使う | 5.3 |
| loading=”lazy” | 画面の外にある画像を、スクロールで近づくまで読み込まない | 5.5 |
| fetchpriority=”high” | 最初に表示される大きな画像を優先して読み込む | 6.3 |
| sizes=”auto” | 遅延読み込みの画像で、実際の表示幅から適切なサイズを選ばせる | 6.7 |
📰 出典:Make WordPress Core「Image performance enhancements in WordPress 6.3」
実際にサンプルの記事ページを確認すると、アイキャッチには fetchpriority="high" が既に付いていました。一方で、次の3つの問題が見つかりました。
- アイキャッチの
sizesが「(max-width: 2560px) 100vw, 2560px」になっていて、本文幅 720px で表示するのに大きすぎる画像が選ばれる - 静的ファイル(CSS・JS・画像)にキャッシュの期間を示すヘッダーがなく、再訪問のたびにサーバーへ確認が発生する
- 親テーマの CSS の URL に、親テーマではなく子テーマのバージョン(
?ver=0.8.0)が付いている
今回はこの3つを直し、使わない画像サイズを作らない設定と、遅延読み込みの調整を加えます。
今回追加・変更したファイル
| ファイル | 内容 |
|---|---|
テーマ functions.php | 親テーマの CSS のバージョン、画像サイズ、アイキャッチの sizes、遅延読み込みの調整を追加 |
テーマ style.css | バージョン 0.10.0 |
docs/htaccess-cache.example | 静的ファイルのブラウザキャッシュ設定の例(新規) |
企画の段階ではプラグインに includes/performance.php を作る予定でしたが、今回の変更はどれも「本文幅」「アイキャッチの位置」といったテーマのレイアウトに依存するものだったため、テーマの functions.php に置きました。ランキングと関連記事の一時保存(transient)は第7回で実装済みです。
計測の方法を決める
改善の前後で同じ条件で比べられるよう、次の3つの方法で計測しました。数値はすべて筆者のローカル環境(Docker)での計測値で、実際のサーバーや回線では変わります。比べるのは「前後の差」だけにしてください。
| 計測するもの | 方法 |
|---|---|
| サーバーが最初の1バイトを返すまでの時間(TTFB) | curl の time_starttransfer を21回測り、中央値をとる |
| 画像の選ばれ方と転送量 | ヘッドレスブラウザで、画面の幅と解像度(1倍・2倍・スマホ3倍)を変えて表示し、選ばれた画像と合計の転送量を記録 |
| 総合的な診断 | Lighthouse 12(Chrome の診断ツール)のパフォーマンス診断をモバイル・デスクトップで各2回 |
# TTFB(サーバーが応答を返し始めるまでの秒数)を測る
for i in $(seq 1 21); do
curl -s -o /dev/null -w '%{time_starttransfer}\n' http://localhost:8088/<記事のスラッグ>/
done | sort -n
テスト用に、幅 3000px の写真風の JPEG(約700KB)をアイキャッチに設定した記事を使いました。
画像サイズを整理する
WordPress は画像をアップロードすると、登録されたサイズごとに縮小版を作ります。サンプルでは次の6種類でした。
docker compose run --rm wpcli wp media image-size
# 2048x2048 / 1536x1536 / large(1024) / medium_large(768) / medium(300) / thumbnail(150)
このテーマの本文幅は 720px、最大幅は 1200px です。高解像度の画面(2倍)で本文幅の画像を表示するにも 1440px あれば足りるため、2048px の中間サイズは使われません。そこで、2048px を作らないようにし、大きな画像を縮小する基準も 2560px から 2048px に下げました。
wp-content/themes/curation-child/functions.php(抜粋)
function curation_child_remove_unused_image_sizes( $sizes ) {
unset( $sizes['2048x2048'] );
return $sizes;
}
add_filter( 'intermediate_image_sizes_advanced', 'curation_child_remove_unused_image_sizes' );
function curation_child_big_image_threshold() {
return 2048;
}
add_filter( 'big_image_size_threshold', 'curation_child_big_image_threshold' );
設定を変えた後に wp media regenerate --yes で縮小版を作り直すと、テスト画像1枚あたりのファイルは(元の画像を含めて)8つから7つに減り、表示に使われる縮小版(-scaled)は 455KB から 306KB になりました。なお、この方法は「作らない」設定なので、wp media image-size の一覧には 2048×2048 が残ります。
📰 出典:WordPress Developer Resources「big_image_size_threshold」
画像サイズの変更は、過去の画像にはさかのぼって反映されません。既存サイトで行う場合は、作り直しの処理時間とディスク容量の変化を事前に確認してください。
アイキャッチの sizes を実際の表示幅に合わせる
今回いちばん効果が大きかったのがこの修正です。sizes 属性は「この画像は画面上でこの幅で表示される」とブラウザに伝えるもので、ブラウザはこの値と画面の解像度から、srcset の中のどの画像を読み込むかを決めます。
WordPress は画像の元の幅から sizes を作るため、「(max-width: 2560px) 100vw, 2560px」、つまり「画面幅いっぱいに表示される」と伝えていました。実際には本文幅 720px で表示されるので、必要以上に大きな画像が選ばれていたのです。
functions.php(curation_child_featured_image_sizes() の抜粋)
$post_id = isset( $instance->context['postId'] ) ? (int) $instance->context['postId'] : 0;
if ( ! is_singular() || get_queried_object_id() !== $post_id ) {
return $content;
}
$content_size = wp_get_global_settings( array( 'layout', 'contentSize' ) );
$width = is_string( $content_size ) ? absint( $content_size ) : 0;
if ( ! $width ) {
return $content;
}
$processor = new WP_HTML_Tag_Processor( $content );
if ( $processor->next_tag( 'IMG' ) && null !== $processor->get_attribute( 'srcset' ) ) {
$processor->set_attribute( 'sizes', sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', $width ) );
}
return $processor->get_updated_html();
本文幅は、第1回で theme.json に書いた layout.contentSize から wp_get_global_settings() で読み込みます。本文幅を変えたときに、ここを直し忘れることがありません。対象は記事ページのアイキャッチ(post-featured-image ブロック)だけで、一覧の画像には影響しません。
2枚目以降の画像は遅延読み込みにする
WordPress は、ページの最初の3枚の画像は画面内に入る可能性が高いとして、遅延読み込みを付けません。このテーマの記事ページでは、最初の画面に入るのはアイキャッチ(なければ本文の1枚目)だけなので、この数を1にしました。
function curation_child_omit_loading_attr_threshold() {
return 1;
}
add_filter( 'wp_omit_loading_attr_threshold', 'curation_child_omit_loading_attr_threshold' );
変更後は、アイキャッチに fetchpriority="high"、本文の画像に loading="lazy" と sizes="auto, …" が付くことを確認しました。
📰 出典:Make WordPress Core「Auto Sizes for Lazy Loaded Images in WordPress 6.7」
ブラウザキャッシュと、親テーマの CSS のバージョン
静的ファイルにキャッシュ期間を付ける
CSS・JS・画像に「この期間はサーバーに確認せずに使ってよい」というヘッダー(Cache-Control)を付けると、2ページ目以降の表示や再訪問が速くなります。サンプルの Apache では mod_expires が使えたため、.htaccess 用の設定例を用意しました。
docs/htaccess-cache.example(抜粋)
<IfModule mod_expires.c>
ExpiresActive On
# テーマ・プラグイン・WordPress 本体の CSS / JS(?ver= 付き)
ExpiresByType text/css "access plus 1 year"
ExpiresByType text/javascript "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
# 画像(アップロード画像を含む)
ExpiresByType image/jpeg "access plus 30 days"
ExpiresByType image/png "access plus 30 days"
ExpiresByType image/webp "access plus 30 days"
</IfModule>
CSS・JS は、WordPress が URL に ?ver= を付けるので、ファイルを更新すれば URL が変わり、1年の長い期間にしても古いものが使われ続けることはありません。アップロード画像は同じ URL のまま差し替えられることがあるため、30日にしています。記事の HTML は対象にしません。
📰 出典:Apache HTTP Server「mod_expires」
親テーマの CSS に親テーマのバージョンを付ける
長いキャッシュ期間を設定すると、?ver= が正しく変わることが重要になります。ところが Twenty Twenty-Five は、自分の style.css を読み込むときに「有効なテーマのバージョン」を使うため、子テーマを使っていると子テーマのバージョンが付きます。親テーマだけを更新したときに URL が変わらず、古い CSS が使われ続けるおそれがあります。
functions.php(抜粋)
function curation_child_fix_parent_style_version() {
$parent = wp_get_theme()->parent();
$style = wp_styles()->query( 'twentytwentyfive-style' );
if ( $parent && $style ) {
$style->ver = $parent->get( 'Version' );
}
}
add_action( 'wp_enqueue_scripts', 'curation_child_fix_parent_style_version', 20 );
親テーマが CSS を登録した後(優先度 10 の後)に、バージョンを親テーマのもの(1.2)に書き換えます。親テーマのファイルは編集しません。
計測結果(ローカル環境での比較)
改善前後の計測結果です。繰り返しになりますが、筆者のローカル環境での値で、実際のサイトの速さを示すものではありません。
| 表示条件 | 選ばれたアイキャッチ(前 → 後) | ページ全体の転送量(前 → 後) |
|---|---|---|
| パソコン幅・解像度1倍 | 1536px → 768px | 約287KB → 約154KB |
| パソコン幅・解像度2倍 | 2560px(-scaled)→ 1536px | 約564KB → 約288KB |
| スマホ幅・解像度3倍 | 1536px → 1536px(変化なし) | 約287KB → 約289KB |
スマホの高解像度の画面では、表示幅 342px の3倍=約1000px が必要なため、もともと適切なサイズが選ばれていました。変化が大きいのはパソコンでの表示です。
Lighthouse 12 のデスクトップ診断では、総転送量が 210KiB から 76KiB に減り、「適切なサイズの画像」の指摘(改善見込み 132KiB)がなくなりました。キャッシュ期間の指摘は7件から1件(30日にした画像。Lighthouse はより長い期間を推奨するため)になりました。スコアはもともとモバイル 99〜100、デスクトップ 100 で、記事が数本しかない軽いサンプルでは差が出ませんでした。
TTFB は、ランキング・関連記事の一時保存がある状態で中央値約50ms、変更の前後で差はありませんでした。今回の変更は画像とキャッシュに関するもので、サーバーの処理時間を減らすものではないためです。参考として、第7回の一時保存を削除した直後の表示は中央値で約200ms(再計算と保存を含む)で、一時保存がある場合(同じ条件で約80ms)より遅くなりました。
つまずきやすい点・注意点
- 計測は同じ条件で、複数回:ローカル環境でも1回ごとの値はかなりばらつきます(TTFB で 40〜220ms 程度)。中央値や複数回の結果で比べましょう。
- Lighthouse のスコアだけを目標にしない:記事が少ない段階では満点に近くなりやすく、実際の利用者の体感とは一致しないことがあります。転送量や画像の選ばれ方など、具体的な項目を見ます。
- キャッシュの二重設定:ホスティングの管理画面や CDN でもキャッシュを設定できる場合、
.htaccessとの二重設定で意図しない期間になることがあります。どこで設定するかを1か所に決めてください。 - ページキャッシュとログイン中の表示:ページ全体のキャッシュ(HTML の保存)はホスティングやプラグインで行うのが一般的です。第7回の閲覧数カウントのように、ページキャッシュと両立する作りになっているかを確認しておきます。
発注者向けメモ:速度対策は「ホスティング選び」とセットで決める
表示速度に大きく効くのは、ページ全体のキャッシュ、CDN(=画像などを利用者の近くのサーバーから配信する仕組み)、サーバーの性能です。これらはホスティング(レンタルサーバー・クラウド)の選択で決まる部分が多く、コード側の工夫だけでは効果が限られます。
- ページキャッシュ・CDN の有無:ホスティングに標準で付いているか、別途用意するか
- 計測の方法と目標:何を、どの画面・回線条件で、どのツールで測るか。改善前の数値を残しておく
- 画像の運用ルール:アップロード前の縮小、アイキャッチの縦横比、画像の形式(JPEG・WebP など)
- ログイン中の編集部の表示:キャッシュが効かないため、管理画面の速さは別に考える
工数が増えるのは、既存の大量の画像を作り直す場合、CDN を導入して URL や証明書の設定が必要な場合、特定の指標(スコアなど)を契約上の目標にする場合です。
打ち合わせでは、次のように聞いてみてください。
- 「表示速度は、何のツールで、どの条件で計測しますか? 改善前の数値を共有してもらえますか?」
- 「ページキャッシュと CDN は、ホスティング側で用意されますか? 閲覧数や PR 表記の仕組みと両立しますか?」
- 「画像のサイズや形式は、アップロード時に自動で整える仕組みがありますか?」
まとめと次回予告
第10回では、表示速度の改善と計測を行いました。
- WordPress 6.8 は srcset・遅延読み込み・fetchpriority などを最初から行うので、まず現状を確認する
- アイキャッチの sizes を本文幅に合わせると、パソコンで表示したときの画像の転送量が大きく減った(ローカル計測)
- 使わない画像サイズは作らず、大きな画像の縮小基準も見直す
- 静的ファイルにキャッシュ期間を付け、親テーマの CSS のバージョンも親テーマのものにする
- 数値は計測環境によって変わるため、同じ条件で前後を比べる。速度の多くはホスティング側で決まる
次回はいよいよ最終回、「権限・編集フロー・運用 ― 下書きレビュー、バックアップ、更新」です。ライターが公開できない権限設計とレビューの流れ、バックアップと復元、更新の手順を扱い、連載全体を振り返ります。
この連載の記事一覧
この記事は連載「WordPressで作るキュレーションメディア」の1回です。連載のほかの回は次のとおりです(連載の一覧ページ)。
- 【WordPressで作るキュレーションメディア 第0回】キュレーションメディアの要件と「低品質まとめ」の教訓 ― Docker で WordPress 6.8 の土台を作る
- 【WordPressで作るキュレーションメディア 第1回】theme.json でデザイントークンを定義する(子テーマの基本)
- 【WordPressで作るキュレーションメディア 第2回】カテゴリ・タグ・「特集」― タクソノミー設計
- 【WordPressで作るキュレーションメディア 第3回】記事・まとめ・ランキングのテンプレートとパターン
- 【WordPressで作るキュレーションメディア 第4回】「引用元カード」ブロック ― 著作権法第32条の引用を仕組みで守る
- 【WordPressで作るキュレーションメディア 第5回】「まとめリスト」と「比較表」をパターンとブロックスタイルで作る
- 【WordPressで作るキュレーションメディア 第6回】著者・監修者プロフィールを表示する(E-E-A-T の考え方)
- 【WordPressで作るキュレーションメディア 第7回】人気記事ランキングと関連記事を小さなプラグインで作る
- 【WordPressで作るキュレーションメディア 第8回】目次と構造化データ(JSON-LD: Article / BreadcrumbList / ItemList)
- 【WordPressで作るキュレーションメディア 第9回】OGP・SNS カードと「広告・PR表記」― ステマ規制への対応
- 【WordPressで作るキュレーションメディア 第10回】表示速度の改善 ― 画像サイズ・キャッシュ・計測(この記事)
- 【WordPressで作るキュレーションメディア 第11回】権限・編集フロー・運用 ― 下書きレビュー、バックアップ、更新










コメント
コメント一覧 (1件)
[…] 前回の第10回では、表示速度の改善と計測を行いました。最終回の今回は、権限と編集フロー、バックアップと復元、更新の手順を作り、連載全体を振り返ります。 […]