Image Lazy Load x WordPress x Cloudinary【WITHOUT Plugin】

WordPress
Performance
Tips

(旧ブログから移行しました。)

Page Speed Insight に翻弄された男の続きです。
まだ画像の LazyLoading を実装していなかったので、実装しました。
今回は WordPress のプラグインを使用することなく自前で用意します。

Medium はすばらしい

Medium の Lazy Loading はすごく心地よいですよね! この遅延ロードはかなり気に入っています。 Google | Lazy Loading Images and Videosにもそのテクニックは紹介されており、画像遅延ロードはもはや必須のメソッドとなりつつあります。 React とかだとreact-lazy-load-image-componentなるものがあったりしていい感じです。 WordPress にも Lazy Loading 用のプラグインがあるのですが、うまい具合にならなかったので自分で実装してみました。 ぜひ参考にしていただけたらと思います!

Front End

以下の流れとなるように記述していきます。

  1. class="lazy"となっている img タグを集める
  2. Intersection Observer を各要素に適用する
  3. 要素を検知したら、data-src を src に置換する

以上の処理をheader.phpに記述していきます。

<script>
  document.addEventListener("DOMContentLoaded", () => {
    let lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

    if ("IntersectionObserver" in window) {
      let lazyImageObserver = new IntersectionObserver((entries, observer) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            let lazyImage = entry.target;
            lazyImage.src = lazyImage.dataset.src;
            lazyImage.srcset = lazyImage.dataset.src;
            lazyImage.classList.remove("lazy");
            lazyImageObserver.unobserve(lazyImage);
          }
        });
      });

      lazyImages.forEach((lazyImage) => {
        lazyImageObserver.observe(lazyImage);
      });
    }
  });
</script>

Intersection Observer は直訳すると交差点観察。
「DOM がここまでスクロールしてきたら HogeHoge する」的なことを簡単に実装できるかなりいい感じの Class です!!
Google | Lazy Loading Images and Videosでも Intersection Observer のテクニックは紹介されています。

FrontEnd はこれで準備 OK!

BackEnd

FrontEnd が 👆 のような処理をできるように土台を作ってあげましょう! 以下の流れで処理を書いていきます。

  1. イベントフック add_filter 関数で、the_content イベントつまり、「記事ページの表示」イベントを登録します。
  2. Img タグの検出と置換 preg_replace_callback 関数にて、正規表現を用いた img タグの検出と、img の要素を書き換えを行います。
    具体的に、
    a. class="lazy"の付与 b. data-src にオリジナルの画像を付与 c. src にダミー画像の付与(スクロールしてくる前、オリジナル画像がロードされる前の画像) を行い、return します。

以上の処理を、function.phpに以下のように記述します。

function filter_lazyload($content) {
  return preg_replace_callback(
    '/<img.*?src\s*=\s*[\"|\'](.*?)[\"|\'].*?>/i',
      function ($matches) {
        $blurred_src = 'https://res.cloudinary.com/${ACCOUNT_ID}/image/fetch/q_50,w_10/' . $matches[1];
        return '<img src="' . $blurred_src . '" data-src="' . $matches[1] . '" style="width: 80%;margin: 0 auto;display: flex;" class="lazy" alt="no-cache" />';
      },
      $content
  );
}
add_filter('the_content', 'filter_lazyload');

この処理を通すと img タグは以下のようになります。

<img
  style="width: 80%;margin: 0 auto;display: flex"
  class="lazy"
  alt="no-cache"
  src="https://res.cloudinary.com/${ACCOUNT_ID}/image/fetch/q_50,w_10/https://sample.com/image.png"
  data-src="https://sample.com/image.png"
/>

ダミーとして表示させる画像についてです。
Medium では、オリジナル画像の低画質&極小版を用いているようです。

今回はその低画質&極小版を取得するために、Cloudinaryというサービスを使用します。
立ち位置的には画像版 CDN です。加えて fetch API も提供しており、URL にパラメータを指定することで任意の形に変換された画像を取得することができます。
詳しくはCloudinary Docs | Fetch remote imagesを参照してください。
個人でブログをやる程度であれば無料で使用し続けることができます。

Fetch API は以下のような形式となります。${} の部分は任意に指定してください。

https://res.cloudinary.com/${ACCOUNT_ID}/image/fetch/${YOUR_PARAMS}/${ORIGIN_URL}

${YOUR_PARAMS}に変換内容を指定していきます。
今回は、Quality: 2 分の 1 Width: 10px のものを取得したいので q_50,w_10と指定します。簡単ですね!

どれくらい効果があるの?

ぼくのブログのGoogle Adsense の審査に合格しました!には記事中画像が 1 枚あります。
オリジナル画像は279KB(デカっ)に対して、ダミー画像は0.74KB! 初回ロードにおいて278KBの節約、350 分の 1になります!画像 1 枚でもかなりの効果です。
たくさんあるんだったらなおさらですね!

これで準備は整いました。こんな感じになりました!!

すごくいい感じ!
WordPress のカスタマイズはほとんどやったことありませんでしたが、簡単に実装することができました!
ぜひ試してみてください(^ ω ^)

実装後の Page Speed Insight

いいね!!!

Ryoma HOSHINO
I'm a little developer for people, education, society, world