こんばんは、WordPress高速化ネタが大好きなあんそくです。

WordPress高速化のためにLazy Load(画像を遅延させて読み込ませる)を使用している方も多いと思います。

私が運営しているGeeklesでも、表示高速化のために「BJ Lazy Load」というプラグインを導入することで、Lazy Loadを行なっています。

しかし、ファーストビューにある画像を遅延読み込みさせてしまうと、ファーストビュー外にある文字などの情報を読み込んだ後で、ファーストビューの画像を読み込むことになるので、ファーストビューのレンダリング完了が遅くなり、体感速度が下がってしまいます。(1文の中に「ファーストビュー」多いな)

Lazy Loadを導入することで、確かにレンダリング速度は上がり、Page Speed InsightsGTmetrixなどのスコアは上がりますが、実際にページを訪れる読者の感じる表示速度が下がってしまうのは本末転倒なので、対策を講じてみました。

BJ Lazy Load

念のため「BJ Lazy Load」を紹介。

BJ Lazy Loadは、WordPressで構築しているWebサイトでLazy Loadを簡単に実装するためのプラグイン。ちょこちょこアップデートもされるので、WordPressのLazy Loadプラグインではおすすめです。

仕組みとしては、コンテンツを出力する際のフィルターフックでimgのsrc属性(URL)の値をbase64でエンコードされた画像に置き換えて、その値をdata-lazy-src属性に退避。それぞれ画像付近までスクロールされたら、src属性に戻して画像の読み込みを開始させるといった感じです。

プラグインの設定には、特定のclassを持っている画像の遅延読み込みを除外するというものがありますが、Geeklesの場合、1枚目の画像に同じclassを付与していないので、これではダメです。

テンプレートが吐き出す形で、ファーストビューにアイキャッチ画像を置いているような場合なら、classを付けるようにテンプレートをカスタマイズして、そのclassを除外するようにプラグイン側で設定すればOKでしょう。

1枚目の画像を遅延読み込みさせない

フィルターフック「the_content」を使って、1枚目の画像に除外するクラスを付与するといった方法も考えましたが、(なんか何かうまくいかなかったので)プラグインのphpファイルを改造することにしました。

プラグインのファイルを弄ると、うまくページが表示されなくなることもあるので注意が必要です。また、プラグインがアップデートされた場合、カスタマイズ部分も上書きされてしまうので、都度カスタマイズを適用し直す必要がでてきます。高頻度でアップデートされるプラグインではないので、その点は我慢の子…。

さて、弄るのはclass-bjll.phpというファイルの197行目付近(バージョン 1.0.7)。

$matches = array();
preg_match_all( '/<img[\s\r\n]+.*?>/is', $match_content, $matches );
$search = array();
$replace = array();
foreach ( $matches[0] as $imgHTML ) {
// don't to the replacement if the image is a data-uri
if ( ! preg_match( "/src=['\"]data:image/is", $imgHTML ) ) {
$placeholder_url_used = $placeholder_url;
// use low res preview image as placeholder if applicable
if ( 'yes' == self::_get_option('preview') ) {
if( preg_match( '/class=["\'].*?wp-image-([0-9]*)/is', $imgHTML, $id_matches ) ) {
$img_id = intval($id_matches[1]);
$tiny_img_data  = wp_get_attachment_image_src( $img_id, 'tiny-lazy' );
$tiny_url = $tiny_img_data[0];
$placeholder_url_used = $tiny_url;
}
}
// replace the src and add the data-src attribute
$replaceHTML = preg_replace( '/<img(.*?)src=/is', '<img$1src="' . esc_attr( $placeholder_url_used ) . '" data-lazy-type="image" data-lazy-src=', $imgHTML );
// also replace the srcset (responsive images)
$replaceHTML = str_replace( 'srcset', 'data-lazy-srcset', $replaceHTML );
// add the lazy class to the img element
if ( preg_match( '/class=["\']/i', $replaceHTML ) ) {
$replaceHTML = preg_replace( '/class=(["\'])(.*?)["\']/is', 'class=$1lazy lazy-hidden $2$1', $replaceHTML );
} else {
$replaceHTML = preg_replace( '/<img/is', '<img class="lazy lazy-hidden"', $replaceHTML );
}

記事内のimg要素の数だけforeachを回し、src属性の値を書き換えている箇所です。

foreachで回していることが分かれば、あとは簡単。1枚目の画像=1度目のループのときだけ、置換処理をしないように変更します。

foreach ( $matches[0] as $i => $imgHTML ) {
if ($i === 0) {
continue;
}

foreachにkeyを追加して、1度目である0のときだけ、何もせずにループを抜けます。これだけ。

確認してみる

カスタマイズ前の1枚目画像

data-lazy-src属性、data-lazy-srcset属性があり、書き換えが行われている

カスタマイズ後の1枚目画像

lazy的なclassや属性はなく、書き換えされていない

これで、1枚目の画像を遅延読み込みさせずにBJ Lazy Loadを使うことができました。もちろん、2枚目以降は「カスタマイズ前の1枚目画像」と同様に書き換えがされています。

プラグインがアップデートされる度にphpファイルを編集し直すのが嫌になったら別の方法を考えましょう。