気づいたかもしれないが、右のカレンダーでは土日祝日は違う色になっている。コンテナタグ MTCalendarIfSaturday、MTCalendarIfSunday、MTCalendarIfHoliday を追加して利用しているからだ。

プラグインとしてつくるのは結構めんどくさいので、直接 Context モジュールに追加することにした。

Context モジュールはここにある。先頭のmtはMTのメインディレクトリ。インストールの仕方によって場所が違うので、ご自分の環境にあわせること。

 <mt>/lib/MT/Template/Context.pm

編集するまえに、念のため、バックアップを取っておこう。

# cp Context.pm Context.pm.orig
# vi Context.pm

214行に以下の3行を追加。

$ctx->register_handler(CalendarIfSaturday => [ \&_hdlr_pass_tokens, 1 ]);
$ctx->register_handler(CalendarIfSunday => [ \&_hdlr_pass_tokens, 1 ]);
$ctx->register_handler(CalendarIfHoliday => [ \&_hdlr_pass_tokens, 1 ]);

さらに2103行 (CalendarIfToday => ($today eq $this_day), のつぎ) に、以下を追加。

CalendarIfSaturday => $day % 7 == 0,
CalendarIfSunday => ($day-1) % 7 == 0,
CalendarIfHoliday => (
$this_day eq '20040101' or
$this_day eq '20040112' or
$this_day eq '20040211' or
$this_day eq '20040320' or
$this_day eq '20040429' or
$this_day eq '20040503' or
$this_day eq '20040504' or
$this_day eq '20040505' or
$this_day eq '20040719' or
$this_day eq '20040920' or
$this_day eq '20040923' or
$this_day eq '20041011' or
$this_day eq '20041103' or
$this_day eq '20041123' or
$this_day eq '20041223'),

カレンダーのところで、コンテナタグ

<MTCalendarIfHoliday><font color="red"></MTCalendarIfHoliday>
日付等
<MTCalendarIfHoliday></font></MTCalendarIfHoliday>

のように使えばよい。つまり、カレンダーの各日付を、祝日の場合にのみ、フォントタグで囲むようにする。フォントの色を、祝日では赤。祝日でない日には、コンテナタグなので、フォントタグが消える。

なお、祝日は今年2004の分しか書いてないので、来年以降については追加して下さい。

メソッド stash の働きをまずみてみる。

stashメソッドは MT::Template::Context モジュール(mt/lib/MT/Template/のところにある)に定義されている。stash を通して、テンプレート構築時の情報を引き出したり、独自の情報を保存することができる。

以下はその例。

# キー foo に値を代入する例
$ctx->stash('foo',$value);
# キー foo から値を取出す例
my $value = $ctx->stash('foo');

さて、ここからは複雑なコンテナタグの話。

<コンテナタグ>
テンプレートに以下の通り、コンテナタグ MTSimpleLoop が使えるようにする。なお、MTSimpleLoopIndex はふつうの変数タグ。

<MTSimpleLoop loops="10">
<$MTSimpleLoopIndex$><br />
</MTSimpleLoop>

では、エディタを起動し、以下の通り、プラグインファイル mt-loop.pl を作成し、保存する。

package MT::Plugin::SimpleLoop;
use MT::Template::Context;
MT::Template::Context->add_container_tag(SimpleLoop => \&loop);
MT::Template::Context->add_tag(SimpleLoopIndex => \&loop_index);
sub loop {
    my $ctx = shift;
    my $args = shift;
    my $content = '';
    my $builder = $ctx->stash('builder');
    my $tokens = $ctx->stash('tokens');
    for my $i(1..$args->{loops}) {
        $ctx->stash('loop_index',$i);
        my $out = $builder->build($ctx, $tokens);
        $content .= $out;
    }
    $content;
}
sub loop_index {
    my $ctx = shift;
    return $ctx->stash('loop_index');
}

テンプレートにコンテナタグを挿入して再構築すれば、ブログにループの回数が以下のように表示される。途中経過は省略。

1
2
...
9
10

では、各行をみていこう。

3行目。コンテナタグの登録。
6~18行目。コンテナタグ対応のサブルーチン。
10行目。Builderクラス(MT::Builder) への参照を得る。
11行目。コンテナタグに囲まれた文字列(トークン)への参照を得る。
12~16行目。ループ。繰返し回数は属性loopsで決まる。
13行目。ループカウンターを loop_index に代入。それをサブルーチン loop_index に利用される。
14行目。トークン(文字列)の解決等を Builder に処理してもらい、結果を変数$outに代入。
15行目。変数 $content に連結させる。つまり、ここの例だと、繰り返す度に、$contentに <$MTSimpleLoopIndex$><br /> = $iの値<br /> が後ろに追加される。
17行目。ループ終了時に、$content に 1<br />2<br />…9<br />10<br /> が残る。それがコンテナタグによって囲まれる文字列のインスタンスとなる。

説明はまだまだ判りにくいが、変数タグを利用して、ループ途中の経過を記憶し、ループ終了後に表示させるともっと理解するかもしれない。

2つ目の例。今度は <$MTHelloWorld world=”Linux”$> のように、タグの属性 world が使えるようにしたい。ただし、world属性を使わなければ1つ目と同じ出力結果、つまり上位互換、にする。

<プラグイン MTHelloWorld の修正>
 エディタを起動し、1つ目のプラグインファイル mt-hello.pl を以下のように修正する。

package MT::Plugin::HelloWorld;
use MT::Template::Context;
MT::Template::Context->add_tag(HelloWorld => \&hello_world);
sub hello_world {
    my $ctx = shift;
    my $args = shift;
    my $world = defined($args->{world}) ? $args->{world} : 'World';
    return "Hello $world.";
}

テンプレートに、<$MTHelloWorld world=”Linux”$> を挿入して再構築すれば、メッセージ Hello Linux が表示される。Linuxを違う文字列にしてもOK。

では各行の意味。
1~2行目。前回同様。
3行目。はっきりとサブルーチンの参照に変えた。5行目はそのサブルーチンの本体。
6行目。参照 $ctx に MT::Template::Context のインスタンスが入る。プラグインに必要な情報がここから得られる。
7行目。参照 $arg に属性の連想配列が入る。
8~9行目。属性worldが定義されていればそれを使い、未定義であればデフォルトの World を使う。

巷にブログは大人気。ここの MT (Movable Type、以下はMTと略) も世界的に実績のあるシステム。とくに機能拡張、プラグイン (Plugin) が容易に追加できることから、MT用のプラグインが色々と出回っている。そこで、今回は考え方や、簡単な作例を用いながら、プラグインの仕組み等を説明する。なお、対応バージョンは 3.0。前の古いバージョンでは修正しないといけないらしい。

<プラグインのインストール先>
 これからつくるプラグイン、あるいはダウンロードしたプラグインは、MTのメインディレクトリにある、plugins というサブディレクトリに入れる。プラグインのファイル名は拡張子が必ず .pl でないといけないので、注意すること。逆に、一時的にプラグインとして機能させたくない場合には、拡張子を他のものに変えるとよい。

<最初のプラグイン MTHelloWorld>
 C言語に習って、「Hello World.」を表示するプラグインを書こう。ファイル名は mt-hello.pl とする。

エディタを用いて、以下を入力し、ファイル mt-hello.pl として保存。

package MT::Plugin::HelloWorld;
use MT::Template::Context;
MT::Template::Context->add_tag(HelloWorld =>sub { return 'Hello World.'; });

つぎに、MTのテンプレートファイル、例えばメインページの適当な箇所に、以下を挿入する。

<$MTHelloWorld$>

メインページを再構築すれば、Webページにメッセージ Hello World が表示される。

では、作成したプラグインの各行を見ていく。
1行目。パッケージ MT::Plugin::HelloWorld の宣言。
2行目。MT::Template::Context を使用するとの宣言。3行目にこれを実際に使う。
3行目。タグ HelloWorld の登録。タグの実態は キーとバリューからなる連想配列。キーはタグ名そのものでないといけない。バリューはサブルーチンで、テンプレートの構築処理時に呼び出される。

注意して欲しいのは、テンプレートに使う際、登録したタグ名に MT というプレフィックス (prefix) がつく。つまり、登録したタグ HelloWorld ⇔ テンプレートでの使用 MTHelloWorld となる。なお、MT専用の変数タグは、HTML固有のタグと区別するために、<$MTタグ$> の形で使う。

<MT専用タグについて>
 MTでは専用タグが2種類あり、コンテナタグと変数タグ。
コンテナタグは主に、ループやコンディションを表し、<MTEntries>…</MTEntries> のように前後囲んで使う。
変数タグは、<$MTEntryBody$> の形で使う。

ブログツール Movable Type で利用可能な Plugin。
詳しい話は こちら を参照されたい。

drk さんが作成・公開された MTWeather プラグイン に、以下3つのタグが使えるように改良を試みた。

<MTWeatherJP へのタグ追加>
  <$MTWhenReported$> 気象庁の発表時間(5時、11時、17時等)
  <$MTMaxAvailable$> 数値として表示可能な最高気温
  <$MTMinAvailable$> 数値として表示可能な最低気温

Movable Type 用プラグイン MTWeatherJP の改良版
  ソース sjis コードeuc コード、または、UTF-8 コード、MTWeatherJP.pl というファイル名で保存すること。

オリジナルMTWeatherJPの著作権は勿論 drk さんが所有しているので、それに準ずる利用法でいいと思う。無料利用OKとか。

判るように、私の追加した行すべてにコメントを付けてある。

私のLinuxサーバでは UTF-8 コードでないと動作しないが、パソコンで見るには sjis コードのほうが便利かもしれない。インストールのしかたはオリジナルMTWeatherJPと同じ、プラグインをMTのpluginsディレクトリに入れるだけでOK。

以下はMTからの使用例。メインページのインデックス・テンプレートに追加するといいだろう。こんなイメージになる。

<!-- Weather_start -->
<h2><$MTDate format="%Y-Success--1080299360"$></h2>
<table align="center" border="0" cellpadding="0" cellspacing="0">
<MTWeatherJP timeout="15" area="栃木県" ie="sjis" dir="/weather/img/">
<tr><td width=30></td><td align=center width=30>
<$MTTodayDate$>日</td>
<td align=center width=30><$MTTomorrowDate$>日</td><td
align=center width=70>気温</td></tr>
<tr><td>栃木</td><td align=center><img src=
"<$MTTodayGifEx$>" width="25" height="15" alt="<$MTToday$>"></td>
<td align=center><img src="<$MTTomorrowGifEx$>" width="25"
height="15" alt="<$MTTomorrow$>"></td>
<td align=center><$MTMinAvailable$>-<$MTMaxAvailable$>
</td></tr>
</MTWeatherJP>
<MTWeatherJP timeout="15" area="東京地方" ie="sjis" dir="/weather/img/">
<tr><td>東京</td><td align=center><img src=
"<$MTTodayGifEx$>" width="25" height="15" alt="<$MTToday$>"></td>
<td align=center><img src="<$MTTomorrowGifEx$>" width="25"
height="15" alt="<$MTTomorrow$>"></td>
<td align=center><$MTMinAvailable$>-<$MTMaxAvailable$>
</td></tr>
</MTWeatherJP>
<MTWeatherJP timeout="15" area="大阪府" ie="sjis" dir="/weather/img/">
<tr><td>大阪</td><td align=center><img src=
"<$MTTodayGifEx$>" width="25" height="15" alt="<$MTToday$>"></td>
<td align=center><img src="<$MTTomorrowGifEx$>" width="25"
height="15" alt="<$MTTomorrow$>"></td>
<td align=center><$MTMinAvailable$>-<$MTMaxAvailable$>
</td></tr>
</MTWeatherJP>
<tr><td colspan=2 align=left><a href="http://www.tenki.jp/">
気象情報</a></td><td colspan=2>
<$MTWhenReported$>時発表</td></tr></table>
<!-- Weather_end -->