fbpx

メニュー

WordPressで複雑な条件付きユーザー権限を実現する

高橋文樹 高橋文樹

この投稿は 7年半 前に公開されました。いまではもう無効になった内容を含んでいるかもしれないことをご了承ください。

タイトルの通りですが、今日やってみたらできたので、軽くご紹介。

WordPressの権限についておさらい

WordPressにはcapability(権限)とrole(役割)という概念があります。Codexのユーザーの種類と権限が勉強になります。

edit_usersなら他のユーザーを編集する権限、manage_optionsなら設定をいじれる権限となります。で、これらのcapabilityを複数持つのが購読者、編集者、管理者などのroleですね。

これらのうち、meta_capという特殊な権限があり、これは「他の権限に翻訳される権限」です。たとえば、 edit_post というcapabilityは「投稿を編集する権限があるか」を意味するのではなく、「特定の投稿を編集する権限があるか」という使われ方をします。実際の使い方を見ると、こんな感じです。

// $post_idの投稿を編集できるか
if ( current_user_can( 'edit_post', $post_id ) ) {
    // なんかする
}

内部的には「投稿の編集画面に入れるか」などの判断に使われています。こういう他の権限に変換しうる権限をmeta_capと呼ぶわけですね。

条件付きの権限

さて、上で見たとおり、ユーザーの権限を判別する関数は引数を2つ取ることができます。この性質を利用して、条件付きの権限を考えてみましょう。破滅派の例で言うと、これまでのアクセス権はこんな感じでした。

  • 投稿者は電子書籍を書き出すことができず、編集者以上じゃないと駄目
  • 電子書籍ファイルへの一覧は編集者以上じゃないとアクセスできない

され、ここで「プレミアム電子書籍サービス」が誕生したとします。具体的に言うと、HamePub Enterprise(エンタープライズ向けePub作成代行)ですね。ここでは、特定のユーザー(お金を払った投稿者)は特定のプレミアム投稿だけ書き出せるようになります。「すべての自分の投稿」ではなく、特定の投稿ですね。

その投稿のIDが10だとすると、これがオッケーにならないといけないわけですね。

if ( current_user_can( 'publish_epub', 10 ) ) {
    // オーケーなはず
}

ここで、「特別な投稿」はカスタムフィールド _is_secret が1になっているとしましょう。で、それを判別する関数をis_secret_post()とすると以下のような分岐が可能です。

if ( is_secret_post( 10 ) ) {
    // true になる
}

これら2つを組み合わせ、current_user_can('publish_epub', $post_id) としたとき……

  • 編集者は常にtrueとなる。
  • 投稿者の場合、該当する投稿が自分のもので、かつプレミアム投稿ならtrue、そうじゃなければfalse

が実現する事になります。そのための具体的なフィルターがmap_meta_capです。早速コードを見てみましょう。

/**
 * ユーザーに特別な権限を付与する
 */
add_filter( 'map_meta_cap', function( $caps, $cap, $user_id, $args ) {
    switch ( $cap ) {
        case 'publish_epub':
            // 引数は$argsに入ってくる
            $post_id = $args[0];
            // デフォルトだとそのまま追加されるので、削除
            $index = array_search( $cap, $caps );
            if ( false !== $index ) {
                array_splice( $caps, $index, 1 );
            } 
            // 投稿を取得
            $post = get_post( $post_id );
            if ( $post->post_author != $user_id ) {
                // 投稿の作者とユーザーIDが一致していなければ、
                // それはつまり編集者と同等の権限がないとダメ
                $caps[] = 'edit_others_posts';
            } elseif ( is_secret_post( $post ) ) {
                // 投稿の作者とユーザーIDが一致しており、
                // なおかつそれがプレミアム投稿なら、
                // ユーザーは投稿権限を持っていればよい
                $caps[] = 'edit_posts';
            } else {
                // 上記に一致しない場合、存在しない権限を割り当てる
                // 結果的に「権限がない」ことになる
                $caps[] = 'do_not_allow';
            }
            break;
    }
    return $caps;
}, 10, 4 );

というわけで、map_meta_capフィルターを使って「権限を別の権限に置き換えるフローに割り込みする」という手法を使うと、わりと複雑な権限が実現できるかと思います。

プラグインだと「役割」ベースの監理をしてくれるヤツは多いですが、特定の条件を満たした時だけなんかしたいという需要は結構あると思うので、参考にしてください。

さて、僕が実行委員長を務めるWordCamp Tokyo 2016はいよいよ今週土曜日、9月17日です。申し込みはこちらから。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-09-12-25-22

すべての投稿を見る

高橋文樹ニュースレター

高橋文樹が最近の活動報告、サイトでパブリックにできない情報などをお伝えするメーリングリストです。 滅多に送りませんので、ぜひご登録お願いいたします。 お得なダウンロードコンテンツなども計画中です。