reviews ?? null; $original_average_rating = $trip->avg_rating ?? null; $original_review_count = $trip->reviews_count ?? null; $trip = \Yatra\Models\Trip::fromStdClass($trip); // Restore review data after conversion if ($original_reviews !== null) { $trip->reviews = $original_reviews; } if ($original_average_rating !== null) { $trip->avg_rating = $original_average_rating; } if ($original_review_count !== null) { $trip->reviews_count = $original_review_count; } } // Get all trip data using Trip model getter methods $title = $trip->getTitle(); $duration = $trip->getDuration(); $difficulty = $trip->getDifficulty(); // Prefer the SQL-aggregated average_rating / review_count that the // repository attaches to every listing row (AVG(r.rating) / // COUNT(DISTINCT r.id) over approved reviews). Falling back to a PHP // recount over `$trip->reviews` is only there for legacy callers that // hand-populate the reviews array without the aggregates. // // Earlier this block ALWAYS recounted from `$trip->reviews` — which // (a) forced the listing service into an N+1 of `findApprovedByTripId` // per displayed trip just to feed the recount, and (b) silently // rendered 0 stars on shortcode/block paths that already pass // aggregates with `reviews => []`. $sql_avg = isset($trip->average_rating) ? (float) $trip->average_rating : null; if ($sql_avg === null && isset($trip->avg_rating)) { $sql_avg = (float) $trip->avg_rating; } $sql_count = isset($trip->review_count) ? (int) $trip->review_count : null; if ($sql_count === null && isset($trip->reviews_count)) { $sql_count = (int) $trip->reviews_count; } $reviews = $trip->reviews ?? []; if ($sql_avg !== null || $sql_count !== null) { $average_rating = $sql_avg !== null ? round($sql_avg, 1) : 0; $review_count = $sql_count !== null ? $sql_count : count($reviews); } else { $review_count = count($reviews); $average_rating = 0; if ($review_count > 0) { $total_rating = 0; foreach ($reviews as $review) { $total_rating += (float) ($review->rating ?? 0); } $average_rating = round($total_rating / $review_count, 1); } } $rating = [ 'average_rating' => $average_rating, 'review_count' => $review_count, 'formatted_rating' => number_format($average_rating, 1), 'has_rating' => $average_rating > 0 && $review_count > 0, ]; if (function_exists('yatra_trip_listing_card_rating_data')) { $rating = array_merge($rating, yatra_trip_listing_card_rating_data($trip, $rating)); } $pricing = $trip->getPricing(); $discount = $trip->getDiscount(); $yatra_dp_flags = function_exists('yatra_get_dynamic_pricing_display_flags') ? yatra_get_dynamic_pricing_display_flags() : [ 'show_original_price' => true, 'show_savings_badge' => true, 'show_urgency_messages' => false, ]; $yatra_listing_urgency = []; if (!empty($yatra_dp_flags['show_urgency_messages'])) { $yatra_tid = (int) ($trip->id ?? 0); $yatra_listing_urgency = function_exists('yatra_trip_card_dynamic_pricing_urgency_lines') ? yatra_trip_card_dynamic_pricing_urgency_lines($yatra_tid, [ 'base_sale_price' => (float) ($pricing['raw_current_price'] ?? 0), 'base_original_price' => (float) ($pricing['raw_original_price'] ?? 0), 'sale_price' => (float) ($pricing['raw_current_price'] ?? 0), 'original_price' => (float) ($pricing['raw_original_price'] ?? 0), 'departure_date' => null, 'spots_remaining' => null, 'availability_id' => null, 'surface' => 'listing', ]) : []; } $image = $trip->getImage(); $permalink = $trip->getPermalink(); $destinations = $trip->getDestinations(); $categories = $trip->getCategories(); $activities = $trip->getActivities(); if (function_exists('yatra_trip_listing_filter_classification_duplicates')) { [$destinations, $activities, $categories] = yatra_trip_listing_filter_classification_duplicates( $destinations, $activities, $categories, $trip ); } $starting_loc = method_exists($trip, 'getStartingLocation') ? $trip->getStartingLocation() : ($trip->starting_location ?? null); $ending_loc = $trip->ending_location ?? null; $starting_loc = is_string($starting_loc) ? trim($starting_loc) : ''; $ending_loc = is_string($ending_loc) ? trim($ending_loc) : ''; $yatra_card_location_line = ''; if ($starting_loc !== '' && $ending_loc !== '' && $starting_loc !== $ending_loc) { $yatra_card_location_line = function_exists('yatra_format_trip_listing_route_line') ? yatra_format_trip_listing_route_line($starting_loc, $ending_loc) : $starting_loc . ' → ' . $ending_loc; } elseif ($starting_loc !== '') { $yatra_card_location_line = $starting_loc; } elseif ($ending_loc !== '') { $yatra_card_location_line = $ending_loc; } $yatra_traveler_type_labels = function_exists('yatra_trip_listing_traveler_type_labels_for_card') ? yatra_trip_listing_traveler_type_labels_for_card($trip) : []; $yatra_trip_type_label = function_exists('yatra_trip_listing_trip_type_label') ? yatra_trip_listing_trip_type_label($trip->trip_type ?? null) : ''; $yatra_primary_category = !empty($categories[0]) ? $categories[0] : null; $yatra_categories_additional = []; foreach ($categories as $yatra_cat_row) { if ($yatra_primary_category && isset($yatra_cat_row->id, $yatra_primary_category->id) && (int) $yatra_cat_row->id === (int) $yatra_primary_category->id) { continue; } $yatra_categories_additional[] = $yatra_cat_row; } $yatra_view_details_icon_slug = function_exists('yatra_trip_listing_card_cta_icon_slug') ? yatra_trip_listing_card_cta_icon_slug($categories, $destinations, $difficulty) : ''; // Check for group discounts availability $has_group_discounts = false; $group_discount_summary = ''; try { // Call the group discount API to check availability $api_url = rest_url('yatra/v1/discounts/group-discounts'); $response = wp_remote_post($api_url, [ 'method' => 'GET', 'body' => [ 'trip_ids' => [$trip->id] ], 'headers' => [ 'Content-Type' => 'application/json', ], ]); if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { $data = json_decode(wp_remote_retrieve_body($response), true); if (isset($data[$trip->id]) && $data[$trip->id]['has_group_discounts']) { $has_group_discounts = true; $group_discount_summary = $data[$trip->id]['summary']; } } } catch (Exception $e) { // Silently fail if API call fails - don't break the page $has_group_discounts = false; } ?>