Native LazyloadにWordpressが対応したこともあり、Lazyloadプラグインを有効化している人は徐々に減ってきていると思います。
Native Lazyloadは細かい部分で制御が効かないので、いまだにプラグインを使用している人も多いかもしれません。
WordPress5.9では、FCP対応で先頭の画像をLazyloadから除外する機能が追加されました。この機能は既存のLazyloadプラグインでは対応していないものが多いです。
autoptimzeのlazyload機能には先頭から何枚目までの画像をlazyload除外する機能があります。autoptimizeのlazyloadを使うのであれば今回の記事は関係ありません。
この記事では既存のLazyloadプラグインの中でLazyloaderプラグインを使用した時に、先頭画像をlazyloadから除外する方法についてまとめています。
Lazyloadプラグインの定番は?
私が使っている定番のLazyload pluginは2つです。
- rocket-lazy-load
- Lazyloader
rocket-lazy-load
もし、わたしが、Lazyloadプラグインを導入するのであれば、WP RocketのLazyloadプラグインを使います。ただ、このプラグイン致命的な欠点があります。外部画像をlazyloadできません。
また、もともと有料プラグインの一部が無料で公開されているため、とてもサポートがプアです。初心者の方にはおススメできません。
Lazyloader
外部画像が多いサイトの場合は、lazysizeを使ったLazyloaderプラグインがおススメです。
lazyloaderプラグインは先頭画像のlazyload除外に未対応
lazyloaderプラグインは、地味ながらもかなり高機能なプラグインです。
しかし、FCP対応のため先頭画像をlazyloadから除外する機能は他のLazyloadプラグイン同様にまだありません。
もちろん、class指定で除外する機能はありますので、記事の先頭に必ずアイキャッチ画像があり、それを除外したい場合はclass指定で除外することも可能だと思います。ただし、決まった画像があるとも限らないのでthe_contentの先頭画像をlazyloadから除外する機能が無いのは残念です。
プラグイン作者が先頭画像をLazyload除外するスニペットを公開
プラグインの作者が先頭画像にLazyload除外のclassを追加するスニペットを公開しています。
このスニペットをfunctions.phpに張り付ければ、先頭画像をLazyloadから除外できます。
<?php
/**
* Add skip-lazy class to first image in content.
*/
add_filter( 'the_content', function( $content ) {
// Check if we have no content.
if ( empty( $content ) ) {
return $content;
}
// Check if content contains caption shortcode.
if ( has_shortcode( $content, 'caption' ) ) {
return $content;
}
if ( ! class_exists( '\Masterminds\HTML5' ) || ! class_exists( '\FlorianBrinkmann\LazyLoadResponsiveImages\Helpers' ) ) {
return $content;
}
// Disable libxml errors.
libxml_use_internal_errors( true );
// Create new HTML5 object.
$html5 = new \Masterminds\HTML5( array(
'disable_html_ns' => true,
) );
// Preserve html entities and conditional IE comments.
// @link https://github.com/ivopetkov/html5-dom-document-php.
$content = preg_replace( '/&([a-zA-Z]*);/', 'lazy-loading-responsive-images-entity1-$1-end', $content );
$content = preg_replace( '/([0-9]*);/', 'lazy-loading-responsive-images-entity2-$1-end', $content );
$content = preg_replace( '/<!--\[([\w ]*)\]>/', '<!--[$1]>-->', $content );
$content = str_replace( '<![endif]-->', '<!--<![endif]-->', $content );
// Load the HTML.
$dom = $html5->loadHTML( $content );
$xpath = new \DOMXPath( $dom );
// Get all image nodes.
// @link https://stackoverflow.com/a/19348287/7774451.
$nodes = $xpath->query( "//img[not(ancestor-or-self::noscript)]" );
$is_modified = false;
$counter = 0;
foreach ( $nodes as $node ) {
$counter++;
if ( $counter > 1 ) {
break;
}
// Check if it is an element that should not be lazy loaded.
// Get the classes as an array.
$node_classes = explode( ' ', $node->getAttribute( 'class' ) );
if ( in_array( 'skip-lazy', $node_classes ) ) {
continue;
}
// Check if it is one of the supported elements and support for it is enabled.
if ( 'img' === $node->tagName ) {
// Get the classes.
$classes = $node->getAttribute( 'class' );
// Add lazyload class.
$classes .= ' skip-lazy';
// Set the class string.
$node->setAttribute( 'class', $classes );
$is_modified = true;
}
}
if ( true === $is_modified ) {
$helpers = new \FlorianBrinkmann\LazyLoadResponsiveImages\Helpers();
$content = $helpers->save_html( $dom, $html5 );
}
// Restore the entities and conditional comments.
// @link https://github.com/ivopetkov/html5-dom-document-php/blob/9560a96f63a7cf236aa18b4f2fbd5aab4d756f68/src/HTML5DOMDocument.php#L343.
if ( strpos( $content, 'lazy-loading-responsive-images-entity') !== false || strpos( $content, '<!--<script' ) !== false ) {
$content = preg_replace('/lazy-loading-responsive-images-entity1-(.*?)-end/', '&$1;', $content );
$content = preg_replace('/lazy-loading-responsive-images-entity2-(.*?)-end/', '$1;', $content );
$content = preg_replace( '/<!--\[([\w ]*)\]>-->/', '<!--[$1]>', $content );
$content = str_replace( '<!--<![endif]-->', '<![endif]-->', $content );
}
return $content;
}, 99 );
このスニペットは、the_contentフィルターを通った先頭画像が対象になります。アイキャッチ画像などthe_contentフィルターを通らないものは対象になりません。
アイキャッチ画像はclassで除外して、アイキャッチ画像が無い場合はこのスニペットで除外するというのが正しい運用かと思います。
アイキャッチ画像がある場合と無い場合の判断は、has_post_thumbnail関数で出来ますので、スニペットの先頭で、判定してreturnすればよろしいかと思います。
LazyloaderプラグインでpictureタグをLazyload除外するには?
pictureタグで囲まれたimgタグなどをlazyloadから丸ごと除外するには、skip-lazyクラスを追加するのではなく、data-skip-lazy属性をpictureタグに追加する必要があります。
<picture data-skip-lazy>
<source>
<img>
</picture>
まとめ
今後はNativeLazyloadが主流になっていき、Lazyloadプラグインの需要はますます下がっていくと思います。しかし、いままでLazyloadプラグインが積み重ねた歴史がありますので、NativeLazyloadで対応していない便利なlazyload機能はまだまだ有効です。