やはりお前らのMTMLは間違っている!
公開日 : 2015-11-25 12:38:58
MTDDC で話してきました。
MTでのCMS構築案件で皆あれこれ工夫しているというのは理解できるのですが、傾向として結果として見通しの悪いテンプレートになっているケースを目にすることが最近増えてきたように思います。理由はいくつかあると思うのですが、以下のようなことではないかと思います。
- 案件の規模が大きくなり、顧客の要望が増え仕様が複雑になってきている
- 実装者のスキルが上がってきており、複雑な要件もMTMLで実現できるようになってきている
後者は良い傾向であるともいえますが、結果として初心者が修正できないテンプレートになったりしては本末転倒かと思います(場合によっては上級者でも他人のテンプレートがわからないといったケースも)。
一例を挙げます(実際はもっと多岐に渡り複雑なケースが散見されます)。
<mt:Entries<mt:If name="want_filter"> field.foo="1"</mt:If>>
...
</mt:Entries>
上記のような書き方をしたいが、できないので色々と工夫しているということでした。以下の例では IF文を一度評価した後で decode_html して再度 mteval でビルド しています。
<mt:For decode_html="1" mteval="1">
<mt:Entries <mt:If name="want_filter">field.foo="1"</mt:If>>
...
</mt:Entries>
</mt:For>
また、下記のようにビルド結果のテキストを置換して再度ビルドするというテクニックを使っているというケースもありました。
<mt:setVarBlock name="search1">/<lz:/g</mt:setVarBlock>
<mt:setVarBlock name="replace1"><</mt:setVarBlock>
<mt:setVarBlock name="replace1" append="1">mt:</mt:setVarBlock>
<mt:setVarBlock name="search2">/<\/lz:/g</mt:setVarBlock>
<mt:setVarBlock name="replace2"><</mt:setVarBlock>
<mt:setVarBlock name="replace2" append="1">/mt:</mt:setVarBlock>
<mt:For regex_replace="$search1","$replace1" regex_replace="$search2","$replace2" mteval="1">
<lz:Entries <mt:If name="want_filter">field:foo="1"</mt:if>>
<lz:If name="__first__"><ul></lz:If>
<li><lz:EntryTitle></li>
<lz:If name="__last__"></ul></lz:If>
</lz:Entries>
</mt:For>
やりたいことは実現できているのですが、以下の課題が残ります。
- 管理画面のテンプレート検索で目的の箇所がヒットしない
- decode_html のパターンでは、HTML(デザイン)の修正時に修正が困難
- やりすぎると見通しが悪くなる
- replace のパターンでは文字列「<lz:」「</lz:」がブロック内の出力結果に含まれていないかどうかを考慮しておく必要がある
DOMDocument プラグインを利用すれば、以下のように書けます。
<mt:getElementById id="tmpl_foo" setvar="tmpl_foo">
<mt:removeAttribute name="id" node="tmpl_foo">
<mt:If name="want_filter">
<mt:setAttribute node="tmpl_foo" attr="field.foo","1">
</mt:If>
<mt:Entries id="tmpl_foo">
...
</mt:Entries>
まず、1行目で MTgetElementById タグで MTEntries ブロック(Node)を取得して変数 tmpl_foo に格納します。 2行目で、MTEntriesブロックから id モディファイアを削除しています。idモディファイアがあると entry_idでのフィルタリングがかかってしまうためです。その後、 MTIFタグで want_filter に値がある時、MTsetAttribute タグで field.foo=1 を追加します。
MTEntries に id 指定しなくても、以下のようにタグ名と index (n番目=1番目は「0」)指定で取得することもできます。
<mt:getElementsByTagName tag_name="Entries","0" setvar="tmpl_foo">
また、何をやっているかをわかりやすくするために GetHashVar プラグインの note モディファイアを使ってコメントを該当タグの中に直接記載することができます(そもそも存在しないモディファイアは無視されるので、プラグインがなくてもこう書けます)。
<mt:getElementsByTagName tag_name="Entries","0" setvar="tmpl_foo"
note="1番目の mt:Entriesタグにカスタムフィールド
foo によるフィルタリングをかける">
<mt:If name="want_filter">
<mt:setAttribute node="tmpl_foo" attr="field.foo","1"
note="want_filterが1の時フィルタリング">
</mt:If>
<mt:Entries id="tmpl_foo"
note="DOM操作でフィルタ指定対象のブロック">
...
</mt:Entries>
ま、スライド見ていただければ言わんとするとことはおわかりいただけるかと思いますが、この手の話しならこれからいくらでもするからな! これからは間違うなよ!