PHP
WordPress
lazyload

wordpressでlazyload(Intersection Observer)

Google Developersに詳しく書かれているIntersection Observerを使った遅延読み込み手法。

イメージと動画の遅延読み込み| Web Fundamentals | Google Developers

ひと昔前はwindowのscrollイベントをhandleしてましたがこれがパフォーマンスが最悪という事で代わりに推進されています。polyfillする事で割と古いブラウザまで使えるのが良きかな。

wordpress内の画像に何も考えずに適用できんかなぁと思い、functions.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からのアクセスの時は何もしないというのがポイント。

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