はじめての DynamicMTML #07 - MTSearchEntries (3) MTSplitVars を組み合わせて複数ワードのOR検索

今回は、前回に引き続き MTSeachEntries についてと、MTSplitVars タグの使い方です。

MTSearchEntries は基本的には1つの検索ワードで検索する仕様になっています。前回のサンプルでも、キーワード欄に入力した1つのキーワードを、動的に検索する方法を紹介しました。

今回は、MTSearchEntries に「 MTSplitVars 」というブロックタグを組み合わせて複数の検索ワードで検索してみます。複数のキーワードは、キーワード欄にカンマ区切りで設定します。

今回のテンプレートの仕様

  • 検索ワードはキーワード欄にカンマ区切りで指定する
  • 複数のキーワードは OR 検索とする(AND 検索は次回)
  • 現在のブログ内のブログ記事から検索する
  • 最新5件を表示する
  • 現在のブログ記事を除く

完成したコード

今回の記事の完成版のコードは次のようになります。

<$mtml tag='mt:SetVars'$>
blog_id=<$mt:BlogID$>
entry_id=<$mt:EntryID$>
keywords=<$mt:EntryKeywords$>
keywords_length=<$mt:EntryKeywords regex_replace="/[^,]|\s/g","" cat="," count_characters="1"$>
limit=5
<$mtml tag='/mt:SetVars'$>

<mt:DynamicMTML>
<mt:SplitVars name="keyword" text="$keywords">
<$mt:Var name="__counter__" setvar="split_counter"$>
<$mt:Var name="keyword" trim="1" regex_replace="/\s| /g","%" setvar="keyword"$>
<mt:SearchEntries query="$keyword" blog_id="$blog_id" not_entry_id="$entry_id">
<$mt:EntryDate format="%Y%m%d%H%M%S" setvar="date"$>
<mt:SetVarBlock name="entries" key="$date">
<li><a href="<$mt:EntryPermalink$>"><$mt:EntryTitle$></a></li>
</mt:SetVarBlock>
</mt:SearchEntries>
<mt:If name="split_counter" eq="$keywords_length">
<mt:Loop name="entries" sort_by="key reverse">
<mt:If name="__counter__" eq="1">
<ul>
</mt:If>
<mt:If name="__counter__" le="$limit">
<mt:Var name="__value__">
</mt:If>
<mt:If name="__counter__" eq="$limit">
</ul>
</mt:If>
</mt:Loop>
</mt:If>
</mt:SplitVars>
</mt:DynamicMTML>

MTSplitVars を使う前に

2011年12月27日現在、Github に公開されている DynamicMTML の MTSplitVars には2つほど不具合があります。その不具合を修正したファイルを用意しました。

このファイルをダウンロードして解凍し、次の場所にある同ファイルと置き換えてください。差し替えないと、今回の記事の内容はうまく動きません。

  • /addons/DynamicMTML.pack/php/tags/block.mtsplitvars.php

MTSplitVars の使い方

MTSplitVars タグは、text モディファイアで指定した文字列を delimiter モディファイアで指定した文字列で分割して、1つずつループで出力するブロックタグです。

まずは MTSplitVars のサンプルを見てみましょう。最もシンプルな例です。

<mt:SplitVars text="MT,MTOS,DynanicMTML">
<mt:If name="__first__"><ul></mt:If>
<li><$mt:Var name="value"$></li>
<mt:If name="__last__"></ul></mt:If>
</mt:SplitVars>

出力結果は次のようになります。

<ul>
<li>MT</li>
<li>MTOS</li>
<li>DynanicMTML</li>
</ul>

このように、text モディファイアにカンマ区切りのテキストを設定すると、カンマで分割された値を value という変数名で順次取り出すことができます。上記のコードを、デフォルト設定のままのモディファイアも省略せずに書くと次のようになります。

<mt:SplitVars name="value" text="MT,MTOS,DynanicMTML" delimiter="," glue="">
<mt:If name="__first__"><ul></mt:If>
<li><$mt:Var name="value"$></li>
<mt:If name="__last__"></ul></mt:If>
</mt:SplitVars>

設定できるモディファイアは以下の通りです。

MTSplitVars のモディファイアなど

name

MTSplitVars タグのループ内で、分割された1つ1つの値を取り出す変数名を指定します。デフォルトは value です。

上記のサンプルでは、デフォルトのままなので、MTVar name="value" で値を取り出しています。

delimiter

区切り文字を指定します。デフォルトはカンマです。

text

分割するテキストを指定します。デフォルトはカンマ区切りのテキストですが、delimiter モディファイアで指定した値で区切ったテキストを指定できます。

glue

1回のループを繋ぎ合わせる文字列を指定します。

MTVar にセットされる値

MTSplitVars タグ内では、以下の値が MTVar にセットされます。

  • __first__: ループの最初
  • __counter__: ループの何回目か
  • __odd__: 奇数回目の出力
  • __even__: 偶数回目の出力
  • __last__: ループの最後

MTSplitVars でキーワードを順次取り出す

MTSplitVars の使い方が分かったところで、さっそくテンプレートを書いていきましょう。

まずは、キーワード欄に保存されているカンマ区切りの文字列を、カンマで分割して順次取り出すようにします。DynamicMTML、ブログ記事アーカイブテンプレートでの利用を前提にします。

このコードは、次のようになります。

<$mtml tag='mt:SetVars'$>
keywords=<$mt:EntryKeywords$>
<$mtml tag='/mt:SetVars'$>

<mt:DynamicMTML>
<mt:SplitVars name="keyword" text="$keywords">
<$mt:Var name="keyword" trim="1" regex_replace="/\s| /g","%" setvar="keyword"$>
<$mt:Var name="keyword"$><br />
</mt:SplitVars>
</mt:DynamicMTML>

以下、コードを分解して解説します。

まず、上段で、MTML タグを使って MTSetVars タグを出力します。その中で、カンマ区切りで入力したキーワード欄の値を keywords という変数にセットします。

<$mtml tag='mt:SetVars'$>
keywords=<$mt:EntryKeywords$>
<$mtml tag='/mt:SetVars'$>

このように、MTML タグで MTSetVars タグを出力すれば、変数をセットするところに MT タグが使えるので便利です。MTML タグについては「MTML タグで MT タグ自体を出力する方法」を参照してください。

下段は、MTDynamicMTML タグで囲み、ダイナミックに処理されるようにします。

上段でセットした変数 keywords の値を MTSplitVars の text モディファイアに渡し(text="$keywords")、順次 keyword という変数名(name="keyword")で取り出します。

<mt:SplitVars name="keyword" text="$keywords">

MTSplitVars 内の1行目で、カンマで分割されたキーワードの前後に余分なスペースが含まれていた場合は取り除き、キーワード中のスペースは任意の1文字を示す「%」に置換しています。

<$mt:Var name="keyword" trim="1" regex_replace="/\s| /g","%" setvar="keyword"$>

MTSplitVars 内の2行目の「<$mt:Var name="keyword"$><br />」は、動作確認のためのものです。

例えば、キーワード欄に「はじめて,dynamicmtml」と入力していた場合、上記のテンプレートにより次のように出力されます。

startup-dymtml-21

MTSearchEntries に渡す変数などをセットする

先ほどまでのコードは次のようになります。変わったのは上段部分です。

<$mtml tag='mt:SetVars'$>
blog_id=<$mt:BlogID$>
entry_id=<$mt:EntryID$>
keywords=<$mt:EntryKeywords$>
keywords_length=<$mt:EntryKeywords regex_replace="/[^,]|\s/g","" cat="," count_characters="1"$>
limit=5
<$mtml tag='/mt:SetVars'$>

<mt:DynamicMTML>
<mt:SplitVars name="keyword" text="$keywords">
<$mt:Var name="keyword" trim="1" regex_replace="/\s| /g","%" setvar="keyword"$>
<$mt:Var name="keyword"$><br />
</mt:SplitVars>
</mt:DynamicMTML>

上段の MTSetVars タグ内に、次のような変数をセットします。

  • ブログID = blog_id
  • 現在のブログ記事ID = entry_id
  • キーワード欄の値 = keywords
  • 分割されたキーワードの個数 = keywords_length
  • リストアップするブログ記事数 = limit

ポイントは「分割されたキーワードの個数」です。

keywords_length=<$mt:EntryKeywords regex_replace="/[^,]|\s/g","" cat="," count_characters="1"$>

この部分は、次の流れで考えると分かりやすいと思います。

  1. regex_replace="/[^,]|\s/g","" で、区切り文字であるカンマ以外を削除
  2. 区切り文字の個数はキーワードの個数よりも1つ少ないので、cat="," でカンマを1つ追加
  3. count_characters="1" で文字数(カンマの数を出力
  4. これが、キーワードの数となる。

MTSearchEntries でブログ記事をリストアップ

次に、上記のコードで取り出した変数 keyword の値を、MTSearchEntries に渡します。最終的なコードは次のようになります。変更部分は下段になります。

<$mtml tag='mt:SetVars'$>
blog_id=<$mt:BlogID$>
entry_id=<$mt:EntryID$>
keywords=<$mt:EntryKeywords$>
keywords_length=<$mt:EntryKeywords regex_replace="/[^,]|\s/g","" cat="," count_characters="1"$>
limit=5
<$mtml tag='/mt:SetVars'$>

<mt:DynamicMTML>
<mt:SplitVars name="keyword" text="$keywords">
<$mt:Var name="__counter__" setvar="split_counter"$>
<$mt:Var name="keyword" trim="1" regex_replace="/\s| /g","%" setvar="keyword"$>
<mt:SearchEntries query="$keyword" blog_id="$blog_id" not_entry_id="$entry_id">
<$mt:EntryDate format="%Y%m%d%H%M%S" setvar="date"$>
<mt:SetVarBlock name="entries" key="$date">
<li><a href="<$mt:EntryPermalink$>"><$mt:EntryTitle$></a></li>
</mt:SetVarBlock>
</mt:SearchEntries>
<mt:If name="split_counter" eq="$keywords_length">
<mt:Loop name="entries" sort_by="key reverse">
<mt:If name="__counter__" eq="1">
<ul>
</mt:If>
<mt:If name="__counter__" le="$limit">
<mt:Var name="__value__">
</mt:If>
<mt:If name="__counter__" eq="$limit">
</ul>
</mt:If>
</mt:Loop>
</mt:If>
</mt:SplitVars>
</mt:DynamicMTML>

下段のコードを分割して解説します。

特別な変数の初期化

MTSplitVars タグ内の最初で、変数 __counter__ の値を変数 split_counter に代入しています。

<$mt:Var name="__counter__" setvar="split_counter"$>

これは、MTSplitVars タグでセットされる特別な変数(__first__ や __counter__ など)が、入れ子になっている MTSearchEntries タグの後ろでは、MTSearchEntries タグの影響を受け、値が変わってしまう問題に対処するためです。この点は、ダイナミックパブリッシングのテンプレートを書くときには注意する必要がありそうです。

そのために、入れ子の後ろでもちゃんと特別な変数にアクセスできるように、最初に別の変数名にセットしておくわけです。

MTSearchEntries でブログ記事をリストアップ

次に、MTSearchEntries タグに、上段の MTSeatVars タグでセットした変数などを渡します。

  <mt:SearchEntries query="$keyword" blog_id="$blog_id" not_entry_id="$entry_id">
<$mt:EntryDate format="%Y%m%d%H%M%S" setvar="date"$>
<mt:SetVarBlock name="entries" key="$date">
<li><a href="<$mt:EntryPermalink$>"><$mt:EntryTitle$></a></li>
</mt:SetVarBlock>
</mt:SearchEntries>

そして、ここでは結果を直接出力せずに、一度 entries というハッシュ変数に代入します。変数 entries のキーは、MTEntryDate タグで取得したブログ記事の公開日を設定しています。こうすることで、後々公開日でソートすることができます。

変数の値を出力する

最後に変数 entries の値を出力します。

  <mt:If name="split_counter" eq="$keywords_length">
<mt:Loop name="entries" sort_by="key reverse">
<mt:If name="__counter__" eq="1">
<ul>
</mt:If>
<mt:If name="__counter__" le="$limit">
<mt:Var name="__value__">
</mt:If>
<mt:If name="__counter__" eq="$limit">
</ul>
</mt:If>
</mt:Loop>
</mt:If>

ここでポイントとなるのは、MTSplitVars タグの最後のループであるかを如何に判断するかです。

ここで MTSplitVars の前半で初期化した変数 split_counter (ループの回数)と、上段でセットした変数 keywords_length (=キーワードの数)を比較します。

<mt:If name="split_counter" eq="$keywords_length">

MTSplitVars は分割したキーワードをループで出力するので、キーワードの数とループの回数が同じであれば、それが最後のループということになります。

後は、MTLoop タグでハッシュ変数 entries の値を出力します。sort_by モディファイアで、キーの値でソートし、降順(reverse)に並べ替えています。

また、この入れ子になっている側のループでは、__counter__ の値は上書きされるのでそのまま使えます。したがって、__counter__ の値を使って出力数を制御しています。

  • __counter__ が 1 と等しい: ループの最初
  • __counter__ が変数 limit 以下:最初の MTSetVars でセットしたリストアップするブログ記事数まで、ハッシュ変数の値(__value__)を出力
  • __counter__ が変数 limit と等しい : ループの最後

MTSetVars で設定する limit の値を変更すれば、リストアップする記事数を変えられますし、sort_by の値を変えれば並び順を変更できます。

以上です。次回は、AND 検索の仕方を紹介します。

  • このエントリーをはてなブックマークに追加
Just a second...