Files
unsupervised-scheduler/templates/admin/instructors.php
T
thatguygriff b5c076c3d6
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 48s
CI / Tests (PHP 8.2) (pull_request) Successful in 49s
CI / Tests (PHP 8.1) (pull_request) Successful in 54s
CI / Coding Standards (pull_request) Successful in 1m5s
CI / PHPStan (pull_request) Successful in 1m11s
CI / Build Plugin Zip (pull_request) Has been skipped
Add Instructors admin page (create + per-capability access)
Completes the instructor-management half of #9: the studio admin can now
create instructor accounts and toggle each instructor's capabilities.

- InstructorController (manage_instructors): list instructors, create a
  us_instructor WP user (emailing a set-password link), and a per-instructor
  capability detail view.
- InstructorCapabilities: pure, unit-tested rules for which managed caps an
  admin may assign and how a submitted form maps to assignments. Managed caps
  are manage_offerings, manage_questions, view_own_payments, export_payments;
  manage_availability and view_own_lessons are core to every instructor.
- A studio admin can never grant a capability it does not itself hold: only
  held caps (checked via current_user_can, so an administrator's dynamic grant
  counts) are offered, and on creation any managed cap the admin lacks is
  denied on the new instructor so they never exceed their creator. The role
  grants the managed caps by default; the page layers per-user overrides.
- AdminMenu: register the Instructors page in the people section.
- Tests for the capability logic; docs/features/user-roles.md updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 17:02:46 -03:00

66 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
if (! defined('ABSPATH')) {
exit;
}
/**
* @var list<array{id: int, name: string, email: string, registered: string}> $instructors
* @var string $pageSlug
* @var string $notice
*/
?>
<div class="wrap">
<h1><?php esc_html_e('Instructors', 'unsupervised-schedular'); ?></h1>
<?php if ('' !== $notice) : ?>
<div class="notice notice-info inline"><p><?php echo esc_html($notice); ?></p></div>
<?php endif; ?>
<h2><?php esc_html_e('Add an instructor', 'unsupervised-schedular'); ?></h2>
<form method="post">
<?php wp_nonce_field('usc_instructor_action'); ?>
<input type="hidden" name="usc_action" value="create">
<table class="form-table">
<tr>
<th><label for="display_name"><?php esc_html_e('Name', 'unsupervised-schedular'); ?></label></th>
<td><input type="text" name="display_name" id="display_name" class="regular-text"></td>
</tr>
<tr>
<th><label for="email"><?php esc_html_e('Email', 'unsupervised-schedular'); ?></label></th>
<td>
<input type="email" name="email" id="email" class="regular-text" required>
<p class="description"><?php esc_html_e('Used as the login. The instructor is emailed a link to set their password.', 'unsupervised-schedular'); ?></p>
</td>
</tr>
</table>
<?php submit_button(esc_html__('Add Instructor', 'unsupervised-schedular')); ?>
</form>
<h2><?php esc_html_e('Current instructors', 'unsupervised-schedular'); ?></h2>
<?php if (empty($instructors)) : ?>
<p><?php esc_html_e('No instructors yet.', 'unsupervised-schedular'); ?></p>
<?php else : ?>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th><?php esc_html_e('Name', 'unsupervised-schedular'); ?></th>
<th><?php esc_html_e('Email', 'unsupervised-schedular'); ?></th>
<th><?php esc_html_e('Registered', 'unsupervised-schedular'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($instructors as $instructor) : ?>
<?php $detailUrl = add_query_arg(['page' => $pageSlug, 'instructor_id' => $instructor['id']], admin_url('admin.php')); ?>
<tr>
<td><a href="<?php echo esc_url($detailUrl); ?>"><?php echo esc_html($instructor['name']); ?></a></td>
<td><?php echo esc_html($instructor['email']); ?></td>
<td><?php echo esc_html($instructor['registered']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>