WordPress の高速化施策 #wpacja2014

WordPress Advent Calendar 2014 ということで12日目を担当します@1shiharaTです。
取り敢えず、今まで Advent Calendar に参加した事がなかったので、今年こそは参加しようと思い立ちました。

とはいえ、ネタもそこまで豊富ではないので…

今回は絞り出して WordPress の高速化施策について語ろうと思います。

目次

0. 原因の調査

まずは、サイトの問題を調べること。それが適切な対処に繋がります。
WordPress は CMSですので、フロントエンド側のボトルネックと”バックエンド側のボトルネック”を調べることが重要となります。

フロントエンド側の調査

主に、開発者ツールを使用して調査することになります。
( 私自身 Chrome を使用しているので Chrome Developer Tool を軸に書きますが、他のブラウザでも出来るかと思います。)

( Chrome Extension )

Google 製のウェブパフォーマンス測定ツールです。
基本的に、Chrome Extension 版を使用することが多いです。

Chrome 開発者ツールの「Network」タブも役に立ちます。

ブラウザがそれぞれのリソースを読み込むのにどれぐらいかかったかというのが一目瞭然です。

簡単に言うと、一番上のリクエストページ自体のレスポンスが遅い場合と、画像などの静的ファイルの読み込みに時間がかかっている場合が一目瞭然です。

バックエンド側の調査

フロントエンド側の調査の結果、リクエストしたページ自体のレスポンスが遅い場合にはコチラの調査を深くほっていかねばなりません。

上記プラグインを有効化すると、ログイン時のアドミンバーにQuery Monitor バーが出現します。

それぞれの項目をクリックすると、データベースクエリーや応答時間、PHPのエラーなど 結構詳細な事項が出てきます。
これに応じて、プラグインを無効にしたり、時間のかかっている箇所を修正したりすることになります。

開発者のためのプラグインも結構たくさんあるのですが、僕が普段使用する中ではこれが一番お手軽かなという気がします。

1.プラグインリソースの最適化

1.1 プラグインのデメリット

WordPress の一つの利点として、拡張性の高いプラグイン機能が思いつきますね。
こんな機能つけたいな…っていう見切り発車的な発想でも、wordpress.org の公式プラグインディレクトリや
Google 先生に聞くと割と解決策が返ってきます。

しかし、その結果プラグインごとに用意された css , jsファイルを個別にロードすることになります。
WordPressのコア機能では、静的ファイルをプラグインを超えてまとめてくれたりはしません。
よって、大量のリソースにリクエストする状態に陥ってしまいます。
どれだけテーマを作成する時に Grunt, Gulp といったタスクランナー を使ってminify かけようと、これではあまり意味がない気がします。

一方、HTTP1.1 では同時接続数が決まっているので、比較的新しいブラウザでも最大で6つのリソースずつしか読み込むことができません。
ココらへんの知識には下記の記事が非常に参考になると思います。

身につけておきたいWebサイト高速化テクニック #2|検証ツールとそもそもHTTPって何だ編

1.2. 解決方法

これは プラグインの仕組み上仕方ないことなので、サーバーサイドで解決することになります。
プラグインから静的リソースを読み込ませる時には、wp_enquene_scripts()といった関数を使って、
wp_head(), wp_footer() に埋め込みます。ですので、比較的簡単に対処することができます。

WordPressにおける静的ファイルの管理

WordPressではどのように静的ファイルを管理しているのかについて、軽く触れます。
基本的に以下のファイルにその記述がなされています。

おおまかに説明すると、WP_Dependencies というclassを拡張して、WP_Scripts, WP_Stylesという classを作成。
functions.wp-scripts.php と functions.wp-styles.php というファイルで、
それぞれの classのインスタンスを関数内で global で取得し、いろんな操作をしています。

ってことは、テーマ内からでも global $wp_scripts, $wp_styles という記述をしてあげれば、出力の調整が可能です。( ちゃんと関数も用意されています )
まぁ、でも面倒ですね

AssetsMinify を使う。

$wp_scriptsや$wp_styles といったインスタンスを使って、自分で圧縮したり、キャッシュを取ることも可能です。
が、ここはWordPress。既にプラグインもあります。
プラグインで起こっている問題もプラグインで解決するという..なんかおかしな状態ですが。

AssetsMinify


このプラグインでは、Assetic という symphony などでも使用されている静的ファイル管理用ライブラリと、
cssMin や jsMin といった Minify するためのライブラリを使っています。

このプラグインを有効化して設定をすると、$wp_scripts, $wp_styles に登録しているcss,jsファイルをひとまとめにしてくれます。
ちゃんとminifyせずに出力したいファイルも登録できるので、何気に便利です。

2. キャッシュを使用する

キャッシュを使用する…といっても、W3 Total Cache といったキャッシュ系プラグインを利用する方法が一番簡単かなと思います。

では、WordPress のプラグインを開発したり、テーマ開発を行う際に私達が行えるキャッシュについて考えてみます。
WordPress でオブジェクトキャッシュを取るには、WP_Cache クラスを利用します。( 正確には wp_cache_add(), wp_cache_get といった関数 )
また、options テーブルに 有効期限を定めたデータを保存する 「Transients API」も用意されています。
Transients は「一時的なデータ」といった意味合いかと思います。(間違っていたらすみません)

これらを利用することで、データベースへの問い合わせも減り、高速化につながります。
例として、twentyfourteen テーマのコードを挙げます。

/**
 * ブログで複数のカテゴリーが登録されているか調べる関数
 *
 * @since Twenty Fourteen 1.0
 *
 * @return 真偽値 : 複数のカテゴリーが登録されている場合は true を返す
 */
function twentyfourteen_categorized_blog() {

     // ‘twentyfourteen_category_count' というキーのデータが見つからない場合
     if ( false === ( $all_the_cool_cats = get_transient( 'twentyfourteen_category_count' ) ) ) {
          // 投稿があるカテゴリーリストを取得
          $all_the_cool_cats = get_categories( array(
               'hide_empty' => 1,
          ) );

          //
          // 取得したカテゴリの数を数える
          $all_the_cool_cats = count( $all_the_cool_cats );

          // ‘twentyfourteen_category_count' というキーでカテゴリ数を保存
          set_transient( 'twentyfourteen_category_count', $all_the_cool_cats );
     }

     // 取得したカテゴリ数が1じゃない場合
     if ( 1 !== (int) $all_the_cool_cats ) {
         // true を返す
          return true;
     } else {
         // false を返す
          return false;
     }
}

/**
 * twentyfourteen_categorized_blog 関数で使用している一時的なデータを削除するアクションフック
 *
 * @since Twenty Fourteen 1.0
 */
function twentyfourteen_category_transient_flusher() {
     // ‘twentyfourteen_category_count’ というキーを持つデータを削除
     delete_transient( 'twentyfourteen_category_count' );
}

// カテゴリー編集時と投稿保存時に上記関数を動作させる
add_action( 'edit_category', 'twentyfourteen_category_transient_flusher' );
add_action( 'save_post',     'twentyfourteen_category_transient_flusher' );

Transients API を使わない場合ですと、twentyfourteen_categorized_blog() と実行した時に
get_category()関数を呼び出して データベースクエリを構築し、結果を取得しています。

しかし、Transients APIを利用することで以下の場合にのみ get_categories() を実行し、取得したカテゴリーを数える処理を行います。

  • テーマをインストールしてから最初の実行時
  • カテゴリー編集時
  • 投稿保存時
  • データをセットしてから24時間後

上記以外の場合は、twentyfourteen_category_count というキーに保存してあるカテゴリー総数を取得します。

3. 画像の最適化

WordPressの場合、画像の最適化をするポイントは2つあります。

  • テーマ内で使用する画像
  • 運用上 uploads ディレクトリへ追加される画像

テーマ内で使用する画像については、制作完了時に JPEGmini や pngmini, ImageOptim といった画像圧縮系ソフトを利用して最適化したり、
Grunt や Gulp といったタスクランナーによって最適化を自動化したり等、いろいろあると思います。

しかし、運用上 uploads ディレクトリへ追加される画像については、中々厳しい側面があります。
定期的に ディレクトリ毎ダウンロードしてソフトを通して再アップロードも面倒なので…

画像の最適化としては、EWWW Image Optimizerを使えば、そこそこ画像を最適化出来ると思います。
プラグイン内に画像最適化用のライブラリを内包しており、php から実行するようになっています。

対応OS

Windows, Mac, Darwin, SunOS, FreeBSD, Linux

内包ライブラリ

jpegtran, jpegmini, optipng, pngout, pngquant, gifsicle

メジャーどころのものしかないので、違うライブラリを使いたい場合には別の方法を考えた方がいいでしょう。

4. データベースの最適化

WordPress の投稿・固定ページ投稿タイプでは、初期状態でリビジョン機能が有効になっています。
リビジョンは差分管理ではなく、そのままの状態をデータベースに保存しています。
例えば、リビジョン数が20あったとすると、20記事分データベースには記事として保存してある状態です。

無効化する方法もあるので、必要ない時は下記の記事を参考にしてください。

WordPressのオートセーブとリビジョン機能をプラグインを使わずに無効化する。 | webOpixel

また、そういったデータベースを最適化するためのプラグインもあります。

5. CloudFlareを使う

もう大分おなじみのCDNサービスです。10月ぐらいに Universal SSL というサービスが始まり、SSL を無料でも利用することが出来るようになりました。
( ただし、WordPress やEC-CUBEなどで利用する場合、管理画面等でリダイレクトループが発生するので、こういったプラグインを使用して下さい。 )
導入もDNSレコードを書き換えるだけで簡単にできます。
優良プランだと、画像の最適化もすることができます。


駆け足になりましたが、僕が普段対処している方法はこんな感じです。
内容の中に間違っている箇所もあるかもしれませんので、その時は指摘していただけると助かります。
次回は、Masaさんです。