PowerCMS™
[ブログ] PowerCMS 6 でのアップデートまとめ を追加しました。
[新着情報] PowerCMSクラウド 月額費用の価格改定に関する追加情報を公開します を追加しました。
[よくあるご質問] サポートサイトへ登録しているアカウントの情報を変更することはできますか? を追加しました。
[新着情報] PHP 8.2 に対応した PowerCMS 6.5 の提供を開始 を追加しました。

PowerCMS ブログ

ホーム > PowerCMS ブログ > PowerCMS 3 > テンプレート・タグを作る(はじめてのMTML)

2012年09月11日

テンプレート・タグを作る(はじめてのMTML)

PowerCMSプラグイン勉強会で紹介してから少し経過してしまいましたが、テンプレート・タグの作成方法を勉強するためのサンプルプラグインを公開しました。はじめて作成する人が理解することを目的としているため、実用性は殆どありませんが、参考にしていただければ幸いです。

尚、PHP(ダイナミックパブリッシング)用のタグを config.php で作成する場合は、DynamicMTMLが有効である必要があります。

config.yamlやconfig.phpを作成する準備もスキップして、手っ取り早く簡単にタグを書く練習をしたい場合、EasyMTMLプラグインを使うと便利です。

最初はサンプルを編集しながら動作を確認するのが良いと思いますが、このプラグインをインストールすると、以下のルールでファイルを配置するだけで、その中にテンプレートタグのコードを書くことができます。

EasyMTMLプラグインを利用してファンクションタグ「MTHello」を作成する場合、以下の名前/内容でファイルを設置します。

Perl版
  • plugins/EasyMTML/perl/function.mthello.pl
sub {
    my ( $ctx, $args, $cond ) = @_;
    return 'Hello World!';
}
PHP版
  • plugins/EasyMTML/php/function.mthello.php
<?php
function smarty_function_mthello( $args, &$ctx ) {
    return 'Hello World!';
}
?>

MyFirstMTMLプラグイン解説

以下、MyFirstMTMLプラグインのサンプルコードについて解説します。

MTSampleFunction1(ファンクションタグ)

単に文字列'Hello MTML.'を出力するものです。_hdlr_sample_function_1 の中で return した値がそのまま出力されます。最もシンプルなファンクションタグです。

MTIfSampleBlockCond(コンディショナルタグ/条件タグ)

条件に一致する、しないを以下のようなテンプレートで分岐します。

<MTIfSampleBlockCond>
    条件に合致する場合
<MTElse>
    条件に合致しない場合
</MTIfSampleBlockCond>

コンディショナルタグですが、$registry ではブロックタグとして登録します。このタグでは、出力される、されないをランダムに入れ替える動作をします。Perlプラグインでは、1(出力される)か0(出力されない)を。PHPプラグインでは $ctx->_hdlr_if( $args, $content, $ctx, $repeat, TRUE ); または $ctx->_hdlr_if( $args, $content, $ctx, $repeat, FALSE );を返します。 config.yaml の中でタグを定義する際に、最後に「?」を付ける必要があります。

tags:
    block:
        IfSampleBlockCond?: $myfirstmtml::MyFirstMTML::Tags::_hdlr_if_sample_block_cond

SampleModifier(グローバルモディファイア)

SampleModifier="!!" と指定することで、出力されるテキストの末尾に渡した文字列を連結して出力するものです。引き数( $text, $arg ) は $text が出力されるオリジナルの文字列、$argがモディファイアに渡された文字列です。

MTSampleBlock(ブロックタグ)

1(fromモディファイアで指定可能)から10(toモディファイアで指定可能)までの数字をカンマ(glueモディファイアで指定可能)で区切って出力する、ただそれだけのタグです。ブロックの中で<mt:var name="__counter__">を記述することで、出力されます。

ブロックタグはやや複雑です。PerlとPHPで書き方のお作法が多少異なるので、ブロックタグについては少し詳しくコードを添えて解説をしてみます。

Perlプラグインでは、出力結果を組み立ててまとめて返す(returnする)
PHPプラグインでは、引き数 $repeat が TRUE の間繰り返し呼び出されるので、都度返す(returnする)

ブロックタグの処理(Perl)

渡される引き数は( $ctx, $args, $cond )の3つです。$ctxはコンテキスト(ブロックタグの中に記載されているファンクションタグに渡す設定など)です(例:$ctx->stash( 'entry', $entry );)。$args はファンクションタグに追加したモディファイアの値がモディファイア名をキーにしたハッシュリファレンスとして格納されています(例:$args->{ blog_id })。$cond(コンディション)については現段階で気にする必要はありません。Perlプラグインの場合、ブロックタグの中で MT::Builderモジュールによってテンプレートをビルドします。

テンプレートをビルドする呪文は以下の通りです(最初のうちはもう、これは「呪文」「おまじない」と考えてくださいw)。

$ctx->stash( 'builder' )->build( $ctx, $ctx->stash( 'tokens' ), $cond );

今回のような複数回のループの処理では、コンテキスト($ctx)に値を渡してセットし、ビルドした文字列を連結していきます。タグの最後ですべて連結し終わったタグを返します(returnする)。

sub _hdlr_sample_block {
    my ( $ctx, $args, $cond ) = @_;
    my $from = $args->{ from } || 1;
    my $to = $args->{ to } || 10;
    my $glue = $args->{ glue } || ',';
    my $tokens  = $ctx->stash( 'tokens' );
    my $builder = $ctx->stash( 'builder' );
    my $res = '';
    for ( $from .. $to ) {
        local $ctx->{ __stash }{ vars }{ __counter__ } = $_; # 変数(mt:varもしくはmt:GetVarで取り出せる)をセット
        $ctx->stash( 'foo', $_ ); # ファンクションタグで取り出すための値のセット
        my $out = $builder->build( $ctx, $tokens, $cond );
        if (! defined( $out ) ) { return $ctx->error( $builder->errstr ) };
        $res .= $out; # ビルドした結果の文字列を連結する
        $res .= $glue if ( $glue && ( $_ != $to ) );
    }
    return $res;
}

ブロックタグの処理(PHP)

渡される引き数は ( $args, $content, &$ctx, &$repeat ) の4つです。$ctx と $repeat は繰り返し処理の中で書き換える必要がありますので、&を付けて受け取ります。$argsはPerlと同じくファンクションタグに追加したモディファイアの値がモディファイア名をキーにした配列として格納されています(例:$args[ 'blog_id' ])。$content にはそのループの中で出力すべきデータが毎回格納されています(最初のループを除く)。最初のループではコンテンツは未定義なので、if (! isset( $content ) ) { で分岐して初期化処理を行っています。

function _hdlr_sample_block ( $args, $content, &$ctx, &$repeat ) {
    $localvars = array( '__counter__', '__out' );
    if (! isset( $content ) ) {
        $ctx->localize( $localvars );
        $vars =& $ctx->__stash['vars'];
        $from = $args[ 'from' ];
        $to = $args[ 'to' ];
        $glue = $args[ 'glue' ];
        if (! $from ) { $from = 1; }
        if (! $to ) { $to = 10; }
        if (! $glue ) $glue = ',';
        $ctx->stash( '__from__', $from );
        $ctx->stash( '__to__', $to );
        $ctx->stash( '__counter__', $from );
        $ctx->stash( '__glue__', $glue );
        $ctx->__stash[ 'vars' ][ '__counter__' ] = $from;
        $ctx->stash( 'foo', $from );
    } else {
        $to = $ctx->stash( '__to__' );
        $glue = $ctx->stash( '__glue__' );
        $out = $ctx->stash( '__out' );
        $counter = $ctx->__stash[ 'vars' ][ '__counter__' ] + 1; // 変数(mt:varもしくはmt:GetVarで取り出せる)をセット
        if ( $glue && $content && $out ) {
            $content = $glue . $content;
        } else {
            $ctx->stash( '__out', TRUE );
        }
        if ( $counter <= $to ) {
            $ctx->__stash[ 'vars' ][ '__counter__' ] = $counter;
            $ctx->stash( 'foo', $counter ); # ファンクションタグで取り出すための値のセット
            $repeat = TRUE; // ループを継続
            return $content;
        } else {
            $ctx->restore( $localvars );
            $repeat = FALSE; // これで、ループの終了
            return $content;
        }
    }
}

ブロックタグの中でセットしたコンテキストをファンクションタグで取り出す

MTSampleFunction2(ファンクションタグ)

冒頭で紹介したファンクションタグは単に文字列'Hello MTML.'を出力するものでしたが、実際のケースでこのようなタグが必要なケースは殆どないでしょう。そこで、最後にブロックタグでセットしたコンテキストをファンクションタグで取り出すもの、また、モディファイアで渡された値を利用するような処理を組み合わせたファンクションタグを作成しました。

ブロックタグで下記のようにセットした値は(値、配列、オブジェクト等が渡せます)

$ctx->stash( キー, 値 );

ファンクションタグの中で、以下のようにして受け取ることができます。

my $foo = $ctx->stash( キー );

今回は、データベースやオブジェクトを使わない、できるけ簡単な例としてサンプルを作成しました。

Movable Typeの公式サイトの開発者向けドキュメントも以前と比べて充実してきていますが、実際に作成していく中で理解しずらいところ、つまづきやすいところなどを意識してサンプルを作成してみました。カスタムタグを作成することで、Movable Type、PowerCMSでのサイト構築の幅が大きく広がることは確実です。機会があれば是非チャレンジしてみてください。

関連リンク


カテゴリー
PowerCMS 3
プラグイン
技術情報

Recent Entries