サブカテゴリー機能について考えてみた。
「MT 3.1では、エントリの存在するカテゴリーしか再構築しません。」
何というか、実に合理的な仕様のように思えます。ところがサブカテゴリー機能が絡むと実に複雑な状況が発生します。つまり、「あるカテゴリーに属するサブカテゴリにエントリが追加されたとき、再構築されるのはサブカテゴリーのみでその親カテゴリーは再構築されない」のです。
この問題は標準のテンプレートでは顕在化しません。しないと言わないまでも少なくとも顕在化しにくいです。
問題点の説明
ここではこの問題がどのような事態を引き起こすかということをもう少し考えてみたいと思います。
標準のカテゴリーアーカイブでは、MTEntriesというコンテナタグでカレントカテゴリーに属するエントリーのリストアップを行っています。MT 3.1ではこれに加えてMTEntriesWithSubCategoriesというコンテナタグが用意されており、その機能はカレントカテゴリに加えてそのサブカテゴリーに属するエントリーをリストアップするというなかなか便利なものです。このタグと前述の再構築規則を組み合わせると、サブカテゴリーにエントリーが追加され、そのサブカテゴリーのアーカイブの再構築は行われますが、それを包含するはずの親カテゴリーのアーカイブの方には反映されない(再構築されない)ということが起きます。
また、エントリーの存在しないカテゴリーも当然存在し得ます。あるカテゴリーにサブカテゴリーを用意し、サブカテゴリーにのみエントリーを追加したとします。そうすると前述の規則に従って親カテゴリーのアーカイブがそもそも生成されない()という現象が観測されるはずです。
このことは例えば、以下のようにカテゴリーアーカイブごとにカテゴリーナビゲーション機能を付加させたいユーザには不評でしょう。
<div class="content"> <h2>Parent Categories</h2> <ul> <MTParentCategories exclude_current="1"> <li><a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"> <MTCategoryLabel></a></li> </MTParentCategories> </ul> <h2>Sub Categories</h2> <MTSubCategories> <MTSubCatIsFirst><ul></MTSubCatIsFirst> <li><a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"> <MTCategoryLabel></a> <MTSubCatsRecurse> </li> <MTSubCatIsLast></ul></MTSubCatIsLast> </MTSubCategories> <MTEntries> <$MTEntryTrackbackData$> ... </MTEntries> </div>
解決方法
まず、こうした瑕疵というか仕様が目立ちにくいようにエントリーの存在しないカテゴリーへのリンクを作らない、MTEntriesWithSubCategoriesを使わない、という後ろ向きの解決方法があります。例えば、上記のParent Categoriesの例だと以下のように修正することで少なくとも存在しないアーカイブへのリンクを避けられます。
<h2>Parent Categories</h2> <ul> <MTParentCategories exclude_current="1"> <MTIfNonZero tag="MTCategoryCount"> <li><a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"> <MTCategoryLabel></a></li> <MTElse> <li><MTCategoryLabel></li> </MTElse> </MTIfNonZero> </MTParentCategories> </ul>
もうひとつはカテゴリーアーカイブの再構築時にその親カテゴリーを遡って再構築するようにMT自体を変更するという方法です。あまりテストしていませんが、以下のようにコードを追加すればよいでしょう。
どうも微妙に不具合がある様子なので公開停止。
このエントリーのトラックバックURL: http://as-is.net/mt/mt-tb.cgi/193
なるほどです。MTIfNonZeroを使うのは良いアイディアですね(チョットしゃーなし感はのこりますけれど)。
個人的には、MTWithSubCategoriesなんてタグは不要で、最初から全表示して(つまり無くても最初から構築すべきではないかと)、逆に絞る方のタグがあればいいと思います。
あ、それはMTParentCategoryでMTEntriesをコンテナすれば良いのかな。
kaminogoyaさんの要求を満たすためには、エントリーを作るときに主カテゴリーを親カテゴリーに、副カテゴリーを子カテゴリーに指定するとうまく行きますね。サブカテゴリーを単に追加用のラベルとして使うわけです。でも面倒です。
あとMTParentCategory内でMTEntriesを使うことはできますが、それを行うカテゴリーはサブカテゴリーでなくてはいけないので解決にならないような。
どもです。
入れてみたのですが…エラー出ます(泣)。
$cat ではなく $cats ではと思うのですが…。
エラーメッセージ書き忘れました。
Got an error: Global symbol "$cat" requires explicit package name at lib/MT.pm line 409. Global symbol "$cat" requires explicit package name at lib/MT.pm line 409. ... 以下似たようなのが沢山出ますが、省略。
mt.cgi を開くときにこんなんでます。
それ多分手でパッチ当ててるでしょう。for文の中にdo while文を入れるのです。$catで問題ありません。
イージーミスしてました。お騒がせ(すんません)。
問題なく動いているようです。後で別途エントリしてトラバしておきますね。ありがとうございました。
あ、新規エントリ作ると…
Can't call method "ping_url_list" on an undefined value at lib/MT.pm line 1089.
となります。これはいかに?
そうですね。外部にPingを打たない設定だとうまく動いていたのですが駄目みたいです。詳しく追いかけている暇がないのでしばらく放置します。
トラックバックを2重に送ってしまってどうもすみません。
サブカテゴリーについて大変参考になりました。
ありがとうございました。
カテゴリトラックバックを外して(削除して)、再度試してみたのですが、一度エラーになるとどうやらダメのようです(どこかに保存されている?)。
ご参考までに。
うーん、カテゴリトラックバックの設定は無関係に起きるようですね。もう少しソースを読んで事情が分かったところでこの改造は再チャレンジしてみるつもりです。
ともあれ、今日はMTSubCategoriesの中でMTCategoryCountを用いるとDraft/Futureのエントリーも含めた値が返ってくる問題に決着がついたのでるんるんなのです。
ここにも例として書かれており、本家等でもサンプルとして在る
<MTSubCategories>
<MTSubCatIsFirst><ul></MTSubCatIsFirst>
<li>
<MTCategoryLabel>
<MTSubCatsRecurse>
</li>
<MTSubCatIsLast></ul></MTSubCatIsLast>
</MTSubCategories>
なテンプレートを作ると がネストしてしまいおそらく殆どの人が想定している挙動と異なるような気がします。
は頭と終わりにだけ在って複数は出てこないことを望んで居ると思うのですが・・・
スタイルシートの設定によっては見た目上実害が無いと思いますが、設定によっては見た目も崩れますし、なによりHTMLが美しくないと思います。
ネストさせることが意図だと思うのですけれど。単にネストさせないだけなら自明の変更で済みますよね。レベルごとに適切なクラスを指定できるのが望ましいのかもしれませんが、ネストすることで何レベル目かが判断できるわけですから、より単純なコンストラクトを用いて実質的に同じことを表現しているに過ぎません。
さて私はHTML的にネストしているのが美しくないという見解には同意しません。先頭と末尾にだけ<ul></ul>が出てくることを「ほとんどの人が望んでいる」というオブザーベーションもおそらく正しくないでしょう。