WordPress 角色(Role)與權限(capability)簡介


作者: | 2010/11/11 | 2 則迴響


最近幾個月非常忙,所以很久都沒發文了… 不過總覺得這樣不太好,所以決定有空還是整理一下工作上遇到的問題。首先要分享的是WordPress 3.0有關會員權限的問題,我想首先從WordPress的使用者權限機制稍作說明來開始好了。

WP 會員權限機制的發展

WordPress早期在1.5版時開始使用的權限設計是採用User Level機制,也就是將內建的全部權限切分為十個等級,而每個等級能做的事都定義出來,所以使用者可以透過存取user的等級來決定權限。

這樣充滿限制的權限設計,可想而知不會太長命,果然到了WP2.0開始就建議大家換用角色(Roles)與能力(Capabilities)機制了,並且到了WP3.0,User Level就成為了不建議使用(deprecated)的功能了。

WP 自訂角色(Roles)與能力(Capabilities)

簡單來說,Roles與Capabilities的機制就是每個角色能擁有許多不同的能力,除了內建的六個角色(超級管理者-Super Admin, 管理者-Administrator, 編輯-Editor, 作者-Author, 投稿者-Contributor, 訂閱者-Subscriber),開發人員也能自訂新的角色,而能力也是如此,除了內建的能力(讀文章、發表文章、管理使用者…等等),也能自訂新的能力。自訂新角色時也能順便指定新的自訂能力,方式是:

[code]
add_role(‘test_role’, ‘測試者’, array(‘test_cap’));
[/code]

你可以把這個語法寫在自訂的plugin裡,當然也能用在佈景(theme)的function.php中。其中test_role是我自訂的新角色,「測試者」是新角色顯示的名稱,而test_cap則是此角色擁有的能力,執行了這行,就代表你的WP出現了一個新的角色-test_role,而這個角色擁有test_cap這項能力。

為什麼你會覺得WP的會員權限很鳥?

我知道WordPress的會員權限設定常常飽受批評,就拿Drupal的權限設定來說,預設的後台設置就非常完整的提供了各項存取的權限設定,WP一比較之下,感覺就弱掉了。不過我個人認為,WP也能辦到一樣的事,只是通常在開發Plugin時,開發者沒有把權限設定的code完整的實作出來。

因為在我們定義好新的角色或新的能力之後,我們必須在自訂的佈景或plugin中加上判斷,透過取得目前User的所屬角色及擁有的能力,再來決定對不同權限作不同的呈現或動作。我想WP預設的會員權限這麼弱,大概因為畢竟WP的大戶是部落客,會員通常只有格主一人,所以權限部份時常沒被定義到也很正常XD。

實作有問題!?

好的,就在實作自訂角色及自訂能力時,問題發生了。有個內建的function叫current_user_can(),wp的官方文件說,我們可以透過它來判斷目前的使用者是否為某特定的角色,或者是否擁有特定的能力,因此它的參數可以是「角色」也可以是「能力」,但是我測試的結果是,給它自訂的「角色」去做判斷,運作是正常的;但給它自訂的「能力」進行判斷,運作就不正常了。

在Google了幾個小時,以及罵了好幾聲髒話之後,我決定去看原始碼。這些跟權限相關的functions定義在wp-includes / capabilities.php 裡,從current_user_can()出發,可以發現它又呼叫了has_cap這個function,去取得目前使用者的所有能力,事情就錯在這裡。

在它把目前使用者所有的能力都放進$capabilities這個陣列後,我自訂的能力它找不到,自訂的角色卻找得到,於是print_r這個陣列後發現它長這樣:

[code]
Array ( [0] => test_cap [test_role] => 1 )
[/code]

白話一點說,它裡面有兩個值。我們可以用$capabilities[0] 去取得 test_cap 這個值,也可以用 $capabilities[‘test_role’]去取得1這個值,偏偏在has_cap裡面,它統一用 $capabilities[‘角色或能力名’] 這種方式來判斷是否擁有某能力,當然 current_user_can 也一併被影響了,所以當我們用 current_user_can(‘test_cap’)時,它只會回傳false,而current_user_can(‘test_role’)才會正確的取得1,並且被判定為True,真是XX你個OO。

解決方案

簡單的解決方式就是用它正常的部份,也就是用角色來判斷就好:

[code]
if (current_user_can(“test_role”))
{
echo ‘yes, he is the right role!’;
}
[/code]

缺點是很鳥、不正常、不合理,照理說能力是可以跨角色的,只拿角色判斷,完全不彈性,不過在plugin設計不複雜的情況下是可行的。那如果我們現階段真的很想用能力來做判斷怎麼辦? 那你可以這樣做:

[code]
// 先取得目前的使用者所屬的角色
$current_user = wp_get_current_user();
$user_roles = $current_user->roles;

// 取得使用者所屬角色後,再檢查這個角色擁有的能力
$role = get_role($user_roles[0]);
foreach ($role->capabilities as $hiscap)
{
// 如果這個角色擁有 test_cap 這個自訂能力
if ($hiscap == ‘test_cap’)
{
echo ‘是的,現在的使用者有test_cap這項能力’;
break;
}
}
[/code]


標籤:,

分類:,

本文作者是Audi Lu

2 則留言

  • Kay.L says:

    因為沒有 define TRUE or FALSE

    add_role(‘test_role’,’測試者’,array(‘test_cap’));

    WP_Role Object
    (
    [name] => test_role
    [capabilities] => Array
    (
    [0] => test_cap
    )

    )

    add_role(‘test_role2′,’測試者 2’,array(‘test_cap2’ => true)); // require to define true or false

    WP_Role Object
    (
    [name] => test_role2
    [capabilities] => Array
    (
    [test_cap2] => 1
    )

    )

    print_r(get_role(‘test_role2’)); // 看看有沒有正確增加

發佈回覆給「Kay.L」的留言 取消回覆

發佈留言必須填寫的電子郵件地址不會公開。

*

*

*

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料