WordPressは世界で最も普及しているCMSですが、2.8以降からは徐々にCMSの殻を破り、様々な機能を提供する総合的なプラットフォームへと進化し始めています。本連載は、WordPressをソリューションとしたWeb制作の現場において必要な、また助けとなる知識やノウハウをご紹介していきます。
第1回目となる今回からは数回にわたって“最低限理解しておくべきWordPressの基本的な5つのルール”についてご紹介します。
ルールはそれぞれ“ルーティング”“デバッグモード”“フックとフィルタ”“キャパビリティ”“データベース”といずれもWordPressの中核をなすものです。これらのルールを理解することで、より高度で複雑な要件にも対応することができ、Web制作そのものを WordPressでマネージメントすることも不可能ではなくなります。
リクエストを処理するルーティング機能
WordPressに限らず、昨今のCMSやアプリケーションフレームワークのほとんどにはルーティング機能が備わっています。ルーティング機能とは、リクエストされたURIを解析し、解析結果に基づいたプログラム呼び出しを行う機能です。「/2010/06/15/123000」や「/study/wordpress/standard」というようなURIは、人間に理解しやすい意味ももちろんありますが、それ以上にプログラムが“何をリクエストされたのか”を理解するためのものです。
WordPressでは、リクエストされたURIに対象となる実体(Webページや画像など)が“無い場合”に、WordPressに要求されたURIであると認識し、リクエストされたURIの解析を行います。つまり、WordPressのアップロード機能などを使ってアップロードした実体へのリクエストには、WordPressは関与しないことになります。「アップロードしたHTMLを直接リクエストすればWordPressは処理を行わない」と言うこの働きを利用した有名なプラグインに「wp-super-cache」があります。
Movable Typeのように、静的なHTMLを構築することでWordPressの働きを抑えることは、たくさんのリクエストを処理したり、安定した運用を目指す際には欠かすことのできない重要な要素の1つですが、安易にキャッシュすることで思わぬ落とし穴にハマることもあります。最近では、静的なHTMLの動的に表示したい一部分だけをJavaScriptで非同期的に更新する手法を良く見かけますが、この方法でも同様のことが言えます。つまり、なんでもかんでもキャッシュすれば軽くなる、というものではありませんので、まずはどのようなアプローチが有効であるかを図る力を身につけるために、WordPressが実際どのようにしてリクエストを処理しているのかを見ていきましょう。
ルーティング機能を提供する3つのクラス
WordPressは、wp、wp_rewrite、wp_queryという3つのクラスにより、リクエストされたURIを処理します。これらのクラスは、“リクエストされた(URIを含めた)環境を最適化する”“URIの構造を解析する”“解析した結果に基づいて記事やページを抽出する”という機能を持ち、リクエストされたURIをこれらの機能に連続的に渡すことでWordPressが何をするか決定します。
リクエストされたURIは、WordPressで処理される前に、Webサーバ(Apacheなど)からPHPに渡されます。この段階では、リクエストの方式は利用しているWebサーバによって様々なものとなっています。
wpクラスは続く処理を一本化するために、リクエストされたURIを普遍的なデータへと最適化し、リクエスト方式それぞれの仕様の差を吸収する役割を持っています。
wp_rewriteクラスはデータベースに登録されているURI解析用の設定を用いてURI構造を解析します。本質的にはルーティング機能は、このwp_rewriteクラスより提供されています。
wp_queryクラスはwp_rewriteクラスが解析した結果を受け取り、記事やページを抽出します。抽出された記事やページは、その属性に基づいたテンプレートを使ってHTMLへと変換され、クライアントへ返します。
前述のキャッシュを検討する際に最も重要なのは、これら3つの処理はWordPressに処理が渡されると必ず行われるという点であり、これら3つの処理がWordPressの処理コストを大きく占めているという点です。HTMLの変換という大きな処理もありますが、これは細分化されており、キャッシュに関わる一連の処理と変換処理にかけるコストがそれほど変わらないので、特殊な条件下にない限り、キャッシュで受けられる恩恵は微々たるものです。
つまり、静的なHTMLを部分的にJavaScriptで更新するような場合に、WordPressを関与させてしまうと、体感速度以上の恩恵があまり受けられないということになります。
こういった点を最初から考慮しておくと、将来トラフィックが増えた際にどのようなアプローチで負荷を軽減するかを計画することができ、Webサイトの構造に最適化した負荷軽減策を実施するまでのリファクタリングの工数を減らす効果が期待できます。
WordPressの仕様を踏まえたURI設計
カテゴリの優先順位
2.8からはカスタムタクソノミーが、3.0からはカスタム投稿タイプが導入され、WebサイトによってはURIの構造が複雑化する傾向にあります。URIはその性質上運用後に変更することが難しい要素ですので、テスト段階でどのようなURIが有効であり、また有効でないのかをチェックすることが重要です。
とくに、パーマリンクにカテゴリやタグを含むURI設計の場合はカテゴリ同士の優先順位などに注意が必要です。
たとえば「abc」カテゴリと「def」カテゴリ両方に属する記事の場合、パーマリンクに含まれるカテゴリ名は先に登録したカテゴリの名称が使われます。この優先順位に対してアプローチできるインターフェースは用意されていないため、運用後に「こっちのカテゴリ名をURIに含んでほしい」というような要件が発生した場合に問題となります。
フィルタ処理によってURIに含まれるカテゴリ名を強制的に変えることは可能ですが、パーマリンクは頻繁に呼び出される要素であり、毎回強制的に変えるのはパフォーマンスの低下につながります。また、強制的に変えたパーマリンクにアクセスした際には本来のカテゴリ名でのパーマリンクにリダイレクトされますので、本質的には意味がありません。
このような問題がありますので、パーマリンクにカテゴリやタグなどのタクソノミーを加えたい場合対象となるタクソノミーはパーマリンクでの分類に限定するのが一般的です。つまり、カテゴリ名をパーマリンクに加える場合には1つの記事は1つのカテゴリにだけ属するよう運用ルールを定めます。
パーマリンクの先頭に置く要素
カテゴリやタグなど任意の単語をパーマリンクに含める場合に注意しなければならない点がもう1つあります。
WordPressのパーマリンク設定は柔軟で強力ですが、カテゴリやタグ、投稿者、投稿タイトルをパーマリンクの先頭においてはなりません。なぜならば、カテゴリやタグなどには定型化できるフォーマットがなく、ページスラッグにも同じことが言えるためです。
これでは既存のページやカテゴリのリストにマッチするものがないかどうかを評価しなければならなくなり、パフォーマンスが低下します。カテゴリやタグ、投稿者名などはパーマリンクに含まれない場合もありますので、評価対象となるのは既存ページのリストです。よって、ページの少ない運用直後ではそれほどパフォーマンスは低下しませんが、運用期間を重ねページの数が増えていくにつれて徐々にパフォーマンスは低下していきます。パーマリンクの先頭に定型化できるパーマリンクタグが指定されていれば、記事かページかの評価はフォーマットへのマッチングで済むのでパフォーマンス低下にはつながりません。
カスタム投稿タイプとカスタムタクソノミーのURI
2.8からはカスタムタクソノミーが導入され、3.0からはカスタム投稿タイプが本格的に利用できるようになりますが、どちらも設定内容によってはコストパフォーマンスを下げるおそれがあるので導入には十分な検証が必要です。
どちらも導入すれば本格的なCMSとしての役割を担えるほど強力な機能ですが、これからも仕様変更の可能性は十分にあるため安易な判断は袋小路に陥る可能性があり危険です。現時点では複雑なURI設計は控えるなど、慎重に取り組んでください。
ルーティングを理解することがWordPressの本質をつかむ第一歩です。次回は開発時にも運用時にも押さえておきたい“デバッグモード”についてお伝えします。