WordPress源码深度解析之:`WordPress`的`Roles`和`Capabilities`:`add_role()`和`add_cap()`的底层实现。

咳咳,各位观众,晚上好!我是今晚的特邀码农讲师,江湖人称“代码挖掘机”。今天咱们要聊的是WordPress权限管理的骨架——RolesCapabilities,重点深入add_role()add_cap()这两个函数的底层运作机制。

为了避免大家听着犯困,我会尽量用轻松幽默的方式,把这些看似高深的代码逻辑掰开了、揉碎了,喂到你们嘴里。准备好了吗?Let’s dive in!

第一幕:Role与Capability——权限世界的基石

首先,咱们得明确一下,什么是Role,什么是Capability?

  • Role (角色): 顾名思义,就是一种身份,比如管理员 (Administrator)、编辑 (Editor)、作者 (Author)、投稿人 (Contributor) 和订阅者 (Subscriber)。每种角色代表着一组特定的权限。你可以理解成一个预设好的权限模板。
  • Capability (权限): 这才是真正干活的。Capability代表着对某个动作的许可,比如edit_posts(编辑文章)、delete_posts(删除文章)、manage_options(管理选项)等等。

Role和Capability的关系就像是:Role是套装,Capability是套装里的单品。一个Role包含了若干个Capability。

第二幕:add_role()函数——创造角色的魔法棒

add_role()函数的作用是创建一个新的Role。它的原型如下:

function add_role( string $role, string $display_name, array $capabilities = array() ): WP_Role|false {
    global $wp_roles;

    if ( isset( $wp_roles->roles[ $role ] ) ) {
        return false;
    }

    $wp_roles->add_role( $role, $display_name, $capabilities );

    return $wp_roles->get_role( $role );
}

是不是感觉有点懵?别怕,咱们逐行解读:

  1. global $wp_roles;: 声明 $wp_roles 为全局变量。$wp_roles 是一个 WP_Roles 类的实例,它负责管理所有的Roles。

  2. if ( isset( $wp_roles->roles[ $role ] ) ) { return false; }: 这段代码判断要添加的Role是否已经存在。如果存在,直接返回 false,防止重复添加。

  3. $wp_roles->add_role( $role, $display_name, $capabilities );: 这才是真正添加Role的地方。它调用 $wp_roles 对象的 add_role() 方法来完成添加操作。注意,这里是调用 WP_Roles 类的方法,而不是全局的 add_role() 函数本身!

  4. return $wp_roles->get_role( $role );: 添加成功后,返回新创建的 WP_Role 对象。

看到这里,你可能会问:全局函数add_role()只是个壳子,真正的添加逻辑在 WP_Roles 类里?Bingo!答对了!

深入WP_Roles类的add_role()方法

让我们看看 WP_Roles 类的 add_role() 方法的实现:

public function add_role( string $role, string $name, array $capabilities = array() ): void {
    if ( isset( $this->roles[ $role ] ) ) {
        return;
    }

    $this->roles[ $role ] = array(
        'name'         => $name,
        'capabilities' => $capabilities,
    );

    $this->role_names[ $role ] = $name;

    $this->set_role( $role );

    /**
     * Fires after a role is added.
     *
     * @since 2.0.0
     *
     * @param string $role Role name.
     */
    do_action( 'add_role', $role );
}
  1. if ( isset( $this->roles[ $role ] ) ) { return; }: 再次检查Role是否已存在,这次是在 $this->roles 数组中检查。

  2. $this->roles[ $role ] = array( 'name' => $name, 'capabilities' => $capabilities, );: 将Role的信息(包括名称和权限)存储到 $this->roles 数组中。$this->rolesWP_Roles 类的一个成员变量,它是一个关联数组,存储了所有已注册的Roles的信息。

  3. $this->role_names[ $role ] = $name;: 将Role的名称存储到 $this->role_names 数组中。这个数组主要用于快速查找Role的名称。

  4. $this->set_role( $role );: 这个方法至关重要!它负责将Role的信息持久化到数据库中。稍后我们会详细分析。

  5. do_action( 'add_role', $role );: 触发 add_role action hook,允许其他插件或主题在Role添加后执行自定义操作。

揭秘set_role()方法——持久化的关键

set_role() 方法负责将Role的信息存储到WordPress的 wp_options 表中。让我们看看它的实现:

private function set_role( string $role ): void {
    if ( empty( $this->roles ) ) {
        return;
    }

    update_option( 'wp_user_roles', $this->roles );

    $this->reinit_role( $role );
}
  1. if ( empty( $this->roles ) ) { return; }: 如果 $this->roles 数组为空,直接返回。

  2. update_option( 'wp_user_roles', $this->roles );: 使用 update_option() 函数将 $this->roles 数组存储到 wp_options 表中,option name为 wp_user_roles。这意味着所有的Roles信息都序列化后存储在一个option里。

  3. $this->reinit_role( $role );: 重新初始化指定的Role。

reinit_role()方法

private function reinit_role(string $role): void
{
    if (isset($this->roles[$role])) {
        $this->roles[$role] = (object)$this->roles[$role];
    }
}

这个方法将指定role从数组转换为对象。

第三幕:add_cap()函数——赋予角色的神力

add_cap()函数的作用是给指定的Role添加Capability。它的原型如下:

function add_cap( string $role, string $cap, bool $grant = true ): void {
    global $wp_roles;

    if ( ! is_object( $wp_roles ) ) {
        $wp_roles = new WP_Roles();
    }

    $wp_roles->add_cap( $role, $cap, $grant );
}

add_role() 类似,全局函数 add_cap() 也是一个壳子,真正的添加逻辑在 WP_Roles 类中。

  1. global $wp_roles;: 声明 $wp_roles 为全局变量。

  2. if ( ! is_object( $wp_roles ) ) { $wp_roles = new WP_Roles(); }: 确保 $wp_roles 是一个 WP_Roles 类的实例。

  3. $wp_roles->add_cap( $role, $cap, $grant );: 调用 $wp_roles 对象的 add_cap() 方法来完成添加操作。

深入WP_Roles类的add_cap()方法

让我们看看 WP_Roles 类的 add_cap() 方法的实现:

public function add_cap( string $role, string $cap, bool $grant = true ): void {
    if ( isset( $this->roles[ $role ] ) ) {
        $this->roles[ $role ]['capabilities'][ $cap ] = $grant;
        $this->update_role( $role );
    }
}
  1. if ( isset( $this->roles[ $role ] ) ) { ... }: 检查指定的Role是否存在。

  2. $this->roles[ $role ]['capabilities'][ $cap ] = $grant;: 将指定的Capability添加到Role的 capabilities 数组中。$grant 参数指定是否授予该权限(true 表示授予,false 表示拒绝)。

  3. $this->update_role( $role );: 更新Role的信息到数据库中。

update_role()方法

private function update_role( string $role ): void {
    update_option( 'wp_user_roles', $this->roles );
}

update_role() 方法非常简单,它只是调用 update_option() 函数将 $this->roles 数组更新到 wp_options 表中,option name 仍然是 wp_user_roles

第四幕:案例分析——实战演练

假设我们要创建一个新的Role,叫做 "Content Manager"(内容管理员),并赋予其 edit_posts(编辑文章)和 publish_posts(发布文章)的权限。我们可以这样做:

// 创建名为 "content_manager" 的Role,显示名称为 "Content Manager"
add_role( 'content_manager', 'Content Manager', array(
    'edit_posts'   => true, // 允许编辑文章
    'publish_posts' => true, // 允许发布文章
));

// 或者,先创建Role,再添加Capability
add_role( 'content_manager', 'Content Manager' );
$role = get_role( 'content_manager' ); // 获取 WP_Role 对象
$role->add_cap( 'edit_posts' );
$role->add_cap( 'publish_posts' );

第五幕:总结与思考

今天我们深入剖析了 WordPress 的 add_role()add_cap() 函数的底层实现。总结一下几个要点:

  • add_role()add_cap() 函数都是全局函数,但它们只是 WP_Roles 类相应方法的代理。
  • WP_Roles 类负责管理所有的Roles和Capabilities。
  • Role的信息(包括名称和权限)存储在 WP_Roles 类的 $roles 数组中。
  • Role的信息最终会被序列化后存储到 wp_options 表中,option name为 wp_user_roles
  • update_option() 函数是持久化Role信息的关键。

思考题:

  1. WordPress是如何判断用户是否有某个Capability的?提示:想想 current_user_can() 函数。
  2. 如果直接修改 wp_options 表中的 wp_user_roles option,会发生什么?有什么需要注意的?
  3. 你能否写一个函数,用于删除指定的Role?

希望今天的讲座对大家有所帮助。记住,代码的世界充满了乐趣,只要你敢于挖掘,就能发现更多精彩! 下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注