Files
unsupervised-scheduler/docs/features/user-roles.md
T
thatguygriff b5c076c3d6
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 48s
CI / Tests (PHP 8.2) (pull_request) Successful in 49s
CI / Tests (PHP 8.1) (pull_request) Successful in 54s
CI / Coding Standards (pull_request) Successful in 1m5s
CI / PHPStan (pull_request) Successful in 1m11s
CI / Build Plugin Zip (pull_request) Has been skipped
Add Instructors admin page (create + per-capability access)
Completes the instructor-management half of #9: the studio admin can now
create instructor accounts and toggle each instructor's capabilities.

- InstructorController (manage_instructors): list instructors, create a
  us_instructor WP user (emailing a set-password link), and a per-instructor
  capability detail view.
- InstructorCapabilities: pure, unit-tested rules for which managed caps an
  admin may assign and how a submitted form maps to assignments. Managed caps
  are manage_offerings, manage_questions, view_own_payments, export_payments;
  manage_availability and view_own_lessons are core to every instructor.
- A studio admin can never grant a capability it does not itself hold: only
  held caps (checked via current_user_can, so an administrator's dynamic grant
  counts) are offered, and on creation any managed cap the admin lacks is
  denied on the new instructor so they never exceed their creator. The role
  grants the managed caps by default; the page layers per-user overrides.
- AdminMenu: register the Instructors page in the people section.
- Tests for the capability logic; docs/features/user-roles.md updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 17:02:46 -03:00

5.7 KiB

Feature: User Roles

Overview

Three custom WordPress user roles control access to all scheduling features: a studio admin who runs the business, instructors who teach, and students who book.

Roles

Studio Admin (us_studio_admin)

Runs the studio. Logs in via standard wp-admin. Can:

  • Create instructor accounts and set/revoke each instructor's capabilities
  • Manage offerings, intake questions, and policies
  • Configure Stripe credentials and per-student billing overrides (card / e-transfer / comp)
  • View the studio-wide scheduler (all upcoming lessons across instructors)
  • View the all-instructor payments report and export it

Capabilities: read, manage_instructors, manage_offerings, manage_questions, manage_policies, manage_billing, view_all_lessons, view_all_payments, export_payments

Any WordPress administrator (manage_options) implicitly holds every studio-admin capability above and the instructor capabilities (notably manage_availability), so a single-instructor studio owner can run the business and teach — managing their own availability and lessons — from one account, without being assigned the us_studio_admin or us_instructor role. This is applied dynamically via the user_has_cap filter (RoleManager::grantStudioCapsToAdministrators()) — it persists nothing and is removed when the plugin is deactivated. The us_studio_admin role exists for non-administrator staff who manage the studio.

Both grants can be turned off independently on the Access admin page (AccessSettings, options us_admin_grant_studio / us_admin_grant_instructor, both default on) — for example, when dedicated us_studio_admin or us_instructor accounts run the studio and administrators should not appear as studio staff. That page is gated on the core manage_options capability (which the plugin never grants or revokes), so an administrator can always reach it to re-enable a grant; disabling one can never lock them out.

Instructor (us_instructor)

Created by the studio admin. Logs in via standard wp-admin. Can:

  • Manage their own availability slots (add/delete), including weekly-recurring windows
  • Manage their own offerings and intake questions
  • View their upcoming confirmed/pending lessons and group enrolments
  • View and export their own payments

Capabilities: read, manage_availability, manage_offerings, manage_questions, view_own_lessons, view_own_payments, export_payments

Student (us_student)

Logs in via the front-end [us_student_login] shortcode. Can:

  • Browse available lesson slots and offerings from all instructors
  • Book a private lesson (single or weekly) and enrol in group classes

Capabilities: read, book_lesson, view_own_lessons

Capability Matrix

Capability Studio Admin Instructor Student Used by
manage_instructors Instructor management
manage_availability Availability
manage_offerings ✓ (own) Offerings
manage_questions ✓ (own) Registration questions
manage_policies Policies
manage_billing Payments (Stripe + overrides)
book_lesson Lesson booking / enrolment
view_all_lessons Scheduler dashboard
view_own_lessons Lesson + group views
view_own_payments Payment reporting
view_all_payments Payment reporting
export_payments ✓ (own) Payment reporting export

Instructor Management

The studio admin gets an Instructors admin page (gated by manage_instructors) to add an instructor — creating the WP user with the us_instructor role and emailing them a set-password link — and to toggle that instructor's per-capability access. The managed capabilities are manage_offerings, manage_questions, view_own_payments, and export_payments; manage_availability and view_own_lessons are core to every instructor and are not managed here. The us_instructor role grants the managed capabilities by default, and the page stores per-user overrides on top of the role.

A studio admin cannot grant a capability it does not itself hold: only capabilities the acting user has (checked via current_user_can(), so an administrator's dynamic grant counts) are offered as toggles, and on creation any managed capability the admin lacks is denied on the new instructor so they never exceed the creator. The grantable/assignment rules live in the pure, unit-tested Auth\InstructorCapabilities; InstructorController applies the result to the WP_User.

Implementation

  • Class: Unsupervised\Schedular\Auth\RoleManager
  • Instructor management controller: Unsupervised\Schedular\Auth\InstructorController
  • Roles are created on plugins_loaded → init and on plugin activation via Installer.
  • Permissions are checked with current_user_can() against the capability string, not the role name.

Tests

  • tests/Unit/Auth/RoleManagerTest.php
  • tests/Unit/Auth/InstructorCapabilitiesTest.php