学習を兼ねてoEmbedが使えるプラグインつくってみました
自分のスキルにちょうどいいドキュメントがなかなか見あたらず、伸ばし伸ばしになっていたbaserCMSのプラグインづくり。年末になりちょっとまとまった時間ができたので、改めて取り組んでみることにしました。
つくったのは、かねてやりたいと思っていた「記事本文でoEmbedを使えるようにするプラグイン」です。
oEmbedってなに?
簡単に言うと、外部サイトのリソース(例:YouTubeの動画やTwitterのツイート)を簡単にウェブページに埋め込めるようにする仕組みです。たとえばYouTubeの動画をページに埋め込みたい場合、通常は
「埋め込みコード」欄にある
<iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/X8VX6_mRABs?rel=0" frameborder="0" allowfullscreen></iframe>
といったコードをコピペするわけですが、oEmbedを使うと動画のURLを記述するだけでそれが可能になります。
興味のある方は、公式ドキュメント(英語)を参照してみてください。
ライブラリを使ってbaserCMSに実装してみた
WordPressではバージョン2.9からこの機能が徐々に拡張されていて、バージョン4.1では29のウェブサービスについてoEmbedを使えるようになっています。WordPressのコアファイル群に /wp-includes/class-oembed.php というものがあり、ここで対象となるウェブサービスを定義しているようです(独自実装ということですね)。
baserCMSにはこうした実装がないのでライブラリの力を借りることにしました。oEmbedのサイトに「Libraries」という項があり、さまざまな言語のライブラリが載っています。なんとなくjQueryライブラリ(oEmbed API Wrapper)がラクっぽい気がしないでもないですが、今回はプラグインの学習ということでPHPライブラリの中の『Essence』を使うことにしました。
WordPressでいう「フィルターフック」のような機能をさぐる
WordPress脳(?)の考え方でいうと、
<?php add_filter( 'the_content', 'my_the_content' ); function my_the_content( $content ) { /* * $content にあるoEmbed対象URLを置換する処理を書く */ return $content; }
みたいな流れになる実装。もちろんbaserCMS(というかCakePHP)では流儀が異なります。文字列置換なのでプラグインのつくりはさほど難しくないはずですが、そもそもその骨格をどう書けばいいのかチンプンとカンプン。baserCMSの公式サイトにある「プラグイン開発について」ページの記述はCakePHPのプラグインがつくれる知識を前提としているようで、これまたさっぱりわかりません。
それでもググって寄り道しながら読み解いたところ、前述のページにある「イベントリスナ」という機能がどうやらキモになっていることがわかりました。
beforeLayoutがフィルターフックみたいなもの?(と解釈)
つくったコードをGitHubで公開しました。
この手の「出力結果に何かしら手を加える」タイプの処理は「ビューイベントリスナ」という仕組みを使うようです。CakePHPではディレクトリ構成やファイル名、クラス名などに規約があるのでそれに従います。そのうえで、記事本文の文字列を取得して置換する処理をかけていきます。
WordPressのプラグインと違い一連の処理がクラス化されている(WordPressのプラグインでは必ずしもクラスを使わなくていい)ので一見とまどいますが、おそらく
public $events = array('beforeLayout'); public function beforeLayout(CakeEvent $event) { /* * 文字列を取得して置換する処理 */ }
がWordPressでいうフィルター関数とフィルターへのフックにあたるのでは、と解釈しました。
$view = $event->subject();
のあたりは、フックから受け取った引数を展開する箇所って感じですかね。
$request = $view->request; if (preg_match('/^admin_/', $request->action)) { return; }
ここはWordPressなら
if ( !is_admin() ) { /* * 何かしらの処理 */ }
と条件分岐させるところでしょうか。
そんなわけで曲がりなりにもイベントリスナを使ったプラグインができあがりました。baserCMSにoEmbedを導入したい方、よろしければご活用くださいませ。
oEmbedでInstagramの画像を埋めてみましたよ。
https://www.instagram.com/p/B6t6rksHiVp/
……と書きながらのウィークポイント
このプラグインでは、『Essence』の replace メソッドを使っています。
記事本文にある対象URLを一括でoEmbed処理してくれる便利メソッドなんですが、逆に言うと明示的にURLを表記したい場合(例:YouTubeの動画URLを表示させるなど)でも問答無用で動画を埋め込みしてしまう弱点があります。
URLを一括置換したくない場合は、従来どおり「埋め込みコード」を使う方がよいかもしれません。
謝辞
制作にあたり、Nextatさんがつくられた『自動保存プラグイン』のコードが参考になりました。ビューイベントリスナを使うコードの骨格やメタデータの書き方など、プラグインづくりの基本的な作法を学ぶことができました。ありがとうございます。
[2014.12.29追記]
一括置換を回避するコードを追加しました
そもそも「埋め込みコードのコピペめんどくさー」という動機でつくったプラグインなので、ちょっと改良。
記事内にURLを記述する際、{} で囲まれたURLについては埋め込みをしない処理を加えました。{} を含むURL文字列を暗号化して『Essence』の replace メソッドに通し、暗号化したURL文字列を書き戻しつつ {} を除去しています。
- {} で囲んだとき
https://twitter.com/tecking/status/549370251763146753 - {} で囲まないとき
https://twitter.com/tecking/status/549370251763146753
[2015.1.8追記]
baserCMS用のテーマやプラグインを配布している『baserマーケット』に登録されました。
oEmbed 有効化 | baserマーケット
https://market.basercms.net/products/detail.php?product_id=71
[2017.7.6追記]
長期間メンテナンスを放置していたらPHP7環境でうまく動作しなかったので、同梱ライブラリを『Embera』に切り替えて再実装しました。『Essence』でも試してみたのですが内部構造がずいぶん変わっており挫折……
『Embera』導入にあたり、PHPのcURLサポートまたは allow_url_fopen = on のいずれかが必須となりましたのでご了承ください。
なお『baserマーケット』で公開しているプラグインは旧版(現在、更新申請中)ですのでご注意ください。
[2018.5.30追記]
遅くなりましたがバージョン4系の対応も確認しました! 3系・4系両方でご使用いただけます。