Files
unsupervised-scheduler/docs/features/editor-blocks.md
T
thatguygriffandClaude Fable 5 7b00811133
CI / Tests (PHP 8.2) (pull_request) Successful in 41s
CI / Tests (PHP 8.1) (pull_request) Successful in 46s
CI / No Debug Code (pull_request) Successful in 2s
CI / PHPStan (pull_request) Successful in 2m45s
CI / Coding Standards (pull_request) Successful in 2m55s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m35s
CI / Build Plugin Zip (pull_request) Skipped
Show a sign-in link instead of the form after email confirmation
Closes #67

When a student lands on the registration page from the confirmation
email (?us_confirmed=1), replace the registration form with the
confirmation message and a "Sign in to your account" link — the form
is useless at that point and re-submitting would only produce an
"account already exists" error. A confirmed-but-unapproved student can
already log in (the pending gate only withholds booking), so signing in
is the natural next step.

The link target follows the booking block's pattern: a loginPageId
block attribute (page picker in the editor sidebar) or login_page_id
shortcode attribute, falling back to wp_login_url(). The expired-link
notice keeps the form as before.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-18 17:53:38 -03:00

100 lines
5.7 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 the "Sign in to your account" link points to after a student confirms their email. `0` = the WordPress login screen. Shortcode equivalent: `[us_student_register login_page_id="…"]`. |
| `us-scheduler/group-classes` | `offeringId` (number) | `0` | Restrict the page to a single group class, for embedding on a page dedicated to that class. `0` = browse all classes. 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.
## 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.
- **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.