PowerCMS ブログ

2014年05月15日

記事n件をランダムに表示するPowerCMSのテンプレート

サポート宛にいただいた質問です。PowerCMSのサポートでは、こういったテンプレートの作成方法に関する質問にもお答えします。

記事をランダムにn件表示させるにはどのようにテンプレートを記述すれば良いでしょうか?

PowerCMSのバナー機能のテンプレート、MTCampaigns (MTBanners) には MTCampaignRandom (MTBannerRandom) ブロックタグや MTCampaigns に shuffle モディファイアがあり、ランダム表示を簡単に実現できます。

しかし、MTEntriesにはこれらのタグ相当の指定はできません。但し、PowerCMSではDynamicMTMLの機能を使うことでテンプレートの記述だけでこれを実現することができます。

  • 再構築の度にランダム表示の場合はスタティックパブリッシング
  • 表示の度にランダム表示の場合は、ダイナミックパブリッシング又はMTDynamicMTMLタグを利用して部分的にダイナミック処理する
  • MTEntriesではなく、MTSearchEntries タグを使う
  • 乱数の生成には MTRand タグを使う

ランダムに表示するために利用するテンプレートタグは以下のタグです。

最初に 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>
カテゴリー
DynamicMTMLPowerCMS 3PowerCMS 4テンプレート作成Tips

ページの先頭へ