TinyWPDKは、WordPressのアクションやフィルターをわかりやすく管理するための非常に小さなプログラムです。テーマを開発するとき、通常はfunctions.phpにアクションやフィルタを定義しますが、TinyWPDKでは、クラスベースでクエリタイプ(WordPressのis_page
やis_single
などで区別されるタイプ)に応じて呼び分けすることができます。また、クエリタイプや個別のページ、タグなどアクションやフィルター別に分類して管理できるため、リクエストごとに細かい制御が可能です。
インストール
ダウンロードリンクからソースを落として、適当な場所に展開してください。例えば、使用するテーマディレクトリ下に展開します。展開すると以下のような階層構造になっています。controllerディレクトリには、Webサーバーのプロセスで書き込み権限を設定します。
1 2 3 4 5 |
themes |- mytheme |- tiny-wpdk |- controller |- ... |
初期化
以下のphpファイルをテーマのfunctions.php内でインクルードします。tiny-wpdkは、parse_query
アクション(管理画面は、after_setup_theme
アクション)のタイミングで初期化されます。
1 |
include get_template_directory() . '/tiny-wpdk/tiny-wpdk.php'; |
アクションやフィルタの呼び出し順については、以下の公式ドキュメントを参照してください。
初期化オプション
起動時に以下のようなオプションが用意されています。DEVELOPMENT
モードでは、クラス情報のキャッシュを利用しません。毎回クラスのメソッドからアクションやフィルタに該当するインスタンスメソッドを探索し、add_action
やadd_filter
を呼び出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?php // DEVELOPMENT or PRODUCTION (default) tiny_wpdk_start(WP_DEBUG ? TinyWPDK::DEVELOPMENT : TinyWPDK::PRODUCTION, array( // falseだと、Controller階層の探索を行ないません。 'controller_lookup' => true, // Controllerのクラス名の先頭に付加する文字列 // クラス名が重複する場合などに利用します。 // ex) My // DefaultController => MyDefaultController 'controller_prefix' => '', // tiny-wpdkの初期化アクション 'bootstrap_action' => 'parse_query', // AdminControllerの初期化アクション 'admin_bootstrap_action' => null, // FirstControllerの初期化アクション 'first_controller_bootstrap_action' => 'after_setup_theme', // 起点のInterceptor 'root_interceptor' => 'TinyWPDK_Interceptor', // interceptor、すべてのアクションやフィルタを中継する(class name or function) 'interceptor' => null, // controllerのあるディレクトリ 'controller_directory' => TEMPLATEPATH . DIRECTORY_SEPARATOR . 'controller', // コントローラ階層のすべてのコントローラを実行する // デフォルトでは、最初に見つかった最も優先度の高いコントローラのみが実行される 'extend_controller' => true, // テンプレートディレクトリ 'template_directory' => TEMPLATEPATH, // adminのテンプレートディレクトリ(デフォルトはtemplate_directoryと一緒) 'admin_template_directory' => join(DIRECTORY_SEPARATOR, array(TEMPLATEPATH ,'view', 'admin')), )); ?> |
各種フックのためのController
各種フックのためのControllerを作成します。デフォルトでは、展開したtiny-wpdkディレクトリ下のcontrollerディレクトリにファイルを作成します。ソースアーカイブには、最初から一通りのコントローラクラスが用意されているので、必要なアクションやフィルタ定義をすぐに追加していくことができます。
例えば、コントローラの実装は以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php class SingularController extends TinyWPDK_Controller { public function init() { // called only first time } // add_action('pre_get_posts', array($this, 'wp_action__pre_get_posts'), 8, 1); public function wp_action__pre_get_posts_8($wp_query) { // do something } } |
TinyWPDK_Controller
を継承します。init
は、parse_query
アクションのタイミングで初回のみ呼ばれます。アクションやフィルタはクラスのインスタンスメソッドとして定義します。
アクションやフィルタの定義
アクションやフィルタのためのメソッドは、以下の正規表現ルールに従って定義します。
1 |
\Awp_(?P<type>action|filter)__(?P<hook>[a-z][a-z_]*[a-z])(?:_(?P<priority>[0-9]+(m|p)?))?(?:_args_(?P<args>[0-9]+))? |
例えば、pre_get_posts
やparse_query
をadd_xxx関数で定義した場合との対応は以下のようになります。
1 2 3 4 5 |
public function wp_action__pre_get_posts_8_args_1($wp_query) {} => add_action('pre_get_posts', array($this, 'wp_action__pre_get_posts_8_args_1'), 8, 1); public function wp_filter__parse_query_10m_args_1($wp_query) {} => add_filter('parse_query', array($this, 'wp_filter__parse_query_10m_args_1'), -10, 1); |
アクションの場合は、wp_action__
で、フィルタの場合は、wp_filter__
で始まります。その後、「イベント名_優先度_args_引数」の数と続きます。優先度や引数定義は任意です。デフォルトで、優先度は10
、引数の数は1
にセットされています。これは、WordPressのadd_action
やadd_filter
のデフォルト引数の値と同じです。
priorityに負数を指定したい場合は、以下のようにm
をつけます。
1 2 3 4 |
public function wp_action__pre_get_posts_8m($qp_query) { // do something } |
1 2 |
public function wp_action__pre_get_posts_8m($wp_query) {} => add_action('pre_get_posts', array($this, 'wp_action__pre_get_posts_8m'), -8, 1); |
Controllerの優先度
TinyWPDKは、WordPressのクエリのタイプから該当するControllerを探索していきます。各リクエストタイプとの対応および探索順は以下のようになります。最初に見つかったControllerクラスが呼ばれます。これは、WordPressのテンプレート階層の探索順と類似しています。
アーカイブ
カテゴリーアーカイブ
- Category{slug}
- Category{ID}
- Category
- Archive
- Index
Default
日付ページ
- Date
- Archive
- Index
Default
タグアーカイブ
- Tag{slug}
- Tag{ID}
- Tag
- Archive
- Index
Default
カスタム投稿タイプアーカイブ
- {post_type}
- PostTypeArchive
- Archive
- Index
Default
個別投稿ページ
- Single{slug}
- Single{ID}
- Single{post_type} or SinglePost
- Single
- Singular
- Index
Default
固定ページ
- Page{pagename}
- Page{ID}
- Page
- Singular
- Index
Default
サイトフロントページ
- FrontPage
- Home
- Index
Default
または
- FrongPage
- 固定ページプロセス
フロントページ:固定ページ&ページフロントがページ
- Home
- Index
Default
コメントポップアップページ
- CommentPopup
- Index
Default
404エラーぺージ
- HTTP404
- Index
Default
404ページの場合、最も遅い404の検出のタイミングが$wp->query()の後になるため、通常のページのプロセスが最初に実行されます。
添付ファイル表示
- {MIME_TYPE} 例:text/plainの場合
- MimeTypeText
- MimeTypePlain
- MimeTypeTextPlain
- SingleAttachment
- Single
- Index
Default
検索結果ページ
- Paged
- Search
- Index
Default
Robots
- Robots
- Index
Default
Feed
- Feed
- Index
Default
Trackback
- Trackback
- Index
Default
Embed
- Embed{post_type}
- Embed
- Index
Default
管理画面
管理画面は、AdminControllerに限られます。
1 2 3 4 5 6 7 8 9 10 11 12 |
class AdminController extends TinyWPDK_AdminController { public function init() { // do something } public function wp_action__admin_head() { // do something } } |
FirstController
parse_queryアクション以前のアクションやフィルタをキャッチするには、FirstController
を使います。FirstController
は、デフォルトではafter_setup_theme
アクションのタイミングで初期化されます。
クエリの履歴
pre_get_postsやthe_postsが呼ばれた回数を保存することができます。
アクションやフィルタの情報
一度読み込まれたクラスのメタデータはファイルにキャッシュされます。アクションやフィルタを追加した時は、キャッシュファイルを削除します。デフォルトでは、tiny-wpdk/controller/hooksにあります。controllerディレクトリの下に生成されます。
テンプレート
コントローラ内でメンバ変数として定義した変数は、デフォルトでテンプレートに引き継がれます。
1 2 3 4 5 6 7 |
class SingleController extends TinyWPDK_Controller { public function init() { $this->myvar = "variable"; } } |
1 2 3 4 |
<?php get_header(); ?> <?php echo $myvar; // => variable ?> <?php echo $this->get('myvar'); // => variable ?> <?php get_footer(): ?> |
ただし、header.phpやfooter.php、sidebar.phpのようなテンプレート階層に含まれないテンプレートに関しては、以下の関数で値の取得が可能です。
1 |
<?php echo tiny_wpdk_param('myvar', 'default value'); ?> |
テンプレートへのフックを停止したい場合は、以下のオプションを設定します。
1 2 3 4 5 6 7 |
class SingleController extends TinyWPDK_Controller { public function init() { $this->options['use_template'] = false; } } |
テンプレートフックの停止をした場合、コントローラのメンバ変数をテンプレートで利用するには、以下が使えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// in controller TinyWPDK_SharedHolder::set('var', 'hoge'); // or $this->hoge = 'foo'; TinyWPDK_SharedHolder::set('_params', $this->getParameters()); // in template <?php echo tiny_wpdk_params('var', 'default value'); // hoge ?> // or <?php echo tiny_wpdk_params('hoge'); // foo ?> // or <?php echo $prop->var // foo ?> // or <?php echo $param->get('var', 'default value') // foo ?> |
やや高度なテンプレート
昨今のWebアプリケーションフレームワークのテンプレートエンジンのように、ちょっとしたレイアウト機能も使えます。layout.phpという名前のテンプレートがテンプレートディレクトリにある場合、レイアウトファイルを使ってコンテンツを出力します。
1 2 3 4 5 6 7 8 9 10 11 |
<?php get_header() ?> <div id="main"> <?php echo $content ?> </div> <div id="sidebar"> <!-- sidebar --> </div> <?php get_footer() ?> |
また、Controllerの階層と同様にlayoutもページタイプによって使い分けることが可能です。Controllerの階層と同様な探索順でlayoutのテンプレートを探します。最初に見つかったものが利用されます。
例:カテゴリーアーカイブの場合
- layout-category-{slug}
- layout-category{ID}
- layout-category
- layout-archive
- layout-index
- layout-default
- layout
テンプレートの出力
任意のテンプレートは以下のようにして出力可能です。Controllerで設定したパラメータも同様にテンプレートの中から利用可能です。
1 2 3 4 5 |
<?php echo $this->render("header") // include header.php ?> <?php echo $content ?> <?php echo $this->render("_ranking", array("myparam" => "hoge")) // include _ranking.php with parameters ?> |
上記では、get_header
関数でなくTinyWPDKの機能を使ってテンプレートを呼び出しています。処理の内容的には大きな違いはありませんが、get_header
関数の中で呼び出しているfilter等の処理は上記では実行されません。
また、テンプレート出力で特定のレイアウトを使いたい場合は、以下のようにできます。
1 |
<?php echo $this->render("content", "layout-ranking") ?> |
複数の指定したレイアウト候補からレイアウトを選択したい場合は以下のようにします。
1 2 3 |
<?php echo $this->render("content", ["layout" => ["layout-latest-ranking", "layout-old-ranking"]]) ?> // または <?php echo $this->render("content", ["myparam" => "value"], ["layout-latest-ranking", "layout-old-ranking"]) ?> |
フラグメント
任意のコンテンツブロックを別のテンプレートで使用したい場合は、以下のようにできます。
1 2 3 4 5 |
<?php $this->begin('information') ?> このコンテンツは、別のテンプレートで使いたいと思います。 <?php $this->end() ?> <?php echo $this->render('ranking') ?> |
1 2 3 |
<div class="alert-info"> <?php echo $this->information ?> </div> |
同じ名前で続けて登録したい場合はappend
を指定できます。
1 2 3 4 5 6 7 8 9 10 11 |
<?php $this->begin('information') ?> <li><span class="date">2016/5/1</span><span class="text">新着</span></li> <?php $this->end() ?> <?php $this->begin('information', ['append' => true]) ?> <li><span class="date">2016/5/1</span><span class="text">新着</span></li> <?php $this->end() ?> <ul> <?php echo $this->information ?> </ul> |
その他のrender
renderIn、renderIfNotExistは通常のrenderと少し異なります。
renderIn
は、該当のテンプレートを出力してendで囲まれるフラグメントを評価します。{{}}
は、プレースホルダとして置換されます。
1 2 3 4 |
<?php $this->renderIn('article', ['foo' => 'bar']) ?> articleテンプレートの出力: {{content}}<br> fooパラメータ:{{foo}} <?php $this->end(true) ?> |
renderIfNotExist
は、テンプレートが存在しない場合のみ、endで囲まれるフラグメントを評価します。
1 2 3 |
<?php $this->renderIfNotExist('article') ?> articleが存在しない場合、このメッセージが表示されます。 <?php $this->end(true) ?> |
管理画面でのふるまい
メニュー作成
管理画面でメニューを作成するにはwordpressの関数admin_xxx_page
を使いますが、TinyWPDKでは以下のようにもできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// // mymenu // |- submenu // $adminMenu = new TinyWPDK_AdminMenu($handler); $adminMenu ->add('menu', array( 'menu_title' => 'mymenu', 'method' => 'mainMenu', 'menu_slug' => 'my_plugins')) ->add('submenu', array( 'parent' => 'my_plugins', 'menu_title' => 'submenu', 'method' => 'submenu')) ->register(); |
AdminControllerの中では、もう少し簡単に作成できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/** * AdminController is called in the administration view. */ class AdminController extends TinyWPDK_AdminController { /** * This is called when the controller object is initialized. * Normally, it's when after_setup_theme action is fired. */ public function init() { $this->addHandler('AdminMainMenuController', 'menu', array( 'menu_title' => 'メインメニュー', )); $this->addHandler('AdminSubMenuController', 'submenu', array( 'menu_title' => 'サブメニュー', 'parent' => 'AdminMainMenuController' )); } } |
addHandler
にはリクエストを処理するコントローラを指定します。
コントローラとビュー
handlerに指定されたコントローラは、_actionパラメータの値に応じて呼びされるメソッドが特定されます。before
やafter
は各アクションが処理される前後で呼ばれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class AdminMainMenuController extends TinyWPDK_AdminController { public function before($params) { } public function after($params) { } public function index($params) { $this->myvar = 'hoge'; return $this->render('index'); } public function update($params) { $this->myvar = 'hoge'; return $this->render('index'); } } |
管理画面でのテンプレートはadminディレクトリ下に作成します。例えば、上記ではindexアクション内でindexテンプレートを描画するように指定しているのでadmin/index.phpがテンプレートとして出力されます。admin/layout.phpがあれば、レイアウトが有効になります。
1 2 3 4 5 6 7 |
<?php echo $myvar; // hoge ?><code></code> <?php echo $this->get('myvar','default value'); // hoge ?> <form action="<?php echo $controller->page('update') ?>" method="post"> <input type="text" name="message" value=""> <button type="submit">Submit</button> </form> |
Interceptor
アクションやフィルタの呼び出しを中継します。アクションやフィルタの前後に色々な処理を実行することができます。インターセプタにはクラスまたは関数を指定することができます。デバッグ時などに便利です。
1 2 3 4 5 6 |
tiny_wpdk_start(TinyWPDK::DEVELOPMENT, array( 'interceptor' => array( 'MyInterceptor' => TinyWPDK_Interceptor::TYPE_CLASS, 'my_interceptor' => TinyWPDK_Interceptor::TYPE_FUNCTION ) )); |
クラス指定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class MyInterceptor extends TinyWPDK_Interceptor { // アクションやフィルタが呼ばれる直前に呼ばれる。 public function before() { $stack = implode(" < ", $this->getWPDK()->getControllerStack()); file_put_contents( get_template_directory() . '/debug.log', sprintf("%s [%s] - %s#%s\n", date('Y-m-d H:i:s'), $stack, get_class($this->getController()), $this->getMetaInfo()['method']), FILE_APPEND ); } // アクションやフィルタの呼び出し後に呼ばれる。 // $resultは、通常フィルタの戻り値が渡される。 public function after($result) { var_dump($result); return $result; } } |
アクションやフィルタの実際の処理は、invoke
というメソッドで呼び出されます。明示的に実行したい場合は、以下のようにします。
1 |
$this->invoke(); |
before
メソッドでfalse
を返すと、以降のInterceptorは実行されません。ですが、アクションやフィルタ自体は実行されます。
関数指定
関数の場合は、Interceptorのオブジェクトとアクションやフィルタに渡される引数が渡されます。関数の場合は、明示的にinvoke
を呼ぶ必要があります。
1 2 3 4 5 6 |
function my_interceptor($interceptor, $args, $direction, $result) { $stack = implode(" < ", $interceptor->getWPDK()->getControllerStack()); file_put_contents(get_template_directory() . '/debug.log', date('Y/m/d h:m:s') . " my_interceptor - $stack - " . get_class($interceptor->getController()) . "#". $interceptor->getMetaInfo()['method'] . PHP_EOL, FILE_APPEND); return $result; } |
$direction
がbefore
のとき、関数の返り値でfalse
を指定すると後続のInterceptorは実行されません。
ダウンロード
以下の規約のもと、ご自由にご利用ください。
規約
- ご利用は自己責任にてお願いいたします。
- バックアップは必ずお取りください。
- 如何なる不具合やトラブル、損害についても責任を負いかねますのでご了承ください。
こちらに移動しました。2016/6/2