Four majors behind on the plugin's only production dependency. No site is using Stripe yet and the integration has not been verified end to end, so the pinned API version can move now at close to zero cost — later it would mean coordinating with live payment traffic. The library surface this plugin uses is four symbols, all in StripeGateway: StripeClient, paymentIntents->create, Webhook::constructEvent and Event. Checked each against the installed v21 by reflection; all present with compatible signatures. Most of the breakage flagged across 18 to 21 is in the V2 Events API, which this does not use — webhooks go through the V1 Webhook::constructEvent path. The pinned Stripe API version moves to 2026-07-29.dahlia. Verified beyond the suite, which mocks the client: a real HMAC-signed payload round-trips through Webhook::constructEvent and returns a Stripe\Event with the expected type and data, and a forged signature still raises SignatureVerificationException. The 21.0.0 ErrorObject retyping to null|string produces no new PHPStan findings. Part of #194 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
Unsupervised Scheduler
A WordPress plugin for instructor/student lesson scheduling — private lessons and group classes — with offerings, intake questions, versioned policies, account registration, and online payments.
Version: 1.0.0 · Requires: WordPress 6.0+, PHP 8.1+ · License: GPL-2.0-or-later
Pre-release. The booking platform is being built feature-by-feature; see Implementation status below.
Overview
The plugin is organised package-by-domain under src/ (PSR-4
Unsupervised\Schedular\). Each domain owns its value objects, repositories,
REST endpoints, and admin/front-end controllers. All data access goes through
repository classes against custom {prefix}us_* tables; permissions are enforced
with WordPress capabilities, never role-name checks. There is no front-end
build step (vanilla JS/CSS in assets/).
Every feature has a spec in docs/features/ describing its data
model, REST API, classes, and tests. For contributor/architecture guidance see
CLAUDE.md.
Implementation status
| Feature | Spec | Status |
|---|---|---|
| User roles & capabilities (studio admin / instructor / student) | user-roles.md | ✅ Implemented |
| Offerings (private-lesson types & group classes) | offerings.md | ✅ Implemented |
| Availability (durations, weekly recurrence, calendar) | availability-management.md | ✅ Implemented |
| Registration questions (per-offering intake) | registration-questions.md | ✅ Implemented |
| Policies (drafting, versioning, tracked acceptance) | policies.md | ✅ Implemented |
| Account registration (invite or open self-approval, email confirmation, signup policy acceptance) | account-registration.md | ✅ Implemented |
| Lesson booking (offering → questions → policies) | lesson-booking.md | ✅ Implemented |
| Group classes (capacity-enforced enrolment) | group-classes.md | ✅ Implemented |
| Student administration (studio-admin view) | student-administration.md | ✅ Implemented |
| Payments (Stripe card charge + e-transfer/comp + receipts + HST) | payments.md | ✅ Implemented |
| Payment reporting (monthly per-instructor + HST + CSV) | payment-reporting.md | ✅ Implemented |
Shortcodes
| Shortcode | Purpose |
|---|---|
[us_booking] |
Student calendar + private-lesson registration flow |
[us_group_classes] |
Browse and enrol in group classes |
[us_student_login] |
Front-end student login |
[us_student_register] |
Account registration — invite-based, or open self-signup with email confirmation + admin approval (accepts signup policies) |
REST API
All endpoints live under /wp-json/us-scheduler/v1/ (e.g. /offerings,
/availability, /bookings, /enrollments, /policies, /questions).
Permissions are enforced via permission_callback capability checks. See each
feature doc for the routes and required capabilities.
Roles & capabilities
Three custom roles — Studio Admin (us_studio_admin), Instructor
(us_instructor), and Student (us_student) — plus a user_has_cap filter
that grants every studio-admin capability to WordPress administrators, so the site
owner runs the studio without a separate role. Full capability matrix in
user-roles.md.
Installation
- Build a distributable zip (see Development):
composer build # -> dist/unsupervised-schedular-<version>.zip - In wp-admin: Plugins → Add New → Upload Plugin, choose the zip, install, and activate.
Activation creates the us_* database tables and registers the roles. CI also
publishes an installable zip artifact on every merge to main.
Development
composer install # install dependencies
composer test # PHPUnit (run after every change)
composer lint # PHPStan (level 6)
composer cs # PHPCS (WordPress coding standards)
composer cs:fix # auto-fix coding standards
composer build # build the plugin zip into dist/
# a single test file / single test
./vendor/bin/phpunit tests/Unit/Offering/OfferingRepositoryTest.php
./vendor/bin/phpunit --filter testInsertReturnsId
Tests use Brain\Monkey and Mockery to
stub WordPress and $wpdb without a full WP install. To run the plugin in a real
WordPress without Docker, wp-now works well: npx @wp-now/cli@latest start.
CI
Gitea Actions (.gitea/workflows/ci.yml) runs on every push and pull request:
lint (PHPCS), static-analysis (PHPStan), test (PHPUnit on PHP
8.1/8.2/8.3), and no-debug (rejects debug statements in src/). On merge to
main a build job publishes the installable plugin zip as an artifact.
License
GPL-2.0-or-later.