TinyWPDK

Download TinyWPDK  Download TinyWPDK

TinyWPDKは、WordPressのアクションやフィルターをわかりやすく管理するための非常に小さなプログラムです。テーマを開発するとき、通常はfunctions.phpにアクションやフィルタを定義しますが、TinyWPDKでは、クラスベースでクエリタイプ(WordPressのis_pageis_singleなどで区別されるタイプ)に応じて呼び分けすることができます。また、クエリタイプや個別のページ、タグなどアクションやフィルター別に分類して管理できるため、リクエストごとに細かい制御が可能です。

tinywpdk-concept

インストール

ダウンロードリンクからソースを落として、適当な場所に展開してください。例えば、使用するテーマディレクトリ下に展開します。展開すると以下のような階層構造になっています。controllerディレクトリには、Webサーバーのプロセスで書き込み権限を設定します。

themes
|- mytheme
  |- tiny-wpdk
    |- controller
    |- ...

初期化

以下のphpファイルをテーマのfunctions.php内でインクルードします。tiny-wpdkは、parse_queryアクション(管理画面は、after_setup_themeアクション)のタイミングで初期化されます。

include get_template_directory() . '/tiny-wpdk/tiny-wpdk.php';

アクションやフィルタの呼び出し順については、以下の公式ドキュメントを参照してください。

プラグイン_API/アクションフック一覧

初期化オプション

起動時に以下のようなオプションが用意されています。DEVELOPMENTモードでは、クラス情報のキャッシュを利用しません。毎回クラスのメソッドからアクションやフィルタに該当するインスタンスメソッドを探索し、add_actionadd_filterを呼び出します。

<?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ディレクトリにファイルを作成します。ソースアーカイブには、最初から一通りのコントローラクラスが用意されているので、必要なアクションやフィルタ定義をすぐに追加していくことができます。

例えば、コントローラの実装は以下のようになります。

<?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アクションのタイミングで初回のみ呼ばれます。アクションやフィルタはクラスのインスタンスメソッドとして定義します。

アクションやフィルタの定義

アクションやフィルタのためのメソッドは、以下の正規表現ルールに従って定義します。

\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_postsparse_queryをadd_xxx関数で定義した場合との対応は以下のようになります。

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_actionadd_filterのデフォルト引数の値と同じです。

priorityに負数を指定したい場合は、以下のようにmをつけます。

public function wp_action__pre_get_posts_8m($qp_query)
{
    // do something
}
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のテンプレート階層の探索順と類似しています。

アーカイブ

カテゴリーアーカイブ
  1. Category{slug}
  2. Category{ID}
  3. Category
  4. Archive
  5. Index
  6. Default
日付ページ
  1. Date
  2. Archive
  3. Index
  4. Default
タグアーカイブ
  1. Tag{slug}
  2. Tag{ID}
  3. Tag
  4. Archive
  5. Index
  6. Default

カスタム投稿タイプアーカイブ

  • {post_type}
  • PostTypeArchive
  • Archive
  • Index
  • Default

個別投稿ページ

  1. Single{slug}
  2. Single{ID}
  3. Single{post_type} or SinglePost
  4. Single
  5. Singular
  6. Index
  7. Default

固定ページ

  1. Page{pagename}
  2. Page{ID}
  3. Page
  4. Singular
  5. Index
  6. Default

サイトフロントページ

  1. FrontPage
  2. Home
  3. Index
  4. Default

または

  1. FrongPage
  2. 固定ページプロセス

フロントページ:固定ページ&ページフロントがページ

  1. Home
  2. Index
  3. Default

コメントポップアップページ

  1. CommentPopup
  2. Index
  3. Default

404エラーぺージ

  1. HTTP404
  2. Index
  3. Default

404ページの場合、最も遅い404の検出のタイミングが$wp->query()の後になるため、通常のページのプロセスが最初に実行されます。

添付ファイル表示

  1. {MIME_TYPE} 例:text/plainの場合
    1. MimeTypeText
    2. MimeTypePlain
    3. MimeTypeTextPlain
  2. SingleAttachment
  3. Single
  4. Index
  5. Default

検索結果ページ

  1. Paged
  2. Search
  3. Index
  4. Default

Robots

  1. Robots
  2. Index
  3. Default

Feed

  1. Feed
  2. Index
  3. Default

Trackback

  1. Trackback
  2. Index
  3. Default

Embed

  1. Embed{post_type}
  2. Embed
  3. Index
  4. Default

管理画面

管理画面は、AdminControllerに限られます。

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ディレクトリの下に生成されます。

テンプレート

コントローラ内でメンバ変数として定義した変数は、デフォルトでテンプレートに引き継がれます。

class SingleController extends TinyWPDK_Controller
{
    public function init()
    {
        $this->myvar = "variable";
    }
}
<?php get_header(); ?>
<?php echo $myvar; // => variable ?>
<?php echo $this->get('myvar'); // => variable ?>
<?php get_footer(): ?>

ただし、header.phpやfooter.php、sidebar.phpのようなテンプレート階層に含まれないテンプレートに関しては、以下の関数で値の取得が可能です。

<?php echo tiny_wpdk_param('myvar', 'default value'); ?>

テンプレートへのフックを停止したい場合は、以下のオプションを設定します。

class SingleController extends TinyWPDK_Controller
{
    public function init()
    {
        $this->options['use_template'] = false;
    }
}

テンプレートフックの停止をした場合、コントローラのメンバ変数をテンプレートで利用するには、以下が使えます。

// 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という名前のテンプレートがテンプレートディレクトリにある場合、レイアウトファイルを使ってコンテンツを出力します。

<?php get_header() ?>

<div id="main">
    <?php echo $content ?>
</div>

<div id="sidebar">
  <!-- sidebar -->
</div>

<?php get_footer() ?>

また、Controllerの階層と同様にlayoutもページタイプによって使い分けることが可能です。Controllerの階層と同様な探索順でlayoutのテンプレートを探します。最初に見つかったものが利用されます。

例:カテゴリーアーカイブの場合

  1. layout-category-{slug}
  2. layout-category{ID}
  3. layout-category
  4. layout-archive
  5. layout-index
  6. layout-default
  7. layout

テンプレートの出力

任意のテンプレートは以下のようにして出力可能です。Controllerで設定したパラメータも同様にテンプレートの中から利用可能です。

<?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等の処理は上記では実行されません。

また、テンプレート出力で特定のレイアウトを使いたい場合は、以下のようにできます。

<?php echo $this->render("content", "layout-ranking") ?>

複数の指定したレイアウト候補からレイアウトを選択したい場合は以下のようにします。

<?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"]) ?>

フラグメント

任意のコンテンツブロックを別のテンプレートで使用したい場合は、以下のようにできます。

<?php $this->begin('information') ?>
このコンテンツは、別のテンプレートで使いたいと思います。
<?php $this->end() ?>

<?php echo $this->render('ranking') ?>
<div class="alert-info">
<?php echo $this->information ?>
</div>

同じ名前で続けて登録したい場合はappendを指定できます。

<?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で囲まれるフラグメントを評価します。{{}}は、プレースホルダとして置換されます。

<?php $this->renderIn('article', ['foo' => 'bar']) ?>
  articleテンプレートの出力: {{content}}<br>
  fooパラメータ:{{foo}}
<?php $this->end(true) ?>

renderIfNotExistは、テンプレートが存在しない場合のみ、endで囲まれるフラグメントを評価します。

<?php $this->renderIfNotExist('article') ?>
articleが存在しない場合、このメッセージが表示されます。
<?php $this->end(true) ?>

管理画面でのふるまい

メニュー作成

管理画面でメニューを作成するにはwordpressの関数admin_xxx_pageを使いますが、TinyWPDKでは以下のようにもできます。

//
// 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の中では、もう少し簡単に作成できます。

/**
 * 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パラメータの値に応じて呼びされるメソッドが特定されます。beforeafterは各アクションが処理される前後で呼ばれます。

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があれば、レイアウトが有効になります。

<?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

アクションやフィルタの呼び出しを中継します。アクションやフィルタの前後に色々な処理を実行することができます。インターセプタにはクラスまたは関数を指定することができます。デバッグ時などに便利です。

tiny_wpdk_start(TinyWPDK::DEVELOPMENT, array(
    'interceptor' => array(
        'MyInterceptor'  => TinyWPDK_Interceptor::TYPE_CLASS,
        'my_interceptor' => TinyWPDK_Interceptor::TYPE_FUNCTION
    )
));

クラス指定

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というメソッドで呼び出されます。明示的に実行したい場合は、以下のようにします。

$this->invoke();

beforeメソッドでfalseを返すと、以降のInterceptorは実行されません。ですが、アクションやフィルタ自体は実行されます。

関数指定

関数の場合は、Interceptorのオブジェクトとアクションやフィルタに渡される引数が渡されます。関数の場合は、明示的にinvokeを呼ぶ必要があります。

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;
}

$directionbeforeのとき、関数の返り値でfalseを指定すると後続のInterceptorは実行されません。

ダウンロード

以下の規約のもと、ご自由にご利用ください。

規約

  • ご利用は自己責任にてお願いいたします。
  • バックアップは必ずお取りください。
  • 如何なる不具合やトラブル、損害についても責任を負いかねますのでご了承ください。

こちらに移動しました。2016/6/2

https://sourceforge.net/projects/tinywpdk/

Download TinyWPDK