Movable Typeプラグインの最近のブログ記事

第2回CMSプロレス 多言語サイトタイトルマッチ - CMS SUNDAY | Doorkeeper

CMSプロレス

参加中です。WordPressさんのお隣です。なんか前半は文化の違いで空気に馴染めず難しかったですけど。

CMSプロレスとは?

  • 同じ仕様のサイトを複数のCMSで構築して競うエンターテイメント性の高いイベント
  • 第一線の開発者達がどのように実装したのかを解説つきで観戦
  • CMSの体育祭!

よくわからないという方はこちらをご覧ください!

 昨年のCMSプロレスの開催レポートはこちら
 ※昨年は、各CMSの代表チームが同じ仕様のウェブサイトを制限時間内に構築するライブコーディングイベントと銘打っていましたが、今回は、事前に構築したウェブサイトをもとにしたプレゼンバトルです

先日、Movable Type6.3がリリースされました。

一番の変更点はダイナミックパブリッシングのPHP7サポートですが、内部的には Smartyのバージョンが2系から3系に変更になっています(PowerCMS/DynamicMTMLの対応は少々お待ち下さい)。

PHP 7 をサポート

PHP 7 を正式にサポートしました。PHP 7 は、PHP 5系と比べてもパフォーマンスの向上が期待できます。

Smarty 3.1 へアップデート

PHP 7 への対応に伴い、Smarty 2 から Smarty 3 へのアップデートされました。

プラグイン開発者へ

ダイナミック・パブリッシングに対応したプラグインについて、直接 Smarty を操作していないかぎりにおいて変更の必要は無いものと想定していますが、動作確認等よろしくお願いいたします。

※(再度) PowerCMS/DynamicMTMLの対応は少々お待ち下さい

MTViewerとは、$ctx であり Smartyである

何のことか分かる人にしかわからないアレゲな書き方ですが、つまるところMTにおけるダイナミック・パブリッシングとはMTのテンプレートをSmartyテンプレートにコンバートしてビルドするという仕組みになっています。実体は mt/php/lib/MTViewer.php です。

MTViewer.phpのコード

この MTViewerクラスの fetchメソッドがテンプレートをビルドするコードなのですが、MTタグをPHPの中で動的にビルドする方法について備忘録がてらメモしておきます。ちなみに、元がSmartyですので、これらはSmartyのテンプレートを渡しても動作します。MTテンプレートを指定した場合、mt/php/lib/prefilter.mt_to_smarty.php がMTのテンプレートをSmartyのテンプレートに変換してからビルドされます。というわけでMTViewerクラスの fetchメソッドにはMTタグをそのまま渡せるのです。

MTテンプレートをPHPコードの中でビルドする

念のためですが、$ctx の初期化については下記の記事を参照ください。

template_id 指定でビルド

$mt = MT::get_instance();
$ctx =& $mt->context();
$str = $ctx->fetch("mt:123");

テンプレート名(template_name) 指定でビルド

$mt = MT::get_instance();
$ctx =& $mt->context();
$str = $ctx->fetch("mt:テンプレート名");

テンプレート指定のビルドについては mt/php/lib/resource.mt.php で定義されています(Smartyのカスタムリソース)。 Smartyのカスタムリソースの作り方は以下のページに。カスタムリソースを作成すれば、例えば S3 に置いたMTテンプレートを指定してビルド、とかまぁ色々できるわけですね。

MTテンプレート文字列指定でビルド

$mt = MT::get_instance();
$ctx =& $mt->context();
$str = $ctx->fetch("eval:<mt:Date>");

ファイルパス指定でビルド

$mt = MT::get_instance();
$ctx =& $mt->context();
$str = $ctx->fetch("file:/path/to/tmpl.tpl");

テンプレート変数をセットしてビルド

$mt = MT::get_instance();
$ctx =& $mt->context();
$ctx->__stash[ 'vars' ][ 'foo' ] = 'bar';
$str = $ctx->fetch('eval:<mt:Var name="foo">');

記事コンテキストをセットしてビルド

$mt = MT::get_instance();
$ctx =& $mt->context();
$entry = $mt->db()->fetch_entry( 1 );
$ctx->stash( 'entry', $entry );
$str = $ctx->fetch('eval:<mt:EntryTitle>');

この辺りを理解しておくと、PHPでサイトを拡張していく際にMTテンプレートが活用できるようになります。例えばPHPで作成したフォームメールのテンプレートにMTタグを使ったり。ということでMT6.3の Tips でした。

既にPowerCMSでやっているものなのですが、再整理の意味で、メモ(てか、ブログサボってたのでリハビリがてらw)。

config.yaml

permissions:
    system.access_cms:
        label: Can Access CMS
        order: 2000
    system.administer:
        inherit_from:
            - system.access_cms

これで、ユーザーの編集画面にシステム権限「Can Access CMS(CMSへのアクセス)」が追加して表示されます。system.administer... 以下を追加しているので、「システム管理者」にチェックを入れると「Can Access CMS(CMSへのアクセス)」にもチェックが入ります。

管理画面のシステム権限設定エリア

ただ、このまま「保存」しても「MT::Authorに can_access_cms メソッドがない」というエラーが出ます。社内で聞いてみたところ「アクセサを定義する必要があります。」とのこと。

config.yaml

callbacks:
    init_app: $myplugin::MyPlugin::Plugin::_cb_init_app

MyPlugin::Plugin::_cb_init_app

sub _cb_init_app {
    require MT::Author;
    *MT::Author::can_access_cms = sub {
        my $author = shift;
        if ( @_ ) {
            $author->permissions(0)->can_access_cms( @_ );
        }
        else {
            $author->is_superuser()
                || $author->permissions(0)->can_access_cms( @_ );
        }
    };
}

これで、あとはMT側がよしなに処理してくれます。もちろん、この権限の有無による振る舞いの分岐はそれぞれの処理に実装する必要があります。

人気記事を表示するのに GoogleAnalyticsを使ってページビューの順に表示させるという方法(PowerCMSなど)がありますがコメント機能が使われていてコメントが活発にやりとりされているサイトの場合、最近 n日のコメント数を基準にするという方法もありますね。話題になっている記事を抽出するのになかなか適した方法かと思います。

https://github.com/junnama/mt-plugin-lively-discussion-entries

<mt:LivelyDiscussionEntries days="7">
# mt:Entriesと同じタグが利用できる
</mt:LivelyDiscussionEntries>

このような処理の時は MT::Object の count_group_byメソッドを使います。

my $group_iter = MT->model( 'comment' )->count_group_by( {
                                            blog_id => $blog_id,
                                            visible => 1,
                                            created_on => { '>' => $ts } } , {
                                            (),
                                            group => [ 'entry_id' ],} );
my $ids = {};
while ( my ( $count, $entry_id ) = $group_iter->() ) {
    $ids->{ $entry_id } = $count;
}
my $i = 0;
my @entries;
for my $entry_id (sort { $ids->{ $b } <=> $ids->{ $a } } keys %$ids) {
    my $entry = MT->model( 'entry' )->load( $entry_id );
    if ( $entry && $entry->status == MT::Entry::RELEASE() ) {
        push ( @entries, $entry );
        $i++;
        if ( $i >= $lastn ) {
            last;
        }
    }
}

こんなページができていて、いい傾向じゃないの(上から目線w)、と思ってまして。

ツッコミと言うわけではないですが、僕も最近色々思ってたことが触れられてたので。

ま、同じことなんですけど、何でこういうエントリを書いてるかというと、PerlでMTMLやHTMLを突っ込むのについついPerlのヒアドキュメントを使っちゃうことがあるからなのです。ひとつのファイルで完結するからどうしても手を抜いてそういう実装をしがちなのですが。

僕なら、テンプレートを tmpl/include に置いた上でこう書きます。

sub template_param_edit_entry {
    my ( $cb, $app, $param, $tmpl ) = @_;
    $app->{ plugin_template_path } =
        File::Spec->catfile( MT->component( 'AwesomePlugin' )->path, 'tmpl' );

    my ( $node, $attr, $include );

    $node = $tmpl->getElementById( 'header_include' );
    $attr = { name => 'include/edit_entry_header.tmpl' };
    $include = $tmpl->createElement( 'include', $attr );
    $tmpl->insertBefore( $include, $node );

    $node = $tmpl->getElementById( 'title' );
    $attr = { name => 'include/edit_entry_title.tmpl' };
    $include = $tmpl->createElement( 'include', $attr );
    $tmpl->insertBefore( $include, $node );
}

DOMに慣れている方なら直感的かと思うし。どっちがいいということではなくて、自分が理解しやすい方法で書けばいいと思います、ええ。

※どっちかと言えば各MTタグにidが振られてないとかそういうのが問題かと思う(一回バージョンアップでidが変わったことあるぜ!!)

追記:天野さんから指摘あり。

plugintemplatepath を使う方法は、複数のプラグインで同じことをしようとした時に片方が効かなくなる。

さらに追記

    $app->{ plugin_template_path } =
        File::Spec->catfile( MT->component( 'AwesomePlugin' )->path, 'tmpl' );

    # の代わりに

    $attr = { name => 'include/edit_entry_header.tmpl',
              component => 'AwesomePlugin' };

とする。

PowerCMS の Pager や PageBute を利用したページ分割は非常に効率が悪いので記事の件数が半端無く多いシチュエーションでは使わない方が絶対にいいです。

記事の更新頻度によって月別、年度別、年別等の time-basedなアーカイブにしたほうがいい。理由は、time-basedなアーカイブは更新対象のアーカイブのみが再構築されるためです。ページングって、1件増えたら、1件削除されたら全アーカイブが1件だけ「ずれて」全再構築されるのです。1件更新されても全アーカイブが再構築対象になります。

というようなことを口を酸っぱくして言ってんのに、結局破綻してしまったというケースに出くわしたので作成しました。

これ、カテゴリとかもニーズあるよね、MT7では標準機能になるよね、と振るだけ振っておいて。

アーカイブマッピングで「手動」を選択

  • https://github.com/alfasado/mt-plugin-monthly-entries-publisher
  • プラグインをインストール
  • ウェブサイト(ブログでも良い)月別アーカイブを作成し、include_blogsで含めるブログを指定する
  • テンプレートマップの再構築オプションは「手動」とする(「再構築しない」を選択しないこと:「再構築しない」だと書き出されない)
  • MTEntriesの__first__ もしくは MTEntriesHeader 内に 「<!--EntriesCount:<mt:EntriesCount>-->」記述を入れる(ファイル出力時にはこの値は削除されます)
  • mt-config.cgi に MonthlyEntriesPublisherTemplateIds テンプレートのIDカンマ区切りを記載
  • mt-config.cgi に MonthlyEntriesPublisherBlogIds として、記事保存時にキューに入れる対象のブログIDをカンマ区切りで記載

再構築はキューで実行されます。ダイナミックパブリッシングには対応していません。

ま、回答数が少ないんだけど半数以上があるという回答ですね。「ある」人がこういうのに反応したんだと捉えることもできるけど、これ、僕が目にしたからこういうポストしたんですね。同じ案件で3回。

MTのアーカイブの柔軟なところは評価されていいんですが、デフォルトだとウェブページのアーカイブマッピングは以下のようになっています。

デフォルトのウェブページのアーカイブマッピング

%-c/%-f

フォルダの指定を忘れて、出力ファイル名を「index」にしてしまうと...

メインページを上書きしてしまうではないですか。

ウェブページのパス指定箇所

マニュアルに書いたでしょ? とか言わずにこういうのはシステムの方でミスを防いでやるのがスマートですよね?

plugins/NoOverwriteMainIndex/config.yaml を置いて(フォルダ名は何でもいいけど)、以下の短いコードをぺたっとするだけです。

プラグインでメインページを上書きしないように設定できる

こういう小さな工夫が使い勝手を向上させ、オペレーションミスによる問題を防いでくれる、ひいては顧客からの質問攻めによる負荷を下げてくれるってもんだと思います。

KeynoteScreenSnapz001

この記事は Movable Type Advent Calendar 2015 の最終日の記事です。

いや、今年も色々ありましたが実は地味に今年のトピックは Movable Type でテンプレートをフル実装する機会に恵まれたことですね。自分のブログ以外ではそんな機会はこれまでなかったのです。しかも PowerCMS じゃありません。予算の関係もあり、今回は Movable Type で行きましょう、ということになったのです。

本題に入る前に少し MTDDC の続きを

日本語変数名の使いどころ

日本語変数名の話しを少ししたよね。実際に有用なシーンに出会ったので紹介しておく。多言語サイトで。

<mt:BlogLanguage setvar="language">
<mt:If name="language" eq="ja">
    <mt:Setvars>
        サイト・パス=/jp/
        ホーム=ホーム
        最新ニュース=最新ニュース
        関連ニュース=関連ニュース
        年度=年度
        キーワード検索=キーワード検索
        サイト内検索=サイト内検索
    </mt:Setvars>
<mt:Else>
    <mt:Setvars>
        サイト・パス=/en/
        ホーム=Home
        最新ニュース=Latest News
        関連ニュース=Related News
        年度=Fiscal
        キーワード検索=Keyword Search
        サイト内検索=Search
    </mt:Setvars>
</mt:If>

<h1><mt:Var name="キーワード検索"></h1>

超わかりやすくないですかい? <mt:Var name="keyword_search_title"> みたいにわざわざ指定する必要ないんだから。同じテンプレートで行けるし、わざわざたくさんのカスタムフィールドを作る必要もない。比較や変数渡しの必要がなければ日本語でOK。

SetVarTemplate の使いどころ

Movable Type Advent Calendar の初日で BUNさんがちょうど書いていましたが、function(関数)のような形で使いまわしできるのがこのタグの良いところです。

複雑な分岐ロジックでなくとも、以下のようなテンプレートを直に分岐等を入れながら書くと、コーディングに修正が入った時の修正箇所が多くなります。

<mt:SetvarTemplate name="breadcrumbs_tmpl" note="パンくずのマークアップ">
<mt:Unless name="no_image"><img class="breadcrumb" src="/assets/img/common/breadcrumb.png" alt=""></mt:Unless>
<mt:If name="breadcrumbs_url">
<a class="breadcrumb" href="<mt:Var name="breadcrumbs_url">">
</mt:If>
<mt:Var name="breadcrumbs_title">
<mt:If name="breadcrumbs_url"></a>
</mt:If>
</mt:SetvarTemplate>

<mt:Var name="breadcrumbs_tmpl" breadcrumbs_url="$url" breadcrumbs_title="$title">

(※コーディングがどうとか言うなよ。俺が書いたんじゃねーんだ。) 要するに、URLとタイトル、画像の有無を渡せばパンくずのマークアップで出力できるというもの。

ここから本題。やはりお前らのMTは間違っている!

タイトルは釣り本気ですが、おおまかなテンプレート構築のフローを書きながらどんな風に作ったのかご紹介しつつ、何が間違っているのかについて考えていきましょう。

※ここで紹介したツール群は、年始に PowerCMS およびそれ以外の方法で(単品やクラウドサービスなど)でご提供する予定です。一部については既に公開しているものもあります。

コーディング素材を受け取って、MTのテンプレートに登録する

まず、制作会社から上がってきたコーディングデータと画像等の素材一式をMTのインデックステンプレートやアイテムに登録します。いくらなんでも自分でチマチマやるのは何なので、新人のデザイナーに「ここからこうやって登録...」といいかけて思ったのです。ハッ! いくら新人でもこんな単純作業に時間を割かせて良いものだろうか。今回の案件ではコーディングに SSIを利用していました。公開サイトでは動的なしくみは使えない制約があったので、ま、MTIncludeにすればええやと思いつつ...

納品されたコーディングデータ素材

とりあえずプラグインを作るところから始めました。でき上がったのがこいつです。

共通アイテム登録画面

ZIPファイルに素材を固めて管理画面からアップロードすると拡張子によってテキストファイル系はテンプレートに(インデックスか、テンプレートモジュールに)、画像等はアイテムに(@commonタグ付きで)登録してくれるものです。インクルードファイルをモジュールに、インクルード元ファイルをインデックス・テンプレートに登録すると、ちゃんと MTIncludeに変換してくれるんですぜ。

テンプレート編集画面の不便いろいろ

これはもう色々あるんですが、最初に大きな声で言っておきたいのは「お前ら声が小さい」「お前ら文字が小さい!」。デフォルトのフォントサイズは14ポイントです。で、これ設定とかで変えられません。アクセシビリティを何だと思ってるのか。年寄りを何だと思っているのか。

ということで次に作ったのがこいつです。ついでに最新の CodeMirror を入れてキーバインディングやスキンを変更できるようにしました。で、僕は MTのテンプレートにおいては「行を折り返す派」です!

テンプレート編集の設定

どうです? 見やすくなったでしょ?

改良後のテンプレートエディタ

次に手をつけたのはウィジェットとメモ欄です。メモ欄のことは MTDDCで話したので今日は詳しく触れませんが、ここ ( alfasado/mt-plugin-template-note ) からダウンロードできます改良されたテンプレート編集画面

しかしそれよりも何よりも「インクルードテンプレート」ウィジェットがあるのに「インクルードされているテンプレート」ウィジェットがないじゃん!

ということで次にこれを作りました。全テンプレートをロードするのでこれ、非同期読み込みです。ええ、これ書くために jQuery 勉強したんだぜマジで。

リンクされているテンプレートウィジェット

これで完璧だよね、とか自己満足して作業進めてたらそれでも足りない何かに気づいたのです。グローバルテンプレートへの移動が不便! そんなこともあろうかと、こいつ ((MT5)ユーザーダッシュボードに左メニューを追加する。 - Junnama Online) を入れておいたのです。でれでもテンプレート編集してる時だし移動したいのは。ということで、次にこれ作ったのさ。テンプレートをブックマーク保存できて、一覧画面、編集画面の右側のウィジェットに表示されるように。

ブックマークウィジェット

グローバルテンプレートの改良

(追記)グローバルテンプレート嫌いな人いるよとなんてうだけど、多言語サイトの共通テンプレートとかどこかのブログに置くのも気持ち悪いし、ブログIDが開発と本番で変わることってざらにあるのだからやはりそういうのはグローバルテンプレートが素直だと思う。ウェブサイトの配下にブログって手もあるけど、ひとつのサイトなのにブログ数が多いのってスマートじゃないと思う。いろんな意味で。(追記ここまで)

Twitter 検索してみたら色々出てくるじゃん。

あれ、途中からリビジョンの話しになったよ。グローバルテンプレートにはリビジョンがない。

2015年ですぜこれ。MT Studioで対応してたので、そいつを切り出して移植。ついでに Diffを見られるようにした(グローバルテンプレートに限らない)。

グローバルテンプレートのリビジョン対応

続いてこれ。

これ見たの、東京から新大阪へ向かう新幹線の中。京都に着いたあたりで見たんだよね。で、新大阪に着くまでにかけるやろかと思って、書けた。

シェルで、また敷居が高いとか何とか、ちゃんとUIも作っといた。

テンプレート一覧画面から実行できる

てか、そもそもテーマが当てられた時にリビジョンが保存されるようにしておいた。

これもなぁ。。。多分MT4で導入された MTInclude多様のテンプレートでページの先頭に空行たくさん入る問題の解決のためなんだろうが、これこそ安易な解決をするな、の好例だと思う。これについての対処としては、コメントタグを先頭に入れて正規表現で置換と言う美しくない解決を(今回は)した。

納品ドキュメントを作りやすく

乗ってきたのでついでに作った。というか上半期末の全社会議での社員の発表で話題に上がっていたので作った。テンプレートに「メモ」を付けておけば、それを含めて一覧に表示してくれる。HTMLで生成したけど、PDF化すればいいんじゃないかと(CSVも考えたけどこっちのほうが現実的っぽかった)。

テンプレートの納品ドキュメント

いい加減疲れてきた。他にも色々作った。他の Advent Calendar に書いたネタ( Authoring Tool Accessibility Guidelines の観点から CMSの画像挿入フローを検証する - Junnama Online )ですが、リッチテキストエディタと画像挿入のところを何とかしたくて リッチテキストエディタ及びエディタへのアイテム挿入に関する機能を拡張する Advanced Editorというプラグインを作った。

だいたい、記事編集画面の title要素は何だ ?

この画面キャプチャ見て何とも思いませんか?

記事編集画面の title要素が不適切。全ての記事で「記事の編集 - ブログ名 - ソフト名」となっている

アクセシビリティもそうだし、そもそもウィンドウやタブをいっぱい開いて作業してる時に何が何だかわかんないと思うんだがこれ、いつからなの? 誰も指摘しなかったのだろうか。プラグイン書いといたので、ご自由に使ってください。

ヒントは現場に転がっているし、声を上げることがコミュニティへの貢献に繋がる

このエントリで言いたかったことは、まさにこの一文なのです。MTQ でも FogBugz でも日本語でもOK。お前ら本当に Data APIが欲しかったの? いや、 Data APIが駄目だとか言ってるわけではなくて、普段 Movable Type 乗りまわしてるのってテンプレート、サイト構築してる我々じゃないか。何も考えずに目の前の仕事を進めるのではなく、考えるヒントは日常の仕事の中に転がっている。“事件は会議室で起こっているんじゃない、現場で起こってるんだ” ってことを再認識した師走の午後でした。

それでは、メリークリスマス、良いお年をお迎えください。

MTDDC で話してきました。

セッション中の私ー

MTでのCMS構築案件で皆あれこれ工夫しているというのは理解できるのですが、傾向として結果として見通しの悪いテンプレートになっているケースを目にすることが最近増えてきたように思います。理由はいくつかあると思うのですが、以下のようなことではないかと思います。

  • 案件の規模が大きくなり、顧客の要望が増え仕様が複雑になってきている
  • 実装者のスキルが上がってきており、複雑な要件もMTMLで実現できるようになってきている

後者は良い傾向であるともいえますが、結果として初心者が修正できないテンプレートになったりしては本末転倒かと思います(場合によっては上級者でも他人のテンプレートがわからないといったケースも)。

一例を挙げます(実際はもっと多岐に渡り複雑なケースが散見されます)。

<mt:Entries<mt:If name="want_filter"> field.foo="1"</mt:If>>
...
</mt:Entries>

上記のような書き方をしたいが、できないので色々と工夫しているということでした。以下の例では IF文を一度評価した後で decode_html して再度 mteval でビルド しています。

<mt:For decode_html="1" mteval="1">
&lt;mt:Entries <mt:If name="want_filter">field.foo="1"</mt:If>&gt;
...
&lt;/mt:Entries&gt;
</mt:For>

また、下記のようにビルド結果のテキストを置換して再度ビルドするというテクニックを使っているというケースもありました。

<mt:setVarBlock name="search1">/<lz:/g</mt:setVarBlock>
<mt:setVarBlock name="replace1"><</mt:setVarBlock>
<mt:setVarBlock name="replace1" append="1">mt:</mt:setVarBlock>

<mt:setVarBlock name="search2">/<\/lz:/g</mt:setVarBlock>
<mt:setVarBlock name="replace2"><</mt:setVarBlock>
<mt:setVarBlock name="replace2" append="1">/mt:</mt:setVarBlock>

<mt:For regex_replace="$search1","$replace1" regex_replace="$search2","$replace2" mteval="1">
    <lz:Entries <mt:If name="want_filter">field:foo="1"</mt:if>>
        <lz:If name="__first__"><ul></lz:If>
        <li><lz:EntryTitle></li>
        <lz:If name="__last__"></ul></lz:If>
    </lz:Entries>
</mt:For>

やりたいことは実現できているのですが、以下の課題が残ります。

  • 管理画面のテンプレート検索で目的の箇所がヒットしない
  • decode_html のパターンでは、HTML(デザイン)の修正時に修正が困難
  • やりすぎると見通しが悪くなる
  • replace のパターンでは文字列「

DOMDocument プラグインを利用すれば、以下のように書けます。

<mt:getElementById id="tmpl_foo" setvar="tmpl_foo">
<mt:removeAttribute name="id" node="tmpl_foo">

<mt:If name="want_filter">
    <mt:setAttribute node="tmpl_foo" attr="field.foo","1">
</mt:If>

<mt:Entries id="tmpl_foo">
...
</mt:Entries>

まず、1行目で MTgetElementById タグで MTEntries ブロック(Node)を取得して変数 tmpl_foo に格納します。 2行目で、MTEntriesブロックから id モディファイアを削除しています。idモディファイアがあると entry_idでのフィルタリングがかかってしまうためです。その後、 MTIFタグで want_filter に値がある時、MTsetAttribute タグで field.foo=1 を追加します。

MTEntries に id 指定しなくても、以下のようにタグ名と index (n番目=1番目は「0」)指定で取得することもできます。

<mt:getElementsByTagName tag_name="Entries","0" setvar="tmpl_foo">

また、何をやっているかをわかりやすくするために GetHashVar プラグインの note モディファイアを使ってコメントを該当タグの中に直接記載することができます(そもそも存在しないモディファイアは無視されるので、プラグインがなくてもこう書けます)。

<mt:getElementsByTagName tag_name="Entries","0" setvar="tmpl_foo"
    note="1番目の mt:Entriesタグにカスタムフィールド 
    foo によるフィルタリングをかける">
<mt:If name="want_filter">
    <mt:setAttribute node="tmpl_foo" attr="field.foo","1"
    note="want_filterが1の時フィルタリング">
</mt:If>

<mt:Entries id="tmpl_foo"
    note="DOM操作でフィルタ指定対象のブロック">
...
</mt:Entries>

ま、スライド見ていただければ言わんとするとことはおわかりいただけるかと思いますが、この手の話しならこれからいくらでもするからな! これからは間違うなよ!

セッション中に紹介したプラグイン

部屋と Movable Type と私

| コメント(0) | トラックバック(0)

この記事は Movable Type Advent Calendar 2014 - Adventar の最終日の記事です。過去2年もトリつとめさせていただきましたけど、気合い入ってるよね、過去の自分。でも今年はあっちに大物(MT Studio)上げたから、ちょっとグダグダ書かせてください。

Movable Type 1.0から13年が経過しました。様々な紆余曲折を経て、特に、ここ日本では本当にたくさんのウェブサイトやブログのCMSとして使われてきました。コマーシャルライセンス、サーバーインストール型、数万円、Perl製というソフトウェアでは希有な存在でしょう。

私が最初に Movable Type に触れた時からも8年が経過しました。ココログを使っていましたから、それをあわせると 10年になります。PowerCMS というプロダクトをリリースしてからも 7年。PowerCMS は Movable Type の歴史の半分以上の年数使われてきました。

また、コマーシャルライセンスと個人無償ライセンスのデュアルライセンスで、ユーザーコミュニティが活発であるのも MTの特長でしょう。 思えば Movable Type 4.0のリリース時に東京のイベント(WebSig24/7)に登壇させていただいたのが、私のMTコミュニティデビューでした。

「Web 屋さんのためのMovable Type4」登壇

野田 純生さま

過去登壇したテーマでいま思うこと
ツールはあくまでもツールに過ぎませんが、サイト制作に用いるツールを選ぶことは、制作体制づくりやワークフローづくり、もっといえば会社組織づくりにさえも深く関係しているのだと振り返ってみて思います。
あの時登壇したことが製品リリースにつながり、結果的に会社も(いい意味で)変わってしまったのですから。
WebSigに登壇してみて
あのときはMT3ベースのPowerCMSからMT4ベースのPowerCMSへの過渡期でした。社内ライブラリであって、まだ製品ではなかったのです。二次会でモデレータの皆様に「売らないのか」「売らないのか」って100回くらい言われたのでカッとなって製品として売り出したらあれから7年で1,000も売れることになりました。
PowerCMSは、WebSigがきっかけで生まれたソフトウェアとも言えます。今日の二次会?でも私を焚き付けてください。きっと何かが生まれるかも。
近況
皆んながWordPressに夢中になっても、相変わらずMT三昧の日々を送っています。 東京に引っ越す気は全くありませんが、週に3日は東京で過ごしています。誰か遊んでください!

※↑誰か遊んでください! が最重要センテンスです。そこはお忘れなきよう!

この時は MT4 をGPLに、という話題がトピックでした。ちょうど7年前の12月にオープンソース・プロジェクトの開始が宣言されています。

このGPL化は結果としてシックス・アパートにとって忘れたい過去となったのでしょう。WordPressに流れたユーザーが戻ることもなかったという判断もあり、MT6からはMTOSは提供されなくなりました。

さて、大切なことを言っておきますが、2015/9/30にMT5.2系がEOL (End of Life): 製品ライフサイクル終了日を迎えます。EOM (End of Maintenance): メンテナンス終了日は今年の9月に既に迎えており「セキュリティに重大な影響を及ぼすと考えられるクリティカルなバグ」以外は修正されませんし、サポートも受けられません。つまり、MTOS は来年 EOL を迎えます。

さて、部屋と「Movable Type」と私という素敵なタイトルでクリスマスに相応しい「Movable Type Advent Calendar 2014」の最終日エントリーを書いているわけですが、本題は実はここからです。

Movable Type 宣言。

さて、(アルファサード株式会社 代表取締役社長としての)私が、来年も Movable Type にフルにコミットしていく宣言としての5つの約束について書きます!

宣言その1〜Movable Type をもっとパワフルにします。

まず、来年も Movable Type やるぞ! を宣言しておきます。これまで以上に付き合っていくことになると思います。私はプラグイン作者でありコミュニティの一員である以前に、Movable Typeを日本で ? 番目に多く販売している会社の代表者です。 Movable Type 関連の複数のプロダクト、サービスを立ち上げることをお約束します。複数。いくつかはクラウドに関連するサービスになるでしょう。Movable Type と付き合い続けてきたウェブ制作者がより仕事をしやすくなり、クライアントに提案しやすくなるようなもの、Movable Type を少し違う世界に連れて行くようなものに取り組みます。ちなみに今年の振り返りはこんな感じです。結構頑張ってるでしょ? 来年はもっと頑張ります。

来年と書きましたが、年末に立て続けに2つ、リリースしました。

まぁ、パワフルにするってことは、もっと売るって受け取っていただいて結構です!

宣言その2〜Movable Type Open Source のメンテナ、PowerCMS サポート兼任担当者を募集します。

前半でも少し触れましたが、MTOSが来年いよいろEOLを迎えるのをきっかけに、アルファサードでMTOS、MT5.2xに対するサポート体制を作りたいと考えています。もちろん、いつまで、を約束することは現時点ではできませんが、まずは以下の取り組みから始めます。

時々の状況によって比率は変わってきますが、PowerCMS サポートエンジニアと Movable Type Open Source(5.2xベース)のメンテナンスを兼務するエンジニア(兼務)を募集します。諸条件等は追って纏めて何らかの求人媒体に出稿しようと思っていますが、我こそは! という方は電子メールで contact@alfasado.jp まで履歴書、職務経歴書、自己PR等を添えてご送付ください。

リンク先のページにも書きましたけど、考えていることはこんなことです。中の人的にはいいね! とかしづらい話題かもしれませんが、コミュニティにとって悪いことやないと思うし、直接商売に影響があるような話しではないと思うんですね。予算なけりゃWordPressかなんかに流れると思うし、中長期で見ればむしろ、いい話しだと思うのです。

  • Movable Type / PowerCMS エンジニアの育成
  • Webサービスのエンジンなどに利用可能なオープンソースのテンプレートエンジン、ORマッパとしての利用促進
  • MTOS メンテナンスの過程で得られた成果・知見の本体へのフィードバック、還元
  • Movable Type / PowerCMS の開発者、Web制作者の裾野を広げる
  • より実験的な Movable Type、例えばコメントやトラックバックを切り離した小さなMovable Type、あるいはスクリーンリーダーで管理画面が扱えるアクセシブルな Movable Type といった実験的、派生的なプロジェクトの推進

色々考えてのことですけど、DynamicMTML や MT Stidio 相応の時間をかけて開発してて、でも商売になったりせんよなこれ。もしくは、PowerCMSにしたって、そりゃもっとたくさんの人に使って欲しい、でも生活もあるやんか。お金も欲しいし、でもなぁ、とかグダグダ悩んでるくらいならデュアルライセンスでいいから、まず公開してみようよ、って思って。そのプラットフォームがない、とか有償版しかないってのも悲しいし。

宣言その3〜Movable Type のiOSクライアント作る、宣言

今年は Mac App Storeデビューしたというトピックもあるんだけど、MTクライアントのMAUS とか ColorTester とかの寄附ボタンとか、押してくれた人(ありがとうございます)とかの数見てると、儲かる仕事にも思えないわけですが、年末年始の休みを利用して少し取り組んでみようと思っています。API、クライアントなければただの仕様?じゃねーかと思うからです。

iOSクライアントのイメージ

宣言その4〜MTを利用してウェブサービス作る、宣言

私にとってのMTは、もはやMTでなく、PowerCMSでなく、開発プラットフォームでありORマッパでありテンプレートエンジンなわけです。であれば、ウェブサービスを仮に作るなら、MTベースで作りたい。万が一ヒットしたとしたらスケールアウトの問題が出てくるだろうけど、最初のリリースの敷居低いから、それこそ当たる当たらん考えててもしょうがないし。

ずっとやってみたかったことだし、アイデアもあるのだ。

宣言その5〜クラウド版のCMS+αのサービスを立ち上げる、宣言

MTはクラウド版あるわけですけど、PowerCMSは現状ありません。AMI や Azureのキットはあるんですけどね。来年は一つ以上、立ち上げを行います。より安心、任せておけるサービスを提供しお客様の選択肢を増やします。

これらの宣言と関係あるかどうかわかんないですが、一人じゃやれへんし、年末の全社会議でも社員に話したけど、来年はピッチ上げるつもりだし、おもしろそうやん、って思ったら一緒に戦おうぜ。よろしくね!

それでは、今年も良いクリスマスを。

MTプラグインのお気に入りに投票する「Movable Type プラデミー賞 2014 とかいうふざけた企画がある模様で、このプラグインこれまでに使ったことあるなー、プラグイン入れ直してちょっと見てみるかどんなんだっけ、とかそういうことになりますよね。なりますよね! ね! ね!

でも、プラグインをインストールするって

  • プラグインをウェブブラウザでダウンロードする
  • FTP(SFTP)クライアントでプラグインをアップロードする
  • その時、plugins ディレクトリと mt-static に(toolsがあればそこにも)それぞれアップする

という手順になりますよね。ファイルが多い時はZIPのままアップしてログインしてCUIで解凍して配置するなんて人もいるかもしれませんが、どっちにしても面倒です。

ということで、プラグイン作りました。plugins、mt-staticディレクトリがWebサーバーから書き込めるパーミッションになっている必要があるので、そこは、まぁテスト環境なりローカル環境で使うという割り切りでお願いします※。

※PowerCMS には プラグイン管理機能(PluginManager.pack) があって、これを使うと常駐スクリプトをサーバーで動かして、そのスクリプトがよしなに配置、パーミッション設定をしてくれます。自動アップデート機能もあります。

プラグインをGitHubやその他の方法で公開している時のメジャーなファイルフォーマットはZIPですよね? で、アーカイブの構成的にはこんな感じになっていると思います。PluginInstallerは、config.yamlを起点にして同じディレクトリ構成になっていることが前提となりますが、ZIPファイルのURLを管理画面から入力して、直接プラグインをインストールすることができます。


    ZIPアーカイブのルート/
    |__ plugins/
       |__ MyPlugin/
           |__ config.yaml
    |__ mt-static/
       |__ MyPlugin/
    |__ tools/
       |__ mt-my-tool/
...

GitHubのページからダウンロードリンクをコピー

システムプラグイン設定からプラグインをインストール

ライセンス

  • PluginInstaller ライセンス(プラデミー賞に1ポチするのが条件! ←嘘や。自己責任でご自由にお使いください)

今日、SEOがテーマのセミナーがあるので、MT、というか PowerCMS のプラグインを作りました。

キーワードの管理画面

テンプレートタグ

自動置換するブロックはテンプレートタグ(ブロックタグ)で指定します。

<MT:Keyword2Link blog_ids="children" add_attr='class="keyword"'>

このブロックのテキストからキーワードにマッチする部分を自動的にリンクにします

</MT:Keyword2Link>

パブリッシュすると、

<a class="keyword" href="http://example.com/keyword/SEO">SEO</a>

みたいなリンクに置換してくれるものです。キーワードとURLは管理画面から入力するだけでなく、CSVから一括で登録することもできます。便利でしょ? 便利、だよね!

※公開はちょっと待ってね。

CSS調整したりJQueryでゴニョゴニョしてもいいのですが、基本的にはプラグインを書きます。とはいっても、メニューやウィジェットの表示非表示程度なら、config.yamlだけ用意すればそれで実現できます。メニューについては別に権限外せば出ないですし、ウィジェットは×クリックで消せばいいんですけどね。

この手のは今までさんっざん書いてると思うけど、そういう問い合わせがあったので。

mt/plugins/MyPlugin/config.yaml

ウェブページの一覧をメニューから削除する

メニューのIDを指定し、displayを0にする。メニューのIDは /lib/MT/App/CMS.pm で定義してあります。

applications:
    cms:
        menus:
            page:manage:
                display: 0

Movable Typeニュースをシステム管理者以外には非表示にする

プラグインのほうがコアモジュールより後に初期化されるから、要するに config.yaml で上書きすれば良いです。ウィジェットのIDも /lib/MT/App/CMS.pm で定義してあります。

widgets:
    mt_news:
        label: Movable Type News
        template: widget/mt_news.tmpl
        singular: 1
        set: sidebar
        handler: $Core::MT::CMS::Dashboard::mt_news_widget
        view: user
        condition: sub { return MT->instance()->user->is_superuser }
        order:
            user: 500

はい、以上。

MAUSのアイコン

Data APIで MTのアイテムを管理する

ここ半年程コツコツとブログエディタ作ってるんですが、まともなクライアントソフトを作ろうと思えば画像の管理機能くらいは欲しいじゃない。アップロードのエンドポイントは標準であるけど、以下のエンドポイントがない。

  • 画像(アイテム)の一覧
  • アイテムの編集(上書き、メタ情報の編集)
  • 削除

これじゃあ、上げっぱなし(アップロードしっぱなし)で、MT3以前と変わらんということになるので、まずエンドポイントを拡張するプラグインを作った。

色々できます。

  • 画像(アイテム)の一覧
  • 画像(アイテム)の検索
  • アイテムの編集(上書き、メタ情報の編集)
  • 削除

https://github.com/junnama/mt-plugin-data-api-endpoint-assets

MAUSに組み込んだ

元々Hack-A-Thon(Hack-A-ThonでMT Image Managerを作った。)で画像管理のための単機能ソフトを作ったんだけど、それだけじゃあんまり面白くないので、MAUS(ブログエディタ)に組み込んだ。

  • 画像の一覧表示、キーワード検索
  • ダブルクリックもしくは右クリックからアプリケーションを選択して画像を開く機能
  • 画像を編集して保存すると上書きアップロードする機能
  • 情報を見る(キーボードショートカットCommand+I)
  • 「情報を見る」画面で、画像のメタデータの編集
  • 画像を削除(キーボードショートカットCommand+Delete)
  • 一覧からエディタへのドラッグ&ドロップ(タグの挿入)
  • 右クリックで、HTMLをクリップボードにコピー(その際に、画像の配置を選べるように)

これはこれで、なかなかに素敵でしょ?

MAUSのキャプチャ(イメージマネージャを追加)

Speed is everything! 軽量なDynamicMTMLを動かす編。

PHPerのためのMovable Type講座

DynamicMTMLは、元来はhtmlファイル内のMTタグを動的処理するために作られました。平たく言えば、静的生成されたページの一部をMTタグで動的に処理するためのものです。但し、DynamicMTMLはこれにとどまらず、タスクやワーカーを処理したり、config.php形式でプラグインを完結に(まとめて)書けたりといった様々な機能を持っています。

今回は、そのあたりの機能は必要とせず、とにかく軽量、速く処理したいということで、ファイル中のMTタグのみを実行するだけ、しかも不要なプラグインは初期化そのものをスキップしてしまうことで、とにかく高速に動かすことを目的とした.mtview.phpを紹介します。

以下のソースをインデックステンプレートにします。

方針:必要なプラグインのみ初期化する。ブログや記事の情報が不要なら、$blog_idをNULLとして、クエリを一回でも省略する。

前提:必要なphpプラグインを一カ所(以下の例ではCustomHandlers/php)以下に纏めてしまう(もしくは配列で必要なプラグインを複数指定する)。通常の処理の際にファイルの重複があるとエラーになってしまうので、plugins以下ではない場所に設置するか、plugins/CustomHandlers/phplib など、phpフォルダとは別のフォルダにおいておくと良いです。

Swift が話題ですね。触るかもしれませんが、もうちょっと先だけど。

何でSwiftの話かって? いや別に深い理由はないんだけど、開発ツール作るのって中々に楽しいよってことで。

テンプレート編集画面で、MTMLがおかしいときに出ますよね、エラー表示。これを返すData APIのエンドポイントを追加します。

テンプレート編集画面でのエラー表示

日曜日に投げるとあんまり見てもらえないから(嘘)。公開してからちょくちょく直したり改修したので改めてドキュメントチックなものを。

MT6のDataAPIのエンドポイントを作ってみた(アイテム関係)。

追加されるエンドポイントは以下のとおり。asset_id指定での取得を追加しました。また、一覧の取得時には sortBy(デフォルトはID)、sortOrder(デフォルトはdescend)、limit(デフォルトは10)、offset(デフォルトは0) 指定できるように。

/sites/:site_id/assets
/sites/:site_id/assets/image
/sites/:site_id/assets/video
/sites/:site_id/assets/audio
/sites/:site_id/assets/:asset_id

取得できるリソースはMT標準の下記にいくつか追加しました。

https://github.com/movabletype/Documentation/wiki/data-api-resource-assets

image_width(画像のみ)
image_height(画像のみ)
icon_url(アイコンのURL。画像の場合はサムネイル)

icon_url については、リスティングスクリーンに表示されるものと同じものが返ります。今のところ45pxサイズ決め打ち。

戻り値はこんな感じ。

{"totalResults":2,"items":[{"icon_url":"http:\/\/mt4local.alfasado.net\/MyMovableType\/exalscript.png","image_width":"32","description":null,"tags":{},"image_height":"32","filename":"exalscript.png","url":"http:\/\/mt4local.alfasado.net\/MyMovableType\/exalscript.png","mimeType":"image\/png","label":"exalscript.png","id":"3"},{"icon_url":"http:\/\/mt4local.alfasado.net\/MyMovableType\/assets_c\/2014\/03\/SafariScreenSnapz006-thumb-45x45-1.png","image_width":"1732","description":null,"tags":{},"filename":"SafariScreenSnapz006.png","image_height":"578","url":"http:\/\/mt4local.alfasado.net\/MyMovableType\/SafariScreenSnapz006.png","mimeType":"image\/png","label":"SafariScreenSnapz006.png","id":"1"}]}

We Love Blog

自分でDataAPI対応のブログエディタ作って更新している世界で唯一の人なんですよおいら(多分、嘘? 嘘じゃないのか?)。画像のアップロードも挿入もできるんだけど、アップロード済みの画像をAPIで取得することができないので、試しに作ってみた。limit も offset もなにもないので、本当に取り敢えず、ね。問答無用に全部取得なのである。早速だけど、追加できるようにしてみたよ。

https://github.com/junnama/mt-plugin-data-api-endpoint-assets

ハマりがちな罠。Facebookとかで既に書いたんだけど。

こういうの、よく作るよね。「記事が保存されたとき」をトリガーにして動作させるプラグイン。MTに限らないけど、WordPressだったらなんだ、フックっていうんだっけ。MTならコールバック。

以下のような実装が必要な時に使います。

  • 記事がポストされたらTwitterに投げる(FacebookでもWeiboでも何でもいいけど)
  • 記事が公開されたらメールで通知を送る
  • 記事が更新されたら関連するアーカイブを再構築する

Facebook

Twitter

このアーカイブについて

このページには、過去に書かれたブログ記事のうちMovable Typeプラグインカテゴリに属しているものが含まれています。

前のカテゴリはMovable Typeです。

次のカテゴリはWeb制作・ビジネスです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Powered by Movable Type 6.2.6