| @@ -189,8 +189,18 @@ | ||
| 189 | 189 | $filters['duration'] = $preset; |
| 190 | 190 | } |
| 191 | 191 | } |
| 192 | 192 | |
| 193 | + // Availability date: keep only a valid Y-m-d calendar date. Trips are | |
| 194 | + // then filtered to those with a departure on that date (see | |
| 195 | + // TripRepository::findWithFilters). | |
| 196 | + if (!empty($params['available_date']) && is_string($params['available_date'])) { | |
| 197 | + $date = \Yatra\Helpers\TripListingFilterBuilder::normalizeAvailableDate($params['available_date']); | |
| 198 | + if ($date !== '') { | |
| 199 | + $filters['available_date'] = $date; | |
| 200 | + } | |
| 201 | + } | |
| 202 | + | |
| 193 | 203 | // Horizontal search "budget" presets (min-max or min+) → price range when explicit prices not set |
| 194 | 204 | if ( |
| 195 | 205 | empty($filters['price_min']) && empty($filters['price_max']) |
| 196 | 206 | && !empty($params['budget']) && is_string($params['budget']) |
| @@ -371,27 +381,36 @@ | ||
| 371 | 381 | } |
| 372 | 382 | |
| 373 | 383 | // Get filtered trips from repository |
| 374 | 384 | $tripResult = $this->tripRepository->findWithFilters($filters, $page, $perPage); |
| 375 | - | |
| 376 | - // Load reviews for each trip (same approach as SingleTripController) | |
| 377 | - $tripsWithReviews = []; | |
| 385 | + | |
| 386 | + // average_rating + review_count are aggregated in the listing | |
| 387 | + // SQL ({@see TripRepository::findWithFilters()} — `AVG(r.rating)` | |
| 388 | + // / `COUNT(DISTINCT r.id)` over the LEFT-JOINed approved-reviews | |
| 389 | + // rows), so the listing card has everything it needs to render | |
| 390 | + // the star block without an extra round-trip per trip. | |
| 391 | + // | |
| 392 | + // A previous version called `findApprovedByTripId(LIMIT 10)` | |
| 393 | + // here for every displayed trip — an N+1 with a JOIN to | |
| 394 | + // wp_users — and recomputed the average from the truncated | |
| 395 | + // list. That was both slow and *less accurate* than the SQL | |
| 396 | + // aggregate (capped at 10 reviews per trip). Drop it. | |
| 397 | + // | |
| 398 | + // `reviews` stays present-but-empty for templates that probe | |
| 399 | + // the property defensively (`is_array($trip->reviews)`). | |
| 378 | 400 | foreach ($tripResult['trips'] as $trip) { |
| 379 | - // Load reviews for this trip | |
| 380 | - $trip->reviews = $this->getReviewsForTrip((int) $trip->id); | |
| 381 | - | |
| 382 | - // Calculate rating stats (same as SingleTripController) | |
| 383 | - $trip->average_rating = $this->calculateAverageRating($trip->reviews); | |
| 384 | - $trip->review_count = count($trip->reviews); | |
| 385 | - | |
| 386 | - $tripsWithReviews[] = $trip; | |
| 401 | + if (!isset($trip->reviews)) { | |
| 402 | + $trip->reviews = []; | |
| 403 | + } | |
| 404 | + $trip->review_count = (int) ($trip->review_count ?? 0); | |
| 405 | + $trip->average_rating = (float) ($trip->average_rating ?? 0); | |
| 387 | 406 | } |
| 388 | - | |
| 407 | + | |
| 389 | 408 | // Get filter options for UI (cached separately) |
| 390 | 409 | $filterOptions = $this->getFilterOptions(); |
| 391 | - | |
| 410 | + | |
| 392 | 411 | return [ |
| 393 | - 'trips' => $tripsWithReviews, | |
| 412 | + 'trips' => $tripResult['trips'], | |
| 394 | 413 | 'total' => $tripResult['total'], |
| 395 | 414 | 'pages' => $tripResult['pages'], |
| 396 | 415 | 'page' => $tripResult['page'], |
| 397 | 416 | 'per_page' => $tripResult['per_page'], |
| @@ -540,24 +559,22 @@ | ||
| 540 | 559 | |
| 541 | 560 | $filters = [$taxonomyType => $slug]; |
| 542 | 561 | |
| 543 | 562 | $result = $this->tripRepository->findWithFilters($filters, 1, $limit); |
| 544 | - | |
| 545 | - // Load reviews for each trip (same approach as getFilteredTrips) | |
| 546 | - $tripsWithReviews = []; | |
| 563 | + | |
| 564 | + // Rating + count come from the listing SQL aggregate; see | |
| 565 | + // {@see self::buildTripListingResult()} for why we don't reload | |
| 566 | + // approved reviews per trip here (was an N+1). | |
| 547 | 567 | foreach ($result['trips'] as $trip) { |
| 548 | - // Load reviews for this trip | |
| 549 | - $trip->reviews = $this->getReviewsForTrip((int) $trip->id); | |
| 550 | - | |
| 551 | - // Calculate rating stats (same as SingleTripController) | |
| 552 | - $trip->average_rating = $this->calculateAverageRating($trip->reviews); | |
| 553 | - $trip->review_count = count($trip->reviews); | |
| 554 | - | |
| 555 | - $tripsWithReviews[] = $trip; | |
| 568 | + if (!isset($trip->reviews)) { | |
| 569 | + $trip->reviews = []; | |
| 570 | + } | |
| 571 | + $trip->review_count = (int) ($trip->review_count ?? 0); | |
| 572 | + $trip->average_rating = (float) ($trip->average_rating ?? 0); | |
| 556 | 573 | } |
| 557 | - | |
| 574 | + | |
| 558 | 575 | return [ |
| 559 | - 'trips' => $tripsWithReviews, | |
| 576 | + 'trips' => $result['trips'], | |
| 560 | 577 | 'total' => $result['total'] |
| 561 | 578 | ]; |
| 562 | 579 | } |
| 563 | 580 | |