2016年10月13日
DynamicMTML でテンプレートを書く時に心がけたいこと
PowerCMS に同梱され、GPLv2 ライセンスでも配布している DynamicMTML は、Movable Type のダイナミックパブリッシングのように動的にビルドする機能を、静的 HTML の中で部分的に使用できるという点が最も特徴的な機能となります。
ダイナミックパブリッシングではなく、DynamicMTML を使用することを選択したのであれば、静的にビルドされる箇所と動的にビルドされる箇所とを意識しながらテンプレートを書くことを心がけたいところです。
その心がけによって、ダイナミックパブリッシングではパフォーマンスが出なかったテンプレートが、DynamicMTML に変更することでパフォーマンスが出る場合があります。
DynamicMTML で動的に MT タグをビルドする方法
基本的な機能の紹介となりますが、DynamicMTML を使ったことのない方のために、DynamicMTML で MT タグをビルドする方法を説明します。
DynamicMTML で動的に MT タグをビルドする際に使用する主なタグは下記の3点になります。
- MTDynamicMTML タグ(ブロックタグ)
- MTRawMTML タグ(ブロックタグ)
- MTML タグ(ファンクションタグ)
インデックステンプレートでのそれぞれの MT タグの使用例が下記です。
<MTBlogName><MTTemplateNote value="ここは静的にビルドされる"> <MTRawMTML> <MTBlogName><MTTemplateNote value="ここは動的にビルドされる"> </MTRawMTML> <MTDynamicMTML> <MTBlogName><MTTemplateNote value="ここは動的にビルドされる"> </MTDynamicMTML> <MTML tag="MTBlogName"><MTML tag="MTTemplateNote" params='value="ここは動的にビルドされる"'>
もし上記のインデックステンプレートを記述したブログ名が「PowerCMS」であれば、出力される HTML の内容は下記になります。
PowerCMS <MTBlogName><MTTemplateNote value="ここは動的にビルドされる"> <MTDynamicMTML> <MTBlogName><MTTemplateNote value="ここは動的にビルドされる"> </MTDynamicMTML> <MTBlogName><MTTemplateNote value="ここは動的にビルドされる">
MTTemplateNote タグで「ここは動的にビルドされる」というメモを残した箇所の周辺は HTML ファイル内にそのまま残り、「ここは静的にビルドされる」というメモを残した箇所の周辺は HTML ファイル内には残らないことが確認できるかと思います。
PHP でファイル内に含まれる <?php ... ?>
と記述した部分が、アクセス時に動的に処理されるように、DynamicMTML では、HTML ファイル内に記述された MT タグの部分が動的に処理されます。
なお、ContactForm や Members 等の CGI で使用する場合は、下記のように MTBuildRecurs タグの記述が追加で必要になります。
<MTBlogName><MTTemplateNote value="ここは静的にビルドされる"> <MTBuildRecurs><MTRawMTML> <MTBlogName><MTTemplateNote value="ここは動的にビルドされる"> </MTRawMTML></MTBuildRecurs> <MTBuildRecurs><MTDynamicMTML> <MTBlogName><MTTemplateNote value="ここは動的にビルドされる"> </MTDynamicMTML></MTBuildRecurs> <MTBuildRecurs> <MTML tag="MTBlogName"><MTML tag="MTTemplateNote" params='value="ここは動的にビルドされる"'> </MTBuildRecurs>
HTML 内に記述された MT タグは、ダイナミックパブリッシングでビルドされる領域になりますが、CGI の実装には出力結果に記述されている MT タグを動的にビルドする機能がないためです。
MTBuildRecurs はタグ名に Recurs という単語が含まれている通り、MT タグを繰り返しビルドします。
具体的には、下記のフローで HTML をビルドします。(正確ではありませんが、わかりやすさを優先して説明します)
- 静的にビルドされる部分をビルドする(1回目)
- MT タグが出力結果に残る
- MTBuildRecurs によって、出力結果に残った MT タグを繰り返しビルドする(2回目)
- 出力結果には MT タグが残らない(ビルド済)
MTML タグの存在意義
前述の記述例を見ると、MTDynamicMTML タグや MTRawMTML タグの使用例の方が明らかにわかりやすいのではないかと思います。
しかしながら、静的にビルドできる部分は再構築時にビルドしてしまい、動的にしかビルドできない部分のみを動的にビルドするといった工夫をしたい場合は、MTML タグが活用できます。
MTML タグを使用する場合と使用しない場合の違い
例えば、URL に指定したパラメータに応じて、出力する記事一覧を変更したいとします。
URL に指定したパラメータに応じて処理を分岐する箇所は、先ほど言及した動的にしかビルドできない箇所です。 なぜなら指定されたパラメータはアクセス時にしか確定しないためです。
この例を MTRawMTML タグを使った例と、MTML タグを使ったインデックステンプレートの記述例をそれぞれ紹介します。(説明のための例なので改善の余地のある冗長な記述になっています)
URL に指定されたパラメータを取得する場合は、MTQuery タグを使用します。
- MTQuery(ファンクションタグ)
MTRawMTML タグを使用する例
<MTRawMTML> <MTSetVarBlock name="cat"><MTQuery key="cat" encode_html="1"></MTSetVarBlock> <MTIf name="cat" eq="A"> <MTEntries category="カテゴリA" limit="3"> <MTEntriesHeader><ul></MTEntriesHeader> <li><a href="<MTEntryPermalink>"><MTEntryTitle></a></li> </MTEntriesFooter></ul></MTEntriesFooter> </MTEntries> <MTElseIf name="cat" eq="B"> <MTEntries category="カテゴリB" limit="3"> <MTEntriesHeader><ul></MTEntriesHeader> <li><a href="<MTEntryPermalink>"><MTEntryTitle></a></li> </MTEntriesFooter></ul></MTEntriesFooter> </MTEntries> <MTElse> <MTEntries limit="3"> <MTEntriesHeader><ul></MTEntriesHeader> <li><a href="<MTEntryPermalink>"><MTEntryTitle></a></li> </MTEntriesFooter></ul></MTEntriesFooter> </MTEntries> </MTIf> </MTRawMTML>
HTML ファイル内には下記が出力されます。
<MTSetVarBlock name="cat"><MTQuery key="cat" encode_html="1"></MTSetVarBlock> <MTIf name="cat" eq="A"> <MTEntries category="カテゴリA" limit="3"> <MTEntriesHeader><ul></MTEntriesHeader> <li><a href="<MTEntryPermalink>"><MTEntryTitle></a></li> </MTEntriesFooter></ul></MTEntriesFooter> </MTEntries> <MTElseIf name="cat" eq="B"> <MTEntries category="カテゴリB" limit="3"> <MTEntriesHeader><ul></MTEntriesHeader> <li><a href="<MTEntryPermalink>"><MTEntryTitle></a></li> </MTEntriesFooter></ul></MTEntriesFooter> </MTEntries> <MTElse> <MTEntries limit="3"> <MTEntriesHeader><ul></MTEntriesHeader> <li><a href="<MTEntryPermalink>"><MTEntryTitle></a></li> </MTEntriesFooter></ul></MTEntriesFooter> </MTEntries> </MTIf>
MTML タグを使用する例
<MTSetVarBlock name="category_a"> <MTEntries category="カテゴリA" limit="3"> <MTEntriesHeader><ul></MTEntriesHeader> <li><a href="<MTEntryPermalink>"><MTEntryTitle></a></li> </MTEntriesFooter></ul></MTEntriesFooter> </MTSetVarBlock> <MTSetVarBlock name="category_b"> <MTEntries category="カテゴリB" limit="3"> <MTEntriesHeader><ul></MTEntriesHeader> <li><a href="<MTEntryPermalink>"><MTEntryTitle></a></li> </MTEntriesFooter></ul></MTEntriesFooter> </MTSetVarBlock> <MTSetVarBlock name="category_none"> <MTEntries limit="3"> <MTEntriesHeader><ul></MTEntriesHeader> <li><a href="<MTEntryPermalink>"><MTEntryTitle></a></li> </MTEntriesFooter></ul></MTEntriesFooter> </MTSetVarBlock> <MTRawMTML> <MTSetVarBlock name="cat"><MTQuery key="cat" encode_html="1"></MTSetVarBlock> </MTRawMTML> <MTML tag="MTIf" params='name="cat" eq="A"'> <MTVar name="category_a"> <MTML tag="MTElseIf" params='name="cat" eq="B"'> <MTVar name="category_b"> <MTML tag="MTElse"> <MTVar name="category_none"> <MTML tag="/MTIf">
HTML ファイル内には下記が出力されます。
<MTSetVarBlock name="cat"><MTQuery key="cat" encode_html="1"></MTSetVarBlock> <MTIf name="cat" eq="A"> <ul> <li><a href="http://example.com/a/post-1.html">カテゴリAの記事1</a></li> <li><a href="http://example.com/a/post-2.html">カテゴリAの記事2</a></li> <li><a href="http://example.com/a/post-3.html">カテゴリAの記事3</a></li> </ul> <MTElseIf name="cat" eq="B"> <ul> <li><a href="http://example.com/b/post-1.html">カテゴリBの記事1</a></li> <li><a href="http://example.com/b/post-2.html">カテゴリBの記事2</a></li> <li><a href="http://example.com/b/post-3.html">カテゴリBの記事3</a></li> </ul> <MTElse> <ul> <li><a href="http://example.com/a/post-1.html">カテゴリAの記事1</a></li> <li><a href="http://example.com/b/post-1.html">カテゴリBの記事1</a></li> <li><a href="http://example.com/a/post-2.html">カテゴリAの記事2</a></li> </ul> </MTIf>
上記の二つの例は、どちらも http://example.com/index.html?cat=A
という URL にアクセスした場合は、カテゴリA というカテゴリの記事一覧が表示され、http://example.com/index.html?cat=B
という URL にアクセスした場合は、カテゴリB というカテゴリの記事一覧が表示されます。
MTRawMTML タグのみを使用した一つ目の例は、記述がシンプルでメンテナンスがしやすい一方で、アクセス時に MTEntries タグを使って、DB から記事一覧を取得し、MT タグをビルドして結果を出力しているため、アクセス時の負荷が非常に高くなります。
一方、MTML タグを使用した例は、再構築時点で DB から取得すべき情報のすべてを HTML 内に展開してしまうため、アクセス時に記事一覧を DB から取得する必要はなく、パラメータ cat
の値に応じて表示内容を分岐するという最小限の動的処理に留めています。(その代わり、再構築時間は長くなります。)
Movable Type や PowerCMS は、基本的には静的出力をメインとする CMS なので、PV の多いウェブサイトなどで有利な傾向にあります。
多くのリクエストを捌こうと思うと、動的にビルドする部分がゼロであることが理想ですが、どうしても動的にビルドしなければならない箇所がある場合は、上記の MTML タグを使った方法のように、リクエスト時の負荷を最小限に抑える工夫をすることが重要になってきます。
補足
MTML タグを使う際にありがちな失敗として、静的出力部分で定義した変数を動的出力部分で使おうとして値が取得できないといったケースがあります。
<MTSetVar name="foo" value="FOO!"> <MTRawMTML> <MTGetVar name="foo"><MTTemplateNote ここの出力結果は「FOO!」ではなく空になる> </MTRawMTML>
静的にビルドする箇所と動的にビルドする箇所はビルドするタイミングが異なるため変数は共有されません。
一手間かけて下記のように修正する必要があります。
<MTSetVar name="foo" value="FOO!"> <MTML tag="MTSetVarBlock" params='name="foo"'><MTVar name="foo"><MTML tag="/MTSetVarBlock"> <MTRawMTML> <MTGetVar name="foo"> </MTRawMTML>
まとめ
上記の内容は常に有効とは限りません。
例えば PV が少ない場合は、テンプレートを工夫し、動的に処理する部分を最小限にしても、大した違いがでない場合がありますし、MTML タグを使用するテンプレートは実装が煩雑になるため、メンテナンス性が落ちます。
例えばサーバスペックを上げたり、冗長構成を取って大量のリクエストを捌ける環境にあるのであれば、テンプレートのメンテナンス性を優先し、シンプルなテンプレートに保つ方が良い戦略かもしれません。
また、動的に処理する部分が少量であってもダイナミックパブリッシングの初期化コストが無視できない状況下では、DynamicMTML を使わずに PHP や SSI を直接使用するという選択肢もあると思います。
下記の判断基準を元に計画的に実装していただければと思います。
- メンテナンス性を取るか、テンプレートのパフォーマンスを取るか
- 再構築のパフォーマンスを取るか、アクセス時のパフォーマンスを取るか
- インフラの最適化をするか、テンプレートの最適化をするか
- カテゴリー
- DynamicMTML
- テンプレート作成Tips
コメントを投稿する