「WordPress 徹底解析(WordPressを拡張するプログラムの構成法 – 処理のクラス化)」いきます。 🙂
前回は、アクションフックの動きと簡単な処理の実装まで行ってみました。
実はこの記事、”プラグインをつくる”としてしまったのですが、WordPress のフックの機能はテーマの functions.php でも同様に使える手法です。
テンプレートファイルの functions.php は、プラグインファイルと読み込み順番が若干違うだけでプラグインと同様な実装ができます。テーマと同時に有効になるプラグインファイルと考えても差し支えないでしょう。というわけで、テーマを主につくる方も読み進めていただければと思います。紹介しているソースも functions.php にかけばそのまま動くはずです。
さて、今回は以下のような WordPress を拡張する上でのプログラム構成のノウハウを、引き続きアクションフックのプラグインのソースを元に紹介していきます。
- 処理のクラス化
- 外部 API の呼び出し
- テンプレートファイルに情報を出力する方法
- 外部 API 呼び出しの並列化
- 管理画面をつくる
まずは「1. 処理のクラス化」より。
処理のクラス化
前回紹介した、アクションフックを使う基本コードは以下のようなものでした。
function prepare($post_ID, $post) { die("test"); } add_action('publish_post', 'prepare', 10, 2);
これをベースに以下の処理を実装していきます。
- 「記事の公開時」にその日のお天気を LWWS API に問い合わせカスタムフィールドに格納する。
- 格納されたお天気情報をテンプレートファイルの記述でアイコン出力する。
大きく2つの機能があり、双方ともカスタムフィールドの値の処理(設定と取得)で関連しています。これらの処理には関数が2個以上は必要そうです。
プラグインやテンプレートファイルの functions.php に定義する関数や変数はグローバルスコープになります。WordPress 本体や他のプラグインと共通的な空間に定義されますので、複数が大きくなり関数が増えるとお互いの干渉が気になってきます。大きなところでは、変数や関数名称の重複です。
このような場合、PHP のクラスの機能を名前空間として使い処理をまとめると、グローバルに対する干渉を最小限に抑えることが出来ます。(またオブジェクト指向をつかったトリックも使えるようになります)
先のグローバル関数をひとつ使ったアクションフックの定義をクラスを使ったものに変更すると次のようになります。
class Otenki { function prepare($post_ID, $post) { die("test"); } } $otenki = new Otenki(); add_action('publish_post', array($otenki, 'prepare'), 10, 2);
クラスを定義(class Otenki {})し、その下で $otenki 変数に Otenki オブジェクトのインスタンス内を格納します。
$otenki = new Otenki();
クラス内に移動したメソッド(function prepare() { } )を add_action するには、’prepare’ と関数名のみを指定していた引数を、 array($otenki, ‘prepare’) と変更しインスタンスを特定できるようにします。
add_action('publish_post', /*ここ→*/array($otenki, 'prepare'), 10, 2);
以上の変更でクラス Otenki が名前空間代わりになります。クラス内部に実装するメソッドや定数・変数は、他との名前の重複など考えず自由に定義できます。
なお、クラス名 Otenki とそのインスタンスを格納する $otenki 変数は依然としてグローバルです。この部分だけ他との干渉を意識します。
(WordPress とのインターフェースになるクラスはいろいろな機能が実装されてしまうためクラス名には悩みますが、、SI業界的(?)には OtenkiPluginFaçade とかでしょうか。モジュール分割の規模によって決めると良いと思います。今回は処理が小さくひとつのクラスで済みそうなので単純に Otenki としました)
では「お天気情報の取得」と「テンプレートファイルからお天気情報を出力する」2つのメソッドを実装します。 まずはソースの骨組みのみ。
class Otenki { /** * カスタムフィールド・メタキー. */ const META_KEY = 'otenki'; /** * APIバージョン情報(V1/JSON). */ const LWWS_V1_JSON = 'LWWS_V1_JSON'; /** * 記事公開フックで天気情報を取得をする. * * @param $post_ID * @param $post * @return none */ function prepare($post_ID, $post) { // お天気 API を呼び出し // Otenki::META_KEY, Otenki::LWWS_V1_JSON を用いて // カスタムフィールドに登録 } /** * カスタムフィールドに取得したお天気アイコンを出力. * * @param none * @return none */ function output() { // Otenki::META_KEY, Otenki::LWWS_V1_JSON を用いて // カスタムフィールドを取得しアイコン HTML を出力 } } $otenki = new Otenki(); add_action('publish_post', array($otenki, 'prepare'), 10, 2);
class 内に prepare と output メソッドが実装され、共通するカスタムフィールドのキーなどが const(定数)で定義されていることが分かります。処理の class 化を行うと、このような共通項がグローバルへの影響無しに自由に実装できるようになります。
さて、アクションフックにより「お天気情報の取得」を担う prepare メソッドの呼び出しはうまくいきそうですが、テンプレートファイルにお天気情報を出力する output メソッドはどのように呼び出せばいいかという疑問がわいてきます。
これは、Otenki クラスのインスタンスが格納されている $otenki 変数がグローバルスコープであることを利用して、テーマのテンプレートファイル内で次のように呼び出すことができます。
$otenki->output();
ただ WordPress のテンプレートタグ的には、オブジェクト指向のメタファーが入ってしまうため、若干違和感があります。WordPress 本体では似たケースで次のような実装がされています。
テンプレートのループで使われる the_post() 関数。
wp-includes/query.php
/** * Iterate the post index in the loop. * * @see WP_Query::the_post() * @since 1.5.0 * @uses $wp_query */ function the_post() { global $wp_query; $wp_query->the_post(); }
グローバルスコープののインスタンスが格納されている変数を関数に持ってきてメソッドを呼び出す、ヘルパー関数を準備しているわけです。
今回のケースも同様にヘルパー関数をつくってあげれば良さそうです。
/** * お天気情報を出力するテンプレートタグ. */ function the_otenki() { global $otenki; $otenki->output(); }
以上の、クラス定義、アクションフックの登録、ヘルパー関数がかかれたプラグインファイルが otenki.php とすると、動作シーケンスの概要は次のようになります。
本来は記事の公開(do_action(‘publish_post’))とテーマ出力処理は同時には起きえませんが、この図では一緒に書いております。逆にこの動きを理解することで、1アクセス内で発生する順次処理の結果を、クラスのインスタンスに保持し、合成した結果を出すような処理もつくることができるでしょう。
というわけで、なかなかプラグインが完成しませんが、、また明日。 🙂
目次
本連載はファイルがない状態からソースコードを実装していく方式を採っています。プログラムの構成法も含めて解説していますので、最初から読んでいくとより理解しやすいでしょう。
- アクションフックのプラグインをつくる編
- 最初に、WordPress の拡張において重要なフックの考え方を、サンプルの動作のひとつである「記事公開時の処理追加」の実装を元に解説します。フックはこの後の画面出力、処理の非同期化や管理画面の付与でも使われていきます。
- 処理のクラス化(この記事)
- WordPress 拡張におけるモジュール設計として、PHP のクラスを用いた方法を紹介します。分かりやすく、他のモジュールとの競合を最小限に抑えられる手法です。
- 外部 API の呼び出し
- LWWS などの REST API に対して WordPress からリクエストを送る解説です。また、ユーザによって設定が異なる値がある場合のモジュール構成も合わせて紹介します。
- 外部 API 呼び出しの非同期化
- 外的要因などで処理スピードの低下が懸念される場合の処理方法です。WP-Cron を用いたスケジュール化手法を解説しています。
- テンプレートファイルからの情報出力
- テンプレートファイルに処理を記述し出力する場合に、拡張モジュールと疎結合にする実装法を紹介します。アクションフックの活用例としても有効です。
- 管理画面をつける
- 管理画面に設定欄を設けユーザが拡張の機能をコントロールできるようにする手法の解説です。また、本連載中のソースコードに最終的なリファクタリングをかけ、他の開発者にこの拡張の意味を表現するプログラミングテクニックも解説します。
- まとめ
- 本連載の概要とまとめ、そして目次です。