WordPressの画像をWebPにしてページの表示を高速化!

お知らせ

概要

  • jpg,gif,pngに変わるWebPがそろそろ普及しだしてきたので流れに乗ってみます。
  • Lighthouseでページ表示のパフォーマンスを見ると、画像によっては容量が半分ぐらいになるとの表示がありました。

Googleの示した事例では、ファイルサイズは非可逆圧縮モードで(同一画像、同等画質の)JPEGと比較して25-34%小さくなり、可逆圧縮モードでPNGと比較して28%小さくなるとしている。

https://ja.wikipedia.org/wiki/WebP

設定前のスコアはこちら。

設定

WordPressでこのWebPを扱おうとなると結構厄介で、なんか怪しいプラグインもあったりするので今まで何回かトライしましたが断念しました。

今回は、こちらのプラグインを使って実現しました。

Converter for Media – Convert WebP and AVIF & Optimize Images | Ease image optimization
Speed up your website by using our WebP & AVIF Converter. Serve WebP and AVIF images instead of standard formats JPEG, PNG and GIF just now!

設定手順

インストール時に、wp-contentディレクトリ直下にファイルが作成されるので、PHPが動いているユーザに対して書き込み権限を一時的に与えておく必要があります。

chmod a+w wp-content

普通にプラグインを上記からインストールします。

wp plugin install webp-converter-for-media --activate

このサービスは、PHP-FPMとnginxによって稼働しているので、こちらのページを参考にしてnginxの設定を変更します。

私の環境では差分は以下のような感じです。

[root@ip-172-26-2-21 nginx]# git diff
diff --git a/nginx/conf.d/triathlon.teraren.com.conf b/nginx/conf.d/triathlon.teraren.com.conf
index 3e174ae..7d3155c 100644
--- a/nginx/conf.d/triathlon.teraren.com.conf
+++ b/nginx/conf.d/triathlon.teraren.com.conf
@@ -1,3 +1,12 @@
+map $http_accept $load_avif {
+       ~image/avif "/wp-content/uploads-webpc/$path.$ext.avif";
+}
+map $http_accept $load_webp {
+       ~image/webp "/wp-content/uploads-webpc/$path.$ext.webp";
+}
+
+
+
 server {
     listen 443 ssl http2;
     listen [::]:443 ssl http2;
@@ -10,8 +19,16 @@ server {
     ssl_certificate_key /etc/letsencrypt/live/teraren.com/privkey.pem;
     ssl_session_cache shared:SSL:1m;
     ssl_session_timeout 5m;
+
     include global/ssl.conf;

+    location ~ /wp-content/(?<path>.+)\.(?<ext>jpe?g|png|gif)$ {
+           add_header Vary Accept;
+           add_header Cache-Control "private" always;
+           expires 365d;
+           try_files $load_avif $load_webp $uri =404;
+    }
+
     location / {
         root /home/matsu/Sites/teraren.com/triathlon;
         index index.php index.html index.htm;
diff --git a/nginx/mime.types b/nginx/mime.types
index 2961256..6a69410 100644
--- a/nginx/mime.types
+++ b/nginx/mime.types
@@ -23,6 +23,7 @@ types {
     image/x-icon                                     ico;
     image/x-jng                                      jng;
     image/x-ms-bmp                                   bmp;
+    image/avif avif;

     font/woff                                        woff;
     font/woff2                                       woff2;

あとは、nginxをreloadします。

systemctl reload nginx

あとは、Wordpressの管理画面上でWebP画像を生成すれば終わりです。

すべての画像は、wp-content/webpc-passthru.phpを経由して、webp画像があればそれを返して、存在していなければ今までと同じ用にgifやpngファイルを返却します。

Performanceスコアが42から56へ改善されました。なぜかSEOなどのスコアも上がっている。。。

プラグインの内部動作

このプラグイン、どうやって動作しているかというのがちょっと興味深いです。

オリジナルの画像は保持しておいて変更はしません。画像をアップロードした直後にWordpressが自動で生成する7個ぐらいのサムネイル画像をWebPに変換する対象としています。

プラグインでの管理画面でのRegenerate imagesは何をやっているかというと、サイズごとの画像をwebpに変換しつつ、もしwebpのほうが容量が大きければ変換は行わないようになっています。

その前提で、wp-content/webpc-passthru.phpがwebpファイルの有無を判定してブラウザに適切なファイルを返却しています。

また、ドキュメントでは分かりづらいですが、この設定を.htaccessの方にすればPHP側でのファイル判定を行わないで、Webサーバ側に判定を任せるようになります。(=wp-content/webpc-passthru.php を使わなくなる)

nginxなのに、via .htaccessを選ぶとエラーの表示は出ちゃいますが、nginxの設定をちゃんと行っていれば問題ないので無視します。

実験

対象のURL:https://triathlon.teraren.com/wp-content/uploads/2022/01/image-4.png

WebPファイルのURL: https://triathlon.teraren.com/wp-content/uploads-webpc/uploads/2022/01/image-4.png.webp

普通にpngをリクエストしてみると、普通にpngファイルが返却される。content-typeヘッダと、content-lengthヘッダで判断できます。

$ curl -I https://triathlon.teraren.com/wp-content/uploads/2022/01/image-4.png
HTTP/2 200
server: nginx/1.20.0
date: Mon, 10 Jan 2022 15:46:10 GMT
content-type: image/png
content-length: 179549
last-modified: Mon, 10 Jan 2022 15:09:19 GMT
etag: "61dc4c1f-2bd5d"
expires: Tue, 10 Jan 2023 15:46:10 GMT
cache-control: max-age=31536000
vary: Accept
cache-control: private
set-cookie: uid=JsIFgGHcVMKhc1BNAwNBAg==; path=/
accept-ranges: bytes

webpをacceptできる用に偽装してリクエストすると、webpが返却されます。

$ curl -H 'accept: image/webp' -I https://triathlon.teraren.com/wp-content/uploads/2022/01/image-4.png
HTTP/2 200
server: nginx/1.20.0
date: Mon, 10 Jan 2022 15:46:40 GMT
content-type: image/webp
content-length: 59626
last-modified: Mon, 10 Jan 2022 15:09:22 GMT
etag: "61dc4c22-e8ea"
expires: Tue, 10 Jan 2023 15:46:40 GMT
cache-control: max-age=31536000
vary: Accept
cache-control: private
set-cookie: uid=JsIFgGHcVOChc1BNAwNEAg==; path=/
accept-ranges: bytes

なかなか頭がよいですね。拡張子がpngでリクエストをしていますが、ファイルのmimeはwebpなので、ちょっと混乱するかもしれませんが、速度優先ってことで良いことにしましょう。

追記

もう少し、スコアを向上させました。

パフォーマンス改善を行うための残り要素は、外部サイトからのWidget読み込みに関連しているので一旦終わり。

コメント

タイトルとURLをコピーしました