阐述 WordPress `WP_Roles` 类的源码:它是如何通过 `$wp_roles` 全局变量实现角色与权限的单例管理。

各位观众老爷,晚上好!我是今天的讲师,咱们今天就来聊聊 WordPress 权限管理的核心——WP_Roles 类,以及它背后的 $wp_roles 全局变量。

准备好了吗?Let’s dive in!

开场白:权限这玩意儿,真要命!

在 Web 开发的世界里,权限管理绝对是个绕不开的坎儿。想想看,你辛辛苦苦搭建的网站,总不能让阿猫阿狗都能随便改吧?谁能发文章?谁能删评论?谁能安装插件?这些都得管起来!

WordPress 作为一个强大的 CMS,自然也有一套完整的权限管理机制。而 WP_Roles 类,就是这套机制的核心大脑,它负责掌管所有的用户角色和权限信息。

WP_Roles 类:角色与权限的总指挥

WP_Roles 类,顾名思义,就是用来管理用户角色的。它定义了各种角色(比如管理员、编辑、作者、投稿者、订阅者),以及每个角色拥有的权限。

我们先来大概看看这个类的主要属性和方法,心里有个数:

  • 属性:

    • $roles: 一个数组,存储了所有角色的信息。每个角色都是一个数组,包含角色名、显示名和拥有的权限。
    • $role_names: 一个数组,存储了所有角色的显示名。
    • $role_objects: 一个数组,存储了所有 WP_Role 对象,每个对象代表一个角色。
  • 主要方法:

    • __construct(): 构造函数,负责初始化角色信息。
    • add_role(): 添加一个新的角色。
    • remove_role(): 删除一个角色。
    • get_role(): 获取一个 WP_Role 对象。
    • get_names(): 获取所有角色的显示名。
    • get_roles(): 获取所有角色的信息。
    • is_role(): 检查一个角色是否存在。
    • role_exists(): 检查一个角色是否存在(别名)。
    • add_cap(): 给角色添加一个权限。
    • remove_cap(): 从角色移除一个权限。
    • get_cap(): 检查角色是否拥有某个权限。

是不是觉得有点眼花缭乱?别怕,我们一点点拆解。

$wp_roles 全局变量:单例模式的妙用

重点来了!WP_Roles 类并不是直接使用的,而是通过一个全局变量 $wp_roles 来实现单例模式。

什么是单例模式?简单来说,就是确保一个类只能被实例化一次。这样可以避免重复创建对象,浪费资源,而且方便全局访问。

在 WordPress 中,$wp_roles 全局变量就是用来存储 WP_Roles 类的唯一实例的。

让我们看看 WordPress 是如何实现这一点的:

// wp-includes/capabilities.php

global $wp_roles;

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

这段代码简洁明了:

  1. 首先,声明一个全局变量 $wp_roles
  2. 然后,检查 $wp_roles 是否已经被设置。
  3. 如果 $wp_roles 还没有被设置,就创建一个 WP_Roles 类的实例,并赋值给 $wp_roles

这样,无论你在 WordPress 的哪个地方使用 $wp_roles,访问的都是同一个 WP_Roles 类的实例。

WP_Roles 类的构造函数:初始化角色信息

当我们创建一个 WP_Roles 类的实例时,构造函数 __construct() 会被自动调用。这个函数的主要任务是从数据库中加载角色和权限信息。

// wp-includes/class-wp-roles.php

    public function __construct() {
        global $wpdb;

        $this->roles = get_option( 'wp_user_roles' );

        if ( empty( $this->roles ) ) {
            /**
             * Fires after the default roles are created.
             *
             * @since 3.0.0
             */
            do_action( 'default_roles' );

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

        $this->role_names = get_option( 'wp_user_roles', array() );

        if ( empty( $this->role_names ) ) {
            $this->role_names = array();
        }

        $this->role_objects = array();

        if ( is_array( $this->roles ) ) {
            foreach ( array_keys( $this->roles ) as $role ) {
                $this->role_objects[ $role ] = new WP_Role( $role, $this->roles[ $role ] );
            }
        }
    }

我们来解读一下这段代码:

  1. 首先,获取全局数据库对象 $wpdb
  2. 然后,尝试从 wp_options 表中获取 wp_user_roles 选项的值,并赋值给 $this->roles。这个选项存储了所有角色的信息。
  3. 如果 $this->roles 为空,说明还没有任何角色信息,那么就触发 default_roles action。这个 action 允许插件或主题添加默认的角色。
  4. 接着,将 $this->roles 更新到 wp_options 表中。
  5. 然后,从 wp_options 表中获取 wp_user_roles 选项的值,并赋值给 $this->role_names
  6. 最后,遍历 $this->roles 数组,为每个角色创建一个 WP_Role 对象,并存储到 $this->role_objects 数组中。

WP_Role 类:角色的具体实现

注意到了吗?在 WP_Roles 类的构造函数中,我们创建了 WP_Role 类的对象。WP_Role 类代表一个具体的角色,它封装了角色的名称、显示名和权限信息。

// wp-includes/class-wp-role.php

class WP_Role {
    public $name;
    public $capabilities;

    public function __construct( $role, $capabilities ) {
        $this->name         = $role;
        $this->capabilities = $capabilities;
    }

    public function add_cap( $cap, $grant = true ) {
        $this->capabilities[ $cap ] = $grant;
        return update_option( 'wp_user_roles', get_option( 'wp_user_roles' ) );
    }

    public function remove_cap( $cap ) {
        unset( $this->capabilities[ $cap ] );
        return update_option( 'wp_user_roles', get_option( 'wp_user_roles' ) );
    }

    public function has_cap( $cap ) {
        if ( isset( $this->capabilities[ $cap ] ) ) {
            return $this->capabilities[ $cap ];
        }

        return false;
    }
}

这个类非常简单:

  • $name: 角色的名称。
  • $capabilities: 一个数组,存储了角色拥有的权限。
  • add_cap(): 给角色添加一个权限。
  • remove_cap(): 从角色移除一个权限。
  • has_cap(): 检查角色是否拥有某个权限。

常用方法解析:增删改查,样样精通

现在,我们来详细看看 WP_Roles 类的一些常用方法,了解它们是如何操作角色和权限的。

  • add_role():添加角色

    这个方法用于添加一个新的角色。

    // wp-includes/class-wp-roles.php
    
        public function add_role( $role, $display_name, $capabilities = array() ) {
            if ( isset( $this->roles[ $role ] ) ) {
                return;
            }
    
            $this->roles[ $role ] = array( 'name' => $display_name, 'capabilities' => $capabilities );
            $this->role_names[ $role ] = $display_name;
            $this->role_objects[ $role ] = new WP_Role( $role, $capabilities );
            update_option( 'wp_user_roles', $this->roles );
    
            /**
             * Fires after a role is added.
             *
             * @since 4.3.0
             *
             * @param string $role Role name.
             * @param string $display_name Role display name.
             * @param array  $capabilities List of role capabilities.
             */
            do_action( 'add_role', $role, $display_name, $capabilities );
    
            return $role;
        }

    这个方法做了以下几件事:

    1. 检查角色是否已经存在,如果存在则直接返回。
    2. 将角色信息添加到 $this->roles 数组中。
    3. 将角色的显示名添加到 $this->role_names 数组中。
    4. 创建一个 WP_Role 对象,并添加到 $this->role_objects 数组中。
    5. $this->roles 更新到 wp_options 表中。
    6. 触发 add_role action。

    使用示例:

    global $wp_roles;
    $wp_roles->add_role( 'customer', 'Customer', array( 'read' => true, 'edit_posts' => false ) );

    这段代码添加了一个名为 "customer" 的角色,显示名为 "Customer",拥有 read 权限,但没有 edit_posts 权限。

  • remove_role():删除角色

    这个方法用于删除一个角色。

    // wp-includes/class-wp-roles.php
    
        public function remove_role( $role ) {
            if ( ! isset( $this->roles[ $role ] ) ) {
                return;
            }
    
            unset( $this->roles[ $role ] );
            unset( $this->role_names[ $role ] );
            unset( $this->role_objects[ $role ] );
            update_option( 'wp_user_roles', $this->roles );
    
            /**
             * Fires after a role is removed.
             *
             * @since 4.3.0
             *
             * @param string $role Role name.
             */
            do_action( 'remove_role', $role );
        }

    这个方法做了以下几件事:

    1. 检查角色是否存在,如果不存在则直接返回。
    2. $this->roles 数组中删除角色信息。
    3. $this->role_names 数组中删除角色的显示名。
    4. $this->role_objects 数组中删除 WP_Role 对象。
    5. $this->roles 更新到 wp_options 表中。
    6. 触发 remove_role action。

    使用示例:

    global $wp_roles;
    $wp_roles->remove_role( 'customer' );

    这段代码删除了名为 "customer" 的角色。

  • get_role():获取角色对象

    这个方法用于获取一个 WP_Role 对象。

    // wp-includes/class-wp-roles.php
    
        public function get_role( $role ) {
            if ( isset( $this->role_objects[ $role ] ) ) {
                return $this->role_objects[ $role ];
            }
    
            return null;
        }

    这个方法很简单,就是从 $this->role_objects 数组中查找对应的 WP_Role 对象,如果找到则返回,否则返回 null

    使用示例:

    global $wp_roles;
    $customer_role = $wp_roles->get_role( 'customer' );
    
    if ( $customer_role ) {
        // Do something with the customer role
        echo "Customer role exists!";
    } else {
        echo "Customer role does not exist.";
    }
  • add_cap():添加权限

    这个方法用于给角色添加一个权限。

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

    这个方法做了以下几件事:

    1. 检查角色是否存在,如果不存在则直接返回。
    2. 将权限添加到 $this->roles 数组中对应角色的 capabilities 数组中。
    3. 调用 WP_Role 对象的 add_cap() 方法,更新角色对象的权限信息。
    4. $this->roles 更新到 wp_options 表中。

    使用示例:

    global $wp_roles;
    $wp_roles->add_cap( 'customer', 'purchase_products' );

    这段代码给名为 "customer" 的角色添加了 purchase_products 权限。

  • remove_cap():移除权限

    这个方法用于从角色移除一个权限。

    // wp-includes/class-wp-roles.php
    
        public function remove_cap( $role, $cap ) {
            if ( ! isset( $this->roles[ $role ] ) ) {
                return;
            }
    
            unset( $this->roles[ $role ]['capabilities'][ $cap ] );
            $this->role_objects[ $role ]->remove_cap( $cap );
            update_option( 'wp_user_roles', $this->roles );
        }

    这个方法做了以下几件事:

    1. 检查角色是否存在,如果不存在则直接返回。
    2. $this->roles 数组中对应角色的 capabilities 数组中删除权限。
    3. 调用 WP_Role 对象的 remove_cap() 方法,更新角色对象的权限信息。
    4. $this->roles 更新到 wp_options 表中。

    使用示例:

    global $wp_roles;
    $wp_roles->remove_cap( 'customer', 'purchase_products' );

    这段代码从名为 "customer" 的角色移除了 purchase_products 权限。

权限的存储方式:wp_options 表的秘密

现在,我们来揭秘一下角色和权限信息是如何存储在数据库中的。

WP_Roles 类会将角色和权限信息存储在 wp_options 表中的 wp_user_roles 选项中。这个选项的值是一个序列化的 PHP 数组。

我们可以通过以下代码来查看这个选项的值:

global $wpdb;
$roles = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'wp_user_roles'" );
$roles = maybe_unserialize( $roles );

echo '<pre>';
print_r( $roles );
echo '</pre>';

这段代码会从数据库中获取 wp_user_roles 选项的值,反序列化后打印出来。你就可以看到角色和权限信息的具体结构了。

map_meta_cap():权限映射的桥梁

WordPress 的权限系统不仅仅是简单的角色和权限的对应关系,还涉及到权限映射。

比如,edit_post 权限并不是直接授予给用户的,而是通过 map_meta_cap() 函数将 edit_post 权限映射到更具体的权限上,比如 edit_others_postsedit_published_posts

map_meta_cap() 函数会根据具体的上下文(比如用户 ID、文章 ID)来判断用户是否真的拥有编辑这篇文章的权限。

这个函数是 WordPress 权限系统的一个重要组成部分,它使得权限管理更加灵活和安全。

案例分析:自定义角色和权限

最后,我们来看一个实际的案例,演示如何自定义角色和权限。

假设我们要创建一个名为 "contributor_plus" 的角色,这个角色拥有投稿者的所有权限,并且可以编辑自己的文章。

首先,我们需要添加这个角色:

add_action( 'init', 'add_contributor_plus_role' );

function add_contributor_plus_role() {
    global $wp_roles;

    if ( ! isset( $wp_roles ) ) {
        return;
    }

    if ( get_role( 'contributor_plus' ) ) {
        return;
    }

    $contributor = get_role( 'contributor' );

    if ( ! $contributor ) {
        return;
    }
    $caps = $contributor->capabilities;
    $caps['edit_posts'] = true;
    $caps['edit_published_posts'] = true;

    add_role( 'contributor_plus', 'Contributor Plus', $caps );
}

这段代码在 init action 中添加了一个名为 "contributor_plus" 的角色,并赋予了 edit_postsedit_published_posts 权限。

总结:权限管理的奥秘

今天,我们深入探讨了 WordPress 权限管理的核心——WP_Roles 类和 $wp_roles 全局变量。

我们了解了:

  • WP_Roles 类是用来管理用户角色的。
  • $wp_roles 全局变量实现了单例模式,确保只有一个 WP_Roles 类的实例。
  • WP_Role 类代表一个具体的角色,封装了角色的名称、显示名和权限信息。
  • WP_Roles 类提供了添加、删除、修改角色和权限的方法。
  • 角色和权限信息存储在 wp_options 表中的 wp_user_roles 选项中。
  • map_meta_cap() 函数实现了权限映射,使得权限管理更加灵活和安全。

通过理解这些概念,你可以更好地掌握 WordPress 的权限管理机制,自定义角色和权限,满足你的实际需求。

希望今天的讲座对你有所帮助!下次再见!

发表回复

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