Lesson Booking block — new sidebar options for logged-out visitors: a Login page dropdown (all published pages; default remains the WordPress login screen with a redirect back) controlling where the "log in to book a lesson" link points, and a Redirect automatically toggle (off by default).
Student Login block — new sidebar options for logged-in visitors: a Booking page dropdown controlling where the "View available lessons" link points and where students land after logging in (default remains the current page), and the same Redirect automatically toggle (off by default; inert until a booking page is chosen).
The link targets are also usable from the shortcodes as [us_booking login_page_id="…"] and [us_student_login booking_page_id="…"]; auto-redirect is block-only.
How
Block attribute schemas are declared both server-side (BlockRegistrar) and in assets/js/blocks.js (required for the wp.serverSideRender preview endpoint to accept them); the editor gains a shared page-select inspector component.
Auto-redirect cannot happen during block rendering (output has already started, so no Location header). BlockRegistrar::maybeAutoRedirect() runs on template_redirect, parses the queried singular page's content for the block — including blocks nested in groups/columns — and redirects when the block opts in. A block whose target is its own page is ignored to avoid redirect loops.
If a chosen page is later deleted, both blocks fall back to their defaults.
Pre-existing bug fixed
Using any of the four shortcodes bare (e.g. [us_booking]) fataled: WordPress core's shortcode_parse_atts('') returns an empty string, not an array, so the strictly-typed render(array $atts) methods threw a TypeError. ShortcodeRegistrar now wraps each callback to normalize non-array attribute values.
Closes #51
## What
- **Lesson Booking block** — new sidebar options for logged-out visitors: a **Login page** dropdown (all published pages; default remains the WordPress login screen with a redirect back) controlling where the "log in to book a lesson" link points, and a **Redirect automatically** toggle (off by default).
- **Student Login block** — new sidebar options for logged-in visitors: a **Booking page** dropdown controlling where the "View available lessons" link points *and* where students land after logging in (default remains the current page), and the same **Redirect automatically** toggle (off by default; inert until a booking page is chosen).
- The link targets are also usable from the shortcodes as `[us_booking login_page_id="…"]` and `[us_student_login booking_page_id="…"]`; auto-redirect is block-only.
## How
- Block attribute schemas are declared both server-side (`BlockRegistrar`) and in `assets/js/blocks.js` (required for the `wp.serverSideRender` preview endpoint to accept them); the editor gains a shared page-select inspector component.
- Auto-redirect cannot happen during block rendering (output has already started, so no `Location` header). `BlockRegistrar::maybeAutoRedirect()` runs on `template_redirect`, parses the queried singular page's content for the block — including blocks nested in groups/columns — and redirects when the block opts in. A block whose target is its own page is ignored to avoid redirect loops.
- If a chosen page is later deleted, both blocks fall back to their defaults.
## Pre-existing bug fixed
Using any of the four shortcodes bare (e.g. `[us_booking]`) fataled: WordPress core's `shortcode_parse_atts('')` returns an empty string, not an array, so the strictly-typed `render(array $atts)` methods threw a TypeError. `ShortcodeRegistrar` now wraps each callback to normalize non-array attribute values.
## Tests
- `tests/Unit/BlockRegistrarTest.php` — attribute schemas, attribute pass-through, auto-redirect behaviour (opt-in, nested blocks, self-target guard, logged-in/out routing).
- `tests/Unit/Booking/BookingPageTest.php`, `tests/Unit/Auth/LoginPageTest.php` — new link-target resolution and fallbacks.
- `tests/Unit/ShortcodeRegistrarTest.php` — new; covers registration and the bare-shortcode normalization.
`composer test` (263 tests), `composer lint` (PHPStan level 10), and `composer cs` all pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The booking block gains a loginPageId attribute choosing which page its
logged-out "log in to book a lesson" link points to (default remains the
WordPress login screen), and the student-login block gains a
bookingPageId attribute controlling the logged-in "View available
lessons" link and the post-login redirect target (default remains the
current page). Both blocks also gain an autoRedirect toggle, off by
default, that sends the visitor straight to the target page; block
rendering starts after output, so the redirect runs on
template_redirect by parsing the queried page's content for the block,
with a self-target guard against redirect loops. The link targets are
also available to the shortcodes as login_page_id/booking_page_id.
Also fixes a pre-existing fatal: WordPress passes an empty string (not
an array) to shortcode callbacks when a shortcode is used without
attributes, so bare [us_booking] etc. threw a TypeError against the
strictly-typed render(array $atts) methods. ShortcodeRegistrar now
wraps each callback to normalize non-array attribute values.
Closes#51
Co-Authored-By: Claude Fable 5 <[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.
Closes #51
What
[us_booking login_page_id="…"]and[us_student_login booking_page_id="…"]; auto-redirect is block-only.How
BlockRegistrar) and inassets/js/blocks.js(required for thewp.serverSideRenderpreview endpoint to accept them); the editor gains a shared page-select inspector component.Locationheader).BlockRegistrar::maybeAutoRedirect()runs ontemplate_redirect, parses the queried singular page's content for the block — including blocks nested in groups/columns — and redirects when the block opts in. A block whose target is its own page is ignored to avoid redirect loops.Pre-existing bug fixed
Using any of the four shortcodes bare (e.g.
[us_booking]) fataled: WordPress core'sshortcode_parse_atts('')returns an empty string, not an array, so the strictly-typedrender(array $atts)methods threw a TypeError.ShortcodeRegistrarnow wraps each callback to normalize non-array attribute values.Tests
tests/Unit/BlockRegistrarTest.php— attribute schemas, attribute pass-through, auto-redirect behaviour (opt-in, nested blocks, self-target guard, logged-in/out routing).tests/Unit/Booking/BookingPageTest.php,tests/Unit/Auth/LoginPageTest.php— new link-target resolution and fallbacks.tests/Unit/ShortcodeRegistrarTest.php— new; covers registration and the bare-shortcode normalization.composer test(263 tests),composer lint(PHPStan level 10), andcomposer csall pass.🤖 Generated with Claude Code