WordPressで権限を付加する「add_cap」で思い通りにいかない場合のメモ

カスタム投稿タイプなどを使っている時に当該ポストタイプの権限を後から付加することがありますが、この時に使うadd_capでハマったのでメモしておきます。

例えば「event」というカスタム投稿タイプがあるとして、

add_action( 'init', 'role_capabilities' );
function role_capabilities(){
	global $wp_roles;
	 if ( isset($wp_roles) ) {
	 	$wp_roles->add_cap( 'contributor', 'delete_published_events' );
	}
}

こんな感じでfunctions.phpやプラグイン中で権限を付加することがあると思います。
この例では「寄稿者」にデフォルトでは用意されていない権限の「公開済み記事の削除権限」を付加しています。

この例のadd_capを使っている箇所を、

//コメントアウト
//$wp_roles->add_cap( 'contributor', 'delete_published_events' );

こんな感じでコメントアウトしてしまいます。

するとどうでしょう、なんとこの例ではコメントアウトしても寄稿者で公開済み記事の削除ができるままなのです。

なぜこんなことが起こるのか、そのカラクリはコアファイルのadd_capの箇所を見てみるとわかります。

// wp-includes/capabilities.php 
function add_cap( $role, $cap, $grant = true ) {
        if ( ! isset( $this->roles[$role] ) )
                return;

        $this->roles[$role]['capabilities'][$cap] = $grant;
        if ( $this->use_db )
                update_option( $this->role_key, $this->roles );
}

ここでupdate_option、つまりデータベース内に権限設定を保存しているんです。

だからコメントアウトした後でも前設定が有効になってしまうのです。
なのでもし前設定を破棄したい時などは、

$wp_roles->remove_cap( 'contributor', 'delete_published_events' );

といった具合に「remove_cap」を使って排除してあげましょう。


私のように色々やりすぎて謎の権限を山ほど作ってしまったり、どの権限を削除してしまったのかもわからなくなってしまった時はDB内のprefix_optionsテーブルの中にあるprefix_user_rolesレコードの中身を他のWPから移し替えるなどして初期化すると良いと思います(prefix部分は個々の環境に合わせてください)。

現状のWPで権限周りはremove_capでひとつづつ消すか、データベースの当該レコードの置き換え、これしか初期化の方法がありません。

わかってしまえばなんということはないのですが、このadd_cap使用時の気軽さがDB操作が加わっているように見えないのでfunctions.phpなどに書いた当該コード部分を毎回参照して権限付与しているものと勘違いしがちなのだと思います。
用語もWP的にはinsertやupdate、deleteといったものが主にDB操作系ですがadd removeというのは珍しいですし、DB内でもoptionsテーブル中にシリアライズ化されて保存されているので気がつきにくいんです・・・。

長く使っている人ほど先入観でやられてしまいそうな気がします。