authenticate($request, $action); if ($apiKey instanceof \WP_REST_Response) { return $apiKey; } $restaurant = Restaurant::where('active', 1)->where('id', $apiKey->restaurant_id)->first(); if (!$restaurant) { return $this->errorResponse($apiKey, $action, $request, 'RESTAURANT_NOT_FOUND', 'Restaurant not found or inactive.', 404); } $widgetId = $this->resolveWidgetId($request, $apiKey); if (!$widgetId) { return $this->errorResponse($apiKey, $action, $request, 'WIDGET_NOT_FOUND', 'No widget_id configured on the API key and none provided in the request.', 400); } $widget = WidgetForm::where('id', $widgetId)->where('restaurant_id', $restaurant->id)->first(); if (!$widget) { return $this->errorResponse($apiKey, $action, $request, 'WIDGET_NOT_FOUND', 'Widget not found for this restaurant.', 404); } // Services configured for the widget (shifts + events). $services = []; foreach ($restaurant->getShiftsAndEvents($widgetId) as $service) { $services[] = [ 'id' => $service->id, 'name' => $service->name, 'type' => ($service instanceof \Alexr\Settings\Event) ? 'event' : 'shift', 'public_notes' => $this->decodeRichText($service->public_notes), 'min_guests' => intval($service->min_covers_reservation), 'max_guests' => intval($service->max_covers_reservation), 'availability_type' => $service->availability_type, ]; } $guestsRange = $restaurant->guestsMinMax($widgetId); // Upcoming closed days. Merge the two arrays from the ClosedDay setting: // - dates: manually closed days // - full_dates: days fully booked // Properties are accessed via __get on SettingCustomized (meta_value JSON), // so we always assign to a local var first and never call is_array() directly // on the magic property. $closedDates = []; $closedDays = ClosedDay::where('restaurant_id', $restaurant->id)->first(); if ($closedDays) { $dates = $closedDays->dates ?? []; $fullDates = $closedDays->full_dates ?? []; if (!is_array($dates)) $dates = []; if (!is_array($fullDates)) $fullDates = []; $closedDates = array_values(array_unique(array_merge($dates, $fullDates))); } $today = evavel_now_timezone_formatted($restaurant->timezone, 'Y-m-d'); $upcomingClosed = array_values(array_filter($closedDates, function($d) use ($today) { return $d >= $today; })); sort($upcomingClosed); $data = [ 'restaurant' => [ 'id' => $restaurant->id, 'name' => $restaurant->name, 'timezone' => $restaurant->timezone, 'language' => $restaurant->language, 'phone' => $restaurant->phone ?? null, 'address' => $restaurant->address ?? null, 'reservation_policy' => $this->decodeRichText($restaurant->reservation_policy), ], 'widget' => [ 'id' => $widget->id, 'name' => $widget->name, 'guests_min' => intval($guestsRange['min']), 'guests_max' => intval($guestsRange['max']), ], 'services' => $services, 'closed_dates' => $upcomingClosed, ]; return $this->successResponse($apiKey, $action, $request, $data, 200); } }