Send students to a chosen page when registration succeeds
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

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]>
This commit is contained in:
2026-07-28 10:58:17 -03:00
co-authored by Claude Opus 5
parent d866aa7295
commit 13d6b3e14e
9 changed files with 339 additions and 20 deletions
+146 -1
View File
@@ -52,6 +52,12 @@ class BlockRegistrarTest extends TestCase
$this->registrationPage = Mockery::mock(RegistrationPage::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->bookingPage,
$this->loginPage,
@@ -126,7 +132,7 @@ class BlockRegistrarTest extends TestCase
array_keys($registered['us-scheduler/student-login']['attributes'])
);
self::assertSame(
['loginPageId', 'inviteOnlyMessage'],
['loginPageId', 'autoRedirect', 'inviteOnlyMessage'],
array_keys($registered['us-scheduler/student-register']['attributes'])
);
self::assertSame(
@@ -397,6 +403,145 @@ class BlockRegistrarTest extends TestCase
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
{
Functions\when('is_admin')->justReturn(false);