タケユー・ウェブ日報

Ruby on Rails や Flutter といったWeb・モバイルアプリ技術を武器にお客様のビジネス立ち上げを支援する、タケユー・ウェブ株式会社の技術ブログです。

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

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

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

  • 事業部
  • 事業部A
  • 事業部B
  • 事業部C
  • 分類
  • 分類A
  • 分類B
    • 分類B1
    • 分類B2
  • 分類C

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

事業部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のチェックと、子孫へのコンテキストスイッチを実現できる。これなら、たとえカテゴリの階層に関係ない。

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