` link * is opened, then redirect back to the registration page with a result flag. */ public function maybeConfirm(): void { if ( is_admin() ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- the token is itself the capability-bearing secret (like a password-reset key); nonces do not apply to an emailed link. $rawToken = sanitize_text_field( Val::string( wp_unslash( $_GET['us_confirm'] ?? '' ) ) ); if ( '' === $rawToken ) { return; } $base = $this->registrationPageUrl(); $userId = RegistrationStatus::userIdForToken( $rawToken ); if ( null === $userId || RegistrationStatus::isTokenExpired( $userId, gmdate( 'Y-m-d H:i:s' ) ) ) { wp_safe_redirect( add_query_arg( 'us_confirmed', 'expired', $base ) ); exit; } RegistrationStatus::confirmEmail( $userId ); $user = get_user_by( 'id', $userId ); // Group invite link signups skip the admin review queue: confirming the // email approves the account on the spot, so the student can sign in // immediately instead of waiting for a studio admin. if ( RegistrationStatus::isAutoApprove( $userId ) ) { RegistrationStatus::approve( $userId ); if ( $user instanceof \WP_User ) { $this->mailer->sendApproved( $user ); } wp_safe_redirect( add_query_arg( 'us_confirmed', 'ready', $base ) ); exit; } if ( $user instanceof \WP_User ) { $this->mailer->notifyAdminsPending( $user ); } wp_safe_redirect( add_query_arg( 'us_confirmed', '1', $base ) ); exit; } /** * Point WordPress's own "Register" links at the studio registration page * while open registration is on and a page is configured. */ public function registerUrl( string $url ): string { if ( ! $this->settings->openRegistrationEnabled() ) { return $url; } $pageId = Val::int( get_option( RegistrationController::OPTION_PAGE, 0 ) ); return $pageId > 0 ? (string) get_permalink( $pageId ) : $url; } /** * Redirect any `wp-login.php?action=register` request (GET or POST) to the * studio registration page, so the bare native form — which cannot collect * required policy acceptances — is never used. */ public function blockNativeRegistration(): void { if ( ! $this->settings->openRegistrationEnabled() ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only routing decision; no state is changed here. $action = sanitize_key( Val::string( wp_unslash( $_REQUEST['action'] ?? '' ) ) ); if ( 'register' !== $action ) { return; } $pageId = Val::int( get_option( RegistrationController::OPTION_PAGE, 0 ) ); if ( $pageId <= 0 ) { return; } wp_safe_redirect( (string) get_permalink( $pageId ) ); exit; } /** * Fail-safe: reject any native registration attempt while open registration * is on, so `register_new_user()` can never create a policy-less account. * * @param \WP_Error $errors Accumulated registration errors. * @return \WP_Error */ public function blockRegistrationErrors( \WP_Error $errors ): \WP_Error { if ( $this->settings->openRegistrationEnabled() ) { $errors->add( 'us_registration_redirect', esc_html__( 'Please register on the studio registration page.', 'unsupervised-schedular' ) ); } return $errors; } private function registrationPageUrl(): string { $pageId = Val::int( get_option( RegistrationController::OPTION_PAGE, 0 ) ); return $pageId > 0 ? (string) get_permalink( $pageId ) : home_url( '/' ); } }