【Movable Type】複数のコンテンツタイプをまとめて出力する
概要
MTにおいて、複数のコンテンツタイプ(のデータ)をマージして出力する方法について解説しています。
新着記事一覧に表示したりサイトのRSSフィードとして配信するなど、複数のコンテンツタイプをまとめて出力したいという場面もあるかと思いますが、現状ではMTLoop
を利用することで実装可能です。
コンテンツタイプ(のデータ)の出力については、以下記事をご参考ください。
構造
複数のコンテンツタイプをマージするMTMLは、おおまかに以下の構造です。
<!-- 出力したいコンテンツタイプの数だけ<mt:Contents>〜</mt:Contents>を用意する -->
<mt:Contents content_type="[コンテンツタイプAのID]" limit="[num]">
<$mt:ContentDate format="%Y%m%d%H%M%S" setvar="key"$>
<mt:SetVarBlock name="cd{$key}">
<!-- 出力する内容(HTMLの構造は他のコンテンツタイプの出力内容と合わせる) -->
</mt:SetVarBlock>
</mt:Contents>
<mt:Contents content_type="[コンテンツタイプBのID]" limit="[num]">
<$mt:ContentDate format="%Y%m%d%H%M%S" setvar="key"$>
<mt:SetVarBlock name="cd{$key}">
<!-- 出力する内容(HTMLの構造は他のコンテンツタイプの出力内容と合わせる) -->
</mt:SetVarBlock>
</mt:Contents>
<!-- 出力表示部分 -->
<mt:Loop name="cd" sort_by="key reverse">
<mt:SetVar name="count" value="1" op="+">
<mt:If name="count" le="[num]"><mt:Var name="__value__"></mt:If>
</mt:Loop>
マージしたいコンテンツタイプの数だけMTContents
を記述します。中身はハッシュ(連想配列)としてデータ単位で格納します。
出力はMTLoop
内の処理が実際の出力として表示されます。MTIf
のle="[num]"
で指定した数だけ<mt:Var name="__value__">
が出力されます。MTContents
内のMTSetVarBlock
で定義した中身が出力されます。
MTContents
内のsetvar="key"
のkey
とname="cd{$key}"
の{$key}
、name="cd{$key}"
のcd
とMTLoop
のname="cd"
のcd
がそれぞれ対応しています。これらの値は任意のもので構いません。
これらの処理はPHPなどプログラミング言語にある処理と同等のものですが(ハッシュの他に配列もあります)、MTの場合はMTタグとして記述するので少し複雑になっています。
なお、これらについて解説したものが公式のGitHubリポジトリにあるので、こちらもご確認ください。公開が古い日付のものですが、振る舞いは現在のMTでもおおむね同じです。
コード例
以下はRSSフィードとしての出力例です。このコードを例に、できる限りくわしく解説していきます。
なお、コンテンツタイプはいずれも以下で設定しています。例では同じ名称とフィールドを設定していますが、実際には出力するHTMLが同じであれば、コンテンツタイプごと各フィールド項目は違っていても問題ありません。
- タイトル(テキスト / 必須)
- 概要(テキスト(複数行))
この例では、以下のことを行っています。
- コンテンツタイプAとコンテンツタイプBの記事をそれぞれ最新20件ずつ抽出
- 抽出した記事をマージし、最新順に並べる
- 最新20件分を実際に出力する
<mt:SetVar name="num" value="20">
<mt:Contents content_type="[コンテンツタイプAのID]" limit="$num">
<mt:ContentDate format="%Y%m%d%H%M%S" setvar="key">
<mt:SetVarBlock name="cd{$key}">
<item>
<title><mt:ContentField content_field="タイトル"><$mt:ContentFieldValue$></mt:ContentField></title>
<description><mt:ContentField content_field="概要"><$mt:ContentFieldValue remove_html="1" trim_to="50+..."$></mt:ContentField></description>
<link><$mt:ContentPermalink$></link>
<guid><$mt:ContentPermalink$></guid>
<content:encoded><mt:ContentField content_field="概要"><$mt:ContentFieldValue encode_xml="1"$></mt:ContentField></content:encoded>
<pubDate><$mt:ContentDate format_name="rfc822"$></pubDate>
</item>
</mt:SetVarBlock>
</mt:Contents>
<mt:Contents content_type="[コンテンツタイプBのID]" limit="$num">
<mt:ContentDate format="%Y%m%d%H%M%S" setvar="key">
<mt:SetVarBlock name="cd{$key}">
<item>
<title><mt:ContentField content_field="タイトル"><$mt:ContentFieldValue$></mt:ContentField></title>
<description><mt:ContentField content_field="概要"><$mt:ContentFieldValue remove_html="1" trim_to="50+..."$></mt:ContentField></description>
<link><$mt:ContentPermalink$></link>
<guid><$mt:ContentPermalink$></guid>
<content:encoded><mt:ContentField content_field="概要"><$mt:ContentFieldValue encode_xml="1"$></mt:ContentField></content:encoded>
<pubDate><$mt:ContentDate format_name="rfc822"$></pubDate>
</item>
</mt:SetVarBlock>
</mt:Contents>
<mt:Loop name="cd" sort_by="key reverse">
<mt:If name="__first__">
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title><$mt:WebsiteName$></title>
<description><$mt:WebsiteName$>のRSSフィード</description>
<link><$mt:WebsiteURL$></link>
</mt:If>
<mt:SetVar name="count" value="1" op="+">
<mt:If name="count" le="$num"><mt:Var name="__value__"></mt:If>
<mt:If name="__last__">
</channel>
</rss>
</mt:If>
</mt:Loop>
コード例ではMTSetVarBlock
内を見やすいように改行・インデント処理していますが、エラーとなり処理がうまくいかない可能性があるため、実際のテンプレートでは改行やインデントはせず1行で記述するようにしてください。
解説:MTSetVar部分
最初に、MTContents
およびMTLoop
内で出力(処理)する記事の数を<mt:SetVar name="num" value="20">
で定義します。変数に定義せず、それぞれ個別に数を指定しても構いません。
<mt:SetVar name="num" value="20">
解説:MTContents部分
以下、MTContents
のMTMLです。
<mt:Contents content_type="[コンテンツタイプAのID]" limit="$num">
<mt:ContentDate format="%Y%m%d%H%M%S" setvar="key">
<mt:SetVarBlock name="cd{$key}">
<item>
<title><mt:ContentField content_field="タイトル"><$mt:ContentFieldValue$></mt:ContentField></title>
<description><mt:ContentField content_field="概要"><$mt:ContentFieldValue remove_html="1" trim_to="50+..."$></mt:ContentField></description>
<link><$mt:ContentPermalink$></link>
<guid><$mt:ContentPermalink$></guid>
<content:encoded><mt:ContentField content_field="概要"><$mt:ContentFieldValue encode_xml="1"$></mt:ContentField></content:encoded>
<pubDate><$mt:ContentDate format_name="rfc822"$></pubDate>
</item>
</mt:SetVarBlock>
</mt:Contents>
上記のコードは、以下のハッシュ(連想配列)を生成します(わかりやすいようにPHPなどでの表記に合わせています / 以降同様)
["YYMMDDhhmmss" => "<item>(省略)</items>"],
["YYMMDDhhmmss" => "<item>(省略)</items>"],
["YYMMDDhhmmss" => "<item>(省略)</items>"],
.
.
.
<mt:ContentDate format="%Y%m%d%H%M%S" setvar="key">
で日時を変数key
として定義します。ハッシュのkey
の値になります(setvar
の値はkey
以外でも問題ありません)
key
の値はかならずしも日付である必要はないですが、数字のフォーマットが扱いやすいため、筆者は日付にすることが多いです。
<mt:SetVarBlock name="cd{$key}">〜</mt:SetVarBlock>
がハッシュのvalue
の値です(見やすいように改行とインデントを入れています)
name="cd{$key}"
の$key
は、MTContentDate
で定義したsetvar
と同じものを$
をつけて指定します。
以下の記述は同じです。どちらで記述するかはお好みで。
name="cd{$key}"
(name="cd" key="$key"
)のcd
の値は任意のもので構いません。
<!-- これと -->
<mt:SetVarBlock name="cd{$key}"></mt:SetVarBlock>
<!-- これは同じ -->
<mt:SetVarBlock name="cd" key="$key"></mt:SetVarBlock>
<mt:SetVarBlock name="cd{$key}">〜</mt:SetVarBlock>
の中身は出力する中身にあわせて適宜変更してください。この部分は通常のコンテンツタイプの一覧を出力する際の記述と同じです。
同様に、コンテンツタイプB、コンテンツタイプC、とマージしたいコンテンツタイプのMTMLを記述します。注意事項として、ハッシュのkey
とvalue
に該当する変数の定義部分であるsetvar="key"
とname="cd{$key}"
(name="cd" key="$key"
)は同じ値を指定します。
<!-- 以下はすべてのコンテンツタイプで共通で指定する -->
<$mt:ContentDate format="%Y%m%d%H%M%S" setvar="key"$>
<mt:SetVarBlock name="cd{$key}">
<!-- (省略) -->
</mt:SetVarBlock>
コンテンツタイプを複数指定することにより、最終的に以下のハッシュ(連想配列)を生成します。
["(コンテンツタイプAの記事)YYMMDDhhmmss" => "(コンテンツタイプAの記事)<item>(省略)</items>"],
["(コンテンツタイプAの記事)YYMMDDhhmmss" => "(コンテンツタイプAの記事)<item>(省略)</items>"],
["(コンテンツタイプAの記事)YYMMDDhhmmss" => "(コンテンツタイプAの記事)<item>(省略)</items>"],
["(コンテンツタイプBの記事)YYMMDDhhmmss" => "(コンテンツタイプBの記事)<item>(省略)</items>"],
["(コンテンツタイプBの記事)YYMMDDhhmmss" => "(コンテンツタイプBの記事)<item>(省略)</items>"],
["(コンテンツタイプBの記事)YYMMDDhhmmss" => "(コンテンツタイプBの記事)<item>(省略)</items>"],
["(コンテンツタイプCの記事)YYMMDDhhmmss" => "(コンテンツタイプCの記事)<item>(省略)</items>"],
["(コンテンツタイプCの記事)YYMMDDhhmmss" => "(コンテンツタイプCの記事)<item>(省略)</items>"],
["(コンテンツタイプCの記事)YYMMDDhhmmss" => "(コンテンツタイプCの記事)<item>(省略)</items>"],
.
.
.
MTContents
部分の記述は以上です。
解説:MTLoop部分
以下はMTLoop
のMTMLです。MTContents
で生成したハッシュ(連想配列)データを出力します。
<mt:Loop name="cd" sort_by="key reverse">
<mt:If name="__first__">
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title><$mt:WebsiteName$></title>
<description><$mt:WebsiteName$>のRSSフィード</description>
<link><$mt:WebsiteURL$></link>
</mt:If>
<mt:SetVar name="count" value="1" op="+">
<mt:If name="count" le="$num"><mt:Var name="__value__"></mt:If>
<mt:If name="__last__">
</channel>
</rss>
</mt:If>
</mt:Loop>
MTLoop
のname
モディファイアの値は、MTContents
内のMTSetVarBlock
で指定したname
モディファイアの値です。
ソートの基準はkey
(今回の例ではYYMMDDhhmmss
)です。sort_by
にkey
だけを指定すると昇順で出力されるので、reverse
も指定して逆順(降順)で出力するようにします。
MTLoop
内ではMTEntriesHeader
のような独自タグが存在しないため、ループ内で最初あるいは最後だけ出力するにはMTIf
の予約変数(__first__
や__last__
)を利用します。
MTContents
で定義した出力部分は以下です。
<mt:SetVar name="count" value="1" op="+">
<mt:If name="count" le="$num"><mt:Var name="__value__"></mt:If>
MTSetVar
で値1
を変数count
として定義します。op="+"
を指定することで、ハッシュ(連想配列)がひとつ処理されるたびに値が1つずつ追加され、変数count
に格納されます。以下のようなイメージです。
count1: いちばんあたらしい記事
count2: 2番目にあたらしい記事
count3: 3番目にあたらしい記事
count4: 4番目にあたらしい記事
count5: 5番目にあたらしい記事
count6: 6番目にあたらしい記事
.
.
.
処理されたもののうち、MTIf
の条件(変数count
の値が$num
以下)に合致するハッシュのvalue
(今回の例では<item>〜</item>
)が出力されます。
MTLoop
部分の解説は以上です。
公式リファレンスなど
- https://www.movabletype.jp/documentation/appendices/tags/loop.html
- https://www.movabletype.jp/documentation/appendices/tags/setvarblock.html
- https://www.movabletype.jp/documentation/mt6/design/templates/calculation.html
- https://github.com/movabletype/Documentation/wiki/Japanese-mtml-guide-3-3
本記事では触れませんでしたが、配列を処理するためのMTFor
というタグもあります。
また、今回はコンテンツタイプを取り上げたためPowerCMSには触れていませんが、PowerCMSでも配列やハッシュ(連想配列)を扱うことが可能です。
Discussion