Send students to a chosen page when registration succeeds #116

Merged
thatguygriff merged 1 commits from feature/registration-success-redirect into main 2026-07-28 15:04:44 +00:00
9 changed files with 339 additions and 20 deletions
+1
View File
@@ -15,6 +15,7 @@ each change under the current top section as you work.
### Added ### 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 **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] ## [1.2.1]
+9 -2
View File
@@ -151,18 +151,25 @@
shortcode: 'us_student_register', shortcode: 'us_student_register',
attributes: { attributes: {
loginPageId: { type: 'number', default: 0 }, loginPageId: { type: 'number', default: 0 },
autoRedirect: { type: 'boolean', default: false },
inviteOnlyMessage: { type: 'string', default: '' }, inviteOnlyMessage: { type: 'string', default: '' },
}, },
inspector: (attributes, setAttributes) => [ inspector: (attributes, setAttributes) => [
el( el(
PanelBody, PanelBody,
{ title: __('After email confirmation', 'unsupervised-schedular'), key: 'confirmation' }, { title: __('After registration', 'unsupervised-schedular'), key: 'confirmation' },
el(PageSelect, { el(PageSelect, {
label: __('Sign-in page', 'unsupervised-schedular'), 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'), defaultLabel: __('WordPress login screen', 'unsupervised-schedular'),
value: attributes.loginPageId, value: attributes.loginPageId,
onChange: (loginPageId) => setAttributes({ 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( el(
+7
View File
@@ -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`. - `[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()`). - 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 ## Token Redirect
A `template_redirect` handler (`RegistrationPage::maybeRedirectToRegistrationPage()`) A `template_redirect` handler (`RegistrationPage::maybeRedirectToRegistrationPage()`)
sends any front-end request carrying a `us_invite` token to the configured sends any front-end request carrying a `us_invite` token to the configured
+11 -1
View File
@@ -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/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` | `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-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="…"]`. | | `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 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 blocks), and redirects when the block opts in. A block whose target is its
own page is ignored to avoid a redirect loop. 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 ## How it works
- **`BlockRegistrar`** (`src/BlockRegistrar.php`) hooks `init` and registers - **`BlockRegistrar`** (`src/BlockRegistrar.php`) hooks `init` and registers
+66 -8
View File
@@ -66,9 +66,20 @@ class RegistrationPage {
if ( is_user_logged_in() ) { if ( is_user_logged_in() ) {
if ( self::RESULT_INVITE === $registered ) { 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
? ''
: '<p><a href="' . esc_url( $continue ) . '">'
. esc_html__( 'Continue to your account', 'unsupervised-schedular' )
. '</a></p>';
return '<div class="us-register-form"><p class="us-success">' return '<div class="us-register-form"><p class="us-success">'
. esc_html__( 'Your account has been created and you are now logged in.', 'unsupervised-schedular' ) . esc_html__( 'Your account has been created and you are now logged in.', 'unsupervised-schedular' )
. '</p></div>'; . '</p>' . $link . '</div>';
} }
return '<p>' . esc_html__( 'You already have an account and are logged in.', 'unsupervised-schedular' ) . '</p>'; return '<p>' . esc_html__( 'You already have an account and are logged in.', 'unsupervised-schedular' ) . '</p>';
@@ -98,7 +109,7 @@ class RegistrationPage {
$confirmResult = sanitize_key( Val::string( wp_unslash( $_GET['us_confirmed'] ?? '' ) ) ); $confirmResult = sanitize_key( Val::string( wp_unslash( $_GET['us_confirmed'] ?? '' ) ) );
// Where the post-confirmation prompt sends students to sign in. // 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(); $policyForms = $this->signupPolicies();
$accountQuestions = $this->questions->findByScope( Question::SCOPE_ACCOUNT, activeOnly: true ); $accountQuestions = $this->questions->findByScope( Question::SCOPE_ACCOUNT, activeOnly: true );
@@ -319,21 +330,68 @@ class RegistrationPage {
return $autoApprove ? self::RESULT_CONFIRM_GROUP : self::RESULT_CONFIRM; 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<int|string, mixed> $atts
*/
private function successPageId( array $atts ): int {
return Val::int( $atts['loginPageId'] ?? $atts['login_page_id'] ?? 0 );
}
/** /**
* URL the post-confirmation sign-in link points to: the chosen login page * URL the post-confirmation sign-in link points to: the chosen login page
* when one is configured (and still exists), otherwise the WordPress login * when one is configured (and still exists), otherwise the WordPress login
* screen. * screen.
*/ */
private function loginUrl( int $loginPageId ): string { private function loginUrl( int $loginPageId ): string {
if ( $loginPageId > 0 ) { return $this->continueUrl( $loginPageId ) ?? wp_login_url();
$url = get_permalink( $loginPageId ); }
if ( is_string( $url ) ) { /**
return $url; * The chosen post-registration page's URL, or null when none is configured
} * (or it has since been deleted). Unlike {@see loginUrl()} this has no
* WordPress-login-screen fallback, so callers that need a page the student
* was actually sent to — the invited-student link and the block's
* auto-redirect — can tell "not configured" from "configured".
*/
public function continueUrl( int $pageId ): ?string {
if ( $pageId <= 0 ) {
return null;
} }
return wp_login_url(); $url = get_permalink( $pageId );
return is_string( $url ) ? $url : null;
}
/**
* Whether this request is a *finished* registration — the states the
* block's auto-redirect may act on:
*
* - an invited student who just signed up and is now logged in, and
* - a self-signup returning from the emailed confirmation link, whether
* their account is ready (`ready`) or awaiting studio approval (`1`).
*
* Deliberately excluded: the intermediate "check your email" step (the
* student would never see the instruction) and every failure — a validation
* error or an expired confirmation link (`expired`) — so the message always
* gets shown. The `us_confirmed` values are set by
* {@see EmailConfirmationHandler::maybeConfirm()}.
*/
public function isRegistrationComplete(): bool {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only display flag; the submit that set it was nonce-checked.
$registered = sanitize_key( Val::string( wp_unslash( $_GET['us_registered'] ?? '' ) ) );
if ( self::RESULT_INVITE === $registered ) {
return is_user_logged_in();
}
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only display flag set by EmailConfirmationHandler's redirect.
$confirmed = sanitize_key( Val::string( wp_unslash( $_GET['us_confirmed'] ?? '' ) ) );
return in_array( $confirmed, [ '1', 'ready' ], true );
} }
/** /**
+49 -4
View File
@@ -109,6 +109,7 @@ class BlockRegistrar {
'type' => 'number', 'type' => 'number',
'default' => 0, 'default' => 0,
], ],
'autoRedirect' => $redirectToggle,
'inviteOnlyMessage' => [ 'inviteOnlyMessage' => [
'type' => 'string', 'type' => 'string',
'default' => '', 'default' => '',
@@ -170,10 +171,11 @@ class BlockRegistrar {
/** /**
* Server-side auto-redirect for blocks that opt in via their autoRedirect * Server-side auto-redirect for blocks that opt in via their autoRedirect
* attribute: logged-out visitors on a page containing the booking block * attribute: logged-out visitors on a page containing the booking block
* are sent to its login page, and logged-in visitors on a page containing * are sent to its login page, logged-in visitors on a page containing the
* the student-login block are sent to its booking page. Hooked on * student-login block are sent to its booking page, and a student who has
* `template_redirect` because block rendering happens after output has * just finished registering is sent to the register block's chosen page.
* started, too late to send a Location header. * Hooked on `template_redirect` because block rendering happens after
* output has started, too late to send a Location header.
*/ */
public function maybeAutoRedirect(): void { public function maybeAutoRedirect(): void {
if ( is_admin() || ! is_singular() ) { if ( is_admin() || ! is_singular() ) {
@@ -185,6 +187,10 @@ class BlockRegistrar {
return; return;
} }
if ( $this->maybeRedirectAfterRegistration( $post ) ) {
return;
}
if ( is_user_logged_in() ) { if ( is_user_logged_in() ) {
$attrs = $this->firstBlockAttrs( $post->post_content, 'us-scheduler/student-login' ); $attrs = $this->firstBlockAttrs( $post->post_content, 'us-scheduler/student-login' );
if ( null === $attrs || ! Val::bool( $attrs['autoRedirect'] ?? false ) ) { if ( null === $attrs || ! Val::bool( $attrs['autoRedirect'] ?? false ) ) {
@@ -217,6 +223,45 @@ class BlockRegistrar {
$this->redirect( $this->bookingPage->loginUrl( $loginPageId ) ); $this->redirect( $this->bookingPage->loginUrl( $loginPageId ) );
} }
/**
* Sends a student whose registration has just completed to the register
* block's chosen page, when the block opts in. Only the finished states
* qualify (see {@see RegistrationPage::isRegistrationComplete()}): a
* failure or the "check your email" step stays put so its message is read.
* Unlike the other blocks there is no login-screen fallback — with no page
* chosen there is nowhere to send them, so the link is shown instead.
*
* Returns whether the redirect was issued (it only ever returns in tests;
* {@see redirect()} exits in production).
*/
private function maybeRedirectAfterRegistration( \WP_Post $post ): bool {
// Checked before parsing the content because it is a couple of query
// args, whereas every front-end request would otherwise pay for a
// third block scan.
if ( ! $this->registrationPage->isRegistrationComplete() ) {
return false;
}
$attrs = $this->firstBlockAttrs( $post->post_content, 'us-scheduler/student-register' );
if ( null === $attrs || ! Val::bool( $attrs['autoRedirect'] ?? false ) ) {
return false;
}
$pageId = Val::int( $attrs['loginPageId'] ?? 0 );
if ( $pageId === $post->ID ) {
return false; // Redirecting the page to itself would loop.
}
$url = $this->registrationPage->continueUrl( $pageId );
if ( null === $url ) {
return false;
}
$this->redirect( $url );
return true;
}
/** /**
* Attributes of the first occurrence of the named block in the content, * Attributes of the first occurrence of the named block in the content,
* searching inner blocks so blocks nested inside groups or columns are * searching inner blocks so blocks nested inside groups or columns are
+2 -4
View File
@@ -14,7 +14,7 @@ if (! defined('ABSPATH')) {
* @var bool $canRegister * @var bool $canRegister
* @var string $inviteOnlyMessage Text shown when registration is closed and no valid invite is present. * @var string $inviteOnlyMessage Text shown when registration is closed and no valid invite is present.
* @var bool $open Whether open (self-approval) registration is enabled. * @var bool $open Whether open (self-approval) registration is enabled.
* @var string $successType '' | 'invite' (created + logged in) | 'confirm' (check email) | 'confirm_group' (check email; auto-approved on confirm). * @var string $successType '' | 'confirm' (check email) | 'confirm_group' (check email; auto-approved on confirm). The invited-student success is rendered by RegistrationPage::render() itself, which returns before this template for logged-in visitors.
* @var string $confirmResult '' | '1' (email confirmed, awaiting approval) | 'ready' (confirmed + auto-approved) | 'expired'. * @var string $confirmResult '' | '1' (email confirmed, awaiting approval) | 'ready' (confirmed + auto-approved) | 'expired'.
* @var string $loginUrl Where the post-confirmation sign-in link points. * @var string $loginUrl Where the post-confirmation sign-in link points.
* @var string $error * @var string $error
@@ -57,9 +57,7 @@ $renderQuestionField = static function (Question $question): void {
}; };
?> ?>
<div class="us-register-form"> <div class="us-register-form">
<?php if ($successType === 'invite') : ?> <?php if ($successType === 'confirm') : ?>
<p class="us-success"><?php esc_html_e('Your account has been created and you are now logged in.', 'unsupervised-schedular'); ?></p>
<?php elseif ($successType === 'confirm') : ?>
<p class="us-success"><?php esc_html_e('Your account has been created. Check your email for a link to confirm your address — once you do, a studio admin will review and approve your account.', 'unsupervised-schedular'); ?></p> <p class="us-success"><?php esc_html_e('Your account has been created. Check your email for a link to confirm your address — once you do, a studio admin will review and approve your account.', 'unsupervised-schedular'); ?></p>
<?php elseif ($successType === 'confirm_group') : ?> <?php elseif ($successType === 'confirm_group') : ?>
<p class="us-success"><?php esc_html_e('Your account has been created. Check your email for a link to confirm your address — once you do, your account is ready to use.', 'unsupervised-schedular'); ?></p> <p class="us-success"><?php esc_html_e('Your account has been created. Check your email for a link to confirm your address — once you do, your account is ready to use.', 'unsupervised-schedular'); ?></p>
+48
View File
@@ -484,6 +484,54 @@ class RegistrationPageTest extends TestCase
self::assertStringContainsString('us-success', $html); self::assertStringContainsString('us-success', $html);
self::assertStringContainsString('now logged in', $html); self::assertStringContainsString('now logged in', $html);
// No page chosen: the sign-in-screen fallback is useless to someone who
// is already signed in, so no link is offered at all.
self::assertStringNotContainsString('<a href', $html);
}
public function testInviteSuccessLinksToTheChosenPage(): void
{
$_GET = [ 'us_registered' => 'invite' ];
Functions\when('is_user_logged_in')->justReturn(true);
Functions\when('sanitize_key')->alias(static fn ($v) => strtolower((string) $v));
Functions\expect('get_permalink')->once()->with(4)->andReturn('http://home.test/welcome/');
$html = $this->ctx['page']->render([ 'loginPageId' => 4 ]);
self::assertStringContainsString('now logged in', $html);
self::assertStringContainsString('href="http://home.test/welcome/"', $html);
}
public function testContinueUrlIsNullWithoutAResolvablePage(): void
{
Functions\when('get_permalink')->justReturn(false);
self::assertNull($this->ctx['page']->continueUrl(0));
self::assertNull($this->ctx['page']->continueUrl(4));
}
public function testIsRegistrationCompleteOnlyForFinishedStates(): void
{
Functions\when('sanitize_key')->alias(static fn ($v) => strtolower((string) $v));
// [ query args, logged in, finished ]
$cases = [
'invited student, now logged in' => [['us_registered' => 'invite'], true, true],
'invited student, not logged in' => [['us_registered' => 'invite'], false, false],
'email confirmed, ready' => [['us_confirmed' => 'ready'], false, true],
'email confirmed, pending review' => [['us_confirmed' => '1'], false, true],
'confirmation link expired' => [['us_confirmed' => 'expired'], false, false],
'awaiting email confirmation' => [['us_registered' => 'confirm'], false, false],
'group signup awaiting confirm' => [['us_registered' => 'confirm_group'], false, false],
'plain page view' => [[], false, false],
];
foreach ($cases as $label => [$get, $loggedIn, $expected]) {
$_GET = $get;
Functions\when('is_user_logged_in')->justReturn($loggedIn);
self::assertSame($expected, $this->ctx['page']->isRegistrationComplete(), $label);
}
} }
public function testInviteOnlyMessageCanBeCustomised(): void public function testInviteOnlyMessageCanBeCustomised(): void
+146 -1
View File
@@ -52,6 +52,12 @@ class BlockRegistrarTest extends TestCase
$this->registrationPage = Mockery::mock(RegistrationPage::class); $this->registrationPage = Mockery::mock(RegistrationPage::class);
$this->groupClassPage = Mockery::mock(GroupClassPage::class); $this->groupClassPage = Mockery::mock(GroupClassPage::class);
// Most requests are not a just-finished registration; the tests that
// exercise that path override this.
$this->registrationPage->shouldReceive('isRegistrationComplete')
->andReturn(false)
->byDefault();
$this->registrar = new TestableBlockRegistrar( $this->registrar = new TestableBlockRegistrar(
$this->bookingPage, $this->bookingPage,
$this->loginPage, $this->loginPage,
@@ -126,7 +132,7 @@ class BlockRegistrarTest extends TestCase
array_keys($registered['us-scheduler/student-login']['attributes']) array_keys($registered['us-scheduler/student-login']['attributes'])
); );
self::assertSame( self::assertSame(
['loginPageId', 'inviteOnlyMessage'], ['loginPageId', 'autoRedirect', 'inviteOnlyMessage'],
array_keys($registered['us-scheduler/student-register']['attributes']) array_keys($registered['us-scheduler/student-register']['attributes'])
); );
self::assertSame( self::assertSame(
@@ -397,6 +403,145 @@ class BlockRegistrarTest extends TestCase
self::assertSame([], $this->registrar->redirects); self::assertSame([], $this->registrar->redirects);
} }
public function testAutoRedirectSendsAFinishedRegistrationToTheChosenPage(): void
{
$this->stubSingularRequest(
30,
[
[
'blockName' => 'us-scheduler/student-register',
'attrs' => ['autoRedirect' => true, 'loginPageId' => 4],
'innerBlocks' => [],
],
],
false
);
$this->registrationPage->shouldReceive('isRegistrationComplete')->andReturn(true);
$this->registrationPage->shouldReceive('continueUrl')
->once()->with(4)->andReturn('https://example.com/welcome/');
$this->registrar->maybeAutoRedirect();
self::assertSame(['https://example.com/welcome/'], $this->registrar->redirects);
}
public function testAutoRedirectSendsAJustLoggedInInvitedStudentToTheChosenPage(): void
{
// The invited-student branch completes logged in, so the logged-in
// student-login branch must not get first claim on the request.
$this->stubSingularRequest(
30,
[
[
'blockName' => 'us-scheduler/student-register',
'attrs' => ['autoRedirect' => true, 'loginPageId' => 4],
'innerBlocks' => [],
],
],
true
);
$this->registrationPage->shouldReceive('isRegistrationComplete')->andReturn(true);
$this->registrationPage->shouldReceive('continueUrl')
->once()->with(4)->andReturn('https://example.com/welcome/');
$this->registrar->maybeAutoRedirect();
self::assertSame(['https://example.com/welcome/'], $this->registrar->redirects);
}
public function testNoRedirectWhenTheRegistrationIsNotFinished(): void
{
// e.g. the "check your email" step, or a validation error — the
// message has to be read, so the block never redirects past it.
$this->stubSingularRequest(
30,
[
[
'blockName' => 'us-scheduler/student-register',
'attrs' => ['autoRedirect' => true, 'loginPageId' => 4],
'innerBlocks' => [],
],
],
false
);
$this->registrationPage->shouldReceive('continueUrl')->never();
$this->registrar->maybeAutoRedirect();
self::assertSame([], $this->registrar->redirects);
}
public function testNoRedirectWhenTheRegisterBlockDoesNotOptIn(): void
{
$this->stubSingularRequest(
30,
[
[
'blockName' => 'us-scheduler/student-register',
'attrs' => ['loginPageId' => 4],
'innerBlocks' => [],
],
],
false
);
$this->registrationPage->shouldReceive('isRegistrationComplete')->andReturn(true);
$this->registrationPage->shouldReceive('continueUrl')->never();
$this->registrar->maybeAutoRedirect();
self::assertSame([], $this->registrar->redirects);
}
public function testNoRedirectWhenTheRegisterBlockHasNoPageChosen(): void
{
$this->stubSingularRequest(
30,
[
[
'blockName' => 'us-scheduler/student-register',
'attrs' => ['autoRedirect' => true],
'innerBlocks' => [],
],
],
false
);
$this->registrationPage->shouldReceive('isRegistrationComplete')->andReturn(true);
// No page chosen: there is no login-screen fallback to redirect to,
// so the student keeps the on-page confirmation instead.
$this->registrationPage->shouldReceive('continueUrl')->once()->with(0)->andReturnNull();
$this->registrar->maybeAutoRedirect();
self::assertSame([], $this->registrar->redirects);
}
public function testNoRedirectWhenTheRegisterBlockPointsAtItsOwnPage(): void
{
$this->stubSingularRequest(
4,
[
[
'blockName' => 'us-scheduler/student-register',
'attrs' => ['autoRedirect' => true, 'loginPageId' => 4],
'innerBlocks' => [],
],
],
false
);
$this->registrationPage->shouldReceive('isRegistrationComplete')->andReturn(true);
$this->registrationPage->shouldReceive('continueUrl')->never();
$this->registrar->maybeAutoRedirect();
self::assertSame([], $this->registrar->redirects);
}
public function testNoRedirectOutsideSingularFrontEndRequests(): void public function testNoRedirectOutsideSingularFrontEndRequests(): void
{ {
Functions\when('is_admin')->justReturn(false); Functions\when('is_admin')->justReturn(false);