孫カテゴリアーカイブに子のリスト表示をする

MTQに「孫カテゴリアーカイブに子のリスト表示をする」という質問が上がっていました。
この質問に答えてみます。

1.考え方

まず、ご希望のようなことを行う際の考え方をまとめます。

1-1.カテゴリの階層を得る

親/子/孫の3階層のカテゴリがあって、孫カテゴリのアーカイブページでだけ、特別な出力をしたいということです。
そのためには、現在出力中のカテゴリアーカイブページが、どの階層のカテゴリのアーカイブページかを調べる必要があります。

そこで、カテゴリの階層を調べる処理を行います。
MTParentCategoriesタグで、親からそのカテゴリまでを得ます。
そして、その間のカテゴリの数を数えて、階層の深さを調べます。

1-2.孫カテゴリとその上の子カテゴリにマークを付ける

孫カテゴリと、その上の子カテゴリには、カレントを示すマークをつけたいということです。
そこで、現在出力中の孫カテゴリと、その上の子カテゴリに、カレントであることを表す値をセットします。

この処理はハッシュを使って行います。
「parent_cat_ids」という名前のハッシュを作り、キーをカテゴリIDにし、そのキーに対応する値を1にします。

例えば、ある孫カテゴリのIDが15で、その上の子カテゴリのIDが10だとします。
この場合、parent_cat_ids{15}と、parent_cat_ids{10}の値を1にします。

1-3.親カテゴリの時だけ処理をする

孫カテゴリから見て、同一の親を持つカテゴリをツリーで出力したいということです。

あるカテゴリから見て、その最上位の親のカテゴリを直接的に得る方法は、残念ながらありません。
ただ、MTParentCategoriesタグを使って、繰り返しの最初の時だけ処理を行えば、間接的に最上位の親のカテゴリを得ることができます。

この処理は、以下のようにタグを組んで行うことができます。

<$mt:SetVar name="is_parent" value="1"$>
<mt:ParentCategories>
  <mt:If name="is_parent" eq="1">
    最上位の親カテゴリの時の処理
    <$mt:SetVar name="is_parent" value="0"$>
  </mt:If>
</mt:ParentCategories>

「最上位である」ということを判断するために、1行目のMTSetVarタグで、変数is_parentに1を代入します。
次に、2行目と7行目のMTParentCategoriesタグで、最上位のカテゴリから順に繰り返します。

繰り返しの1回目(=最上位)では、変数is_parentの値が1になっています。
したげって、3行目のMTIfタグの条件が成立して、4行目以降に進み、最上位の親カテゴリの時の処理を行います。
そして、5行目のMTSetVarタグで、変数is_parentに0を代入して、「最上位である」という状況をオフにします。

一方、繰り返しの2回目以降では、1回目の最後で変数is_parentに0を代入したので、3行目のMTIfタグの条件は成立しません。
したがって、4行目と5行目の処理は行われず、結果として何も起こらないことになります。

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

ここまでの話に沿って、実際にテンプレートを組むと、以下のようになります。

<$mt:SetVar name="cur_depth" value="0"$>
<mt:ParentCategories>
  <$mt:CategoryID setvar="cat_id"$>
  <$mt:SetVar name="parent_cat_ids" key="$cat_id" value="1"$>
  <$mt:SetVar name="cur_depth" op="++"$>
</mt:ParentCategories>

<mt:If name="cur_depth" eq="3">
  <$mt:SetVar name="is_parent" value="1"$>
  <mt:ParentCategories>
    <mt:If name="is_parent" eq="1">
      <mt:SubCategories>
        <mt:SubCatIsFirst><ul></mt:SubCatIsFirst>
        <$mt:CategoryID setvar="cat_id"$>
        <mt:If name="parent_cat_ids" key="$cat_id">
          <mt:If tag="CategoryCount">
            <li><a href="<$mt:CategoryArchiveLink$>"><$mt:CategoryLabel$>★</a>
          <mt:Else>
            <li><$mt:CategoryLabel$>★
          </mt:If>
          <$mt:SubCatsRecurse$>
        <mt:Else>
          <mt:If tag="CategoryCount">
            <li><a href="<$mt:CategoryArchiveLink$>"><$mt:CategoryLabel$></a>
          <mt:Else>
            <li><$mt:CategoryLabel$>
          </mt:If>
        </mt:If>
        <mt:SubCatIsLast></ul></mt:SubCatIsLast>
      </mt:SubCategories>
      <$mt:SetVar name="is_parent" value="0"$>
    </mt:If>
  </mt:ParentCategories>
</mt:If>

6行目までの部分は、上記の1-1.と1-2.に沿った部分です。
カテゴリの階層の深さを、変数cur_depthに求めます。
また、ハッシュparent_cat_idsを使って、孫カテゴリからその親までの各カテゴリに、カレントであることを表す値をセットしています。

8/34行目では、MTIfタグを使って、変数cur_depthの値が3(=孫カテゴリ)の時だけ、処理を行うようにしています。
9/10/11/32/33行目は、上記の1-3.に沿った処理です。

そして、11~31行目で、MTSubCategoriesタグを使って、カテゴリのリストを出力しています。
まず、各カテゴリを出力する際に、カレントかどうかで、出力を分けます。
この処理は、14行目のMTSetVarタグと、15/22/28行目のMTIfタグで行っています。
14行目で、変数cat_idにカテゴリのIDを代入します。
15行目のMTIfタグで、ハッシュ内のそのIDのカテゴリの値を調べ、カレントを表す値(1)が入っているかどうかを判断して、処理を分けます。

16~21行目は、カレントである場合の処理です。
カテゴリのラベルの後に、カレントのマーク(★)を出力しています。
また、カレントのカテゴリの場合は、その下の階層も出力するので、MTSubCatsRecurseタグを使っています(21行目)。

一方、23~27行目は、カレントでない場合の処理です。
こちらの場合は、下の階層は出力しないので、MTSubCatsRecurseタグを入れていません。