[WordPress]新規ユーザー登録時に選べる権限を制限する

Wordpressにて、自分に設定されている権限レベル以下の権限のみを取得して、
新規登録画面で登録出来る権限を制御できるようにしてみた。

権限一覧の取得

1
2
3
4
function xx(){
  global $wp_roles;
  $all_roles = $wp_roles->roles;
}

出力

1
2
3
4
5
6
7
8
9
10
11
[(権限名-スラッグ)] => Array
        (
            [name] => 権限名
            [capabilities] => Array
                (
                    [read] => 1
                    [level_0] => 1
                    権限内容                    
                )

        )

シリアライズ

自分に設定されている権限を取得する。
ただし、DBを直接除くとシリアライズされている。

とはいえ、取得は普通にWPの関数で可能。

get_user_meta(ID, 'wp_capabilities', true);

セットは以下のように

update_user_meta($user_id, 'wp_capabilities', ['staff' => 1]);

取得

自分のレベルを取得

1
2
global $current_user;
$mylevel = $current_user->user_level;

これで一見取れているようにみえたが、なぜかレベルの低いユーザーもレベルが10と取得されてしまった。
なので、実際に入っているデータの、level_xxを見て一致させていく泥臭い手法をとった。

1
2
3
4
5
6
7
8
9
10
11
12
$uid = wp_get_current_user()->get('ID');
//自分のロール
$my_role = get_user_meta($uid, 'wp_capabilities', true);
$my_role = key($my_role);
$myobj = $wp_roles->role_objects[$my_role]->capabilities;
$mylevel = 0;
for($i = 10; $i>=0; $i--){
    if(isset($myobj['level_'.$i]) && $myobj['level_'.$i]){
        $mylevel = $i;
        break;
    }
}

アクセス可能な権限をレベルで判別

あとは取得したレベルと、権限の一覧のレベルを比べて、自分の方が大きければ取得していけばよい。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
global $wp_roles;

$aste_user_role = [];
foreach($wp_roles->role_objects as $key=>$role){
    $level = 0;
    for($i = 10; $i>=0; $i--){
        if(isset($role->capabilities['level_'.$i]) && $role->capabilities['level_'.$i]){
            $level = $i;
            break;
        }
    }
    if($mylevel >= $level){
        $aste_user_role[] = [$key, $wp_roles->role_names[$key]];
    }
}

結果

1
2
3
4
5
6
7
8
9
10
11
12
13
array (size=8)
  0 => 
    array (size=2)
      0 => string 'administrator' (length=13)
      1 => string 'システム管理者' (length=21)
  1 => 
    array (size=2)
      0 => string 'staff' (length=5)
      1 => string 'スタッフ' (length=12)
  2 => 
    array (size=2)
...
...

表示

新規登録

新規登録画面への表示は、user_new_formのフックで行う。
フック内でHTMLを直接書いて対応。

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
//ユーザー登録画面
function user_new_form_css() {
  ?>
  <table class="form-table">
  <tr>
      <th scope="row">権限ロール <span class="description">(必須)</span></th>
      <td><select name="user_role">
                <?php
                $tempo = '';
                foreach ($aste_user_role as $val) {
                    $selected = 'selected';
                    if($val[0] == 'subscriber'){
                        $tempo .= '<option value="' . $val[0] . '"' . $selected . '>' . $val[1] . '</option>';
                    }else{
                        $tempo .= '<option value="' . $val[0] . '" >' . $val[1] . '</option>';
                    }
                }
                echo $tempo;
                ?>
            </select>
        </td>
    </tr>
    </table>
    <?php
}
add_action( 'user_new_form', 'user_new_form_css' );

編集

編集画面は、personal_optionsのフックで対応。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function add_profile_custom ($profileuser) {
  //権限
    global $aste_user_role; //自身が参照可能な権限リスト
    set_aste_role();
    $html = '<tr><th scope="row">権限ロール <span class="description">(必須)</span></th>';
    $html .= '<td><select name="user_role">';
    //このユーザーの権現を取得
    $current_role = get_user_meta($profileuser->ID, 'wp_capabilities', true);
    $current_role = key($current_role);
    foreach ($aste_user_role as $val) {
        $r = $current_role;
        $selected = '';
        if ($r == $val[0]) {
            $selected = ' selected="selected" ';
        }
        $html .= '<option value="' . $val[0] . '"' . $selected . '>' . $val[1] . '</option>';
    }
    $html .= '</select></td></tr>';
    echo $html;
}
add_action( 'personal_options', 'add_profile_custom');

登録処理

登録は新規は、user_register、更新は、profile_update
どちらも処理としては同じ。
$_POSTから取得した値をシリアライズして入れる、のみ。

1
2
3
4
5
6
7
function save_custom_options_fields( $user_id ) {
  //権限ロール
    $role_name = $_POST['user_role'];
    update_user_meta($user_id, 'wp_capabilities', [$role_name => 1]);
}
add_action( 'profile_update', 'save_custom_options_fields' ); //更新
add_action('user_register', 'save_custom_options_fields');  //新規登録

既存のものを非表示に

既存で表示されている権限設定のセレクトボックスを非表示に。

新規登録

上記、新規登録で項目を追加したフックと同じ関数内で実装する。
特定のクラスもIDも振られてないので、x番目と指定して非表示とする。
ただし、これはCSS3となっているので非対応のブラウザだと見えてしまうと思う。
他にいい方法があれば知りたい。

1
2
3
?><style type="text/css">
  table.form-table tr.form-field:nth-of-type(9)
</style><?php

編集

上記、編集で項目を追加したフックと同じ関数内で実装する。
こちらはクラスが振ってあるので、それを指定して非表示とする。

1
2
3
?><style type="text/css">
  .user-role-wrap, /*権限グループ*/
</style><?php

まとめ

これにて完成。
非表示にする箇所がかなり無理矢理だけれども、なんとか見た目は整った。
プラグインなどを使えばこの辺一発で出来たりするのだろうか。
ちなみに、権限の編集にはプラグインを使用した。
WordPress › User Role Editor « WordPress Plugins

参考

security – Getting a List of Currently Available Roles on a WordPress Site? – WordPress Development Stack Exchange
wordpressのユーザ権限を管理画面以外から変更する必要があり、~ – Yahoo!知恵袋

   このエントリーをはてなブックマークに追加