The block editor's group-class picker fetches GET /offerings, whose
permission callback only accepted book_lesson — a capability held by
students alone. Administrators and instructors editing a page were
rejected with a 403 and the picker silently rendered an empty list.
Read access now accepts book_lesson or manage_offerings. The listing is
unchanged: active offerings only, public ones plus the invite-only
classes the caller has been granted, without the e-transfer email.
Closes#121
Co-Authored-By: Claude Opus 5 <[email protected]>
Three bug fixes for the 1.2.1 section:
- Fixed-size fields (question labels, offering titles/notes/e-transfer
email, policy titles/slugs) no longer silently fail to save when the
value exceeds its column length. The REST endpoints reject over-long
values with a 400, the admin controllers refuse to insert them, and the
form inputs carry a maxlength so the browser blocks over-long entry.
Limits are MAX_* constants on the value objects, kept in lockstep with
the schema columns.
- Students are kept out of wp-admin entirely. New StudentAdminGuard
redirects front-end-only users (no back-office capability) away from the
dashboard and hides the admin bar for them, while administrators, studio
admins, and instructors keep full access.
- The Add/Edit Offering instructor picker now includes WordPress
administrators when they act as instructors (the default single-account
setup), so a solo studio owner is selectable instead of the dropdown
being empty.
composer test (618), composer lint, composer cs all pass.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Add Auth\UserName::format(), which prefers a user's first + last name, then
their nickname, avoiding display_name (which can be the login/username).
Route the instructor name through it in both the front-end offerings response
(instructor_name) and the back-end group-class summary and details views.
Tests: composer test (513), composer lint, composer cs all pass.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Group classes now carry a specific class time (alongside date and duration)
and an assigned instructor:
- Schema: add `class_time` (TIME) to `us_offerings`; `Offering` gains
`normalizeTime`/`sessionWindows`. (Rides the pending 1.0.0->1.1.0 dbDelta
upgrade, so no version bump.)
- Offering form: class-time field, plus a studio-admin instructor picker
(plain instructors always own their own classes).
- `ClassSlotReconciler`: assigning an instructor clears their open booking
slots overlapping each session and flags already-booked lessons that clash
(a booked lesson is never deleted). Uses new
`AvailabilityRepository::findOverlapping`.
- Front end: `GET /offerings` exposes `instructor_name`; the enrolment page
shows who teaches each class and when it meets.
Back-office group-class views redesigned:
- Instructor **My Group Classes** and studio-admin **Group Classes** are now
per-class summaries with enrolment counts, not flat student lists.
- Each links through (`?class_id=<id>`) to a per-class **details page**
(schedule panel, roster with payment status, and — for invite-only classes
— the add/make-available/invite-by-email controls). Invite-only membership
is managed entirely from this page.
- Invite actions are allowed for the class's owning instructor or any
`view_all_lessons` studio admin, so an owner-operator (studio admin who also
teaches) can reach every class's roster and invites from the Group Classes
page.
Tests: composer test (508), composer lint, composer cs all pass.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Group classes can now be marked invite-only (us_offerings.access_mode).
Invite-only classes are hidden from the public catalog and reachable only
when the instructor lets someone in via one of three paths, managed from
My Lessons -> My Group Classes:
- Add students directly: enrols them now with a pending payment.
- Make available: grants registered students access to self-enrol through
the normal paid flow (multi-select, emailed a notice).
- Invite by email: tokenised registration invite tied to the class for a
non-account address; after they register the class becomes enrollable.
Reuses an existing pending invite instead of sending a second link.
New us_group_access table records grants; GET /offerings merges granted
invite-only classes for the caller; enrolment requires a grant
(403 invite_required) and flips it to enrolled on success.
composer test (487), composer lint, composer cs all pass.
Co-Authored-By: Claude Opus 4.8 <[email protected]>