Bulk delete availability slots from the admin list view
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 1m40s
CI / Tests (PHP 8.1) (pull_request) Successful in 46s
CI / Tests (PHP 8.2) (pull_request) Successful in 45s
CI / Tests (PHP 8.3) (pull_request) Successful in 1m34s
CI / PHPStan (pull_request) Successful in 2m52s
CI / Build Plugin Zip (pull_request) Has been skipped

The list view of Current Slots gets a checkbox per unbooked slot, a
select-all header checkbox, and a Delete selected button submitting a
new bulk_delete form action. Each id is ownership-checked through the
same path as single delete; the repository's is_booked guard refuses
booked slots as a second layer. Row checkboxes attach to the bulk form
via the HTML form attribute because the table already contains the
per-row delete forms and forms cannot nest.

Closes #57

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
2026-07-05 22:25:35 -03:00
co-authored by Claude Fable 5
parent aaa24e524f
commit c743ed5459
4 changed files with 175 additions and 6 deletions
+25 -6
View File
@@ -54,17 +54,36 @@ class AvailabilityController {
}
if ( 'delete' === $action ) {
$slotId = absint( Val::int( $_POST['slot_id'] ?? 0 ) );
if ( $slotId > 0 ) {
$slot = $this->repository->findById( $slotId );
if ( $slot && $slot->instructorId === $instructorId ) {
$this->repository->delete( $slotId );
}
$this->deleteOwnSlot( absint( Val::int( $_POST['slot_id'] ?? 0 ) ), $instructorId );
}
if ( 'bulk_delete' === $action ) {
// The array itself carries no data; each element is coerced and
// absint-sanitized individually below.
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput
$rawIds = $_POST['slot_ids'] ?? [];
foreach ( is_array( $rawIds ) ? $rawIds : [] as $rawId ) {
$this->deleteOwnSlot( absint( Val::int( $rawId ) ), $instructorId );
}
}
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
/**
* Delete a slot only when it exists and belongs to the given instructor.
* The repository additionally refuses to delete booked slots.
*/
private function deleteOwnSlot( int $slotId, int $instructorId ): void {
if ( $slotId <= 0 ) {
return;
}
$slot = $this->repository->findById( $slotId );
if ( $slot && $slot->instructorId === $instructorId ) {
$this->repository->delete( $slotId );
}
}
private function addSlot( int $instructorId ): void {
// phpcs:disable WordPress.Security.NonceVerification.Missing
$startDt = AvailabilitySlot::normalizeDateTime( sanitize_text_field( Val::string( wp_unslash( $_POST['start_dt'] ?? '' ) ) ) );