Add studio-defined account-registration questions
CI / Tests (PHP 8.2) (pull_request) Successful in 44s
CI / Tests (PHP 8.1) (pull_request) Successful in 45s
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 2m46s
CI / PHPStan (pull_request) Successful in 2m58s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m41s
CI / Build Plugin Zip (pull_request) Skipped

Studio admins can now define registration questions that every new student
answers as a required second step during signup, with each student's answers
shown under a "Registration Information" section in the admin.

Extends the existing Registration domain: us_questions gains a scope column
(offering | account) and a nullable offering_id, and account answers reuse
us_question_answers with registration_type = 'account'. Authoring reuses the
Offerings -> Questions page via an "Account signup" scope (studio-admin only).
The registration form becomes two steps (progressive enhancement via
assets/js/register.js; works without JS); required answers are validated before
the account is created and apply to all signup paths (invite, group link,
self-approval). StudentHistory::registrationInfo() powers the admin section.

Bumps the plugin version to 1.1.0 so dbDelta runs the schema migration.

Closes #90

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
2026-07-23 09:59:59 -03:00
co-authored by Claude Opus 4.8
parent 34e8f660ab
commit 49c59a950c
23 changed files with 702 additions and 98 deletions
+8 -1
View File
@@ -126,6 +126,7 @@ class QuestionEndpoint {
isRequired: $request->has_param( 'is_required' ) ? (bool) $request->get_param( 'is_required' ) : $existing->isRequired,
sortOrder: $request->has_param( 'sort_order' ) ? Val::int( $request->get_param( 'sort_order' ) ) : $existing->sortOrder,
isActive: $request->has_param( 'is_active' ) ? (bool) $request->get_param( 'is_active' ) : $existing->isActive,
scope: $existing->scope,
id: $id,
);
@@ -167,8 +168,14 @@ class QuestionEndpoint {
/**
* Ensure the offering exists and the caller owns it (or is a studio admin).
* Account-scoped questions have no offering and are not managed over REST, so
* a null offering id is rejected as not found.
*/
private function requireOfferingOwner( int $offeringId ): ?\WP_Error {
private function requireOfferingOwner( ?int $offeringId ): ?\WP_Error {
if ( null === $offeringId ) {
return new \WP_Error( 'not_found', __( 'Question not found.', 'unsupervised-schedular' ), [ 'status' => 404 ] );
}
$offering = $this->offerings->findById( $offeringId );
if ( null === $offering ) {