namespace, '/timetable/(?P\d+)/availability', [ 'methods' => 'GET', 'callback' => [$this, 'show'], // Public: the booking widget reads availability for anonymous visitors. 'permission_callback' => [RsvRestPolicy::class, 'open'], 'args' => [ 'date' => ['type' => 'string', 'required' => true, 'format' => 'date'], ], ]); } public function show(WP_REST_Request $request): WP_REST_Response { $id = (int) $request->get_param('id'); $service = new RsvTimetableService(); $timetable = $service->get($id); if ($timetable === null || $timetable->id === null) { return new WP_REST_Response(['error' => 'Timetable not found'], 404); } try { $availability = $service->get_availability_on_date($id, $timetable->block_size, new DateTime($request->get_param('date'))); } catch (Throwable $e) { Logger::error($e); return new WP_REST_Response(['error' => $e->getMessage()], 400); } return new WP_REST_Response($availability, 200); } }