PukiWikiに画像遅延読込・画像リサイズプラグインを導入して画像の読み込みを高速化する!

PukiWikiに画像遅延読込・画像リサイズプラグインを導入して画像の読み込みを高速化する!

PukiWikiはシンプルなシステム構成なため、WordPressに比べて高速に動作する。しかし、私が実現しようとしているのは画像を多用した松本零士私設博物館であるため、何かしら手を打っておかないと画像を転送する重さでサイトを見て貰えない可能性がある。そこで、画像を表示用にリサイズし、しかも遅延読み込みをさせるプラグインを作ってみた。
前回の記事と同様にサブドメインを連番で用意してあるので、今回はmuseum-19サブドメインの内容をmuseum-20サブドメインにコピーし、検証しながら作業を進めた。メニューページが「MenuBar」ではなく「メニューバー」になっている(日本語ページ名でPukiWiki用URL短縮ライブラリにより短縮される)ので要注意。

※2019/12/21追記
本プラグインを導入した場合、「skin」フォルダに格納されているpukiwiki.skin.phpのFacebookおよびTwitterへのOGPタグ部分を修正しないと、アイキャッチ画像が連動しない
そのため、「OGPタグを修正する」章を追加した。

※2020/04/30追記
FacebookのOGP仕様が変更になった関係で、本記事で取り上げているプラグインをURL短縮ライブラリに正式に対応させてバージョンアップしている。
内容の詳細に関しては、次の記事を参照されたい。

画像遅延読み込みの必要性

サイトのページ表示速度が遅いと、単純に見て貰えなくなる。実際にGoogleが公表したモバイルページの調査結果は次の通りだ。

この調査結果によると、

  • 表示に3秒以上かかると約53%のユーザーは離脱する
  • 表示速度が1秒から5秒に落ちると直帰率は90%上昇する
  • 表示速度が1秒から6秒に落ちると直帰率は106%上昇する
  • 表示速度が1秒から10秒に落ちると直帰率は123%上昇する

となるようだ。
PukiWikiレスポンシブデザインに改造してあるので、スマホ等のモバイルデバイスにも対応しているが、最近のスマホのカメラでさえ2,000万画素はあるから、1枚の画像が3MBにも達する。画像の大きさもさることながら、何もしなければページに表示されていない画像を転送してしまうので、その分ページ全体の表示が遅くなる。表示されていない画像のせいでユーザの離脱と直帰率を高めてしまい、結果として「見て貰えないサイト」になってしまうのでは割に合わない。
そこで、ユーザがページをスクロールして画像が表示される時に「画像を遅延して読み込み」をすれば、画像を多用したサイトでもユーザは表示速度の低下を気にせずに見てくれるだろう。また、画像の大きさにも気を付けなければならないのは当然で、無駄に大きい画像をページに添付するのは避けた方が良い。本来であれば、画像を添付した際に自動的に複数の解像度の画像を作成し、デバイスの解像度に合わせた画像を表示してやれば非常に効率的だ。今回はそこまではやらないが、画像をリサイズするプラグインを組み合わせることで、手軽かつ簡単に画像の遅延読み込みと表示画像のリサイズを実現する。

プラグインの設定と設置

例によって画像遅延読み込み・画像リサイズプラグインは本サイトのダウンロードページにアップロードしているので、ダウンロードしてローカルの作業フォルダに解凍する。

解凍すると図のように「image」フォルダにimgタグ用のダミー画像「spacer.png」があるので、サーバの「image」フォルダにFTPする。同様に「skin」フォルダには画像の遅延読み込みを可能とするJavaScriptファイル「lazysizes.min.js」があるので、同様にサーバの「skin」フォルダにFTPする。「resize_cache」は画像リサイズプラグインが作成する画像のキャッシュフォルダで、中身はカラだが同名のフォルダをPukiWikiのルートに作成する必要がある。
プラグインはPukiWiki標準のrefプラグインを遅延読み込みと画像リサイズに対応させた「ref.inc.php」と、画像をリサイズする「resize_image.inc.php」だ。この2つをサーバの「plugin」フォルダにFTPし、FTPしたファイル属性(パーミッション)を「644」に、「resize_cache」フォルダの属性を「777」に設定すれば良い。
次に、「skin」フォルダの「pukiwiki.skin.php」にコードを追加してJavaScriptを組み込む。私のソースだと230行付近になるが、</head>タグの直前ぐらいに次のコードを追加してやる。

skin\pukiwiki.skin.php

<!-- 遅延読込・画像リサイズ対応 -->
<script src="skin/lazysizes.min.js" async=""></script>

</head>

以上で設置は完了するが、一応設定も可能にしてある。通常は設定を変更する必要はないが、サイトに合せて設定して貰えれば良い。

pulugin\ref.inc.php

// 画像遅延読み込み・画像リサイズ対応
// resize_imageを画像表示に利用する場合はTRUEに設定
define('PLUGIN_REF_RESIZE_IMAGE', TRUE);

上記設定で、画像リサイズプラグインを利用したくない場合(それでも画像の遅延読み込みをしたい場合)はコメントアウトすれば良い。
画像リサイズプラグインでは、どんな画像でもJPEG形式に変換するため、アニメーションGIF等を多用するサイト(ってあるのかな?)では利用しない方が良いだろう。

pulugin\resize_image.inc.php

// 画像幅初期値(未設定でオリジナルサイズ)
define('PLUGIN_RESIZE_IMAGE_WIDTH', '');
// 画像高さ初期値(未設定でオリジナルサイズ)
define('PLUGIN_RESIZE_IMAGE_HEIGHT', '');
// 画像品質初期値(JPEG品質値70)
define('PLUGIN_RESIZE_IMAGE_QUALITY', '70');
// リサイズ画像キャッシュディレクトリ
define('PLUGIN_RESIZE_IMAGE_CACHE', DATA_HOME . 'resize_cache/');
// ブラウザキャッシュ有効期限(初期値として1日を設定)
define('PLUGIN_RESIZE_IMAGE_CACHE_SECONDS', '86400');

画像リサイズプラグインでリサイズする画像の幅・高さ・品質(100が最高品質)、そしてキャッシュディレクトリとブラウザキャッシュの有効期限を設定しているので、サイトによっては適宜設定を変更して欲しい。

OGPタグを修正する

本プラグイン一式を導入すると、自動的にページに存在する画像をリサイズして遅延読み込みをするが、その際にHTMLの構文的に「image」フォルダに格納したスペーサー画像を指定している。
具体的には、

<img class=”lazyload” src=”image/spacer.png” data-src=”実際に表示する画像” ~ />

としている(”実際に表示する画像”部分は画像リサイズプラグインのコードとなる)。
これはプラグイン側で自動で編集しているが、HTMLのimgタグでsrcを指定しないとHTML構文エラーとなってしまうからに他ならない。
私としたことが「FacebookおよびTwitterに連動するアイキャッチ画像はページの先頭の画像ファイルとする(ただしPukiWikiのフェイスマーク画像は除外する)」とした、(しかも自分で決めた)仕様をスッカリ忘れていた(๑ >؂•̀๑)テヘペロ
そこで、「skin」フォルダのpukiwiki.skin.phpを次のように修正する(修正は本サイトの記事「PukiWikiにSEO対応プラグインを導入してサイト構成を変更する!」でプラグインの導入とプログラムを修正している前提とする)。

skin\pukiwiki.skin.php(修正前)

<?php echo $head_tag ?>

<!-- ここからFacebook OGPタグ -->
<meta property="fb:app_id" content="【FacebookのアプリID】" />
<meta property="og:title" content="<?php
    if ($title == "" or $title == $defaultpage) {
        echo $page_title;
    } else {
        echo $title;
    }
?>" />
<meta property="og:type" content="article" />
<meta property="og:url" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ?>" />
<?php if (stripos($head_tag, 'og:description') == false) { ?>
<meta property="og:description" content="<?php echo $str = str_replace(array("\r\n", "\r", "\n", " ", " "), '', mb_substr(strip_htmltag($body, $all = TRUE), 0, 160, "UTF-8")); ?>" />
<?php } ?>
<meta property="og:site_name" content="<?php echo $page_title ?>" />
<meta property="og:image" content="<?php
    $url = 'https://' . $_SERVER['HTTP_HOST'] . '/';
    preg_match_all('/<img.*?src=(["\'])(?!.*image\/face\/)(?!.*google\.com\/)(.+?).*?>/', $body, $img_array);
    $chk = mb_substr($img_array[2][0], 2);
    if ($chk == "") {
        echo $url . 'image/eye-catch.png';
    } else {
        echo $url . $chk;
    }
?>" />
<!-- ここまでFacebook OGPタグ -->

<!-- ここからTwitter OGPタグ -->
<meta name="twitter:site" content="" />
<meta name="twitter:title" content="<?php
    if ($title == "" or $title == $defaultpage) {
        echo $page_title;
    } else {
        echo $title;
    }
?>" />
<?php if (stripos($head_tag, 'twitter:description') == false) { ?>
<meta name="twitter:description" content="<?php echo $str = str_replace(array("\r\n", "\r", "\n", " ", " "), '', mb_substr(strip_htmltag($body, $all = TRUE), 0, 160, "UTF-8")); ?>" />
<?php } ?>
<meta name="twitter:image" content="<?php
    $url = 'https://' . $_SERVER['HTTP_HOST'] . '/';
    preg_match_all('/<img.*?src=(["\'])(?!.*image\/face\/)(?!.*google\.com\/)(.+?).*?>/', $body, $img_array);
    $chk = mb_substr($img_array[2][0], 2);
    if ($chk == "") {
        echo $url . 'image/eye-catch.png';
    } else {
        echo $url . $chk;
    }
?>" />
<meta name="twitter:card" content="summary_large_image" />
<!-- ここまでTwitter OGPタグ -->

skin\pukiwiki.skin.php(修正後)

<!-- ここからFacebook OGPタグ -->
<meta property="fb:app_id" content="【FacebookのアプリID】" />
<meta property="og:title" content="<?php
    if ($title == "" or $title == $defaultpage) {
        echo $page_title;
    } else {
        echo $title;
    }
?>" />
<meta property="og:type" content="article" />
<meta property="og:url" content="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ?>" />
<?php if (stripos($head_tag, 'og:description') == false) { ?>
<meta property="og:description" content="<?php echo $str = str_replace(array("\r\n", "\r", "\n", " ", " "), '', mb_substr(strip_htmltag($body, $all = TRUE), 0, 160, "UTF-8")); ?>" />
<?php } ?>
<meta property="og:site_name" content="<?php echo $page_title ?>" />
<meta property="og:image" content="<?php
    $url = 'https://' . $_SERVER['HTTP_HOST'] . '/';
    preg_match_all('/<img.*?src=(["\'])(?!.*image\/face\/)(?!.*google\.com\/)(?!.*spacer\.png)(.+?).*?>/', $body, $img_array);
    $chk = mb_substr($img_array[2][0], 2);
    if ($chk == "") {
        echo $url . 'image/eye-catch.png';
    } else {
        echo $url . $chk;
    }
?>" />
<!-- ここまでFacebook OGPタグ -->

<!-- ここからTwitter OGPタグ -->
<meta name="twitter:site" content="" />
<meta name="twitter:title" content="<?php
    if ($title == "" or $title == $defaultpage) {
        echo $page_title;
    } else {
        echo $title;
    }
?>" />
<?php if (stripos($head_tag, 'twitter:description') == false) { ?>
<meta name="twitter:description" content="<?php echo $str = str_replace(array("\r\n", "\r", "\n", " ", " "), '', mb_substr(strip_htmltag($body, $all = TRUE), 0, 160, "UTF-8")); ?>" />
<?php } ?>
<meta name="twitter:image" content="<?php
    $url = 'https://' . $_SERVER['HTTP_HOST'] . '/';
    preg_match_all('/<img.*?src=(["\'])(?!.*image\/face\/)(?!.*google\.com\/)(?!.*spacer\.png)(.+?).*?>/', $body, $img_array);
    $chk = mb_substr($img_array[2][0], 2);
    if ($chk == "") {
        echo $url . 'image/eye-catch.png';
    } else {
        echo $url . $chk;
    }
?>" />
<meta name="twitter:card" content="summary_large_image" />
<!-- ここまでTwitter OGPタグ -->

面倒なのでFacebookとTwitterのOGPタグを全部提示したが、ファイルを修正して保存したら「skin」フォルダにFTPする。
これで本プラグインを導入してもFacebookやTwitterにアイキャッチ画像が正しく連動する。

実際に使って効果を見てみる

FrontPageの劇場版「銀河鉄道999」のパンフレット画像は、2475✕3482ドット約4MBある。

これを図のように1024✕1441ドットの表示とし、遅延読み込みを実施するとどうなるか?

画像の遅延読み込みとリサイズをしていないmuseum-19サブドメインをChromeでチェックすると、201リクエストで4.4MBを転送しているのが分かる。

同様に画像の遅延読み込みとリサイズを実施したmuseum-20サブドメインをChromeでチェックすると、203リクエストで264KBしか転送していないのが分かる。
ページ単体として画像が1つしかなく、TwitterのタイムラインやFacebookページも読み込んでいるので、ページ全体が表示されるのにmuseum-19サブドメインと比較して0.47秒しか差が出なかったが、転送量は約5.8%にまで圧縮された。
プラグインの効果はあるが、それ以上にTwitterタイムラインやFacebookページ、それと忍者おまとめボタンがボトルネックになっていることが分かる。

ここまでの改造の成果

ここまでの改造の成果であるPukiWikiはこちらなので、「実際どうなのか?」を確認したい人は参照して欲しい。

今回も前回と同様にゲストアカウントを用意したので、スパムや破壊行為は困るが(スパムフィルタspam_filter.phpは導入済みだが)、ユーザー名とパスワードは次の通りだ。

ユーザー名:guest
パスワード:guest

ファイルの添付やページの凍結・解除は行なえないが、ほぼ全てのPukiWikiの作業が可能なので、色々と試してみて欲しい。「案外PukiWikiって使えるな」と思っていただければ、私としても嬉しく思う。

おわりに

今回の画像遅延読込・画像リサイズプラグインでは、基本的にプラグインの導入だけでページの表示速度向上を狙っている。PukiWikiの場合、画像表示にはrefプラグインを使うのが一般的だし、自動的に画像をJPEG品質値70で表示して遅延読み込みさせるので、既存のページを変更することなくプラグインの恩恵が受けられる仕組みだ。
冒頭に述べたように、本来なら画像ファイルを添付する際に手を加えた方が良いだろう。ページ編集画面は工夫したい所ではあるので、画像リサイズプラグインを応用する形で実装を予定したい(あくまで予定)。
・・・PukiWikiの改造って、キリがないなぁ。(;´Д`)

 

 

この記事が気に入ったら
いいね ! をお願いします


ITで何かお手伝いできることはありませんか?

CTA-IMAGE

本サイトでは、外部サービスと連携して「ITの困った」を解決します!

PukiWikiカテゴリの最新記事