Sample Site

GradeAの先行くWordPress高速化 – 必ず結果の出る実践的HTTPリクエスト削減法

WordPress は、プラグインで手軽に機能が拡張できる反面、あちこちに css や js が散乱し、放っておくとベスト・プラクティスからは程遠い状態になりがちです。

もちろんこういった問題の解決を図るプラグインも多数リリースされていますが、ページ単位の処理なので、サイト全体の構成を通して最適にはなりません。

そこで第1部「サイト高速化の「戦略」と「戦術」- GradeAのその先へ」、第2部「サイトに適したリソース配置とasync/defer完全マスター – レンダリング優先のグッド・プラクティス」では、数あるベスト・プラクティスの全体を俯瞰し、個々の Tips やテクニックからは見え難い、最適化の考え方や道筋を提案しました。

その総仕上げとして今回は、WordPress サイトを例題に、必ず結果の出る HTTP リクエストの削減方法を提案したいと思います。

実践的手法の概要

HTTP リクエストの削減を目的とした css、js の結合系プラグインでは、「サイトが正しく機能しない」といったことが頻繁に起き、その修正にはトライ&エラーが必要です。

プラグインの幾つかは、トラブルに対処するための調整機能を提供してくれていますが、サポート・フォーラムを見ていると、そういった機能を使いこなす前に(あるいは存在すら知らずに)導入を断念するケースも少なくありません。

元はと言えばプラグインの導入で増えた乱雑な css や js を、ページ内の文脈に合わせて自動で結合すること自体、ムリな話です。「どのファイルをどう結合すべきか」は人手で仕分け、ある程度シンプルになったところでプラグインの力を借りる – 数あるプラグインを試して私が得た結論は、結局はこれが王道かつ近道だと言うことです。

そこで今回は、どのプラグインにも手を加えることなく css や js を見通しよく人手で結合し、残りをプラグインで自動結合する、という方針で臨むことにします。人手 とは言え、結合を簡単化する補助的なツールを作成しましたので、ご安心を。

以下、その概要です。

人手による結合

サイト高速化の「戦略」と「戦術」- GradeAのその先へ」でも述べたように、まずは以下の観点で css や js をグループに仕分けます。

  • <head> に配置するリソース:「Above the hold」のコンテンツに関連するリソース
  • </body> に配置するリソース:サイト全体を通して共通なリソース

このうち、結合の対象とするのは WordPress の標準的な方法で挿入されたファイルとします。

「標準的な方法」とは、wp_enqueue_*() で挿入されたことを意味します(アクション・フックの wp_headwp_footer をトリガーに、外部ファイルの読み込みコードを直接 echo で吐き出すのは、今や時代遅れなのですョ 😉 )。

作戦としては以下の通りです。

  • wp_enqueue_*() でキューイングされているリソースを抽出する
  • 一旦個々のリソースを wp_dequeue_*() で解除する
  • 解除したリソースを、適当なツールで結合する
  • 結合したリソースを wp_enqueue_*() でキューに登録する

最も面倒な作業が「キューイングされているリソースの抽出」ですが、各プラグインのソースコードを調べることなく、この作業を簡単化するツールは後半で説明します。

また、リソースの結合には PHP プログラム「minify」を使います。応答性という点ではベストではありませんが、次のようなメリットがあります。

  1. 使い方が簡単
  2. インストールが簡単
  3. グループが構成できる
  4. gzip 圧縮やキャッシュ有効期限の設定ができる
  5. 圧縮ファイルを予めキャッシュできるため、負荷が低い
  6. 304 Not Modified の応答ができる
  7. APC や Memcache の導入も可能
  8. 幾つかの WordPress プラグインと親和性が良い

特にグループを構成できる点が、今回の趣旨にはぴったりです。また安定運用の暁には、構成したグループを静的ファイルに置き換え、CDN に叩き込めば完璧です!

プラグインによる結合

前章の結合で残ったリソースは次のいずれかでしょう。

  • ページに個別のリソース
  • ベスト・プラクティスに従い、</body> 直前に置けば良いスクリプト

これらをプラグインで再結合します。

過去記事 では Head CleanerWP Minify(現在は更新停止、セキュリティ問題アリ)をオススメしましたが、改めて19のプラグインをざっと評価した結果、以下の理由により、今回は Autoptimize をイチオシとします。

  • インラインの css や js も結合ファイルに含めるため、不具合が起きにくい
  • 結合から外す除外指定の自由度が高く、柔軟な構成が可能
  • </body> 直前の配置を基本に、一部を <head> に置くことも可能
  • 細かな調整を可能とするアクション・フックが豊富
  • 予め不具合の出るプラグインへの対応が埋め込まれている
  • defer 属性がサポートされている
  • サポート・フォーラムが活発で、何より作者の気合いが感じられる
評価したプラグイン一覧
プラグイン名 結合対象 除外指定 gzip圧縮 cache設定 備考
Autoptimize 全 css、js y y y 除外指定が秀逸、css の遅延読み込みも可
Better WordPress Minify wp_enqueue_*() y y y css の url() 展開OK、cache 期限はデフォルト2時間
AssetsMinify wp_enqueue_*() y n n jQuery 依存関係ダメ、Compass・SASS・LESS 可、要 PHP 5.3+
Simple Minify wp_enqueue_*() y n n AssetsMiify の改悪版、結合数少、プロトコル省略不可
Minify wp_head(), wp_footer() n n n Memcached 利用可、要 .htaccess 連携、設定項目少
WP Minify Fix 全 css、js y y y WP Minify のセキュリティ対策版、他ドメイン結合可、HTML 縮小、FirePHP 連携
Dependency Minification wp_enqueue_*() y y y 有効後サイト閲覧要、プロトコル省略不可
Combine CSS / Combine JS wp_enqueue_*() y y n デバッグ機能あり
MiniPress 全 css、js n n n β版、設定項目無
Asynchronous Javascript wp_print_scripts() n n n Head.JS、結合不可、Jetpack, WP Most Popular 併用不可
Async JS and CSS wp_head(), wp_footer(), wp_enqueue_*() y n n 設定項目多め、結合不可、css インライン化
MnCombine wp_head(), wp_footer() y n y 開発/製品の2モード
MinQueue wp_enqueue_*() y n y css、js のリストアップ機能あり
WP Deferred Javascripts wp_enqueue_scripts() y n n LABjs、結合不可
JS & CSS Script Optimizer wp_enqueue_*() y ? ? メモリ消費で落ちるとのコメント多数
External Files Optimizer 全 css、js n n n 更新停止
CleanerPress wp_enqueue_scripts(), wp_head(), wp_print_styles() y n y <head> 整形、Head.JS
Head Cleaner 全 css、js y y y <head> の整形
W3 Total Cache 全 css、js y y y 超多機能

css、js結合の実践的手法

例題として、ローカルに仕立てたサーバー http://localhost/ のドキュメント・ルート直下に WordPress 3.9 + TwentyFourteen を、そして以下のプラグインをインストールしました。

  • Meteor Slides
    • インラインと外部スクリプトを組み合わせて使うため、自動結合で問題が起き易いパターンです。本例では「Above the fold」のコンテンツ、かつ各ページ共通のリソースという想定です。スクリプトの読み込み後にレンダリングするので表示が遅れがちですが、カスタマイズ機能を活用し、初期のレンダリングに必要な HTML をサーバー側で構築する例をお見せします。
  • jQuery Smooth Scroll
    • これも各ページ共通で使う想定です。
  • SyntaxHighlighter Evolved
    • クライアント側でレンダリングするタイプの代表で、リフローFOUC が避けらません。高速化の観点からは、サーバー側で HTML を構築する GeSHi を使った プラグイン の方が良いでしょう。コードに応じて読み込むリソースが変わるので、ページ毎に個別のリソースという想定です。
  • WP Social Bookmarking Light
    • wp_headwp_footer を介して css や js の読み込みを直接 echo するプラグインの代表です。Hatena に対応してるので、背に腹は代えられないという人なら。

この例題に対するリソース配置のゴールを以下のように設定しました。

  • スライドショーを素早く表示させるため、そのリソースは <head> に配置する
  • ただし後続のページ解析を妨げないよう、スクリプトは async 付きで読み込む
  • また体感速度が速くなるよう、HTML は可能な限りサーバー側で構築する
  • Syntax Highlighter 用のリソースは、結合した上で </body> 直前に配置する
  • ソーシャルメディア用のスクリプトは </body> 直前に配置する

ページ構成のゴール

以下、この例題を元に具体的に説明していきます。手順は多目ですが、ガンバって付いて来て下さい。きっと報われます 😀 。

  1. キューイングされているリソースのハンドル名を調べる
  2. minify のインストールと基本設定
  3. groupsConfig.php に結合対象のリソースをグループとして登録する
  4. functions.php でグループ化した各リソースをキューから削除する
  5. functions.php でグループをキューに登録する
  6. 残ったリソースをプラグインで結合する
  7. 初期のレンダリングを高速化する
  8. 参考情報

キューイングされているリソースのハンドル名を調べる

まずは次のコードを、テーマ(あるいは子テーマ)の functions.php に追加します。

/**
 * Make the list of enqueued resources
 **/
function my_get_dependency( $dependency ) {
    $dep = "";
    if ( is_a( $dependency, "_WP_Dependency" ) ) {
        $dep .= "$dependency->handle";
        $dep .= " [" . implode( " ", $dependency->deps ) . "]";
        $dep .= " '$dependency->src'";
        $dep .= " '$dependency->ver'";
        $dep .= " '$dependency->args'";
        $dep .= " (" . implode( " ", $dependency->extra ) . ")";
    }
    return "$dep\n";
}

function my_style_queues() {
    global $wp_styles;
    echo "<!-- WP_Dependencies for styles\n";
    foreach ( $wp_styles->queue as $val ) {
        echo my_get_dependency( $wp_styles->registered[ $val ] );
    }
    echo "-->\n";
}
add_action( 'wp_print_styles', 'my_style_queues', 9999 );

function my_script_queues() {
    global $wp_scripts;
    echo "<!-- WP_Dependencies for scripts\n";
    foreach ( $wp_scripts->queue as $val ) {
        echo my_get_dependency( $wp_scripts->registered[ $val ] );
    }
    echo "-->\n";
}
add_action( 'wp_print_scripts', 'my_script_queues', 9999 );

続いてページを表示し、HTML ソースから以下のようなコメントを抜き出します。

<!-- WP_Dependencies for styles
ハンドル名 [依存するハンドル名...] 'パス' 'バージョン' '属性' (付加情報...)
...
-->

<!-- WP_Dependencies for scripts
ハンドル名 [依存するハンドル名...] 'パス' 'バージョン' '属性' (付加情報...)
...
-->
ハンドル名
wp_enqueue_style()wp_enqueue_script() でキューに挿入されるリソースのハンドル名です。
依存するハンドル名
先立って読み込んでおくべきリソースのハンドル名が上位から順に並びます。
パス
wp_register_style()wp_register_script() で登録されたリソースへのパスです。
バージョン
登録時に指定されたバージョン文字列です。
属性
css の場合はメディアタイプが表示されます。同一タイプであれば結合が可能です。
付加情報
css であれば IE 用の条件付コメントがここに表示されます。js の場合、1 (true) が立っていればフッターで読み込まれることを示し、それ以外は「読み込みに先立って実行されるべきインライン・コード」が現れます。

ここでのポイントは、色々なタイプのページを表示し、サイトに共通なリソース群や、優先して <head> に配置すべきリソース群など、グループ分けを行うことです。

今回は、Meteor Slides が各ページ共通、かつ優先すべきリソースという想定ですので、以下を <head> に置くリソースとして抽出しました。個別ページ用の comment-reply.min.js や IE 用の css などは含んでいません。

<!-- WP_Dependencies for styles
genericons [] 'http://localhost/wp-content/themes/twentyfourteen/genericons/genericons.css' '3.0.2' 'all' ()
twentyfourteen-style [genericons] 'http://localhost/wp-content/themes/twentyfourteen/style.css' '' 'all' ()
twentyfourteen-ie [twentyfourteen-style genericons] 'http://localhost/wp-content/themes/twentyfourteen/css/ie.css' '20131205' 'all' (lt IE 9)
meteor-slides [] 'http://localhost/wp-content/plugins/meteor-slides/css/meteor-slides.css' '1.0' 'all' ()
blogsynthesis-scroll-to-top-style [] 'http://localhost/wp-content/plugins/jquery-smooth-scroll/css/jss-style.min.css' '' 'all' ()
-->

<!-- WP_Dependencies for scripts
jquery [jquery-core jquery-migrate] '' '1.10.2' '' ()
jquery-cycle [jquery] 'http://localhost/wp-content/plugins/meteor-slides/js/jquery.cycle.all.js' '' '' ()
jquery-metadata [jquery] 'http://localhost/wp-content/plugins/meteor-slides/js/jquery.metadata.v2.js' '' '' ()
jquery-touchwipe [jquery] 'http://localhost/wp-content/plugins/meteor-slides/js/jquery.touchwipe.1.1.1.js' '' '' ()
twentyfourteen-script [jquery] 'http://localhost/wp-content/themes/twentyfourteen/js/functions.js' '20131209' '' (1)
meteorslides-script [jquery jquery-cycle] 'http://localhost/wp-content/plugins/meteor-slides/js/slideshow.js' '' '' (var meteorslidessettings = {"meteorslideshowspeed":"2000","meteorslideshowduration":"5000","meteorslideshowheight":"200","meteorslideshowwidth":"940","meteorslideshowtransition":"fade"};)
blogsynthesis-scroll-to-top-script [jquery] 'http://localhost/wp-content/plugins/jquery-smooth-scroll/js/jss-script.min.js' '' '' ()
-->

ハンドル名 jquery には パス が現れず、jquery-corejquery-migrate への依存が指定されています。それぞれのパスは次の通りです。

  • wp-includes/js/jquery/jquery.js
  • wp-includes/js/jquery/jquery-migrate.min.js

パスが空のハンドル名が出てきたら、面倒でも Handles and Their Script Paths Registered by WordPress を調べて下さい。

またこれらの情報は優先度が高い順に並ぶとは限りません。結合対象とする css と js のハンドル名をピックアップし、順番に注意した上で並べ換えておきましょう。

minify のインストールと基本設定

ダウンロード・リンク から最新版を落とし、解凍後、「min」ディレクトリだけをサーバーにアップロードします。「min」はドキュメント・ルートに置くことが推奨されていますが、今回は wp-content の直下に配置してみました。

minifyの構成

基本設定で重要なのは2か所です。min/config.php を開き、以下を参考に設定して下さい。

キャッシュ保存場所の設定

次は、「min」の直下に「cache」というディレクトリを作成する場合の例です。

/**
 * For best performance, specify your temp directory here. Otherwise Minify
 * will have to load extra code to guess. Some examples below:
 */
//$min_cachePath = 'c:\\WINDOWS\\Temp';
//$min_cachePath = '/tmp';
//$min_cachePath = preg_replace('/^\\d+;/', '', session_save_path());
$min_cachePath = dirname(__FILE__) . '/cache';

作成したディレクトリには、お使いのサーバーに合わせてパーミッションを設定します。大抵の場合は 755 で OK でしょう。

キャッシュ有効期間

ブラウザやプロキシー・サーバーに保持させるキャッシュ期間を「秒」で指定します。出来る限り長く(1か月)設定し、「Grade A」の条件を保ちましょう。

/**
 * Cache-Control: max-age value sent to browser (in seconds). After this period,
 * the browser will send another conditional GET. Use a longer period for lower
 * traffic but you may want to shorten this before making changes if it's crucial
 * those changes are seen immediately.
 *
 * Note: Despite this setting, if you include a number at the end of the
 * querystring, maxAge will be set to one year. E.g. /min/f=hello.css&123456
 */
$min_serveOptions['maxAge'] = 2592000; /* one month */
その他

$min_builderPassword は、min/builder を利用しない($min_enableBuilder = false)限り、気にする必要はありません。min/builder は、index.php に引き渡すクエリ文字列を構築する補助ツールです。詳しくは Minify 2.1 on mrclay.org を参照してください。

groupsConfig.php に結合対象のリソースをグループとして登録する

ピックアップしておいた結合対象の css と js を、サイト共通のリソース・グループとして min/groupsConfig.php に登録します。条件付きコメントで読み込まれる IE 用 css は含まないよう注意してください。

今回は、<head> に置く site-csssite-js をグループとして登録しました。もちろんグループは幾つでも定義する事ができます。

/** 
 * You may wish to use the Minify URI Builder app to suggest
 * changes. http://yourdomain/min/builder/
 *
 * See http://code.google.com/p/minify/wiki/CustomSource for other ideas
 **/

return array(
    // 'css' => array('//css/file1.css', '//css/file2.css'),
    'site-css' => array(
        '//wp-content/themes/twentyfourteen/genericons/genericons.css',
        '//wp-content/themes/twentyfourteen/style.css',
        '//wp-content/plugins/meteor-slides/css/meteor-slides.css',
        '//wp-content/plugins/jquery-smooth-scroll/css/jss-style.min.css',
    ),

    // 'js' => array('//js/file1.js', '//js/file2.js'),
    'site-js' => array(
        '//wp-includes/js/jquery/jquery.js',
        '//wp-includes/js/jquery/jquery-migrate.min.js',
        '//wp-content/plugins/meteor-slides/js/jquery.cycle.all.js',
        '//wp-content/plugins/meteor-slides/js/jquery.metadata.v2.js',
        '//wp-content/plugins/meteor-slides/js/jquery.touchwipe.1.1.1.js',
        '//wp-content/plugins/meteor-slides/js/slideshow.js',
        '//wp-content/plugins/jquery-smooth-scroll/js/jss-script.min.js',
        '//wp-content/themes/twentyfourteen/js/functions.js',
    ),
);

(コメント以外の)先頭の // は minify 独自の表記法で、ドキュメント・ルートを表します。

上の例ではローカルの jquery.js を結合対象にしていますが、CDN を使いたい場合には外してください。またリモート・ファイルを加えることも可能です。詳しくは Non-File Sources を参考にして下さい。

設定後、http://localhost/wp-content/min/?g=site-csshttp://localhost/wp-content/min/?g=site-js にそれぞれアクセスできるか確認しておきましょう。

ちなみに Apache サーバー なら、「min/.htaccess」の設定により ? が省略可能です。プロキシーによっては ? 付きのリクエストがキャッシュされないことがあるそうなので、できれば省略しましょう。

functions.php でグループ化した各リソースをキューから削除する

次に、結合対象の各リソースをキューから削除するコードを追加します。同時にこれらと依存関係のある IE 用 css も解除しておきます(後で復活させるので、ご心配なく)。

/**
 * Dequeue resources
 **/
function my_dequeue_styles() {
    wp_dequeue_style( 'genericons' );
    wp_dequeue_style( 'twentyfourteen-style' );
    wp_dequeue_style( 'twentyfourteen-ie' );
    wp_dequeue_style( 'meteor-slides' );
    wp_dequeue_style( 'blogsynthesis-scroll-to-top-style' );
}
add_action( 'wp_print_styles', 'my_dequeue_styles' );

function my_dequeue_scripts() {
    wp_dequeue_script( 'jquery' );
    wp_dequeue_script( 'jquery-cycle' );
    wp_dequeue_script( 'jquery-metadata' );
    wp_dequeue_script( 'jquery-touchwipe' );
    wp_dequeue_script( 'meteorslides-script' );
    wp_dequeue_script( 'twentyfourteen-script' );
    wp_dequeue_script( 'blogsynthesis-scroll-to-top-script' );
}
add_action( 'wp_print_scripts', 'my_dequeue_scripts' );

functions.php でグループをキューに登録する

css の挿入

続いて、グループ site-css を挿入します。

ポイントは IE 用 css の再挿入です。wp_enqueue_scripts()wp_print_styles() とでは、後者の方が後に実行されるため、ハンドル名を変えて再登録します。

/**
 * Eequeue resources
 **/
function my_enqueue_styles() {
    wp_enqueue_style( 'site-css', site_url() . '/wp-content/min/?g=site-css', array(), '1.0' );
    wp_enqueue_style( 'my-enqueue-ie', get_template_directory_uri() . '/css/ie.css', array( 'site-css' ) );
    wp_style_add_data( 'my-enqueue-ie', 'conditional', 'lt IE 9' );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_styles' );
js の挿入

さらに、グループ site-js を挿入します。

ここでの最初のポイントは js の配置です。今回 site-js<head> に配置するので、wp_enqueue_script() の5番目の引数 $in_footer には false を設定します。

第2のポイントは「読み込みに先立って実行されるべきインライン・コード」の設定です。本例ではスライドショーの設定がこれに当たり、wp_localize_script() を使って埋め込みます。

function my_enqueue_scripts() {
    wp_enqueue_script( 'site-js', site_url() . '/wp-content/min/?g=site-js', array(), '1.0', false );
    wp_localize_script( 'site-js', 'meteorslidessettings', array(
        "meteorslideshowspeed"      => "2000",
        "meteorslideshowduration"   => "5000",
        "meteorslideshowheight"     =>  "200",
        "meteorslideshowwidth"      =>  "940",
        "meteorslideshowtransition" => "fade",
    ) );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );

またより低レベルな関数 add_data() を使う方法もあります(css には add_data() のラッパー関数 wp_style_add_data() が有るのに js に無いのは何故でしょう?)。

function my_enqueue_scripts() {
    wp_enqueue_script( 'site-js', site_url() . '/wp-content/min/?g=site-js', array(), '1.0', false );
    $js = <<<EOT
var meteorslidessettings = {
    "meteorslideshowspeed":"2000",
    "meteorslideshowduration":"5000",
    "meteorslideshowheight":"200",
    "meteorslideshowwidth":"940",
    "meteorslideshowtransition":"fade"
};
EOT;
    global $wp_scripts;
    $wp_scripts->add_data( 'site-js', 'data', $js );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );

CDN の jQuery を使う場合は、site-js の登録を次のコードに置き換えます。

function my_enqueue_scripts() {
    wp_deregister_script( 'jquery' );
    wp_enqueue_script( 'jquery', '//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js', array(), '1.11.0', false );
    wp_enqueue_script( 'site-js', site_url() . '/wp-content/min/?g=site-js', array( 'jquery' ), '1.0', false );
    ...
}

最後のポイントは、site-js への async 属性の付与です。ちょっと危ういハックですが、公式サポートがまだ実現していない 以上、やむを得ないですネ。

function my_add_async( $url ) {
    if ( strpos( $url, '/min/?g=site-js' ) !== FALSE ) {
        return "$url' async id='site-js";
    }
    return $url;
}
add_filter( 'clean_url', 'my_add_async', 11, 1 );

他にも非同期化できるスクリプトがあれば可能な限り asyncdefer を付けましょう。詳しくは「サイトに適したリソース配置とasync/defer完全マスター – レンダリング優先のグッド・プラクティス」を参考にしてください。

残ったリソースをプラグインで結合する

ここまでで結合していない or できない css、js は次のいずれかでしょう。

  • 標準的な手法で登録されてはいるが、ページごとに異なるリソース
  • wp_headwp_footer などのアクション・フックをトリガーに直接埋め込まれたリソース

これらを Autoptimize で結合し、</body> 直前に配置します。

今回の例題では、「読み込みに先立って実行されるべきインライン・コード」への対応がキモです。そのままではインライン部分がファイルに結合され、</body> 直前へと持っていかれてしまいます。

これを防止するため Autoptimize の除外リストに、インライン・スクリプトに含まれる文字列 meteorslides を(ついでに googleapissite-js も)設定します。

Autoptimizeの設定

あるいは次のようにアクション・フィルタでも設定できます。詳しくは Autoptimize に同梱されている autoptimize_helper.php_example を参照して下さい。

/*
 * Autoptimize filter: Exclude js files
 * @see: /wp-content/plugins/autoptimize/autoptimize_helper.php_example
 */
function my_jsexclude( $exclude ) {
    return "googleapis,site-js,meteorslides," . $exclude;
}
add_filter( 'autoptimize_filter_js_exclude', 'my_jsexclude', 10, 1 );

Autoptimize は、デフォルトで </body> 直前のスクリプトに defer 属性を付けてくれますが、他との依存関係がなければ、さらに async 属性も付けちゃいましょう!

/*
 * Autoptimize filter: Add async attribute
 * @see: /wp-content/plugins/autoptimize/autoptimize_helper.php_example
 */
function my_override_defer( $defer ) {
    return $defer . "async ";
}
add_filter( 'autoptimize_filter_js_defer', 'my_override_defer', 10, 1 );

初期のレンダリングを高速化する

Meteo Slides は、スライドショーのテンプレートや css、js を(子)テーマのディレクトリに放り込んでおくことで、元ファイルを修正せずにカスタマイズが可能です。

そこで、wp-content/plugins/meteor-slides/includes/meteor-slideshow.php を(子)テーマのディレクトリにコピーし、127行目付近の次のコードを改修します。

echo '<img style="visibility: hidden;" class="meteor-shim" src="' . $meteor_shim[0] . '" alt="" />';

上記コードでは、スクリプトが実行されるまで1枚目の画像が表示されません。「Above the fold のコンテンツは、可能な限りサーバーサイドで構築する」ために、「style="visibility: hidden;"」を削除しちゃいましょう!

以上で終了です。フ〜、お疲れ様でした 😉 。

参考情報

おまけ – Autoptimize を使いこなす

Autoptimize は、ページ中のすべてのインライン・コードや自サイトにホストされた外部リソースを1つのファイルに結合することを基本に、そこから問題のあったリソースを外していくというアプローチを元に設計されています。

そこで、トラブルを解消し、効果を最大限に引き出す Autoptimize の隠れた機能とオプションの使い方を紹介しておきます。

【 結合の対象外とするブロックの指定 】

<!--nooptimize--><!--/noptimize--> で囲んだコード・ブロックを、結合の対象外とします。

<!--noptimize-->
    <script>alert( 'this will not get autoptimized' );</script>
<!--/noptimize-->
【 Force JavaScript in </body>? 】

Autoptimize はデフォルトで、スクリプトの読み込みを </body> 直前に移動させます。JavaScript は HTML の最後で読み込むのがパフォーマンス上はベストですが、問題が生じる場合が多々あります。

このオプションを有効にすると、Autoptimize は <head> セクションにあるスクリプトをそのまま <head> にとどめます。特に jQuery ベースのテーマに有効なオプションです。

【 Look for scripts only in <head>? 】

jQuery ベースのテンプレートなど、大抵は上記と組み合わると効果を発揮するオプションで、<head> 内のスクリプトだけを結合対象とします。例えばサイトに共通なリソースが <head> セクションに集約されていれば、キャッシュ *  のサイズを適切に維持することができます。

* Autoptimize がサーバーに生成するキャッシュとブラウザ・キャッシュの両方を指します。詳しくは 作者のブログ記事 をご覧ください。

【 Exclude scripts from Autoptimize 】

結合対象外とするスクリプトを、そのブロックに含まれる文字列をカンマ区切りで指定します。例えば whatever.js, another.js などです。またカンマ前後の空白はトリムされます。

デフォルトの設定が必要なければ、空にしておきましょう。また先頭から順に処理されるので、追加は先頭に行うのが吉です。

【 Add try-catch wrapping 】

外部スクリプトの読み込みとインライン・スクリプトの実行順序が崩れると、エラーが発生する場合があります。このオプションを有効にすると、エラー発生時にも繰り返し実行を試みる try-catch ループでインライン・スクリプトを囲みます(同時にログをコンソールに出力)。JavaScript のエラーが発生する場合に試すべきオプションです。

【 Generate data:URIs for images 】

小さな背景画像を Data URI 化します。画像ファイルへの HTTP リクエストを削減する効果があります。

【 Look for styles only in <head>? 】

<head> セクション外にある CSS を結合の対象外とします。スタイル崩れが発生した時に、試してみるべきオプションです。

【 Defer CSS loading 】

CSS を遅延読み込みします。特にモバイル向けコンテンツは、「Above the fold」のレンダリングを優先させるため、必要最低限のスタイルをインラインで展開し、残りを後から読み込むのが良いとされます。

このオプションを有効にする場合、<head> セクションにインライン展開したスタイルを <!--noptimize--><!--/noptimize--> で囲む必要があります。

【 Inline all CSS? 】

ページ・ビューや訪問者の少ないサイトなら、CSS のインライン化が有効な場合もありますが、それ以外では、パフォーマンスを低下させるでしょう。このオプションは、CSS の遅延読み込みを無効にします。

【 Exclude CSS from Autoptimize 】

結合の対象外とする CSS を、そのブロックに含まれる文字列をカンマ区切りで指定します。スタイル崩れが発生した時に、試してみるべきオプションです。

注意事項 !!

本記事では全てを一気に設定する感じで説明しましたが、本来は少しずつグループ化するリソースを増やしながら動作確認をし、進めるべきです。

また提案したプロセスの最大の難点は、functions.phpgroupsConfig.php の2つを同時に更新しなければならないことです。本番環境でこれら2つの更新に時間差が生じるとマズイことになるのは容易に想像がつきますよネ。

万全を期するなら、groupsConfig.php に登録するグループ名を site-js-0.1, site-js-0.2, … というように1ステップずつ刻んで追加していき、運用が安定したら整理するというやり方があるかと思います。

また少なくとも functions.php は、すぐに元に戻せるようバックアップしておきましょう。可能なら、テスト環境を準備するのが吉です 😀 。

まとめ

サイト全体を通して共通するリソースとページに個別のリソースを分けて束ねることで、初回訪問時はもとより、ページ遷移時の表示速度をも向上させることができます。これは、直帰率を下げることにもつながると思います。

その際、すべてをプラグイン任せにせず、逆に手作業を主体とすることで、起こりがちなトラブルを回避し、また個々のプラグインに手を入れることなく css や js を結合する方法について述べました。

そもそも「どのリソースをどう束ねるか」にはヒトの高度な分析力が必要で、完全自動というワケにはいかないでしょう。ただし面倒なところにはツールを使って簡単化できることを提案したつもりです。

またプラグイン導入の際は、単に機能面だけじゃなく、高速化の観点で選定することも大事な Tips の1つだと思います。

「CloudFlare 導入、一発 OK!」も悪くはありませんが(そういうサービスですからネ)、自サイトのリソース削減に四苦八苦している人、サイト全体を通した最適化で更なる高みを目指したい人は、ぜひお試しあれ。必ず結果は出ると思いますョ。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

海外からの投稿は受け付けていません