Files
unsupervised-scheduler/docs/features/editor-blocks.md
T
thatguygriffandClaude Opus 5 13d6b3e14e
CI / Tests (PHP 8.2) (pull_request) Successful in 49s
CI / Tests (PHP 8.1) (pull_request) Successful in 1m0s
CI / Coding Standards (pull_request) Successful in 2m51s
CI / PHPStan (pull_request) Successful in 2m57s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m40s
CI / Build Plugin Zip (pull_request) Skipped
CI / No Debug Code (pull_request) Successful in 2s
Send students to a chosen page when registration succeeds
The Student Registration block's "After email confirmation" panel becomes
"After registration": the page it selects is now where a newly registered
student continues to, and a new autoRedirect toggle sends them there
instead of showing the link.

Only the two finished states qualify (RegistrationPage::isRegistrationComplete):
an invited student who is now logged in, and a self-signup back from the
emailed confirmation link. A validation error, an expired confirmation
link, and the intermediate "check your email" step all stay on the page so
their message is read.

The invited-student success previously had no link at all; it gains a
"Continue to your account" one. That path deliberately has no
WordPress-login-screen fallback — pointing someone already signed in at the
login screen helps nobody — so continueUrl() distinguishes "no page chosen"
from "page chosen", and the redirect does nothing until one is picked.

Closes #115

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-28 10:58:17 -03:00

112 lines
7.0 KiB
Markdown

# Editor Blocks
Gutenberg dynamic-block wrappers for the plugin's four front-end shortcodes,
so the pages can be previewed and styled inside the block editor instead of
appearing as grey shortcode text.
## Blocks
| Block | Wraps shortcode | Front-end renderer |
|---|---|---|
| `us-scheduler/booking` | `[us_booking]` | `Booking\BookingPage::render()` |
| `us-scheduler/student-login` | `[us_student_login]` | `Auth\LoginPage::render()` |
| `us-scheduler/student-register` | `[us_student_register]` | `Auth\RegistrationPage::render()` |
| `us-scheduler/group-classes` | `[us_group_classes]` | `GroupClass\GroupClassPage::render()` |
The shortcodes remain registered for back-compat; blocks and shortcodes share
the same page objects (constructed once in `Plugin::boot()`), so front-end
output is identical either way. Pasting a shortcode into the block editor
auto-converts it to the matching block via a `transforms.from` shortcode
transform.
## Block options
Four blocks have sidebar (inspector) options:
| Block | Attribute | Default | Effect |
|---|---|---|---|
| `us-scheduler/booking` | `loginPageId` (number) | `0` | Page the "log in to book a lesson" link points to for logged-out visitors. `0` = the WordPress login screen (with a redirect back to the current page). |
| `us-scheduler/booking` | `autoRedirect` (boolean) | `false` | Send logged-out visitors straight to the login page instead of showing the link. |
| `us-scheduler/student-login` | `bookingPageId` (number) | `0` | Page the "View available lessons" link points to for logged-in visitors, and the post-login redirect target. `0` = the current page. |
| `us-scheduler/student-login` | `autoRedirect` (boolean) | `false` | Send logged-in visitors straight to the booking page instead of showing the link. Does nothing until a booking page is chosen. |
| `us-scheduler/student-register` | `loginPageId` (number) | `0` | Page students continue to once registration finishes — the "Sign in to your account" link after they confirm their email, and the "Continue to your account" link an invited student gets on the spot. `0` = the WordPress login screen for the confirmation link, and no link at all for the (already signed-in) invited student. Shortcode equivalent: `[us_student_register login_page_id="…"]`. |
| `us-scheduler/student-register` | `autoRedirect` (boolean) | `false` | Send students straight to that page instead of showing the link. Does nothing until a page is chosen — there is no login-screen fallback here. |
| `us-scheduler/group-classes` | `offeringId` (number) | `0` | Restrict the page to a single group class, for embedding on a page dedicated to that class. The class description is then omitted — only the schedule, instructor, price and enrolment controls are shown, so the surrounding page's own copy is not repeated. `0` = browse all classes, descriptions included. Shortcode equivalent: `[us_group_classes offering="…"]`. |
The page selects list all published pages; if a chosen page is later deleted,
the blocks fall back to their defaults. The group-classes block's class
select is a dropdown of active group classes fetched from
`GET /us-scheduler/v1/offerings?kind=group_class`; a stored class that is no
longer offered shows as "Unavailable class #N" rather than silently falling
back to all classes. The link targets are also available
to the shortcodes as `[us_booking login_page_id="…"]` and
`[us_student_login booking_page_id="…"]`; auto-redirect is block-only.
Auto-redirect cannot happen during block rendering (output has already
started, so a `Location` header cannot be sent). Instead
`BlockRegistrar::maybeAutoRedirect()` runs on `template_redirect`, parses the
queried singular post's content for the block (including inside nested
blocks), and redirects when the block opts in. A block whose target is its
own page is ignored to avoid a redirect loop.
The registration block's auto-redirect additionally only fires on a
**finished** registration — `RegistrationPage::isRegistrationComplete()`: an
invited student who is now logged in (`?us_registered=invite`), or a
self-signup back from the emailed confirmation link (`?us_confirmed=ready|1`).
The intermediate "check your email" step and every failure (a validation
error, `?us_confirmed=expired`) stay on the page so the student reads the
message. That check runs before the content is parsed, so an ordinary page
view does not pay for the extra block scan.
## How it works
- **`BlockRegistrar`** (`src/BlockRegistrar.php`) hooks `init` and registers
each block with `register_block_type()`: a `render_callback` per block, the
shared editor script (`assets/js/blocks.js`, handle
`us-scheduler-blocks`), and the front-end stylesheet
(`assets/css/frontend.css`, handle `us-scheduler`) as the block `style` so
it also loads inside the editor and previews pick up theme styling.
- **`assets/js/blocks.js`** (vanilla JS, no build step) registers the client
side of each block — title, icon, keywords, shortcode transform — and
renders the editor preview with `wp.serverSideRender`, which fetches the
server-rendered markup via the `/wp/v2/block-renderer` REST route.
- **`BlockPreview`** (`src/BlockPreview.php`) supplies static, script-free
markup for editor previews. `BlockRegistrar::isEditorPreview()` detects the
block-renderer context via the `REST_REQUEST` constant (front-end template
rendering never happens inside a REST request) and renders the preview
instead of the live page.
## Editor preview behaviour
Live pages cannot run in the editor: booking and group classes are populated
by JavaScript making authenticated REST calls (and may load Stripe.js),
registration requires a valid invite token, and login short-circuits for
logged-in users (the editing admin always is). Each preview therefore
reproduces the live wrapper elements and CSS classes with representative
placeholder content:
- **Booking** — `#us-booking-app` with sample `.us-day` / `.us-slot` rows and
disabled Book buttons.
- **Group classes** — `#us-group-app` with a sample `.us-class` card and a
disabled Enrol button. When `offeringId` pins a single class the preview
drops the sample description, matching what the live page renders in that
mode.
- **Login** — the real `templates/frontend/login-page.php` template (it has
no request-state dependencies).
- **Registration** — a disabled sample of the `.us-register-form` fields.
Each preview starts with a `.us-editor-note` paragraph explaining what the
published page shows instead. The note class only appears in editor previews.
## Tests
- `tests/Unit/BlockRegistrarTest.php` — hook registration, block/asset
registration, attribute schemas, front-end delegation to the page objects,
preview-mode routing, auto-redirect behaviour.
- `tests/Unit/Booking/BookingPageTest.php` — logged-out login-link targets
and fallbacks.
- `tests/Unit/Auth/LoginPageTest.php` — logged-in booking-link targets and
fallbacks.
- `tests/Unit/BlockPreviewTest.php` — preview markup mirrors the live CSS
classes/ids and includes the editor note.