wordpressでlazyload（Intersection Observer）

Google Developersに詳しく書かれているIntersection Observerを使った遅延読み込み手法。
[イメージと動画の遅延読み込み| Web Fundamentals | Google Developers](https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/?hl=ja)
ひと昔前はwindowのscrollイベントをhandleしてましたがこれがパフォーマンスが最悪という事で代わりに推進されています。polyfillする事で割と古いブラウザまで使えるのが良きかな。

wordpress内の画像に何も考えずに適用できんかなぁと思い、functions.phpに追記するのみで動くように書いてみました。
プラグインとか入れたくないし。

```PHP:functions.php
// lazy load
function lazyload_attachment_image_attributes( $atts, $attachment ) {
  if(!empty($atts['class'])){
    if(strpos($atts['class'], 'lazyload') === false){
      $atts['data-src'] = $atts['src'];
      $atts['src'] = 'data:image/gif;base64,R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7';
      $atts['data-srcset'] = $atts['srcset'];
      $atts['srcset'] = false;
      $atts['class'] .= ' lazyload';
    }
  }
  return $atts;
}
function lazyload_the_content( $content ) {
  $pattern ="/<img(.*?)class=\"(.*?)\"(.*?)>/i";
  $result = preg_match_all($pattern, $content, $matches);
  if($result > 0){
    $src_pattern = "/src=\"(.*?)\"/i";
    foreach ($matches[0] as $key => $match) {
      if(strpos($match, "lazyload") === false) {
        preg_match($src_pattern, $match, $src);
        $lazy_img = str_replace("src=", "data-src=", $match);
        $lazy_img = str_replace("srcset=", "data-srcset=", $lazy_img);
        $lazy_img = str_replace("sizes=", "data-sizes=", $lazy_img);
        $lazy_img = str_replace("/>", "src='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' />", $lazy_img);
        $lazy_img = str_replace('class="', 'class="lazyload ', $lazy_img);
        $content = str_replace($match, $lazy_img, $content);
      }
    }
  }
  return $content;
}
function loazyload_wp_head() {
  $script = <<<EOT
	<!-- lazyload -->
	<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script><!-- polyfill -->
    <script>
      // lazy load
      document.addEventListener("DOMContentLoaded", function() {
        var lazyImages = [].slice.call(document.querySelectorAll("img.lazyload"));

        if ("IntersectionObserver" in window) {
          var lazyImageObserver = new IntersectionObserver(function(entries, observer) {
            entries.forEach(function(entry) {
              if (entry.isIntersecting) {
                var lazyImage = entry.target;
                lazyImage.src = lazyImage.dataset.src;
                lazyImage.onload = function(e) {
                  e.target.classList.remove("lazyload");
                };
                if (lazyImage.dataset.srcset !== undefined) {
                  lazyImage.srcset = lazyImage.dataset.srcset;
                }
                lazyImageObserver.unobserve(lazyImage);
              }
            });
          });

          lazyImages.forEach(function(lazyImage) {
            lazyImageObserver.observe(lazyImage);
          });
        } else {
          // Possibly fall back to a more compatible method here
        }
      });
    </script>
	<!-- /lazyload -->

EOT;
  echo $script;
}

function isClawler(){
  $ua = $_SERVER['HTTP_USER_AGENT'];
  $crawler_arr = array(
    "Googlebot"		// google
  ,"Baiduspider"		// Baidu
  ,"bingbot"		// Bing
  ,"Yeti"			// NHN
  ,"NaverBot"		// NaverBot
  ,"Yahoo"		// Yahoo
  ,"Tumblr"		// Tumblr
  ,"livedoor"		// livedoor
  );
  foreach ($crawler_arr as $value) {
    if (stripos($ua, $value) !== false) {
      return true;
    }
  }
  return false;
}
// bot以外の場合に遅延読み込みを設定する
if (!isClawler()) {
  add_filter('the_content','lazyload_the_content', 10, 2);
  add_filter('wp_get_attachment_image_attributes', 'lazyload_attachment_image_attributes', 10, 2 );
  add_filter('wp_head', 'loazyload_wp_head', 10, 2);
}
```

突貫ですが手元では問題なく動いていそうです。
画像検索にインデックスされるようにBotからのアクセスの時は何もしないというのがポイント。

実際動かしながら引き続きアップデートかけていきたいと思います。