Collect a birth year instead of a full date of birth
CI / Tests (PHP 8.1) (pull_request) Successful in 43s
CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.2) (pull_request) Successful in 50s
CI / PHPStan (pull_request) Successful in 2m55s
CI / Coding Standards (pull_request) Successful in 3m0s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m40s
CI / Build Plugin Zip (pull_request) Skipped

Signup and the profile page now ask for a four-digit year between 1900 and
the current year. Anything else — a short year, a full date, a year in the
future — is discarded rather than stored, so a typo cannot leave a nonsense
age on the record.

The year lives in a new us_birth_year user meta rather than reusing
us_date_of_birth, which would have left one key holding two formats. The old
key is not migrated in bulk. Instead GuardianService handles it in two
halves: birthYear() falls back to the year of the old date when the new key
is absent, so a student added before this change still shows one, and
setBirthYear() deletes the old date on every save.

That deletion is what makes the fallback safe rather than merely tidy.
Without it, clearing the birth year on a student who predates the change
would leave the old date behind for the fallback to read straight back, and
the year could never be cleared at all.

Stored in user meta, so no Schema.php change and no USC_VERSION bump.

Closes #147

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-07-29 20:47:56 -03:00
co-authored by Claude Opus 5
parent 3a83decc82
commit 7e2bba79fe
15 changed files with 219 additions and 77 deletions
+3 -3
View File
@@ -18,7 +18,7 @@ if (! defined('ABSPATH')) {
* @var float $creditBalance Balance of the account that settles this student's charges — the guardian's for a child.
* @var string $creditCurrency
* @var array{id: int, name: string, email: string}|null $guardian The parent/guardian who books for this student, or null when they book for themselves.
* @var list<array{id: int, name: string, date_of_birth: string, relationship: string}> $children Children this student books for.
* @var list<array{id: int, name: string, birth_year: string, relationship: string}> $children Children this student books for.
* @var array{id: int, name: string, email: string} $payer Who is billed for this student — themselves, or their guardian.
* @var string $pageSlug
* @var string $backUrl
@@ -131,8 +131,8 @@ $renderLessons = static function (array $rows, bool $withActions = false): void
<?php foreach ($children as $child) : ?>
<li>
<a href="<?php echo esc_url($detailUrl($child['id'])); ?>"><?php echo esc_html($child['name']); ?></a>
<?php if ($child['date_of_birth'] !== '') : ?>
<span class="description"><?php echo esc_html($child['date_of_birth']); ?></span>
<?php if ($child['birth_year'] !== '') : ?>
<span class="description"><?php echo esc_html($child['birth_year']); ?></span>
<?php endif; ?>
</li>
<?php endforeach; ?>
+1 -1
View File
@@ -6,7 +6,7 @@ if (! defined('ABSPATH')) {
}
/**
* @var list<array{id: int, name: string, email: string, registered: string, upcoming: int, enrolments: int, guardian: array{id: int, name: string, email: string}|null, children: list<array{id: int, name: string, date_of_birth: string, relationship: string}>}> $students
* @var list<array{id: int, name: string, email: string, registered: string, upcoming: int, enrolments: int, guardian: array{id: int, name: string, email: string}|null, children: list<array{id: int, name: string, birth_year: string, relationship: string}>}> $students
* @var string $pageSlug
*/
+7 -7
View File
@@ -8,7 +8,7 @@ if (! defined('ABSPATH')) {
}
/**
* @var list<array{id: int, name: string, date_of_birth: string, relationship: string}> $children
* @var list<array{id: int, name: string, birth_year: string, relationship: string}> $children
* @var list<\Unsupervised\Schedular\Registration\Question> $questions Account-scope questions, asked once per child.
* @var string $error Validation error from the last submission, if any.
* @var string $notice Confirmation of a completed add/edit/remove, if any.
@@ -42,8 +42,8 @@ if (! defined('ABSPATH')) {
<input type="text" name="child_name" id="us-edit-name-<?php echo esc_attr((string) $child['id']); ?>" value="<?php echo esc_attr($child['name']); ?>" required>
</p>
<p>
<label for="us-edit-dob-<?php echo esc_attr((string) $child['id']); ?>"><?php esc_html_e('Date of birth', 'unsupervised-schedular'); ?></label>
<input type="date" name="child_dob" id="us-edit-dob-<?php echo esc_attr((string) $child['id']); ?>" value="<?php echo esc_attr($child['date_of_birth']); ?>">
<label for="us-edit-birth-year-<?php echo esc_attr((string) $child['id']); ?>"><?php esc_html_e('Birth year', 'unsupervised-schedular'); ?></label>
<input type="number" name="child_birth_year" id="us-edit-birth-year-<?php echo esc_attr((string) $child['id']); ?>" value="<?php echo esc_attr($child['birth_year']); ?>" min="1900" max="<?php echo esc_attr(current_time('Y')); ?>" step="1" inputmode="numeric" placeholder="<?php esc_attr_e('YYYY', 'unsupervised-schedular'); ?>">
</p>
<p>
<button type="submit"><?php esc_html_e('Save', 'unsupervised-schedular'); ?></button>
@@ -52,8 +52,8 @@ if (! defined('ABSPATH')) {
</form>
<?php else : ?>
<span class="us-family-child-name"><?php echo esc_html($child['name']); ?></span>
<?php if ($child['date_of_birth'] !== '') : ?>
<span class="us-family-child-dob"><?php echo esc_html($child['date_of_birth']); ?></span>
<?php if ($child['birth_year'] !== '') : ?>
<span class="us-family-child-birth-year"><?php echo esc_html($child['birth_year']); ?></span>
<?php endif; ?>
<span class="us-family-child-actions">
<a href="<?php echo esc_url(add_query_arg('us_edit_child', $child['id'], (string) get_permalink())); ?>"><?php esc_html_e('Edit', 'unsupervised-schedular'); ?></a>
@@ -80,8 +80,8 @@ if (! defined('ABSPATH')) {
<input type="text" name="child_name" id="us-child-name" required>
</p>
<p>
<label for="us-child-dob"><?php esc_html_e('Date of birth', 'unsupervised-schedular'); ?></label>
<input type="date" name="child_dob" id="us-child-dob">
<label for="us-child-birth-year"><?php esc_html_e('Birth year', 'unsupervised-schedular'); ?></label>
<input type="number" name="child_birth_year" id="us-child-birth-year" min="1900" max="<?php echo esc_attr(current_time('Y')); ?>" step="1" inputmode="numeric" placeholder="<?php esc_attr_e('YYYY', 'unsupervised-schedular'); ?>">
</p>
<p>
<label for="us-child-relationship"><?php esc_html_e('Your relationship to them', 'unsupervised-schedular'); ?></label>
+2 -2
View File
@@ -90,8 +90,8 @@ if (! defined('ABSPATH')) {
<input type="text" name="children[0][name]" id="us-child-0-name">
</p>
<p>
<label for="us-child-0-dob"><?php esc_html_e('Date of birth', 'unsupervised-schedular'); ?></label>
<input type="date" name="children[0][dob]" id="us-child-0-dob">
<label for="us-child-0-birth-year"><?php esc_html_e('Birth year', 'unsupervised-schedular'); ?></label>
<input type="number" name="children[0][birth_year]" id="us-child-0-birth-year" min="1900" max="<?php echo esc_attr(current_time('Y')); ?>" step="1" inputmode="numeric" placeholder="<?php esc_attr_e('YYYY', 'unsupervised-schedular'); ?>">
</p>
<?php foreach ($accountQuestions as $question) : ?>
<?php