読者です 読者をやめる 読者になる 読者になる

元フリーエンジニアライフ

Ruby on Rails とか MovableType とかAWSやってるフリーランスウェブエンジニアの記録でした。現在は法人成りしてIT社長。

記事に設定されたカテゴリのうち、あるカテゴリの子または子孫に属するもののみを表示する

たとえば、製品情報をMTのブログ記事で管理していて、カテゴリで製品の「分類」や「事業部」などを保持している場合に、ブログ記事アーカイブ中でその製品を管轄する「事業部」を表示したくなったときなど。(えらく具体的な例だ)

カスタムフィールドで保持していれば表示は簡単だが、「事業部」ごとにアーカイブを書き出したいときなどはこの方法が楽なのである。

子カテゴリを表示したいとき

事業部A かつ 分類B1 に属する製品情報があったとしよう。

製品がどの事業部に属するかを表示したくなったとき、MTEntryCategoriesでは分類も出てしまうのでうまくいかない。列挙してMTIfで逐一判定なんてのはありえない。

すこし処理コストが気になるけど、MTIfのlikeを使ってこんな感じでできる。

<mt:SetVarBlock name="entry_category_ids">,<mt:EntryCategories glue=","><mt:CategoryID></mt:EntryCategories>,</mt:SetVarBlock>
<mt:SubCategories category="事業部">
    <mt:SetVarBlock name="matcher"><$MTCategoryID$></mt:SetVarBlock>
    <mt:If name="entry_category_ids" like="$matcher">
        <$MTCategoryLabel escape="html"$>
    </mt:If>
</mt:SubCategories>

まず記事に設定されたカテゴリのIDを連結して、検索用の文字列をつくり、変数entry_category_idsに入れておく。生成された文字列は「,1,2,3,」のように、どのIDの前後にも「,」が付いていて、たとえば「,1,」のような文字列で検索できるようになっている。glueだけだと、先頭と終端のIDについて「,」が足りないので検索できない。(「,」をつけて検索しないと、たとえば「1」が「10」にマッチしてしまう)

つぎに、MTSubCategoriesで「事業部」のサブカテゴリを回しつつ、entry_category_idsにIDが含まれるカテゴリを探す。

みつかれば、それが製品に設定された「事業部」というわけだ。

子孫カテゴリを表示したいとき

上記の方法では、製品に設定された分類を表示するには、うまくいかない。

製品に設定された「分類B1」は「分類」の直接の子ではなく、子の子、つまり孫なので、SubCategoriesでは出てこないからだ。

単純に MTSubCategories をネストさせたのでは、たとえばもう1階層増えてひ孫が設定された場合に破綻してしまう。それでいちいちテンプレート修正とか、ダサいよね。

こういうときは再帰を使うのが簡単だ。上記のコードを少し手直しして...

<mt:SetVarBlock name="entry_category_ids">,<mt:EntryCategories glue=","><mt:CategoryID></mt:EntryCategories>,</mt:SetVarBlock>
<mt:SetVarTemplate name="category_loop_tmpl">
    <mt:SetVarBlock name="matcher"><$MTCategoryID$></mt:SetVarBlock>
    <mt:If name="entry_category_ids" like="$matcher">
        <$MTCategoryLabel escape="html"$>
    </mt:If>
    <mt:HasSubCategories>
        <mt:SubCategories>
            <$MTVar name="category_loop_tmpl"$>
        </mt:SubCategories>
    </mt:HasSubCategories>
</mt:SetVarTemplate>
<mt:SubCategories category="分類">
    <$MTVar name="category_loop_tmpl"$>
</mt:SubCategories>

category_loop_tmpl再帰関数的に使うことで、繰り返しIDのチェックと、子孫へのコンテキストスイッチを実現できる。これなら、たとえカテゴリの階層に関係ない。

ただし、こういうのがテンプレート中に散在すると非常に見づらいので、なるべくテンプレートモジュールに切り出すとかして見通しをよくするのがよいと思う。キャッシュが使えるしね。