capabilities. * * @return array */ public static function defaults() { /** * Filters which roles get the plugin capabilities on install. * * @param array $roles Role => capabilities. */ return (array) apply_filters( 'kdocs_default_capabilities', array( 'administrator' => self::ALL, 'editor' => array( self::STRUCTURE, self::ANALYTICS ), 'author' => array( self::ANALYTICS ), 'docs_editor' => array( self::STRUCTURE, self::ANALYTICS ), ) ); } /** * Adds the default capabilities to existing roles. */ public static function install() { foreach ( self::defaults() as $name => $caps ) { $role = get_role( $name ); if ( ! $role ) { continue; } foreach ( $caps as $cap ) { $role->add_cap( $cap ); } } } /** * Removes the capabilities from every role (uninstall). */ public static function uninstall() { foreach ( wp_roles()->role_objects as $role ) { foreach ( self::ALL as $cap ) { $role->remove_cap( $cap ); } } } /** * Administrators keep the settings capability. * * @param array $allcaps User capabilities. * @return array */ public static function keep_admins( $allcaps ) { if ( ! empty( $allcaps['manage_options'] ) ) { $allcaps[ self::SETTINGS ] = true; } return $allcaps; } /** * Labels. * * @return array */ public static function labels() { return array( self::STRUCTURE => array( 'label' => __( 'Manage structure', 'karma-docs' ), 'help' => __( 'Knowledge bases, categories, order, moving and importing articles.', 'karma-docs' ), ), self::ANALYTICS => array( 'label' => __( 'View analytics', 'karma-docs' ), 'help' => __( 'Analytics reports, exports and the feedback inbox (with reader emails).', 'karma-docs' ), ), self::SETTINGS => array( 'label' => __( 'Manage settings', 'karma-docs' ), 'help' => __( 'Settings, design, tools and setup. Administrators always have it.', 'karma-docs' ), ), ); } /** * Roles and their plugin capabilities. * * @return array */ public static function matrix() { $roles = array(); foreach ( wp_roles()->role_objects as $name => $role ) { $names = wp_roles()->role_names; $caps = array(); foreach ( self::ALL as $cap ) { $caps[ $cap ] = $role->has_cap( $cap ) || ( self::SETTINGS === $cap && $role->has_cap( 'manage_options' ) ); } $roles[] = array( 'role' => $name, 'name' => translate_user_role( $names[ $name ] ?? $name ), 'caps' => $caps, 'locked' => $role->has_cap( 'manage_options' ) ? array( self::SETTINGS ) : array(), ); } $caps = array(); foreach ( self::labels() as $cap => $label ) { $caps[] = array( 'cap' => $cap ) + $label; } return array( 'roles' => $roles, 'caps' => $caps, ); } /** * Routes: GET / POST /permissions. * * @param string $ns Namespace. */ public function routes( $ns ) { register_rest_route( $ns, '/permissions', array( array( 'methods' => 'GET', 'callback' => static fn() => rest_ensure_response( self::matrix() ), 'permission_callback' => array( Routes::class, 'can_admin' ), ), array( 'methods' => 'POST', 'callback' => array( $this, 'save' ), 'permission_callback' => static fn() => Routes::can_admin() && current_user_can( 'promote_users' ), 'args' => array( 'role' => array( 'type' => 'string', 'required' => true, ), 'cap' => array( 'type' => 'string', 'required' => true, 'enum' => self::ALL, ), 'granted' => array( 'type' => 'boolean', 'required' => true, ), ), ), ) ); } /** * POST /permissions: grants or removes one capability. * * @param \WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function save( $request ) { $role = get_role( sanitize_key( (string) $request['role'] ) ); if ( ! $role ) { return new \WP_Error( 'kdocs_not_found', __( 'Role not found.', 'karma-docs' ), array( 'status' => 404 ) ); } $cap = (string) $request['cap']; if ( self::SETTINGS === $cap && $role->has_cap( 'manage_options' ) && ! $request['granted'] ) { return new \WP_Error( 'kdocs_locked', __( 'Administrators always manage settings.', 'karma-docs' ), array( 'status' => 400 ) ); } if ( $request['granted'] ) { $role->add_cap( $cap ); } else { $role->remove_cap( $cap ); } return rest_ensure_response( self::matrix() ); } }