2014年05月15日
記事n件をランダムに表示するPowerCMSのテンプレート
サポート宛にいただいた質問です。PowerCMSのサポートでは、こういったテンプレートの作成方法に関する質問にもお答えします。
記事をランダムにn件表示させるにはどのようにテンプレートを記述すれば良いでしょうか?
PowerCMSのバナー機能のテンプレート、MTCampaigns (MTBanners) には MTCampaignRandom (MTBannerRandom) ブロックタグや MTCampaigns に shuffle モディファイアがあり、ランダム表示を簡単に実現できます。
しかし、MTEntriesにはこれらのタグ相当の指定はできません。但し、PowerCMSではDynamicMTMLの機能を使うことでテンプレートの記述だけでこれを実現することができます。
- 再構築の度にランダム表示の場合はスタティックパブリッシング
- 表示の度にランダム表示の場合は、ダイナミックパブリッシング又はMTDynamicMTMLタグを利用して部分的にダイナミック処理する
- MTEntriesではなく、MTSearchEntries タグを使う
- 乱数の生成には MTRand タグを使う
ランダムに表示するために利用するテンプレートタグは以下のタグです。
- MTDynamicMTML | テンプレートタグリファレンス
- setvar | グローバル・モディファイアリファレンス
- MTEntriesCount | テンプレートタグリファレンス
- MTRand | テンプレートタグリファレンス
- MTSearchEntries | テンプレートタグリファレンス
- MTSetVarTemplate | テンプレートタグリファレンス
- MTFor | テンプレートタグリファレンス
最初に MTEntriesCount タグで記事の総数を得ます。これをsetvarモディファイアで変数に入れ、opモディファイアで1を引きます。100件の場合99をセットします。 MTSearchEntries は、queryモディファイアを付けなければ全ての記事が対象になります。 また、このタグには、offset (何件目から)、lastn (何件読み込むか) モディファイアが指定できます。さらに、unique モディファイアと not_entry_idモディファイアを渡すことで、指定したIDの記事を除外することが可能です。
MTRandタグは、minモディファイアと maxモディファイアを指定して乱数を取得するタグです。0から99までの値を得てこれを MTSearchEntries タグの offsetモディファイアに渡すことで、ランダムに記事を抽出するようにします。not_entry_id を複数回渡すことで、これらの記事が除外してロードされるため、2回目以降のループの直前で常に最大記事数 (max_offset変数) を opモディファイアで1ずつ減らして行きます。
記事を5件ランダムに表示させるテンプレートの記述例
<MTDynamicMTML>
<MTIgnore>
MTDynamicMTMLタグで囲むことでテンプレートがファイルの中にそのまま出力され、
表示の時点でダイナミックに処理される
</MTIgnore>
<$mt:EntriesCount setvar="entries_count"$>
<mt:var name="entries_count" value="1" op="-" setvar="max_offset">
<MTIgnore>記事が100件の時、99がセットされる</MTIgnore>
<mt:rand min="0" max="$max_offset" setvar="random_offset">
<MTIgnore>
0から99の乱数を得て、一回目の表示。
このとき、変数 published_entry_id に記事IDをセットする
</MTIgnore>
<MTSearchEntries lastn="1" offset="$random_offset">
<MTEntryId setvar="published_entry_id"> <MTEntryTitle>
</MTSearchEntries>
<MTIgnore>
2から5件目の表示については、繰り返し処理のため
MTSetVarTemplateでテンプレートをセットしてその後 MTFor でループ出力する
</MTIgnore>
<MTSetVarTemplate name="output_random">
<MTIgnore>
not_entry_id を追加して行くため、opモディファイアで max_offset を1ずつ減らす
2回目 99 → 98、3回目 98 → 97...</MTIgnore>
<mt:var name="max_offset" value="1" op="-" setvar="max_offset">
<mt:rand min="0" max="$max_offset" setvar="random_offset">
<MTSearchEntries lastn="1" offset="$random_offset" not_entry_id="$published_entry_id" unique="1">
<MTEntryId setvar="published_entry_id"> <MTEntryTitle>
</MTSearchEntries>
</MTSetVarTemplate>
<MTIgnore>
2から5件目の表示についてを MTFor タグでループ出力する
</MTIgnore>
<mt:for from="1" to="4">
<mt:var name="output_random">
</mt:for>
</MTDynamicMTML>
5月16日追記
その後、社内で検証した結果、もっとシンプルに実現できるテンプレートがあることがわかりました。MTEntriesのuniqueモディファイアを使う方法です。
<$MTEntriesCount setvar="entries_count"$>
<$MTGetVar name="entries_count" op="--" setvar="max_offset"$>
<MTFor from="1" to="5">
<$MTGetVar name="max_offset" op="--" setvar="max_offset"$>
<$MTRand min="0" max="$max_offset" setvar="random_offset"$>
<MTEntries limit="1" offset="$random_offset" unique="1">
<$MTEntryTitle$>
</MTEntries>
</MTFor>
unique="1 | 0"
このモディファイアを付与すると、その MTEntries ブロックは、同じテンプレート内で使用した MTEntries ブロックで出力したブログ記事を除いて出力 します。 次のサンプルは、ひとつめの MTEntries で @featured シークレットタグが付けられたブログ記事の最新3件にフィルタリングを、ふたつめの MTEntries ブロックでは、最新7件のブログ記事にフィルタリングするようにしています。ふたつめの MTEntries ブロックには unique モディファイアが付与されていますので、出力する最新7件のブログ記事の中には、ひとつめの MTEntries ブロックで出力した @featured シークレットタグの付いた、最新3件のブログ記事は含まれません。
MTRand以外はMT標準のテンプレート・タグで実現できます。
5月19日追記
最初に記事の総数を取得するところで使用している MTEntriesCount
タグは間違っており、正しくは MTBlogEntryCount
タグの誤りでした。お詫びいたします。
例えば対象となるウェブサイトやブログの記事が全部で100件あるとき、本来は MTBlogEntryCount
タグで「100
」を取得するところですが、MTEntriesCount
タグでは ウェブサイトまたはブログの [投稿設定] で [公開の既定値] の [表示される記事数] により設定された条件に合致する件数、「10
」などを取得してしまい、結果として最初の10件程度からランダム表示となってしまいます。
<MTDynamicMTML>
<$MTSetVar name="limit" value="5"$>
<$MTBlogEntryCount setvar="max"$>
<MTIf name="limit" gt="$max">
<$MTSetVar name="limit" value="$max"$>
</MTIf>
<MTFor from="1" to="$limit">
<$MTSetVar name="max" op="--"$>
<$MTRand min="0" max="$max" setvar="offset"$>
<MTEntries offset="$offset" limit="1" unique="1">
<$MTEntryTitle$>
</MTEntries>
</MTFor>
</MTDynamicMTML>
タグの説明を追加します。
<$MTTemplateNote value="以下の内容を部分的にダイナミックパブリッシングで処理。"$>
<MTDynamicMTML>
<$MTTemplateNote value="本来 MTEntries ブロックタグの limit モディファイアで指定する、出力件数。"$>
<$MTSetVar name="limit" value="5"$>
<$MTTemplateNote value="記事総数。"$>
<$MTBlogEntryCount setvar="max"$>
<$MTTemplateNote value="出力件数が記事総数を超える場合。"$>
<MTIf name="limit" gt="$max">
<$MTTemplateNote value="出力件数を記事総数に変更。"$>
<$MTSetVar name="limit" value="$max"$>
</MTIf>
<$MTTemplateNote value="出力件数分のループ。"$>
<MTFor from="1" to="$limit">
<$MTTemplateNote value="未出力記事の総数マイナス1 (例: 4, 3, 2, 1, 0)。"$>
<$MTSetVar name="max" op="--"$>
<$MTTemplateNote value="0から「未出力記事の総数マイナス1」までの無作為な整数。"$>
<$MTRand min="0" max="$max" setvar="offset"$>
<$MTTemplateNote value="「0から『未出力記事の総数マイナス1』までの無作為な整数」件目の未出力記事。"$>
<MTEntries offset="$offset" limit="1" unique="1">
<$MTTemplateNote value="記事内容の出力 (任意タグ)。"$>
<$MTEntryTitle$>
</MTEntries>
</MTFor>
</MTDynamicMTML>
コメントを投稿する