MovableTypeのプラグイン作成(邦訳)
MovableTypeのプラグインを作成したくなったので、参考資料を邦訳してみることにしました。元の文はDeveloping Movable Type Plug-insでオライリーの記事です。
えぃやっ、でやってしまったので、いい加減な意訳が多いです…。意味不明、間違っている等の苦情ありましたら、ご一報願いますm(_ _)m。
※(2005/05/05追加)この記事がO'reillyのBlog Hacksという本で紹介されている(#60『MovableTypeのプラグインを開発する』)ことを知りました。この本にはBlog技術にまつわる話がいろいろ載っており、Blogを使って何かしようとされている方には非常におすすめな1冊です。
※(2006/12/01追加)この記事が毎日コミュニケーションズのMOVABLETYPE PLUGINS DIRECTORY
という本で紹介されました(pp.189 『column プラグインを開発したい人のために④』)。この本には様々なMovableTypeのプラグインが紹介されており、MovableTypeの機能を拡張されたい方には是非お勧めな一冊です。
(以下邦訳、インデックスの方は"続き"を見てください)
この文章ではMovableType(以下MT)のプラグインのフレームワーク、全てのAPI(Application Programming Interface)、核となるシステムへのフックの仕方の基礎、データの保持機構について解説します。MTのプラグイン作成にはPerlの知識とオブジェクト指向の考え方がわかっていれば大丈夫。
MovableType プラグインフレームワーク
一般的に言って、MTのプラグインで何ができるのかといえば、テンプレートに適用される文章整形エンジンに、タグを値と置換する『変数タグ』、繰り返しなどに用いられる『コンテナタグ』、内容に作用するフィルターを指定する『グローバルフィルター』に加え、条件に応じて内容を取り扱う『条件タグ』を追加するといったことに限定されます。また、MTのバージョン2.6では、文章整形エンジンへフックするAPIの登場によってプラグインのフレームワークがテンプレートの整形から切り離されたため、独自の文章整形エンジンを作成することができるようになりました。加えてプラグインからMTのデータ保持機構へ直接アクセスできるようにもなりました。では、このフレームワークの特徴についてこの文章を通して迫ってみましょう。
プラグインをインストールすることはとても簡単です。単純にMTがおいてある(つまりmt.cgiがある)ディレクトリーの下にあるpluginsという名前のディレクトリーの中に、コードを配置すればいいだけです(もし古いバージョンを使用しているなら、このディレクトリーを作らなければならないでしょう)。MTはpluginsディレクトリーにある全ての*.plをプラグインとして読み込むでしょう。プラグインは同じMTで運営されている限り全てのブログで有効になります。
プラグインのフレームワークに加えて、MTは開発者が彼らの独自拡張のアプリケーションのためのコマンドラインユーティリティを作成できるように、拡張可能でドキュメントが整った一連の機能性をそのオブジェクト思想に則ったPerlモジュールによって提供しています。しかし、この文章ではそのことまでカバーしていません。
では、はじめてのプラグインを作成してみましょう。
MTHelloWorld: はじめてのプラグイン
でははじめに、ベーシックな変数タグ、つまりは単純にそのタグに出会ったときに値をタグと置換するものをつくってみましょう。
use MT::Template::Context;
MT::Template::Context->add_tag(HelloWorld => sub { return 'Hello World.'; } );
1;
このコードをファイル名をmt-helloworld.plとして先述のpluginsディレクトリーに保存してください。そしてテンプレートの中で<$MTHelloWorld$>を使ってみてください。そのテンプレートを再構築すると<$MTHelloWorld$>がHello Worldという文字列に置き換えられているはずです。では中身のコードに迫ってみましょう。
まず最初の行で、MT::Plugin::HelloWorldのパッケージであることを宣言しています。この宣言は必要ではありませんが、この宣言することによって他のMTのプラグインとのネームスペースの干渉を避けることができます。MT::Plugin::を使用しているのも同様の理由によるものです。
2行目でMT::Template::Contextを呼び出しています。このモジュールはプラグイン開発の肝となる要素を含んでいる部分で、テンプレートの構築によって文章が生成されるときの仕事台になります。
最後にHelloWorldタグを単純なHashを引数にすることによって登録します。Hashのキーは登録したいタグの名前にします。"MT"という接頭語が想定されているので、システムによって自動的に付加されます(つまりキーをHelloWorldにしたらMTHelloWorldというタグ名で登録されます)。Hashの値は文章を構築中に登録したタグに遭遇したときに呼び出されて欲しいサブルーチンを指定します。今回の場合、単純だったので、直接値にサブルーチンを記述しましたが、通常は外部の名前付きサブルーチンを呼び出す無名サブルーチンを記述するのがよい形です。こうすることによって、コードが見やすくなり、複数のタグからサブルーチンを再利用することができるようになります。
ではより進んだことをしましょう。特定の世界に対して"Hello"を言うようにしたいとしましょう。またその世界は、テンプレートによって指定できるようにするものとします。以下のコードがこの要望を満たします。
use MT::Template::Context;
MT::Template::Context->add_tag(HelloWorld => \&hello_world);
sub hello_world {
my $ctx = shift;
my $args = shift;
return "Hello " . (defined($args->{world}) ? $args->{world} : 'World');
}
1;
こうすれば<$MTHelloWorld world="Krypton"$>が使えるようになり、Hello Kryptonが挿入されるようになったはずです。もしworld属性を指定しなかった場合、Hello Worldとなります。では違いをみてみましょう。
3行目で外部にある名前付きサブルーチンを呼び出すようにしました。サブルーチンにははじめの2行で見ることができるように、プラグインのルーチンで使用できる2つの参照をMTが渡しています。わかりやすく書いたために冗長な書き方ですが、ここはお好みでどうぞ。
$ctxであらわされるはじめの参照はMT::Template::Contextの現在のインスタンスです。このオブジェクトはテンプレートの整形プロセッサーの現在の状態に対する全ての情報をもっており、これはすべてのプラグインに対して、根本になるものです。このオブジェクトの共通部分については後のセクションで探求しましょう。
2番目の参照、つまり$argsで宣言されている参照は、テンプレートで定義されている属性のHashです。サブルーチンの3行目、そして最後の行では、このHashをworld属性が定義されているかどうかを確かめるため、そしてそれに従って、Worldをデフォルト値として結果を返しています。他の引数はすべて無視するのがよいです。(おそらく他の引数は全体に適用されるフィルターハンドラです)
注)今回の例では、常にテンプレートに何かを挿入しましたが、ある条件に基づいては何も挿入したくないということがあるでしょう。そのような場合は、定義されていない値ではなくnull文字列を返さなければなりません。プラグインから返された定義されていない値はエラーとして扱われ、処理を停止させます。
値の置き換えは実のところあまりおもしろくありません。プラグインの真の実力はシステムにフックし他のタグとともに使われるきときにあらわれます。プラグインのフレームワークの残りの話を続ける前に、MTの処理にフックする一般的な方法について見てみることにしましょう。
The Stash
MTのテンプレート処理にフックするには、MT::Template::Contextモジュールで提供されているstashを使用します。stashを通してMTが現在処理中の情報を取得することができます。またstashを使用することによって、他の関連づけられたタグが後から使用するために、自身の情報を格納することもできます。以下が簡単な例です。
$ctx->stash('foo',$value);
# この行はfooの値を取得し、$valueに代入します。
my $value = $ctx->stash('foo');
MTはテンプレートを処理中に出合ったタグに対して再帰的にこのように動作するため、コンスタントに追加、取得、値の消去がstashに行われます。以下がMTがテンプレート処理中に使用するいくつかのキーです。
blog | 現在のMT::Blogのインスタンスに対する参照。 |
blog_id | 現在のweblogのID値(Integer型)。MT::Blog->idの値と等しい。 |
entries | 現在処理中のMT::Entryオブジェクト配列に対する参照 |
entry | 現在の文脈におけるMT::Entryのインスタンスに対する参照 |
category | 現在の文脈におけるMT::Placementのインスタンスに対する参照 |
comment | 現在の文脈におけるMT::Commentのインスタンスに対する参照 |
ping | 現在の文脈におけるMT::Ping (TrackBack ping)のインスタンスに対する参照 |
tag | 現在処理中のタグ名のString表現。"MT~"という名前の"MT"の部分は省略されている。 |
タグ以外では、これらのstashに蓄えられた参照はMTによってデータベースからメモリに展開されたコンテンツに対するアクセスを提供します。これはテンプレートタイプや他のタグによって決定されたテンプレートが処理すべき現在の文脈に応じて展開されます。
後の例でみるようにstashに蓄えられたこれらの情報は自前のプラグインを作成するのにとても便利です。では、話を戻してMTのプラグインのフレームワークに関する残りの話の続きをしましょう。
Container Tags(コンテナタグ)
先述のとおり、値を置換するタグはおもしろみにかけます。MTによってサポートされる別の方法としてコンテナタグがあります。その名前が示すとおり、このタイプのタグは別のマークやテンプレートタグを開始タグと終了タグの間に含むことができます。コンテナタグはテンプレートのコードをひと塊まりとして処理すること、そして他のタグの出力結果から文章を生成することが可能です。以下にしめすのはMTのはじめから組み込まれているコンテナタグであるMTEntriesの簡単な例です。このタグはエントリーの題をテンプレートのMTEntryTitleの部分に挿入します。
<$MTEntryTitle$><br />
</MTEntries>
コンテナタグをプログラムするにはもう少し考える必要があります。なぜなら、コンテナタグの中身はさらなる処理を要求するからです。値を置換するタグを伴ったコンテナタグの簡単な例を見てください。
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');
foreach my $i (1..$args->{loops}){
$ctx->stash('loop_index',$i);
my $out = $builder->build($ctx, $tokens);
$content .= $out;
}
}
sub loop_index {
my $ctx = shift;
return $ctx->stash('loop_index');
}
1;
このプラグインを実装することによって、以下のようにして数のリストをつくれます。
<$MTSimpleLoopIndex$><br />
</MTSimpleLoop>
一つずつ解説していきます。コンテナタグや置換タグをその関連するサブルーチンとともに登録する前に、MT::Template::Contextクラスを使用することを宣言しています。loopの繰り返しルーチンに移ったとき、まずContextクラスと引数のHashへの参照を変数を先に割り当てています。
コンテナタグは変数の対応関係が他のテンプレートタグとは異なります。これはコンテナタグ自身のサブルーチンから抜ける前に、コンテナタグの中身をテンプレート処理エンジンに引き渡さなければならないためです。例にあらわれているように、テンプレート構築クラス(MT::Builder)に対する参照をstashから取得し、$builderに格納しています。加えて、一連の処理中のトークンに対する参照も取得し、$tokensに格納しています。
配置が終わると、loopが開始されます。まず、stashに現在のループ回数を格納します。次に現在の文脈と処理中のトークンをbuilderに渡し、$outにその結果を格納します。そして$contentに結果である$outを結合していき次のループへと再びすすみます。
loop_indexがどのように使われているか見てください。ここでstashからループ回数を取得し、Stringとしてそれを返しています。
この例がstashとともに機能するタグのよい例となったことでしょう。というわけで、MTのプラグインによる拡張の可能性を紹介していきたいと思います。
Conditional Tags(条件タグ)
条件タグは利便性のためにAPIにつけたされた特別なコンテナタグなので、すらすら読めることでしょう。
条件タグとして登録されたサブルーチンはtrueかfalseの値を返すことだけが必要です。MTは条件タグが通ったかどうかで、自動的にさらなる処理を行うか、あるいは出力を剥ぎ取るかを決定します。言い換えれば、builderオブジェクトを条件でラッピングする必要があるのです。以下に単純な2つの条件タグの実装を示します。
use MT::Template::Context;
MT::Template::Context->add_conditional_tag(IncludeThis => sub { return 1 });
MT::Template::Context->add_conditional_tag(ExcludeThis => sub { return 0 });
このプラグインを実装することによって以下のマーク付けがテンプレートで可能になります。
<MTExcludeThis>This text will be stripped.</MTExcludeThis>
"This text will appear."だけが残りました。MTのテンプレートビルダーにtrue(つまり1)が渡ったためです。
Global Filters(グローバルフィルター)
グローバルフィルターはタグではありません。MTのテンプレートタグのいずれに対しても付け加えることが出来る属性のことです。グローバルフィルターは一つの値(きわめて多くの場合、"1"が有効であることを示します)をとり、挿入前にタグの中身に対して適用されるフィルターを呼び出します。MT備え付けのグローバルフィルターにはマーク付けタグを除去するもの、XMLのエンコードをするもの、テキストを小文字(例えばA→aにする)ものなどがあります。
グローバルフィルターはカスタマイズしがいがありますが、一般的にとても単純です。以下は空行を除去するグローバルフィルターの例です。
use MT::Template::Context;
MT::Template::Context->add_global_filter(strip_blanks => sub { \&strip_blanks });
sub strip_blanks {
my $text = shift;
my $arg_value = shift;
my $ctx = shift;
$text=~s/^\s*?\n//gm if ($arg_value);
return $text
}
1;
前同様、冗長にこのコードは書かれています。グローバルフィルターに渡される値はタグベースのものとはことなることに注意してください。グローバルフィルターには処理されたテキストの実体、属性の値(hoge="1"なら"1")、Contextクラスのインスタンスに対する参照が順に与えられます。
この例では、属性の値が$arg_valueに蓄えられています。そして、Contextオブジェクトが$ctxに蓄えられていますが使われていませんので、無視できます。この例では単純に正規表現による置換を作用させて結果を返しています。
このプラグインは以下のよう使います。
...
</MTEntries>
これによってタグ内の全ての空行は取り除かれます。
Text-Formatting Plugins(テキスト整形プラグイン)
MTのバージョン2.6のリリースでは、文章整形エンジンへフックするAPIの登場によってプラグインのフレームワークがテンプレートの整形から切り離されました。このタイプのプラグインは、XHTML等のフォーマットを気にせずに、MTのブラウザベースのインターフェスで一般のユーザが文章を作成するのに、機能的でよりやさしい手段を提供することを目的としています。
テキスト整形エンジンは構造化された文章記法のフォーマットを別のマークアップ言語(HTMLのMLはMarkup Languageでマークアップ言語の一種であることを示しています)、例えばXHTMLに置き換えます。ある場合はテキスト整形プラグインはグローバルフィルターのようになるでしょう。しかしながら、注意すべき違いがあります。すべての筆者が同じフォーマットスタイルを使用することを強制するために、グローバルフィルターを用いるならば、明示的にそれぞれのテンプレートで宣言されなければなりません、加えてMTのプレビューレンダリングには効果が及びません。以下の例は、Tikiと呼ばれる記法を用いて開発した、初期のテキスト整形プラグインのサブセットです。
use MT;
MT->add_text_filter('tiki' => {
label => 'TikiText',
docs => 'http://www.mplode.com/tima/projects/tiki/',
on_format => \&tiki;
});
sub tiki {
my $text=shift;
my $ctx=shift;
require Text::Tiki;
my $processor=new Text::Tiki;
return $processor->format($text);
}
ここにはどのようにしてこのタイプのプラグインを実装するかにおけるいくつかの大きな違いがあります。まずはContextモジュールではなく、MTモジュールを使用してテキスト整形プラグインを登録していることです。もう一つの大きな違いはテキスト整形プラグインを登録することに、より関わっています。
テキスト整形エンジンは1つのキーと関連づけられたオプションのHashによって登録されます。この例ではキーとして"tiki"を使用しました。構築するときにそれぞれのエントリーでどの整形エンジンを使用するか決定するのに使用されるので、キーは非常に重要です。キーは小文字であるべきで、アルファベットとアンダーバー("_")のみで構成されているべきです。このキーは一度展開されたら換えるべきではありません。
tikiキーに関連づけられたオプションのhashに目を向けてみましょう。labelキーにTikiTextという値を指定していますが、TikiTextはMTのインターフェイスとして使われることでしょう。次にこのフォーマットに対するドキュメントのURLを指定しています(MTはユーザが簡単にアクセスできるよう、そのインターフェイスにおいてこのドキュメントに対するリンクを作成します)。そしてまた前と同じように、on_format属性を使用してこのテキストフォーマットを扱うサブルーチンを定義しました。
Tikiのサブルーチンでは、テキスト整形プラグインで処理されるべきテキストが受け渡され、追加的にContextオブジェクトも受け取っていますが、これはテンプレートを構築中に呼び出されることを想定したものです。TikiTextプロセッサは他で使用することも考えて別のPerlモジュールとして作っていたので、ここでは単純にインスタンスを作成し、処理をさせ、整形済みのテキストを結果として返しています。
Error Handling(エラー処理)
開発者にとって、物事が計画どおりにいかないことはしばしばなので、エラーに対処する準備をしなければなりません。例を単純に簡単にするために、エラー処理全般についてお話します。では見てみましょう。
先述のとおり、プラグインのルーチンから定義されていない値が返されるとエラーとしてMTによって割り込みがかけられ、処理が停止します。このエラーメッセージは『500 Internal Server Error』よりも多くの情報を含んでいるため、どこでエラーがおきたか、そしてどうやって修正したらよいかをユーザに教えることができます。
MTのContextクラスはMT::ErrorHandlerクラスからerrorメソッドを継承しており、システムやユーザへと渡されるエラー条件やメッセージを返します。
また、Contextクラスはerrstrメソッドを継承しており、最後におきたエラーメッセージのセットを取得することができます。
これらのメソッドには多くの使用方法がありますが、以下のような使われ方が一般的です。
# 今回は、MTEntryの中に置かれるべきタグについてチェックします。
$ctx->error('MT'.$ctx->stash('tag').' has been
called outside of an MTEntry context.')
unless defined($ctx->stash('entry'));
# 必要とするname属性が与えられているか調べます。
$ctx->error('name is a required argument of '.$ctx->stash('tag').'.')
unless defined($args->{'name'});
# テンプレートを構築中におきたエラーを捕捉し、文脈へそれを返します。
defined(my $out = $builder->build($ctx,$tokens))
or return $ctx->error($builder->errstr);
Plugin Data Storage(データ保持プラグイン)
バージョン2.6のプラグインフレームワークからはMT::PluginDataクラスが追加されました。これはプラグイン開発者に直接MTのデータ保持機構へアクセスする便利な機能を提供します。MT::EntryやMTがもともと持っている同様のオブジェクトと同じように、MT::PluginDataはMT::Objectを継承しています。この抽象クラス、すなわちMT::ObjectはMTが使用するデータ保持機構の違いを吸収しています。(MTは現在のところBerkeley DB、MySQL、SQLite、そしてPostgreSQLをサポートしています。)
MT::Objectを継承したクラスに付加されるpluginやkey、dataメソッドはモジュールでユニークである必要があります。
plugin | このプラグインを識別するためのユニークな名前の実体。 |
key | 対応するデータベースのレコードを識別するためのユニークなキーの実体。 |
data | データベースに蓄えられるデータ構造への参照。 MTはデータを直列化(serialize)するために標準的なPerlのモジュールであるStorableを使用している。 |
以下に示すのはコメントに作用するプラグインの一部分です。
my $data = MT::PluginData->new;
$data->plugin('my-plugin');
$data->key('unique-key');
$data->data($big_data_structure);
# $big_data_structureは参照であることに注意してください。
# $data->data('string'); # エラーになります
# $data->data(\'string'); # 正しいです!
$data->save or die $data->errstr; # saveはMT::Objectから継承しています。
# 別の場所でデータを取得するには…
my $data = MT::PluginData->load({plugin => 'my-plugin',
key => 'unique-key'});
my $big_data_structure = $data->data;
この例では表面を示しただけにすぎません。MTのデータ保持機構については別の文献やそのコードをあたるのがよいでしょう。重要なのはこういうものがあるんだという利点をつかむことです。
実践編
自前のMTのプラグインを作成することを通して、そしてMT仲間が作ったコードを読むことによって私が学んできた実践編の要約を記します。
- プラグインのpackageを宣言しましょう。これによって自身のネームスペースを作り、ユーザがインストールするであろう他のプラグインとの干渉を避けることができます。より明らかにするために接頭辞としてMT::Plugin::を使用することを強く推奨します。
- プラグインのバージョンを宣言しましょう。将来の使用も考えるとメタデータは非常に有効に機能します。これによって区別が可能になるのです。バージョンの宣言は次の2行によって行います。use vars qw( $VERSION );
$VERSION = 0.0; - コンパイル時にMTのシステムでない外部モジュールを呼び出すのは避けましょう。MTはCGIが呼び出されるごとにすべてのプラグインをロードしコンパイルします。無駄な機能を呼び出すことによって面倒なエラーが起きるのを避けるために、そのモジュールを必要とするサブルーチン内にてモジュールをuse宣言することが推奨されます。テキスト整形プラグインの例で示したように、Test::Tikiモジュールのuse宣言はグローバルスコープではなくサブルーチンのスコープで行っています。
- コードの冒頭ですべてのタグの宣言をおこないましょう。タグの実際の機能は外部の名前付きサブルーチンの中に書きましょう。こうすることによって順々に実行され、コードが読みやすく、かつデバックしやすくなります。タグの機能をタグの登録の外に置くことは、コードの再利用性以外にも利点があります。例えば、複数のタグが同じサブルーチンを共有でき、その組み合わせによってタグの名前に応じて異なった働きをさせることができるようになります。
- 名前付けには一定のルールを設けましょう。MTのタグの様式はWikiと同様で、スペースは削除されそれぞれの語の先頭は大文字になります。タグに名前をつけるとき、継承関係があることを考えて名前づけをするようにしましょう。先のコンテナタグの例でSimpleLoopとSimpleLoopIndexと名前をつけました。SimpleLoopとSimpleIndexではなく。こうしたことによってSimpleLoopIndexがSimpleLoopに属していることが明らかになっています。(この継承関係はMTのテンプレートタグを見れば、より納得できるはずです。)
- stashに蓄えられる変数にはユニークな接頭語をつけましょう。先のコンテナタグの例では、loop_indexというキーで値をstashに格納しましたが、これはまったくユニークなものではありません。なぜなら他のプラグイン開発者がこれと同じキーを使って値をstashに格納するかもしれないからです。私がstashに値を格納する場合、キーにプラグインの名前を接頭語として使うようにしています。こうすればstashの中の値をみわけやすくなり、ユニークになるため、他のプラグインとの干渉をさけるのに役立ちます。
結論
このプラグインフレームワーク紹介の弾丸ツアーで、PerlやMTのプラグインフレームワークの豊富な機能をもってすれば、システムを柔軟に、そしてよりパワフルに拡張できることがわかっていただけたなら幸いです。オブジェクト指向のPerlに関するより多くのノウハウをもってすれば、MTがもつ潜在能力によってさまざまなパブリッシングアプリケーションの構築が可能になるだけでなく、非常に簡単に実装できることでしょう。
詳細や最新の情報は以下のリソースをチェックしてみてください。
- Movable Type
- Movable Type Online Documentation
- The MT-Plugin Directory
- The Movable Type Plugin Developers (mt-dev) Mailing List
- Movable Type Plugin Support Forum
- Six Log: Six Apartのブログ、Six ApartはMovableTypeを開発した会社です。
- tima thinking outloud: mt-plugins: 作者(原文を書いたTimothy Appnelさん)のプラグインページ
原文のコピーライト
Copyright c 2000-2003 O'Reilly & Associates, Inc. All Rights Reserved.
All trademarks and registered trademarks appearing on the O'Reilly Network are the property of their respective owners.
コメント
ありがとうございます。ご指摘のとおりでした。
Posted by: fenrir : November 30, 2003 01:13 AMこんばんわ。fenrirさんのこの偉大なエントリを参考にして、自分でもplugin作ってみました。もう、感謝感謝です。
Posted by: mya : November 30, 2003 10:43 PM実は僕も日本語で概要が指定した単語数にならないことにむかついてプラグインを作ろうとしていました。すばらしいです!!是非使わせていただきたいと思います>myaさん。
Posted by: fenrir : November 30, 2003 10:51 PM同じ考えを持つ方って、やっぱりいらっしゃるんですね〜^^;
で、件のpluginですが、後述のURLから持って行けると思います(pluginディレクトリそのまんまですが^^;)。よかったら試してみていただけますか?
http://www.mya.dyndns.org/mt/plugins/first_n_words.pl
スイマセン、上記のURLのファイルにsyntax error残ったままでした^^; 早速なおしましたので、再度取得よろしくお願いします。
Posted by: mya : November 30, 2003 11:28 PMありがとうございますっ!!ありがたく使わせていただきます。これでJavaScriptともお別れできる~(今まではJavaScriptで文字数で文字列を切る関数を作って使っていました…)
Posted by: fenrir : December 1, 2003 01:20 AMはじめまして。
ワタシもこの元ネタのページを読んで、プラグインをいくつか作りましたが、ほとんどソースを読んだだけで勝手な解釈をしているところが多かったようで、エラー処理以降などは本当に有難いです。
MTは日本語で使うには、まだ少し使いにくいところがあるので、もっといろいろ日本語対応のプラグインを作られる方が多くなるといいですね。
休日表示カレンダープラグインを作りました。プラグイン作成にあたっては、この邦訳が役に立ちました。感謝します。ご興味があれば、
http://nlogn.ath.cx/jcalendarcolor/
からどうぞ。
コメントする
- 匿名でのコメントは受け付けておりません。
- お名前(ハンドル名可)とメールアドレスは必ず入力してください。
- メールアドレスを表示されたくないときはURLも必ず記入してください。
- コメント欄でHTMLタグは使用できません。
- コメント本文に日本語(全角文字)がある程度多く含まれている必要があります。
- コメント欄内のURLと思われる文字列は自動的にリンクに変換されます。
- 投稿ボタンを押してエラーがでなければ、投稿は成功しています。反映されるまでには少し時間がかかります。
はじめまして。とてもありがたい邦訳ですね!
さて、条件タグのサンプルを試してみましたところ、ExcludeThisのタグ "</ExcludeThis>" が残ってしまいます。
> MT::Template::Context->add_conditional_tag(Excludethis => sub { return 0 });
の、"Excludethis"を"ExcludeThis"に直したところ、正常に動作するようになりました。
Posted by: はや : November 30, 2003 12:32 AMご報告まで。