Movable Typeで製品情報のテーブルを作る
Movable Typeで、次のように製品別に各情報(ソフトウェア/FAQ/ダウンロード)の有無を、テーブル形式で表示する方法を紹介します。
| ソフトウェア | FAQ | ダウンロード | |
|---|---|---|---|
| 製品A | ○ | × | ○ |
| 製品B | ○ | ○ | × |
| 製品C | × | ○ | ○ |
このエントリーは、MTQのフォーラムで質問された回答の情報展開です。
1.ブログの構造
まず「製品」ブログがあり、そこに投稿されているブログ記事のタイトルは次のようになっています。
- 製品A
- 製品B
- 製品C
「製品」ブログと別に、「ソフトウェア」「FAQ」「ダウンロード」の各ブログがあり、そこに「製品」ブログと同じブログ記事タイトルのブログ記事を必要に応じて作成します。ここでは次のような状態になっていると仮定します。また各ブログ記事にはブログ名と同じカテゴリもひもづいています。
- 「ソフトウェア」ブログ
ブログ記事:製品A・製品B(カテゴリ:ソフトウェア) - 「FAQ」ブログ
ブログ記事:製品B・製品C(カテゴリ:FAQ) - 「ダウンロード」ブログ
ブログ記事:製品A・製品C(カテゴリ:ダウンロード)
上記の状態で、冒頭のような製品別に情報有無を示すテーブルを作成します。
| ソフトウェア | FAQ | ダウンロード | |
|---|---|---|---|
| 製品A | ○ | × | ○ |
| 製品B | ○ | ○ | × |
| 製品C | × | ○ | ○ |
2.テンプレート
テーブルを作成するためのテンプレートは次のようになります。
<mt:SetHashVar name="list">
<$mt:SetVar name="1" value="ソフトウェア"$>
<$mt:SetVar name="2" value="カタログ"$>
<$mt:SetVar name="3" value="FAQ"$>
</mt:SetHashVar>
<mt:SetVarTemplate name="foo">
<$mt:SetVar name="pname_cat" value="0"$>
<mt:TopLevelCategories category="$category">
<$mt:CategoryLabel setvar="catname"$>
<mt:If name="catname" eq="$pname">
<$mt:SetVar name="pname_cat" value="1"$>
<mt:If tag="CategoryCount">
<td>○</td>
<mt:Else>
<td>×</td>
</mt:If>
</mt:If>
<$mt:SubCatsRecurse$>
</mt:TopLevelCategories>
<mt:Unless name="pname_cat">
<td>×</td>
</mt:Unless>
</mt:SetVarTemplate>
<table>
<thead>
<tr>
<th></th>
<mt:Loop name="list">
<th><$mt:GetVar name="__value__"$></th>
</mt:Loop>
</tr>
</thead>
<tbody>
<mt:Entries>
<$mt:EntryTitle setvar="pname"$>
<tr><td><$mt:GetVar name="pname"$></td>
<mt:Loop name="list">
<$mt:GetVar name="__key__" setvar="blog_id"$>
<$mt:GetVar name="__value__" setvar="category"$>
<mt:Blogs include_blogs="$blog_id">
<$mt:GetVar name="foo"$>
</mt:Blogs>
</mt:Loop>
</tr>
</mt:Entries>
</tbody>
</table>
3.テンプレートの解説
まず、最初のMTSetHashVarタグでブログIDとブログ名のハッシュを用意します。
<mt:SetHashVar name="list">
<$mt:SetVar name="1" value="ソフトウェア"$>
<$mt:SetVar name="2" value="カタログ"$>
<$mt:SetVar name="3" value="FAQ"$>
</mt:SetHashVar>
サンプルテンプレートでは、MTSetHashVarタグの次にMTSetVarTemplateタグがありますが、この説明は後回しにして、最後のtable要素出力用のサブテンプレートについて説明します。
<table>
<thead>
<tr>
<th></th>
<mt:Loop name="list">
<th><$mt:GetVar name="__value__"$></th>
</mt:Loop>
</tr>
</thead>
<tbody>
<mt:Entries>
<$mt:EntryTitle setvar="pname"$>
<tr><td><$mt:GetVar name="pname"$></td>
<mt:Loop name="list">
<$mt:GetVar name="__key__" setvar="blog_id"$>
<$mt:GetVar name="__value__" setvar="category"$>
<mt:Blogs include_blogs="$blog_id">
<$mt:GetVar name="foo"$>
</mt:Blogs>
</mt:Loop>
</tr>
</mt:Entries>
</tbody>
</table>
MTLoopタグで、さきほどのハッシュを読み込んでthead要素とth要素を出力します。
<mt:Loop name="list">
<th><$mt:GetVar name="__value__"$></th>
</mt:Loop>
tbody要素ではMTEntriesタグでブログ記事を順番に読み出します。テーブルの一番左にブログ記事タイトルを出力するため、一旦変数pnameにブログ記事タイトルを保持して、それを出力します。
<mt:Entries>
<$mt:EntryTitle setvar="pname"$>
<tr><td><$mt:GetVar name="pname"$></td>
次のMTLoopタグでは、ハッシュ変数listのキーと値をそれぞれ読み出して、変数blog_idと変数categoryに保持します。変数blog_idはMTBlogsタグのblog_idモディファイアに利用して各ブログの情報を読み出します。
<mt:Loop name="list">
<$mt:GetVar name="__key__" setvar="blog_id"$>
<$mt:GetVar name="__value__" setvar="category"$>
<mt:Blogs include_blogs="$blog_id">
<$mt:GetVar name="foo"$>
</mt:Blogs>
</mt:Loop>
MTBlogsタグブロックで冒頭の表の○×部分の情報を出力しますが、ここでさきほどスキップしたMTSetVarTemplateタグの内容(変数foo)を利用します。
<mt:SetVarTemplate name="foo">
<$mt:SetVar name="pname_cat" value="0"$>
<mt:TopLevelCategories category="$category">
<$mt:CategoryLabel setvar="catname"$>
<mt:If name="catname" eq="$pname">
<$mt:SetVar name="pname_cat" value="1"$>
<mt:If tag="CategoryCount">
<td>○</td>
<mt:Else>
<td>×</td>
</mt:If>
</mt:If>
<$mt:SubCatsRecurse$>
</mt:TopLevelCategories>
<mt:Unless name="pname_cat">
<td>×</td>
</mt:Unless>
</mt:SetVarTemplate>
MTSetVarTemplateタグではTopLevelCategoriesタグを使って各ブログのカテゴリを順次読み出します。
<mt:TopLevelCategories category="$category">
<$mt:CategoryLabel setvar="catname"$>
読み出したカテゴリがブログ名と等しいカテゴリ名であれば、そのカテゴリに属するブログ記事数をMTIfタグとMTCategoryCountを組み合わせて判定し、記事が投稿されていれば○を、投稿されていなければ×をtd要素と組み合わせて出力します。
<mt:If name="catname" eq="$pname">
<$mt:SetVar name="pname_cat" value="1"$>
<mt:If tag="CategoryCount">
<td>○</td>
<mt:Else>
<td>×</td>
</mt:If>
</mt:If>
また、ブログ名と等しいカテゴリが1つも存在しない場合を考慮して、次の部分で×を出力します。
<mt:Unless name="pname_cat">
<td>×</td>
</mt:Unless>
変数pname_catはカテゴリ繰り返し処理の前に「0」を設定して、カテゴリ名とブログ名が等しい場合に「1」を設定するようにしています。
<$mt:SetVar name="pname_cat" value="0"$>
…中略…
<mt:If name="catname" eq="$pname">
<$mt:SetVar name="pname_cat" value="1"$>
最終的な形は、これに「Movable TypeでMTPagesタグとMTEntriesタグを入れ子にして動作させる方法」を組み合わせています。
具体的には、table要素全体をMTPagesタグで括って、ウェブページに作成した製品情報からブログ記事を取り出し、さらに各ブログの情報を取り出しています。ブログ記事を取り出す際にMTPagesのコンテキストと競合しないよう、MTEntriesタグにinclude_blogsモディファイアを与えます。
そのサブテンプレートについては以下の記事のコメント欄の最後の部分をご覧ください。
前述の記事や本エントリーで紹介するテンプレートを組み合わせれば、ブログ・カテゴリ・ウェブページ・ブログ記事の情報を組み合わせた、さまざまなテーブルを作ることができると思います。色々試してみてください。
Movable TypeでMTPagesタグとMTEntriesタグを入れ子にして動作させる方法
Movable Typeのブログ記事とウェブページの一覧を入れ子にして動作させる方法を紹介します。
MTQに投稿された質問のやりとりで気がついたのですが、本エントリーで紹介する方法で正常に動作できるようです。
1.ウェブページとブログ記事の設定状態
同一のブログ(ブログID=2)に、次のタイトルでウェブページとブログ記事をそれぞれ3つずつ投稿しているものとします。ブログ記事はウェブページと異なるブログでも構いませんがここでは同一ブログとします。
ウェブページ
- 製品A
- 製品B
- 製品C
ブログ記事
- 製品Aのニュース
- 製品Bのニュース
- 製品Cのニュース
2.ウェブページ一覧にブログ記事一覧を表示(失敗例)
1項の記事が投稿されている状態で、次のサブテンプレートを設定したインデックステンプレートを作ります。
<mt:Pages>
<mt:PagesHeader>
<ul>
</mt:PagesHeader>
<li>Page: <$mt:PageTitle$></li>
<mt:Entries>
<mt:EntriesHeader>
<ul>
</mt:EntriesHeader>
<li>Entry: <$mt:EntryTitle$></li>
<mt:EntriesFooter>
</ul>
</mt:EntriesFooter>
</mt:Entries>
<mt:PagesFooter>
</ul>
</mt:PagesFooter>
</mt:Pages>
このインデックステンプレートを再構築すると、次のようにブログ記事タイトルの部分にウェブページタイトルが出力されてしまいます。

これはウェブページのコンテキストとブログ記事のコンテキストが干渉するためと思われます。
3.ウェブページ一覧にブログ記事一覧を表示(成功例)
そこで、次のようにMTEntriesタグにinclude_blogsタグを与えます。
<mt:Pages>
<mt:PagesHeader>
<ul>
</mt:PagesHeader>
<li>Page: <$mt:PageTitle$></li>
<mt:Entries include_blogs="2">
<mt:EntriesHeader>
<ul>
</mt:EntriesHeader>
<li>Entry: <$mt:EntryTitle$></li>
<mt:EntriesFooter>
</ul>
</mt:EntriesFooter>
</mt:Entries>
<mt:PagesFooter>
</ul>
</mt:PagesFooter>
</mt:Pages>
これで、ブログ記事タイトルが適正に出力されるようになります。

include_blogsモディファイアでブログIDを指定するので、ウェブページとブログ記事は異なるブログでも構いません。
4.ウェブページ一覧に関連のブログ記事一覧を表示(その1)
この方法を利用して、ウェブページ一覧に関連のブログ記事一覧を表示させてみます。
3項のサブテンプレートを使って、MTPageTitleを変数page_titleに保持し、MTEntriesタグ内にMTIfタグを追加して、ウェブページタイトルとブログ記事タイトルを比較します。
<mt:Pages>
<mt:PagesHeader>
<ul>
</mt:PagesHeader>
<li>Page: <$mt:PageTitle$></li>
<$mt:PageTitle setvar="page_title"$>
<mt:Entries include_blogs="2">
<mt:EntriesHeader>
<ul>
</mt:EntriesHeader>
<mt:if tag="EntryTitle" like="$page_title">
<li>Entry: <$mt:EntryTitle$></li>
</mt:if>
<mt:EntriesFooter>
</ul>
</mt:EntriesFooter>
</mt:Entries>
<mt:PagesFooter>
</ul>
</mt:PagesFooter>
</mt:Pages>
これで製品ウェブページに関するブログ記事を振り分けて表示することができます。

5.ウェブページ一覧に関連のブログ記事一覧を表示(その2)
4項よりさらに現実的な方法として、ブログ記事のカテゴリに「製品A」「製品B」「製品C」をそれぞれ与え、ウェブページタイトルとブログ記事のカテゴリ名で判定するようにします。
<mt:Pages>
<mt:PagesHeader>
<ul>
</mt:PagesHeader>
<li>Page: <$mt:PageTitle$></li>
<$mt:PageTitle setvar="page_title"$>
<mt:Entries include_blogs="2">
<mt:EntriesHeader>
<ul>
</mt:EntriesHeader>
<mt:if tag="EntryCategory" eq="$page_title">
<li>Entry: <$mt:EntryTitle$></li>
</mt:if>
<mt:EntriesFooter>
</ul>
</mt:EntriesFooter>
</mt:Entries>
<mt:PagesFooter>
</ul>
</mt:PagesFooter>
</mt:Pages>
これも4項と同様の結果を得られます。
6.注意事項
MTEntriesタグ内でMTPageに関するテンプレートタグを使うとコンテキストエラーになるので、MTEntriesタグでウェブページに関する情報を利用したい場合は、MTEntriesタグの前で変数に保持してください。
ウェブページの一覧をウェブページで表示する
「Movable Type 5 プロフェッショナルガイド」のサポートサイトを作成中ですが、その中で、ウェブページの一覧をウェブページで表示するというカスタマイズを行っているので、紹介します。
概要
サポートサイトのサンプルデータのページは次のような構成になっています。
- サンプルデータ目次一覧をウェブページで作成(①)
- サンプルデータのページをウェブページで作成(②)
①のサンプルデータ目次一覧は、次のようになっています。

②のサンプルデータのページは、次のようになっています。

このような構成にする場合のポイントは次の4つです。
- A.①のサンプルデータ目次一覧には自ウェブページや他のウェブページを表示しない
- B.①のサンプルデータ目次一覧は節番号順に表示
- C.①のパンくずリストには「ホーム > サンプルデータ目次 」だけを表示
- D.②のパンくずリストには「ホーム > サンプルデータ > ×××××」と表示
Aの「他のウェブページ」というのは、サンプルデータ以外にも、書籍内のリンクページや、訂正情報などをウェブページで作成しており、それらのページを指しています。
以下、A~Dの実現方法を簡単に説明します。
Aの実現方法
ウェブページ一覧を出力する際、次のように、folderモディファイアで、サンプルデータ以外のウェブページを除外しています。さらに、unlessタグで「サンプルデータ目次」のウェブページを省いています。
<mt:pages folder="サンプルデータ">
<mt:unless tag="pageTitle" eq="サンプルデータ目次">
…中略…
</mt:unless>
</mt:pages>
①②のウェブページは「サンプルデータ」というフォルダに出力するようにし、それ以外のウェブページは「サンプルデータ」フォルダに含まないように設定しておきます。
Bの実現方法
「Aの実現方法」のPageタグ、Unlessタグの中に、次のように、節番号でソートするサブテンプレートを記述します(もう少しエレガントな方法があるかもしれませんが)。
<mt:pages folder="サンプルデータ">
<mt:unless tag="pageTitle" eq="サンプルデータ目次">
<mt:if tag="pageTitle" like="^\d-\d\s.*$">
<mt:setvarblock name="key"><mt:pageTitle regex_replace="/(\d)-(\d).*/","0$1-0$2" /></mt:setvarblock>
</mt:if>
<mt:if tag="pageTitle" like="^\d\d-\d\s.*$">
<mt:setvarblock name="key"><mt:pageTitle regex_replace="/(\d\d)-(\d).*/","$1-0$2" /></mt:setvarblock>
</mt:if>
<mt:if tag="pageTitle" like="^\d-\d\d\s.*$">
<mt:setvarblock name="key"><mt:pageTitle regex_replace="/(\d-\d\d).*/","0$1-$2" /></mt:setvarblock>
</mt:if>
<mt:if tag="pageTitle" like="^\d\d-\d\d\s.*$">
<mt:setvarblock name="key"><mt:pageTitle /></mt:setvarblock>
</mt:if>
<mt:setvarblock name="val"><li><a href="<mt:pagePermalink />" title="<mt:pageTitle />"><mt:pageTitle /></a></li></mt:setvarblock>
<mt:setvar name="list{$key}" value="$val" />
</mt:unless>
</mt:pages>
<ul>
<mt:loop name="list" sort_by="key numeric">
<mt:getVar name="__value__" />
</mt:loop>
</ul>
また、テンプレートタグを評価するために「ウェブページ」アーカイブテンプレートのPageBodyタグにmtevalモディファイアを追加しています。
<$mt:PageBody mteval="1"$>
実際には、次のように、プライベートタグを使って、「@eval」を設定したウェブページのみ、テンプレートタグを評価するようにしています。
<mt:PageIfTagged tag="@eval">
<$mt:PageBody mteval="1"$>
<mt:else>
<$mt:PageBody$>
</mt:PageIfTagged>
CとDの実現方法
パンくずリストのサブテンプレートを「ウェブページ」アーカイブテンプレートに追加し、次のようにしています。
<p class="breadcrumbs">
<a href="<mt:blogURL />">ホーム</a> >
<mt:setVar name="folder_flag" value="0" />
<mt:unless tag="PageBasename" like="^index">
<mt:parentFolders glue=" > ">
<mt:setVar name="folder_flag" value="1" />
<a href="<mt:folderLink />"><mt:folderLabel /></a>
</mt:parentFolders>
</mt:unless>
<mt:if name="folder_flag"> > </mt:if>
<mt:pageTitle />
</p>
出力ファイル名が「index」で始まらない場合、つまり②のウェブページの場合だけ、パンくずリストにフォルダ名を出力するようにしています。
記事タイトルを番号順に並べる for Movable Type 4.2
Movable Type 4.2 で、ランダムに作成したブログ記事やウェブページのタイトルの先頭に「1、2、3...」という番号を割り当てている場合、番号順に記事タイトルを並べるカスタマイズです。
次のように、ランダムに作成したウェブページがあると仮定します。

これらのウェブページを、次のようにタイトルに付与した番号順に並べて表示することを想定します。
- ウェブページA
- ウェブページB
- ウェブページC
- ウェブページD
- ウェブページE
- ウェブページF
- ウェブページG
- ウェブページH
- ウェブページI
- ウェブページJ
- ウェブページK
- ウェブページL
並び替える方法として、次のようなサブテンプレートが思いつくでしょう。
<mt:pages sort_by="title" sort_order="ascend">
<mt:pagesHeader>
<ul>
</mt:pagesHeader>
<li><a href="<mt:pagePermalink />" title="<mt:pageTitle escape="html" />"><mt:pageTitle escape="html" /></a></li>
<mt:pagesFooter>
</ul>
</mt:pagesFooter>
</mt:pages>
MTPages タグに sort_order モディファイアに title を設定することで title でソートします。また sort_order モディファイアに ascend を設定することで昇順表示します。
しかしながら、出力結果から、大きな番号のものが正常にソートされないことが分かります。

そこで次のサブテンプレートを利用します。
<mt:pages>
<mt:if tag="pageTitle" like="^\d\..*">
<mt:setVarBlock name="key"><mt:pageTitle escape="html" regex_replace="/^(\d)\..*/","0$1" /></mt:setVarBlock>
<mt:elseIf tag="pageTitle" like="^\d+\..*">
<mt:setVarBlock name="key"><mt:pageTitle escape="html" /></mt:setVarBlock>
</mt:if>
<mt:setVarBlock name="val"><li><a href="<mt:pagePermalink />" title="<mt:pageTitle escape="html" />"><mt:pageTitle escape="html" /></a></li></mt:setVarBlock>
<mt:setVar name="title_data{$key}" value="$val" />
</mt:pages>
<mt:loop name="title_data" sort_by="key numeric">
<mt:if name="__first__">
<ul>
</mt:if>
<mt:getVar name="__value__" />
<mt:if name="__last__">
</ul>
</mt:if>
</mt:loop>
複雑に見えますが、やりたいことは「記事タイトルの項番が1桁のときに、項番の頭に『0』を付与して、その値でソート」です。つまり、「1、2、3...」という項番を「01、02、03...」に変換し、桁数を統一します。そして、変換した記事タイトルでソートします。
2行目の MTIf タグの like モディファイアで、記事タイトルの先頭に1桁の番号とピリオドがついているものだけをフィルタリングし、ブロック内で変数 key にウェブページタイトルを設定します。そのとき regex_replace モディファイアで、1桁の項番の前に「0」を付与しています。
4行目では記事タイトルの先頭に2桁の番号とピリオドがついているものだけをフィルタリングし、ブロック内で変数 key にウェブページタイトルを設定します。ここでは何も加工しません。
7行目の setVarBlock タグでは、実際の出力に使うウェブページタイトル(マークアップつき)を、変数 val に取得します。
そして、8行目の setVar タグで、ハッシュ変数 title_data に、キーが変数 key、値に変数 val を設定します。これでウェブページタイトルをソートする準備ができました。
後は、11行目の MTLoop タグで、変数 title_data を読み込ませ、sort_by モディファイアで、ハッシュのキーを数値によりソートします。念のため、1~8行目の桁合わせの処理をせずに MTLoop タグの数値によるソートを行ってみましたが、期待通りの結果にはなりませんでした。
これで次のような出力を得ることができます。

なお、インデックステンプレートを利用してウェブページ全体を出力するには、次のように lastn モディファイアに件数を指定する必要があるかもしれません。
<mt:blogPageCount setvar="page_count">
<mt:pages lastn="$page_count">
...後略...
ブログ記事で利用する場合は、サブテンプレートの「mt:pages」や「mt:pageXX」を、「mt:entries」「mt:entryxx」に置き換えてください。
本エントリーでは、テンプレートタグだけで並べ替えを実現する方法を紹介しましたが、番号順に並べる方法は色々あります。例えば、記事タイトルを最初から「01、02、03...」と設定しておき、出力時に先頭の 0 を削除する方法でも構いません。あるいは、概要フィールドにソート用の数値を設定しておき、MTPages タグで sort_by="excerpt" を設定するのも良いでしょう。カスタムフィールドを利用する手もあります。
2008.12.21
ハッシュ変数名に「title」という名称を用いるとエラーになるため、ハッシュ変数名を変更しました。
ウェブページのデザインを切り替える
Movable Type 4のウェブページのデザインを切り替える方法です。しっかり書く時間がないので、概要のみにとどめておきます。
ウェブページに、
- 製品情報
- 会社概要
- 採用情報
- お問い合わせ
- サポート
という5つのページがあり、「製品情報」と「採用情報」だけ異なるデザインを与えるケースで説明します。
方法は色々ありますが、ウェブページのタイトルで振り分ける場合、ウェブページテンプレートに次のように記述します。
<mt:if tag="pageTitle" eq="製品情報">
<mt:include module="製品情報" />
<mt:elseIf eq="採用情報">
<mt:include module="採用情報" />
<mt:else>
<mt:include module="その他" />
</mt:if>
インクルード先のテンプレートモジュールに、すべてのサブテンプレートを記述するか、includeタグの代わりに、ブロック内にサブテンプレートを記述します。
「その他」が必要ない場合(すべてのウェブページに対応するデザインがある場合)、次のような方法があります。
<mt:pageTitle setvar="page_title" />
<mt:include module="$page_title" />
ページタイトルをそのままインクルードするテンプレートモジュール名にしています。
2010.01.27
リストに誤りがあったので修正しました。
