Files
unsupervised-scheduler/src/Auth/RoleManager.php
T
thatguygriffandClaude Opus 4.8 67f8144a4a
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.2) (pull_request) Successful in 41s
CI / Tests (PHP 8.3) (pull_request) Successful in 51s
CI / Tests (PHP 8.1) (pull_request) Successful in 54s
CI / Coding Standards (pull_request) Successful in 58s
CI / PHPStan (pull_request) Successful in 1m9s
CI / Build Plugin Zip (pull_request) Has been skipped
Make WP admins instructors too, and add an Access toggle page
A WordPress administrator previously inherited the studio-admin
capabilities but not `manage_availability`, so the studio owner running
as an admin had no way to reach "My Availability" or act as the
instructor — breaking single-instructor businesses.

Grant the instructor capabilities to administrators as well (via the
existing `user_has_cap` filter), and make both grants — studio-admin and
instructor — independently toggleable from a new Access admin page.

- RoleManager: extract `INSTRUCTOR_CAPS`; apply studio and instructor
  cap sets to administrators, each gated on a stored toggle (default on).
- AccessSettings + templates/admin/access.php: two options
  (`us_admin_grant_studio` / `us_admin_grant_instructor`), gated on the
  core `manage_options` capability so disabling a grant can never lock an
  administrator out of re-enabling it.
- AdminMenu: register the Access page after Studio Settings; keep the
  studio sidebar separator visible for any administrator.
- Tests for the toggles and the new settings reader; docs updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-08 16:39:41 -03:00

147 lines
4.5 KiB
PHP

<?php
declare(strict_types=1);
namespace Unsupervised\Schedular\Auth;
class RoleManager {
public const STUDIO_ADMIN = 'us_studio_admin';
public const INSTRUCTOR = 'us_instructor';
public const STUDENT = 'us_student';
public const CAP_MANAGE_AVAILABILITY = 'manage_availability';
public const CAP_VIEW_LESSONS = 'view_own_lessons';
public const CAP_BOOK_LESSON = 'book_lesson';
public const CAP_MANAGE_INSTRUCTORS = 'manage_instructors';
public const CAP_MANAGE_STUDENTS = 'manage_students';
public const CAP_MANAGE_OFFERINGS = 'manage_offerings';
public const CAP_MANAGE_QUESTIONS = 'manage_questions';
public const CAP_MANAGE_POLICIES = 'manage_policies';
public const CAP_MANAGE_BILLING = 'manage_billing';
public const CAP_VIEW_ALL_LESSONS = 'view_all_lessons';
public const CAP_VIEW_ALL_PAYMENTS = 'view_all_payments';
public const CAP_VIEW_OWN_PAYMENTS = 'view_own_payments';
public const CAP_EXPORT_PAYMENTS = 'export_payments';
/**
* Capabilities granted to the `us_studio_admin` role, and implicitly to any
* WordPress administrator (see {@see grantStudioCapsToAdministrators()}).
*
* @var list<string>
*/
public const STUDIO_ADMIN_CAPS = [
self::CAP_MANAGE_INSTRUCTORS,
self::CAP_MANAGE_STUDENTS,
self::CAP_MANAGE_OFFERINGS,
self::CAP_MANAGE_QUESTIONS,
self::CAP_MANAGE_POLICIES,
self::CAP_MANAGE_BILLING,
self::CAP_VIEW_ALL_LESSONS,
self::CAP_VIEW_ALL_PAYMENTS,
self::CAP_EXPORT_PAYMENTS,
];
/**
* Capabilities granted to the `us_instructor` role, and implicitly to any
* WordPress administrator (see {@see grantStudioCapsToAdministrators()}) so a
* single-instructor studio owner can both run the business and teach from one
* account — managing their own availability and lessons without being assigned
* a separate `us_instructor` role.
*
* @var list<string>
*/
public const INSTRUCTOR_CAPS = [
self::CAP_MANAGE_AVAILABILITY,
self::CAP_MANAGE_OFFERINGS,
self::CAP_MANAGE_QUESTIONS,
self::CAP_VIEW_LESSONS,
self::CAP_VIEW_OWN_PAYMENTS,
self::CAP_EXPORT_PAYMENTS,
];
public function __construct( private AccessSettings $access = new AccessSettings() ) {}
public function register(): void {
add_action( 'init', [ $this, 'createRoles' ] );
add_filter( 'user_has_cap', [ $this, 'grantStudioCapsToAdministrators' ], 10, 1 );
}
public function createRoles(): void {
if ( get_role( self::STUDIO_ADMIN ) === null ) {
$studioCaps = [ 'read' => true ];
foreach ( self::STUDIO_ADMIN_CAPS as $cap ) {
$studioCaps[ $cap ] = true;
}
add_role(
self::STUDIO_ADMIN,
__( 'Studio Admin', 'unsupervised-schedular' ),
$studioCaps
);
}
if ( get_role( self::INSTRUCTOR ) === null ) {
$instructorCaps = [ 'read' => true ];
foreach ( self::INSTRUCTOR_CAPS as $cap ) {
$instructorCaps[ $cap ] = true;
}
add_role(
self::INSTRUCTOR,
__( 'Instructor', 'unsupervised-schedular' ),
$instructorCaps
);
}
if ( get_role( self::STUDENT ) === null ) {
add_role(
self::STUDENT,
__( 'Student', 'unsupervised-schedular' ),
[
'read' => true,
self::CAP_BOOK_LESSON => true,
self::CAP_VIEW_LESSONS => true,
]
);
}
}
/**
* Grant every studio-admin capability to WordPress administrators.
*
* The studio owner runs the site as an administrator (`manage_options`) and
* should manage offerings, questions, policies, billing, and reports without
* being assigned the separate `us_studio_admin` role. The instructor
* capabilities are granted too, so a single-instructor studio owner can manage
* their own availability and lessons and act as the instructor from the same
* account. Applied dynamically via the `user_has_cap` filter, so nothing is
* persisted and the grant disappears when the plugin is deactivated.
*
* Both grants are independently toggleable from the Access settings page (see
* {@see AccessSettings}); they default on, preserving the single-account setup.
*
* @param array<string, bool> $allcaps All capabilities currently held by the user.
* @return array<string, bool>
*/
public function grantStudioCapsToAdministrators( array $allcaps ): array {
if ( empty( $allcaps['manage_options'] ) ) {
return $allcaps;
}
if ( $this->access->adminsAreStudioAdmins() ) {
foreach ( self::STUDIO_ADMIN_CAPS as $cap ) {
$allcaps[ $cap ] = true;
}
}
if ( $this->access->adminsAreInstructors() ) {
foreach ( self::INSTRUCTOR_CAPS as $cap ) {
$allcaps[ $cap ] = true;
}
}
return $allcaps;
}
}