From 372f981a0896ce81aafcfa38b6484e3b17ea87f7 Mon Sep 17 00:00:00 2001 From: James Griffin Date: Sun, 7 Jun 2026 10:24:33 -0300 Subject: [PATCH 1/2] Add registration-page selector to the Invites page Invitation links previously pointed at the site home page, which usually does not host the [us_student_register] shortcode. Let the studio admin choose the registration page (stored in the us_registration_page_id option); invitation links now point there, falling back to the home page when unset (with a warning notice). - RegistrationController: OPTION_PAGE constant; set_page action; pass the page id/url to the template. - templates/admin/invites.php: wp_dropdown_pages selector + save; build the invite link from the selected page. - Doc updated. Co-Authored-By: Claude Opus 4.8 --- docs/features/account-registration.md | 1 + src/Auth/RegistrationController.php | 13 ++++++++- templates/admin/invites.php | 40 +++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/docs/features/account-registration.md b/docs/features/account-registration.md index 16297ce..e136211 100644 --- a/docs/features/account-registration.md +++ b/docs/features/account-registration.md @@ -41,6 +41,7 @@ recorded in `us_policy_acceptances` with `registration_type = account` and ## Admin Interface **Invites** in wp-admin (`manage_students`, studio admin only): +- Select the **registration page** (the page hosting `[us_student_register]`), stored in the `us_registration_page_id` option; invitation links point there (falling back to the home page if unset) - Invite an email (creates a pending invite + link) - List pending invites; revoke an invite diff --git a/src/Auth/RegistrationController.php b/src/Auth/RegistrationController.php index f70f5e6..2bc1308 100644 --- a/src/Auth/RegistrationController.php +++ b/src/Auth/RegistrationController.php @@ -5,6 +5,11 @@ namespace Unsupervised\Schedular\Auth; class RegistrationController { + /** + * Option storing the page ID that hosts the [us_student_register] shortcode. + */ + public const OPTION_PAGE = 'us_registration_page_id'; + public function __construct( private InviteRepository $invites ) {} public function renderPage(): void { @@ -16,7 +21,9 @@ class RegistrationController { $this->handleFormAction(); } - $pendingInvites = $this->invites->findPending(); + $pendingInvites = $this->invites->findPending(); + $registrationPageId = (int) get_option( self::OPTION_PAGE, 0 ); + $registrationPageUrl = $registrationPageId > 0 ? (string) get_permalink( $registrationPageId ) : ''; include USC_PLUGIN_DIR . 'templates/admin/invites.php'; } @@ -26,6 +33,10 @@ class RegistrationController { // phpcs:disable WordPress.Security.NonceVerification.Missing $action = sanitize_key( wp_unslash( $_POST['usc_action'] ?? '' ) ); + if ( 'set_page' === $action ) { + update_option( self::OPTION_PAGE, absint( $_POST['registration_page_id'] ?? 0 ) ); + } + if ( 'invite' === $action ) { $email = sanitize_email( wp_unslash( $_POST['email'] ?? '' ) ); diff --git a/templates/admin/invites.php b/templates/admin/invites.php index b5ce256..3861330 100644 --- a/templates/admin/invites.php +++ b/templates/admin/invites.php @@ -5,12 +5,46 @@ if (! defined('ABSPATH')) { exit; } -/** @var list<\Unsupervised\Schedular\Auth\Invite> $pendingInvites */ +/** + * @var list<\Unsupervised\Schedular\Auth\Invite> $pendingInvites + * @var int $registrationPageId + * @var string $registrationPageUrl + */ ?>

+

+
+ + + + + + + +
+ 'registration_page_id', + 'id' => 'registration_page_id', + 'selected' => $registrationPageId, + 'show_option_none' => esc_html__('— Select a page —', 'unsupervised-schedular'), + 'option_none_value' => '0', + ] + ); + ?> +

+
+ +
+ + +

+ +

@@ -38,13 +72,13 @@ if (! defined('ABSPATH')) { + - token, home_url('/'))); ?> + token, $linkBase)); ?> email); ?> - -- 2.52.0 From 330900a24654a39fedfde40a394708fe3fcb587e Mon Sep 17 00:00:00 2001 From: James Griffin Date: Sun, 7 Jun 2026 10:31:11 -0300 Subject: [PATCH 2/2] Auto-redirect invite tokens to the registration page; rename invite button - RegistrationPage::maybeRedirectToRegistrationPage() (hooked on template_redirect): any front-end request carrying a us_invite token is redirected to the configured registration page (token preserved), unless already there. Covers links shared before a page was selected; no-op when no page is set. - Invites button text: "Send Invite" -> "Generate Invitation Link". - Doc updated. Co-Authored-By: Claude Opus 4.8 --- docs/features/account-registration.md | 7 +++++++ src/Auth/RegistrationPage.php | 25 +++++++++++++++++++++++++ src/ShortcodeRegistrar.php | 1 + templates/admin/invites.php | 2 +- 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/features/account-registration.md b/docs/features/account-registration.md index e136211..7c49b99 100644 --- a/docs/features/account-registration.md +++ b/docs/features/account-registration.md @@ -48,6 +48,13 @@ recorded in `us_policy_acceptances` with `registration_type = account` and ## Frontend Shortcode - `[us_student_register]` — the registration page. Shows the form for a valid pending invite; otherwise shows an "by invitation only" message (in `invite` mode). +## Token Redirect +A `template_redirect` handler (`RegistrationPage::maybeRedirectToRegistrationPage()`) +sends any front-end request carrying a `us_invite` token to the configured +registration page (preserving the token), unless it is already on that page. This +covers invitation links generated/shared before a registration page was selected. +No-op when no registration page is set. + ## Capabilities - `manage_students` — manage invites (studio admin; administrators inherit it via the `user_has_cap` filter). Added to `RoleManager::STUDIO_ADMIN_CAPS`. diff --git a/src/Auth/RegistrationPage.php b/src/Auth/RegistrationPage.php index 0603231..bcafff2 100644 --- a/src/Auth/RegistrationPage.php +++ b/src/Auth/RegistrationPage.php @@ -52,6 +52,31 @@ class RegistrationPage { return (string) ob_get_clean(); } + /** + * Redirect to the configured registration page when an invite token lands + * elsewhere (e.g. a link generated before the page was selected). Hooked on + * `template_redirect`. + */ + public function maybeRedirectToRegistrationPage(): void { + if ( is_admin() ) { + return; + } + + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only token used only to build the redirect target. + $token = sanitize_text_field( wp_unslash( $_GET['us_invite'] ?? '' ) ); + if ( '' === $token ) { + return; + } + + $pageId = (int) get_option( RegistrationController::OPTION_PAGE, 0 ); + if ( $pageId <= 0 || is_page( $pageId ) ) { + return; + } + + wp_safe_redirect( add_query_arg( 'us_invite', rawurlencode( $token ), (string) get_permalink( $pageId ) ) ); + exit; + } + /** * Process the submitted registration. Returns true on success or an error * message string on failure. diff --git a/src/ShortcodeRegistrar.php b/src/ShortcodeRegistrar.php index 24a1762..0fb3501 100644 --- a/src/ShortcodeRegistrar.php +++ b/src/ShortcodeRegistrar.php @@ -32,6 +32,7 @@ class ShortcodeRegistrar { add_shortcode( 'us_booking', [ $this->bookingPage, 'render' ] ); add_shortcode( 'us_student_login', [ $this->loginPage, 'render' ] ); add_shortcode( 'us_student_register', [ $this->registrationPage, 'render' ] ); + add_action( 'template_redirect', [ $this->registrationPage, 'maybeRedirectToRegistrationPage' ] ); add_action( 'wp_enqueue_scripts', [ $this, 'enqueueAssets' ] ); } diff --git a/templates/admin/invites.php b/templates/admin/invites.php index 3861330..0d7c19f 100644 --- a/templates/admin/invites.php +++ b/templates/admin/invites.php @@ -55,7 +55,7 @@ if (! defined('ABSPATH')) { - +

-- 2.52.0