diff --git a/CHANGELOG.md b/CHANGELOG.md index 9935427..bd308fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ each change under the current top section as you work. ### Added - The **Group Classes** block can now be pinned to a single class, under **Classes shown → Class** in the block sidebar (shortcode: `[us_group_classes offering="…"]`). Pick a class and the block shows only that one, so it can be embedded on a page that describes the class. In this mode the class's own description is left out to avoid repeating the page copy — the card shows the schedule, instructor, price, enrolment deadline and the enrol/withdraw controls. Leaving it on **All classes** keeps the full browsable catalog with descriptions. +- The **Student Registration** block can now send students onward to a page of your choosing once they finish registering. Its **After email confirmation** panel is now **After registration**: the page you pick there is where the link shown to a newly registered student points — the "Sign in to your account" link after they confirm their email, and a "Continue to your account" link for an invited student, who is signed in immediately. A new **Redirect automatically** option takes them straight there instead of showing the link. Registration errors are never skipped — a failed sign-up and an expired confirmation link still show their message on the page, as does the "check your email to confirm your address" step. The redirect needs a page to be chosen; with none set, students see the link (or, for invited students, just the confirmation) as before. ## [1.2.1] diff --git a/assets/js/blocks.js b/assets/js/blocks.js index 96cdd1f..7c24482 100644 --- a/assets/js/blocks.js +++ b/assets/js/blocks.js @@ -151,18 +151,25 @@ shortcode: 'us_student_register', attributes: { loginPageId: { type: 'number', default: 0 }, + autoRedirect: { type: 'boolean', default: false }, inviteOnlyMessage: { type: 'string', default: '' }, }, inspector: (attributes, setAttributes) => [ el( PanelBody, - { title: __('After email confirmation', 'unsupervised-schedular'), key: 'confirmation' }, + { title: __('After registration', 'unsupervised-schedular'), key: 'confirmation' }, el(PageSelect, { label: __('Sign-in page', 'unsupervised-schedular'), - help: __('Where the sign-in link shown after a student confirms their email address sends them.', 'unsupervised-schedular'), + help: __('Where students are sent once registration finishes — after they confirm their email address, or straight away for an invited student.', 'unsupervised-schedular'), defaultLabel: __('WordPress login screen', 'unsupervised-schedular'), value: attributes.loginPageId, onChange: (loginPageId) => setAttributes({ loginPageId }), + }), + el(ToggleControl, { + label: __('Redirect automatically', 'unsupervised-schedular'), + help: __('Send students straight to that page instead of showing the link. Requires a page to be chosen; errors and the "check your email" step are never skipped.', 'unsupervised-schedular'), + checked: !!attributes.autoRedirect, + onChange: (autoRedirect) => setAttributes({ autoRedirect }), }) ), el( diff --git a/docs/features/account-registration.md b/docs/features/account-registration.md index e0d29c7..4e20698 100644 --- a/docs/features/account-registration.md +++ b/docs/features/account-registration.md @@ -128,6 +128,13 @@ recorded in `us_policy_acceptances` with `registration_type = account` and - `[us_student_register]` — the registration page. In `invite` mode: shows the form for a valid pending invite, else an "by invitation only" message. In `self_approval` mode: shows the form to anyone (editable email), and renders confirmation-result notices from `?us_confirmed=1|expired`. - The invitation-only message is customisable: block attribute `inviteOnlyMessage` (set under the block's **Invitation-only notice** panel) / shortcode attribute `invite_only_message`. Blank falls back to the default wording (`RegistrationPage::inviteOnlyMessage()`). +## Where Students Go Next +The block's **After registration** panel picks the page a student continues to once +registration finishes, and whether they get there by hand or automatically. + +- **Sign-in page** (`loginPageId` / `login_page_id`) — the target of the "Sign in to your account" link shown after email confirmation (`?us_confirmed=1|ready`, falling back to the WordPress login screen) and of the "Continue to your account" link an invited student sees on the spot (`?us_registered=invite`; no link at all with no page chosen, since an already-signed-in student has no use for the login screen). +- **Redirect automatically** (`autoRedirect`, block only) — sends the student to that page instead of showing the link, via `BlockRegistrar::maybeAutoRedirect()` on `template_redirect`. It fires only on those two finished states (`RegistrationPage::isRegistrationComplete()`), so the "check your email" step, a validation error, and an `expired` confirmation link are always shown rather than redirected past. With no page chosen nothing happens — there is deliberately no login-screen fallback for the redirect. See `editor-blocks.md`. + ## Token Redirect A `template_redirect` handler (`RegistrationPage::maybeRedirectToRegistrationPage()`) sends any front-end request carrying a `us_invite` token to the configured diff --git a/docs/features/editor-blocks.md b/docs/features/editor-blocks.md index 67e520e..3b76daf 100644 --- a/docs/features/editor-blocks.md +++ b/docs/features/editor-blocks.md @@ -29,7 +29,8 @@ Four blocks have sidebar (inspector) options: | `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/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, @@ -48,6 +49,15 @@ 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 diff --git a/src/Auth/RegistrationPage.php b/src/Auth/RegistrationPage.php index feb6c62..5623675 100644 --- a/src/Auth/RegistrationPage.php +++ b/src/Auth/RegistrationPage.php @@ -66,9 +66,20 @@ class RegistrationPage { if ( is_user_logged_in() ) { if ( self::RESULT_INVITE === $registered ) { + // An invited student is done the moment they land here logged in, + // so this is where their "continue" link belongs. The sign-in-page + // fallback is deliberately not used: pointing someone who is + // already signed in at the login screen helps nobody. + $continue = $this->continueUrl( $this->successPageId( $atts ) ); + $link = null === $continue + ? '' + : '
' + . esc_html__( 'Continue to your account', 'unsupervised-schedular' ) + . '
'; + return '' . esc_html__( 'Your account has been created and you are now logged in.', 'unsupervised-schedular' ) - . '
' . esc_html__( 'You already have an account and are logged in.', 'unsupervised-schedular' ) . '
'; @@ -98,7 +109,7 @@ class RegistrationPage { $confirmResult = sanitize_key( Val::string( wp_unslash( $_GET['us_confirmed'] ?? '' ) ) ); // Where the post-confirmation prompt sends students to sign in. - $loginUrl = $this->loginUrl( Val::int( $atts['loginPageId'] ?? $atts['login_page_id'] ?? 0 ) ); + $loginUrl = $this->loginUrl( $this->successPageId( $atts ) ); $policyForms = $this->signupPolicies(); $accountQuestions = $this->questions->findByScope( Question::SCOPE_ACCOUNT, activeOnly: true ); @@ -319,21 +330,68 @@ class RegistrationPage { return $autoApprove ? self::RESULT_CONFIRM_GROUP : self::RESULT_CONFIRM; } + /** + * The page id chosen for the post-registration destination, from either the + * block (`loginPageId`) or shortcode (`login_page_id`) attribute. + * + * @param array