2010年12月アーカイブ

MT meets PHP.

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

年末だというのに...

大晦日に何か面白いもの作って公開するってのを数年前までやっていたんだけど今年はちょっと無理ですね。年明け早々にはお披露目出来るかと思います(何が!?)。

標題は納会の時の僕の社内プレゼンのテーマですが、今PHPによるMTの拡張っていうテーマでコードをあれこれ書いてます。

さて、↓反応遅れましたが。

「育てる時代にふさわしいCMSベスト5」で一位に選んでいただきました(ありがとうございます...しかしあの電話が取材だったのか!?)。

といってもその1位がどうの、とか書かれている内容とは違うところに少し反応してみます。それは取り上げられているCMSの中で、

MT(Power CMS for MT)以外全て(多分)PHPで書かれている!んですよ。

とはいえMTもPower CMS for MTもPHPにも対応していて、ただ管理画面はPerl、出力形式をPerlによるスタティック生成とPHPによるダイナミックパブリッシングの両方をサポートしているということになります。

MTのダイナミックパブリッシングがPerlでなくPHPであることからもわかるように、やっぱりPerl CGIとかと比較して手軽に動的生成行うのならPHP選択ってことになると思います。FastCGIなんか入れるとキビキビ動くようにはなりますけど、とはいってもサーバーのメモリとか考えるとPHPの手軽さってやっぱりあるんだと思います。

ということは関係あるのかどうかわかんないんですが(関係ないです!)、この2ヶ月ほどMTのPHPのライブラリを見直してみつつ、MTのPHPフレームワークを拡張する新しいクラスを作っていてついでにちょっとした管理画面とかも作ってみました。

管理画面1

管理画面2

ちゃんと動くし、まぁ軽量っちゃー軽量ですね。アーカイブをダイナミックパブリッシングにしておけば本当にPHPのCMSです(本当って何だ?)。まぁ大規模サイトに導入するときはスタティック最強だと僕は思っていて、MTが選ばれるのもあの何ていうか(好き嫌いの多い)「再構築」があるからだと思うわけですが、PHPで書きたくなる気持ちも分かります。

で、PHPで拡張する仕組みを作って表示側をリアルタイムに変えられるようになると何だか書きたくなるもののパターンって変わるんですね。つまり何かWordpressっぽいというか、そういうのを書きたくなる。例えば携帯キャリアやスマートフィン対応とか検索ワードのハイライトとかLPOとか日本語URLとか、何か言語と言語をとりまく環境が作りたいものを左右するって不思議な感じです。

ところで、MTのダイナミックパブリッシングに「多くのプラグインが対応していないからMTのダイナミックパブリッシングは使えない」みたいな可哀想な言われ方をしていて(Power CMS for MTはすべてダイナミックパブリッシング対応ですが...400以上のPHPプラグインが!)、何で両対応しないかって、書き方のお作法が違うんですよね。MT5になってadodbをベースにしたclass.baseobject.phpってのが出来てFind()やLoad()やSave()も実装されてはいるものの、書き方のお作法が違うから両方対応するのが面倒になるわけです。なので、

    $categories = $app->load( 'Category', array( 'label' => $category ) );

とか

    $terms = array( 'blog_id' => $blog_id, 'id' => $id );
    $args  = array( 'limit' => 1 );
    $entry = $app->load( 'Entry', $terms, $args );

とか、

    $entry = $app->get_by_key( 'Entry', array( 'blog_id' => $blog_id, 'foo' => $foo ) );

とか

    $app->can_edit_entry($entry);

とか

    $foo = app->param('foo');

とか

    $user = app->user();

とか出来るようにしてみたら書きやすいんじゃないかと思ってそうしてみたら...

本当に書きやすいです。はやくやっとけばよかった。

PHPであれこれやってみて感じること

やっぱり軽快さというかそのあたりは使いたくなるのはわかるけど、変に直接HTMLの中に書ける手軽さは「ついつい」なコードを書いてしまいがち。なのでやっぱりMTならMTの作法でテンプレートエンジンによってアプリケーションのロジックとコンテンツをちゃんと分けるようにすべきだなぁと。

あと、関数名重複や変数のスコープの意識とか考えさせられますね。かといって function powercms_util_func_hoge() とか長ったらしい書き方を強要させられるのも何だかと思うので、ちゃんとクラス作成してとか名前空間指定してとか(って名前空間指定できるようになったのってPHP 5.3.0からなんだ!)って、PHP製のCMS作ってる人はど苦労してないんだろうかとか思いつつ、ちょっと本格的にPHPでMT製のサイトを拡張できる仕組みを作ってます。

管理画面のサンプルも近々公開できると思います。来年は案件用の管理画面とかについてもPerl/PHPの両方で提案できるようにしたいと思います。

と、いうことで(どういうことだ?)、皆様良いお年を。

スペード 曇り 晴れ

絵文字テスト

大きな写真カメラとか長い文章とか。

512pxの写真

拡大画像へのリンク

Creative Commons License
TypePad 絵文字アイコン画像 by Six Apart Ltd is licensed under a Creative Commons 表示 2.1 日本 License.
Permissions beyond the scope of this license may be available at http://start.typepad.jp/typecast/.

以下、長いページが携帯でうまく分割されるかのサンプル(文章に意味はないですわーい (嬉しい顔))

iPhone(スマートフォン)からの閲覧の際にテンプレートを分岐させてみた時に考えたこととか。

Power CMS fot MTの次のバージョンに向けて開発を進めている新しいDynamicMTMLが面白いので実運用テストを兼ねてiPhone(スマートフォン)からの閲覧とphone to携帯3キャリアからの閲覧の際にテンプレートを分岐させてみましたexclamation×2

他にもいくつか「日本語URLでのアクセス(現在は無効化しましたが)」とか「検索エンジンのリファラでキーワードハイライト」とかスマートフォンや携帯向けに自動サムネイル変換とかもやってます。

* 新しいDynamicMTMLNEWについては近日公開しますsoonPHPで色々拡張できます(Wordpressのプラグインを動かしたりとかわーい (嬉しい顔))

今回は黒野さんのiPhoneテンプレートを利用させてもらい、同一URLでスタティックに吐かれたアーカイブをDynamicMTMLで分岐表示させてみました。ついでに携帯関係のライブラリを突っ込んで携帯3キャリア対応も。

現在のメインページ、ブログ記事テンプレートをモジュールに持って行き、iPhoneテンプレートの2つのテンプレートをこれもモジュールに。 メインページ、ブログ記事のテンプレートを下記のようにします(mt:rawmtmltag、mt:ifsmartphoneはプラグインによる拡張)。

テンプレートの修正

メインページ:

<mt:rawmtmltag tag="mt:ifsmartphone">
    <mt:include module="iPhone-メインページ">
<mt:rawmtmltag tag="mt:else">
<mt:rawmtmltag tag="mt:ifkeitai">
    <mt:include module="携帯-メインページ">
<mt:rawmtmltag tag="mt:else">
    <mt:include module="PC-メインページ">
<mt:rawmtmltag tag="/mt:else">
<mt:rawmtmltag tag="/mt:ifkeitai">
<mt:rawmtmltag tag="/mt:else">
<mt:rawmtmltag tag="/mt:ifsmartphone">

ブログ記事:

<mt:rawmtmltag tag="mt:ifsmartphone">
    <mt:include module="iPhone-ブログ記事">
<mt:rawmtmltag tag="mt:else">
<mt:rawmtmltag tag="mt:ifkeitai">
    <mt:include module="携帯-ブログ記事">
<mt:rawmtmltag tag="mt:else">
    <mt:include module="PC-ブログ記事">
<mt:rawmtmltag tag="/mt:else">
<mt:rawmtmltag tag="/mt:ifkeitai">
<mt:rawmtmltag tag="/mt:else">
<mt:rawmtmltag tag="/mt:ifsmartphone">

iPhone用テンプレートは同一URLでの分岐なので、各リンクの/i/を削除。

基本、これだけで決定なのですが、スマートフォンからのアクセスの際に大きな写真があった場合に400px(どちらか長い方の)に縮小し、640pxの画像へのリンクになるように(携帯の場合はフォーマット変換して180pxから300pxの画像へのリンクに)。携帯の場合、見出しタグを区切りに2,000バイトでページ分割。

また、スマートフォン、PCに関わらず検索エンジンからの流入にの際にキーワードをハイライトするなど。このあたりはページ出力前に処理を割り込めるPHPプラグインのフレームワークを作成したのでコールバックプラグインを作成してそこに記述。

CSSの調整

トップページ :

.group { background-color: #669999 !important; }
/*
    「最近の見出し」の背景画像が読み込まれるまでの時間、白い背景に白い影付き文字で読めないので
*/
#home li a { font-size:86% !important; }
/*
    記事ページのテキストとのバランスでちょっと小さく
*/

*/
/↓i/css/style.css
*/

* {
    margin: 0;
    padding: 0;
    background: transparent;
    overflow-x: auto; /* <=追加 */
}

コード(pre,code要素)が多いので、横に長くなった時にサイズがおかしくなってしまうし、長いURL等があった時にはみ出したエリアの長さにあわせたサイズになってしまうのでとてもじゃないけど文字が読めなくなります。 オーバーフローした部分はiPhoneの場合は指2本でスクロールすることが出来ます。ついでにコードを読みやすく。

pre {
    padding: 0.2em;
    border: 1px solid gray;
    width: auto;
    overflow-x: auto;
    color: inherit;
    background-color: #f6f6f6;
    font-family: monospace;
    margin : 0.4em;
}

目考察:月が変わる毎にビルドされるテンプレートモジュール

以下は駄文というかわりとどうでもいい考察ですがあせあせ (飛び散る汗) 気になったのはトップページのテンプレートです。<MTEntries lastn="9999">って(通常は有り得ないんでしょうが理屈的には)、最大60,014件のエントリーを毎回出力する可能性があるわけですねexclamation&question

過去記事はリンクのように見えて実際はひとつのインデックス・アーカイブに吐かれるわけで、記事が一件追加される毎に(インデックス・アーカイブなので記事に関わらず常に再構築が走る時にはこのテンプレートが)再構築処理されます。

アプローチとしては(今回はプラグインとか書かないつもりだったので)、素直に月別アーカイブにしてインクルードする、というものがある訳ですが、過去記事のリストについてはせっかく過去6ヶ月に限定しているわけですからテンプレート修正なんかの際に過去何年もの月別アーカイブアーカイブを再構築するってのも非効率な気がしました。

そこで、「前提として過去のエントリーを更新することはまず、ない」ということで月が変わった場合にのみ再構築されるキャッシュされたテンプレートモジュール、ってのを考えてみました。

インデックス・テンプレート側

<$mt:Include module="cache_ts" cache="1" key="cache_ts" ttl="31536000"$ trim="1" setvar="cache_ts">
<mt:ignore>
    モジュール「cache_ts」テンプレートには <mt:date format="%Y%m"> とだけ記述
    ttl="31536000" * = 1年(365日)
    例 : 前回キャッシュが2010年11月ならばcache_tsは「201011」
</mt:ignore>
<mt:date format="%Y%m" setvar="current_ts">
<mt:ignore>
    例 : 現在が2010年12月ならばcurrent_tsは「201012」
</mt:ignore>

<mt:if name="cache_ts" ne="$current_ts">
<mt:ignore>
201011 != 201012 の場合のみキャッシュをクリアしてcache_tsの内容を「201012」に更新して再セット
</mt:ignore>
<$mt:Include module="cache_ts" cache="1" key="cache_ts" ttl="-31536000" setvar="dummy"$>
<$mt:Include module="cache_ts" cache="1" key="cache_ts"  ttl="31536000" setvar="cache_ts" $>
<mt:else>
</mt:else>
</mt:if>

<mt:setvarblock name="cache_key_monthly">cache_key_monthly_<mt:var name="cache_ts"></mt:setvarblock>
<mt:setvarblock name="cache_key_entries">cache_key_entries_<mt:var name="cache_ts"></mt:setvarblock>

<mt:ignore>
cache_key_monthly => cache_key_monthly_201012(cache_key_monthly_201011)
cache_key_entries => cache_key_entries_201012(cache_key_entries_201011)
</mt:ignore>

<ul id="home" selected="true">
        <li class="group">最新のブログ記事20件</li>
    <MTEntries lastn="20">
        <li><a href="<$MTEntryPermalink$>" target="_self"><$MTEntryTitle$>[<$MTEntryDate$>]</a></li>
    </MTEntries>
        <li class="group">過去記事アーカイブ</li>
        <li><a href="#monthlyArchives">過去6ヶ月の記事を見る</a></li>
</ul>
<$mt:Include module="過去記事月リスト" cache="1" key="$cache_key_monthly" ttl="31536000"$>

<ul id="m<$MTArchiveDate format="%j"$>">
<MTArchiveList archive_type="Monthly" lastn="1">
<mt:ignore>
    現在の月分だけは毎回再構築
</mt:ignore>
    <MTEntries lastn="9999">
            <li><a href="<$MTEntryPermalink$>" target="_self"><$MTEntryTitle$>[<$MTEntryDate$>]</a></li>
    </MTEntries>
</MTArchiveList>
<$mt:Include module="前月以前の記事リスト" cache="1" key="$cache_key_entries" ttl="31536000"$>
</ul>

モジュール側

(モジュール)過去記事月リスト:
<ul id="monthlyArchives">
    <MTArchiveList archive_type="Monthly" lastn="6">
    <li><a href="#m<$MTArchiveDate format="%j"$>"><$MTArchiveTitle$></a></li>
    </MTArchiveList>
</ul>

(モジュール)前月以前の記事リスト:
<MTArchiveList archive_type="Monthly" lastn="6">
<mt:unless name="__first">
<mt:ignore>
    こちらでは現在の月分だけはスキップ
</mt:ignore>
    <MTEntries lastn="9999">
            <li><a href="<$MTEntryPermalink$>" target="_self"><$MTEntryTitle$>[<$MTEntryDate$>]</a></li>
    </MTEntries>
</mt:unless>
</MTArchiveList>

当然ですが、過去6ヶ月間のブログ記事を削除した場合なんかにはこのモジュールは再構築されないといけないわけですね。 このあたりの細かい制御は...テンプレートベースでは残念ながら出来ないのが現状です。

カスタムフィールドが使えるケースであればブログのカスタムフィールドとかで「モジュールキャッシュをクリアする」みたいなチェックボックスを付けて対応するとか、どうしても裏技っぽくなっちゃいますね。

モジュールキャッシュの一覧とクリアが出来る一覧ページとかがあればいいわけですよね。ニーズあるでしょうか? (権限をどうするんでしょうね...)

ダミーのインデックステンプレートを作って再構築を「手動」にして、更新したい時に再構築するとか。

<$mt:Include module="cache_ts" cache="1" key="cache_ts" ttl="-31536000" setvar="dummy"$>
<$mt:Include module="cache_ts" cache="1" key="cache_ts"  ttl="31536000" setvar="cache_ts" $>

とかしておくと、まぁクリアできなくもないですけど(続く...かも)。

ついでに..ダイアログをPHPで作ってみたハート

絵文字挿入ダイアログ

Facebook

Twitter

このアーカイブについて

このページには、2010年12月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2010年11月です。

次のアーカイブは2011年1月です。

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

Powered by Movable Type 6.2.6