CI / Tests (PHP 8.2) (pull_request) Successful in 58s
CI / Tests (PHP 8.1) (pull_request) Successful in 58s
CI / No Debug Code (pull_request) Successful in 3s
CI / Coding Standards (pull_request) Successful in 2m53s
CI / PHPStan (pull_request) Successful in 3m0s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m42s
CI / Build Plugin Zip (pull_request) Skipped
Every account-signup question was asked of everybody who registered, on the same terms: "school and grade" had to be put to an adult signing themselves up, and a question a studio needed answered for each student could only be made required by demanding it of everyone. A question now carries an audience — everyone, or only the students someone registers on behalf of — and its own required flag for each side, so optional for you and required for every student you enrol is expressible. Both settings are account-scope only: an offering asks its questions once, about the student being booked, so there is no second audience to differ from, and an offering question mirrors its single "required" into both columns. Every caller reads askedOfSelf()/isRequiredForSelf()/isRequiredForChild() rather than the raw flags, so a students-only question can neither block the account holder nor have an answer filed against them by a crafted post. The family screen, which only ever adds a student, is held to the students' rule. is_required_child arrives from dbDelta defaulting to 0, which would quietly stop every existing required question being required of the students a guardian registers — the case it most likely existed for. A one-time backfill copies is_required across, guarded by its own option so a question later made optional for students stays that way. Closes #163 Co-Authored-By: Claude Opus 5 <[email protected]>
113 lines
6.6 KiB
PHP
113 lines
6.6 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
use Unsupervised\Schedular\Registration\QuestionField;
|
|
|
|
if (! defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* @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.
|
|
* @var int $editingId Child whose row is open for editing; 0 for none.
|
|
*/
|
|
?>
|
|
<div class="us-family">
|
|
<h3><?php esc_html_e('Your profile', 'unsupervised-schedular'); ?></h3>
|
|
|
|
<?php if ($notice !== '') : ?>
|
|
<p class="us-success"><?php echo esc_html($notice); ?></p>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($error !== '') : ?>
|
|
<p class="us-error" role="alert"><?php echo esc_html($error); ?></p>
|
|
<?php endif; ?>
|
|
|
|
<?php if (empty($children)) : ?>
|
|
<p><?php esc_html_e('You have not added any students yet. Add one below to start booking lessons for them.', 'unsupervised-schedular'); ?></p>
|
|
<?php else : ?>
|
|
<ul class="us-family-list">
|
|
<?php foreach ($children as $child) : ?>
|
|
<li class="us-family-child">
|
|
<?php if ($editingId === $child['id']) : ?>
|
|
<form method="post" action="" class="us-family-edit">
|
|
<?php wp_nonce_field('us_family'); ?>
|
|
<input type="hidden" name="us_family_action" value="edit">
|
|
<input type="hidden" name="child_id" value="<?php echo esc_attr((string) $child['id']); ?>">
|
|
<p>
|
|
<label for="us-edit-name-<?php echo esc_attr((string) $child['id']); ?>"><?php esc_html_e('Name', 'unsupervised-schedular'); ?> <span class="us-required" aria-hidden="true">*</span></label>
|
|
<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-birth-year-<?php echo esc_attr((string) $child['id']); ?>"><?php esc_html_e('Birth year', 'unsupervised-schedular'); ?> <span class="us-required" aria-hidden="true">*</span></label>
|
|
<input type="number" name="child_birth_year" required 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>
|
|
<a href="<?php echo esc_url((string) get_permalink()); ?>"><?php esc_html_e('Cancel', 'unsupervised-schedular'); ?></a>
|
|
</p>
|
|
</form>
|
|
<?php else : ?>
|
|
<span class="us-family-child-name"><?php echo esc_html($child['name']); ?></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>
|
|
<form method="post" action="" class="us-family-remove">
|
|
<?php wp_nonce_field('us_family'); ?>
|
|
<input type="hidden" name="us_family_action" value="remove">
|
|
<input type="hidden" name="child_id" value="<?php echo esc_attr((string) $child['id']); ?>">
|
|
<button type="submit"><?php esc_html_e('Remove', 'unsupervised-schedular'); ?></button>
|
|
</form>
|
|
</span>
|
|
<?php endif; ?>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
<?php endif; ?>
|
|
|
|
<form method="post" action="" class="us-family-add">
|
|
<?php wp_nonce_field('us_family'); ?>
|
|
<input type="hidden" name="us_family_action" value="add">
|
|
|
|
<h4><?php esc_html_e('Add a student', 'unsupervised-schedular'); ?></h4>
|
|
<p>
|
|
<label for="us-child-name"><?php esc_html_e('Name', 'unsupervised-schedular'); ?> <span class="us-required" aria-hidden="true">*</span></label>
|
|
<input type="text" name="child_name" id="us-child-name" required>
|
|
</p>
|
|
<p>
|
|
<label for="us-child-birth-year"><?php esc_html_e('Birth year', 'unsupervised-schedular'); ?> <span class="us-required" aria-hidden="true">*</span></label>
|
|
<input type="number" name="child_birth_year" id="us-child-birth-year" required 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>
|
|
<input type="text" name="child_relationship" id="us-child-relationship" placeholder="<?php esc_attr_e('Parent', 'unsupervised-schedular'); ?>">
|
|
</p>
|
|
|
|
<?php if (! empty($questions)) : ?>
|
|
<fieldset class="us-reg-questions">
|
|
<legend><?php esc_html_e('About this student', 'unsupervised-schedular'); ?></legend>
|
|
<?php foreach ($questions as $question) : ?>
|
|
<?php
|
|
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- QuestionField::render() escapes every interpolated value.
|
|
echo QuestionField::render(
|
|
$question,
|
|
'us_answers[' . (int) $question->id . ']',
|
|
'us-family-q-' . (int) $question->id,
|
|
isRequired: $question->isRequiredForChild()
|
|
);
|
|
?>
|
|
<?php endforeach; ?>
|
|
</fieldset>
|
|
<?php endif; ?>
|
|
|
|
<p>
|
|
<button type="submit"><?php esc_html_e('Add student', 'unsupervised-schedular'); ?></button>
|
|
</p>
|
|
</form>
|
|
</div>
|