各カテゴリの最新1件のエントリーを新しい順に並べるカスタマイズ

昨日、mixi の Movable Type のコミュニティで、以下のような質問があって、「あーこれならハッシュを使ってできるんじゃない?」と思ってテンプレートを考えていました。

  • 各カテゴリの最新エントリーを1つずつ表示
  • カテゴリは、エントリーの新しい順に自動で並び替え
  • 最新3件のカテゴリのみを表示(MTCategories lastn="3"的なイメージ)

で、今朝 mixi に投稿しようと思ったら、The blog of H.Fujimotoさんがハッシュを使ったやり方で答えだしていたので、僕はこっちでエントリーしておきます。

完成したソース

<mt:TopLevelCategories>
 <mt:Entries lastn="1">
 <mt:EntryDate format="%Y%m%d" setvar="entry_date" />
 <mt:SetVarBlock name="entry_list" key="$entry_date"><a href="<$mt:EntryPermalink$>"><$mt:EntryTitle$> (<$mt:CategoryLabel$>)</a></mt:SetVarBlock>
 </mt:Entries>
<mt:SubCatsRecurse />
</mt:TopLevelCategories>

<mt:SetVarBlock name="entry_lists"><mt:Loop name="entry_list" sort_by="key reverse">__<mt:GetVar name="__counter__" />__<li><mt:GetVar name="__value__" /></li></mt:Loop></mt:SetVarBlock>

<dt>各カテゴリの最新1件を新しいものから3つ表示</dt>
<dd>
 <ul>
 <mt:GetVar name="entry_lists" regex_replace="/__4__.*/","" regex_replace="/__[0-9]__/g","" />
 </ul>
</dd>

解説

テンプレートの考え方

まず、考え方の流れは次のとおりです。

  1. カテゴリを全部リストアップしながら、そのカテゴリの最新のブログ記事を1件出力する。この段階では、ブログ記事はカテゴリ名の順で並ぶ。
  2. リストアップされた記事を、投稿された順に並び替える。
  3. 最新3件を残して4件目以降はカットする。

ハッシュ変数 entry_list の作成

テンプレートの上段で、ハッシュ変数 entry_list を作成します。

<mt:TopLevelCategories>
 <mt:Entries lastn="1">
 <mt:EntryDate format="%Y%m%d" setvar="entry_date" />
 <mt:SetVarBlock name="entry_list" key="$entry_date"><a href="<$mt:EntryPermalink$>"><$mt:EntryTitle$> (<$mt:CategoryLabel$>)</a></mt:SetVarBlock>
 </mt:Entries>
<mt:SubCatsRecurse />
</mt:TopLevelCategories>

MTTopLevelCategories タグで、常にトップレベルカテゴリからカテゴリをリストアップします。

カテゴリをリストアップしながら、そのカテゴリ中の最新1件のブログ記事を取得し、20090118 のような形式の投稿日をキーとして、ハッシュ変数 entry_list に格納していきます。

ハッシュ変数 entry_list を投稿日が新しい順に並び替え

この時点でハッシュ変数 entry_list に格納されているブログ記事は、カテゴリ名順に並んでいます。これをキー(投稿日)を基準に並び替えて取得し、今度は配列変数 entry_lists に格納します。

このとき、次の段階で件数を絞り込むために、各項目の頭に「 __1__ 」のような番号を振っておきます。

最新3件を残して4件目以降はカット

この時点で、ブログ記事は各カテゴリの最新1件が、投稿日が新しい順に並びました。あとは、今回は最新3件だけ欲しいので、4件め以降はカットします。

ここではアナログ的に、regex_replace モディファイアを使います。MTFor タグを使うことも考えましたが、再構築時の負担が増える気がしたので、そちらの方法は考えるのをやめました。

<dt>各カテゴリの最新1件を新しいものから3つ表示</dt>
<dd>
 <ul>
 <mt:GetVar name="entry_lists" regex_replace="/__4__.*/","" regex_replace="/__[0-9]__/g","" />
 </ul>
</dd>

正規表現で、4件目以降、すなわち「 __4__ 」以降をすべてカットします。その後、「 __1__ 」という形式の連番をすべてカットします。

これで、最新3件のみが残ります。もし、最新5件のみ残すように変更したい場合は、ソース中の「 __4__ 」の部分を「 __6__ 」とすればOKです。

以上です。多分、The blog of H.Fujimotoさんの方は、もっとスマートな解決策を出してくれるんだと思います。

【2009-01-19 追記】

やはりカテゴリを記事が投稿された順に表示する(その2) - The blog of H.Fujimotoの方がスマートでした。僕も勉強になりました。