Completes the second half of #9 — instructor management. The capability slice (the us_studio_admin role and the cap matrix) shipped in #10; this adds the Instructors admin page the issue specifies.
What changed
InstructorController (gated on manage_instructors): lists instructors, creates a us_instructor WordPress user (emailing them a set-password link via wp_new_user_notification), and a per-instructor capability detail view.
InstructorCapabilities — the pure, unit-tested rules: which managed capabilities the acting admin may assign, and how a submitted form maps to per-user grants/denials. Kept free of WordPress so it's testable (mirrors how StudentController pairs with StudentSchedule).
AdminMenu registers the page in the "people" section, and that section's separator now accounts for manage_instructors.
Templates instructors.php (list + create form) and instructor-detail.php (capability toggles).
Capability model
The managed (toggleable) capabilities are manage_offerings, manage_questions, view_own_payments, and export_payments. manage_availability and view_own_lessons are core to every instructor and aren't managed here. The us_instructor role grants the managed caps by default; the page layers per-user overrides on top (no change to RoleManager, matching the capability matrix).
A studio admin can never grant a capability it does not itself hold:
only caps the acting user holds are offered as toggles — checked via current_user_can(), so an administrator's dynamic studio grant counts;
on creation, any managed cap the admin lacks is explicitly denied on the new instructor, so a new account can never exceed its creator.
Checks
composer test (189 tests, 541 assertions), composer lint (PHPStan L6 — no errors), composer cs (PHPCS) all green. New InstructorCapabilitiesTest; docs/features/user-roles.md updated.
Completes the second half of #9 — **instructor management**. The capability slice (the `us_studio_admin` role and the cap matrix) shipped in #10; this adds the **Instructors** admin page the issue specifies.
## What changed
- **`InstructorController`** (gated on `manage_instructors`): lists instructors, creates a `us_instructor` WordPress user (emailing them a set-password link via `wp_new_user_notification`), and a per-instructor capability detail view.
- **`InstructorCapabilities`** — the pure, unit-tested rules: which managed capabilities the acting admin may assign, and how a submitted form maps to per-user grants/denials. Kept free of WordPress so it's testable (mirrors how `StudentController` pairs with `StudentSchedule`).
- **AdminMenu** registers the page in the "people" section, and that section's separator now accounts for `manage_instructors`.
- Templates `instructors.php` (list + create form) and `instructor-detail.php` (capability toggles).
## Capability model
The managed (toggleable) capabilities are `manage_offerings`, `manage_questions`, `view_own_payments`, and `export_payments`. `manage_availability` and `view_own_lessons` are core to every instructor and aren't managed here. The `us_instructor` role grants the managed caps by default; the page layers **per-user overrides** on top (no change to `RoleManager`, matching the capability matrix).
**A studio admin can never grant a capability it does not itself hold:**
- only caps the acting user holds are offered as toggles — checked via `current_user_can()`, so an administrator's dynamic studio grant counts;
- on creation, any managed cap the admin lacks is explicitly denied on the new instructor, so a new account can never exceed its creator.
## Checks
`composer test` (189 tests, 541 assertions), `composer lint` (PHPStan L6 — no errors), `composer cs` (PHPCS) all green. New `InstructorCapabilitiesTest`; `docs/features/user-roles.md` updated.
Closes #9.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Completes the second half of #9 — instructor management. The capability slice (the
us_studio_adminrole and the cap matrix) shipped in #10; this adds the Instructors admin page the issue specifies.What changed
InstructorController(gated onmanage_instructors): lists instructors, creates aus_instructorWordPress user (emailing them a set-password link viawp_new_user_notification), and a per-instructor capability detail view.InstructorCapabilities— the pure, unit-tested rules: which managed capabilities the acting admin may assign, and how a submitted form maps to per-user grants/denials. Kept free of WordPress so it's testable (mirrors howStudentControllerpairs withStudentSchedule).manage_instructors.instructors.php(list + create form) andinstructor-detail.php(capability toggles).Capability model
The managed (toggleable) capabilities are
manage_offerings,manage_questions,view_own_payments, andexport_payments.manage_availabilityandview_own_lessonsare core to every instructor and aren't managed here. Theus_instructorrole grants the managed caps by default; the page layers per-user overrides on top (no change toRoleManager, matching the capability matrix).A studio admin can never grant a capability it does not itself hold:
current_user_can(), so an administrator's dynamic studio grant counts;Checks
composer test(189 tests, 541 assertions),composer lint(PHPStan L6 — no errors),composer cs(PHPCS) all green. NewInstructorCapabilitiesTest;docs/features/user-roles.mdupdated.Closes #9.
🤖 Generated with Claude Code