リストを一定件数ずつ区切って出力する

FacebookのMovable Type勉強会のグループに、「フォルダの一覧を4つずつ区切って、ul/li要素のリストで出力したい」というような内容の質問がありました。
この事例のように、各種のオブジェクトのリストを、一定件数ずつに区切って出力したいことは、よくあることです。
この方法を紹介します。

1.考え方

質問の事例では、リストを4件ずつ区切りたいということでした。
このような場合、まず繰り返しの回数を数え、それを4で割った余りを求めます。
繰り返しが1回進むごとに、余りは以下のようになります。

繰り返し
回数
余り
11
22
33
40
51
62
73
80
91
102
113
120
131
......

4個ずつ区切る場合、各グループの最初は、繰り返しの1回目、5回目、9回目・・・になります。
これらの場合、繰り返し回数を4で割った余りは、上の表より常に1です。
したがって、「繰り返し回数を4で割った余りが1」という条件を満たす時に、グループの最初だけで出力すべき内容を出力するようにします。

同様に、各グループの最後は、繰り返しの4回目、8回目、12回目・・・になります。
これらの場合、繰り返し回数を4で割った余りは、上の表より常に0です。
したがって、「繰り返し回数を4で割った余りが0」という条件を満たす時に、グループの最後だけで出力すべき内容を出力するようにします。

ただ、リストに出力する個数が4の倍数になっていない場合、最後のグループでは、グループの最後に出力すべき内容が出力されなくなります。
リストに出力する個数が4の倍数でない場合、繰り返しを終えた時点で、繰り返し回数を4で割った余りは、上の表より0以外の値になります。
そこで、繰り返し終了後に余りが0以外であれば、グループの後に出力すべき内容を出力します。

2.テンプレートの組み方のパターン

上記の考え方に沿って、リストの出力を一定件数ずつ区切る場合のテンプレートの組み方を一般化すると、以下のようになります。
なお、繰り返し回数と余りは、それぞれctrとmodという変数に代入しています。

<$mt:SetVar name="ctr" value="1"$>
<繰り返し系のブロックタグ>
  <$mt:SetVar name="mod" value="$ctr"$>
  <$mt:SetVar name="mod" op="%" value="区切る件数">
  <mt:If name="mod" eq="1">
    グループの最初に出力する内容
  </mt:If>
  個々のオブジェクトを出力する処理
  <mt:If name="mod" eq="0">
    グループの最後に出力する内容
  </mt:If>
  <$mt:SetVar name="ctr" op="++"$>
</繰り返し系のブロックタグ>
<mt:If name="mod" ne="0">
  グループの最後に出力する内容
</mt:If>

1行目のMTSetVarタグでは、繰り返しの回数を1に初期化します。
3行目と4行目で、繰り返し回数を区切る件数で割った余りを、変数modに求めます。
また、12行目のMTSetVarタグで、繰り返しが1回進むごとに、変数ctrの値を1ずつ増やします。

5~7行目は、余りが1の時に、グループの最初の時だけ、オブジェクトの前に何かを出力する処理です。
また、9~11行目は、余りが0の時に、グループの最後の時だけ、オブジェクトの後に何かを出力する処理です。
そして、最後の14~16行目は、余が0でない(=リストの個数が件数の倍数でない)時に、グループの最後の時の内容を出力する処理です。

3.フォルダのリストの出力

上記の話に沿って、トップレベルのフォルダのリストを、4件ずつ区切ってul/li要素で出力するテンプレートを組むと、以下のようになります。
なお、個々のli要素には、グループ内の1番目~4番目のそれぞれに、List01~List04のクラスを振るようにしています。

<$mt:SetVar name="ctr" value="1"$>
<mt:TopLevelFolders>
  <$mt:SetVar name="mod" value="$ctr"$>
  <$mt:SetVar name="mod" op="%" value="4"$>
  <mt:If name="mod" eq="1">
    <ul>
  </mt:If>
  <li class="List0<mt:If name="mod" eq="0">4<mt:Else><$mt:GetVar name="mod"$></mt:If>"><$mt:FolderLabel$></li>
  <mt:If name="mod" eq="0">
    </ul>
  </mt:If>
  <$mt:SetVar name="ctr" op="++"$>
</mt:TopLevelFolders>
<mt:If name="mod" ne="0">
  </ul>
</mt:If>

li要素のクラスの出力が複雑ですが、この部分を分解して書くと、以下のようになります。

class="List0
<mt:If name="mod" eq="0">
  4
<mt:Else>
  <$mt:GetVar name="mod"$>
</mt:If>
"

グループの1回目~3回目までは、List01~List03のクラスを振ります。
これらの時には、余り(変数mod)の値が1~3になりますので、「List0」の後に余りの値をそのまま出力します(5行目のMTGetVarタグ)。

一方、グループの4回目では、List04のクラスを振ります。
この場合、余りの値は0になっていますので、余りをそのまま出力すると「List00」になってしまいます。
そこで、MTIfタグで余りが0かどうかを判断し(2行目のMTIfタグ)、0の時は「4」を出力します(3行目)。

4.変数や条件判断は必須

Movable Type 5.1 Webサイト製作ガイドVolume 2この例のように、手の込んだ処理をしようとすると、変数や条件判断を避けて通ることができません。
拙著「Movable Type 5.1 Webサイト製作ガイドVolume 2」では、変数や条件判断について、かなり詳しく解説しています。
「変数や条件判断がよく分からない」という方は、ぜひ拙著をお読みください。