| @@ -44,19 +44,43 @@ | ||
| 44 | 44 | // Get all trip data using Trip model getter methods |
| 45 | 45 | $title = $trip->getTitle(); |
| 46 | 46 | $duration = $trip->getDuration(); |
| 47 | 47 | $difficulty = $trip->getDifficulty(); |
| 48 | -// Calculate rating directly from reviews array (working correctly) | |
| 48 | + | |
| 49 | +// Prefer the SQL-aggregated average_rating / review_count that the | |
| 50 | +// repository attaches to every listing row (AVG(r.rating) / | |
| 51 | +// COUNT(DISTINCT r.id) over approved reviews). Falling back to a PHP | |
| 52 | +// recount over `$trip->reviews` is only there for legacy callers that | |
| 53 | +// hand-populate the reviews array without the aggregates. | |
| 54 | +// | |
| 55 | +// Earlier this block ALWAYS recounted from `$trip->reviews` — which | |
| 56 | +// (a) forced the listing service into an N+1 of `findApprovedByTripId` | |
| 57 | +// per displayed trip just to feed the recount, and (b) silently | |
| 58 | +// rendered 0 stars on shortcode/block paths that already pass | |
| 59 | +// aggregates with `reviews => []`. | |
| 60 | +$sql_avg = isset($trip->average_rating) ? (float) $trip->average_rating : null; | |
| 61 | +if ($sql_avg === null && isset($trip->avg_rating)) { | |
| 62 | + $sql_avg = (float) $trip->avg_rating; | |
| 63 | +} | |
| 64 | +$sql_count = isset($trip->review_count) ? (int) $trip->review_count : null; | |
| 65 | +if ($sql_count === null && isset($trip->reviews_count)) { | |
| 66 | + $sql_count = (int) $trip->reviews_count; | |
| 67 | +} | |
| 68 | + | |
| 49 | 69 | $reviews = $trip->reviews ?? []; |
| 50 | -$review_count = count($reviews); | |
| 51 | -$average_rating = 0; | |
| 52 | - | |
| 53 | -if ($review_count > 0) { | |
| 54 | - $total_rating = 0; | |
| 55 | - foreach ($reviews as $review) { | |
| 56 | - $total_rating += (float) ($review->rating ?? 0); | |
| 70 | +if ($sql_avg !== null || $sql_count !== null) { | |
| 71 | + $average_rating = $sql_avg !== null ? round($sql_avg, 1) : 0; | |
| 72 | + $review_count = $sql_count !== null ? $sql_count : count($reviews); | |
| 73 | +} else { | |
| 74 | + $review_count = count($reviews); | |
| 75 | + $average_rating = 0; | |
| 76 | + if ($review_count > 0) { | |
| 77 | + $total_rating = 0; | |
| 78 | + foreach ($reviews as $review) { | |
| 79 | + $total_rating += (float) ($review->rating ?? 0); | |
| 80 | + } | |
| 81 | + $average_rating = round($total_rating / $review_count, 1); | |
| 57 | 82 | } |
| 58 | - $average_rating = round($total_rating / $review_count, 1); | |
| 59 | 83 | } |
| 60 | 84 | |
| 61 | 85 | $rating = [ |
| 62 | 86 | 'average_rating' => $average_rating, |
| @@ -69,8 +93,29 @@ | ||
| 69 | 93 | } |
| 70 | 94 | |
| 71 | 95 | $pricing = $trip->getPricing(); |
| 72 | 96 | $discount = $trip->getDiscount(); |
| 97 | +$yatra_dp_flags = function_exists('yatra_get_dynamic_pricing_display_flags') ? yatra_get_dynamic_pricing_display_flags() : [ | |
| 98 | + 'show_original_price' => true, | |
| 99 | + 'show_savings_badge' => true, | |
| 100 | + 'show_urgency_messages' => false, | |
| 101 | +]; | |
| 102 | +$yatra_listing_urgency = []; | |
| 103 | +if (!empty($yatra_dp_flags['show_urgency_messages'])) { | |
| 104 | + $yatra_tid = (int) ($trip->id ?? 0); | |
| 105 | + $yatra_listing_urgency = function_exists('yatra_trip_card_dynamic_pricing_urgency_lines') | |
| 106 | + ? yatra_trip_card_dynamic_pricing_urgency_lines($yatra_tid, [ | |
| 107 | + 'base_sale_price' => (float) ($pricing['raw_current_price'] ?? 0), | |
| 108 | + 'base_original_price' => (float) ($pricing['raw_original_price'] ?? 0), | |
| 109 | + 'sale_price' => (float) ($pricing['raw_current_price'] ?? 0), | |
| 110 | + 'original_price' => (float) ($pricing['raw_original_price'] ?? 0), | |
| 111 | + 'departure_date' => null, | |
| 112 | + 'spots_remaining' => null, | |
| 113 | + 'availability_id' => null, | |
| 114 | + 'surface' => 'listing', | |
| 115 | + ]) | |
| 116 | + : []; | |
| 117 | +} | |
| 73 | 118 | $image = $trip->getImage(); |
| 74 | 119 | $permalink = $trip->getPermalink(); |
| 75 | 120 | $destinations = $trip->getDestinations(); |
| 76 | 121 | $categories = $trip->getCategories(); |
| @@ -158,11 +203,17 @@ | ||
| 158 | 203 | </a> |
| 159 | 204 | <?php else: ?> |
| 160 | 205 | <img src="<?php echo esc_url($image['url']); ?>" alt="<?php echo esc_attr($image['alt']); ?>"> |
| 161 | 206 | <?php endif; ?> |
| 162 | - <?php if ($discount['has_discount']): ?> | |
| 207 | + <?php if ($discount['has_discount'] && !empty($yatra_dp_flags['show_savings_badge'])): ?> | |
| 163 | 208 | <div class="yatra-discount-badge"> |
| 164 | - <?php echo esc_html($discount['discount_text']); ?> OFF | |
| 209 | + <?php | |
| 210 | + printf( | |
| 211 | + /* translators: %s: discount text (e.g. "10%") */ | |
| 212 | + esc_html__('%s OFF', 'yatra'), | |
| 213 | + esc_html($discount['discount_text']) | |
| 214 | + ); | |
| 215 | + ?> | |
| 165 | 216 | </div> |
| 166 | 217 | <?php endif; ?> |
| 167 | 218 | <?php if ($has_group_discounts): ?> |
| 168 | 219 | <div class="yatra-group-discount-badge" title="<?php echo esc_attr($group_discount_summary); ?>"> |
| @@ -179,11 +230,14 @@ | ||
| 179 | 230 | </svg> |
| 180 | 231 | </button> |
| 181 | 232 | <?php endif; ?> |
| 182 | 233 | <!-- Difficulty level overlay on bottom-right --> |
| 183 | - <?php if ($difficulty['has_difficulty'] && !empty($difficulty['icon'])): ?> | |
| 234 | + <?php if ($difficulty['has_difficulty'] && (!empty($difficulty['icon_picker']) || !empty($difficulty['icon']))): ?> | |
| 184 | 235 | <div class="yatra-difficulty-overlay"> |
| 185 | - <?php echo yatra_svg_icon($difficulty['icon'], 'difficulty-icon'); ?> | |
| 236 | + <?php | |
| 237 | + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped | |
| 238 | + echo yatra_stored_picker_icon_markup($difficulty['icon_picker'] ?? null, 'mountain', 'difficulty-icon'); | |
| 239 | + ?> | |
| 186 | 240 | <?php echo ' ' . esc_html($difficulty['level']); ?> |
| 187 | 241 | </div> |
| 188 | 242 | <?php endif; ?> |
| 189 | 243 | </div> |
| @@ -302,9 +356,9 @@ | ||
| 302 | 356 | </div> |
| 303 | 357 | </div> |
| 304 | 358 | <?php endif; ?> |
| 305 | 359 | |
| 306 | - <?php if (!empty($difficulty['has_difficulty']) && empty($difficulty['icon'])) : ?> | |
| 360 | + <?php if (!empty($difficulty['has_difficulty']) && empty($difficulty['icon']) && empty($difficulty['icon_picker'])) : ?> | |
| 307 | 361 | <div class="yatra-trip-stat"> |
| 308 | 362 | <div class="yatra-stat-icon difficulty"> |
| 309 | 363 | <?php echo yatra_svg_icon('mountain', ''); ?> |
| 310 | 364 | </div> |
| @@ -366,9 +420,10 @@ | ||
| 366 | 420 | $first_category = $yatra_categories_additional[0]; |
| 367 | 421 | if (!empty($first_category->icon)) { |
| 368 | 422 | $icon_data = maybe_unserialize($first_category->icon); |
| 369 | 423 | if (is_array($icon_data) && isset($icon_data['type']) && $icon_data['type'] === 'icon' && !empty($icon_data['value'])) { |
| 370 | - echo yatra_svg_icon($icon_data['value'], 'category-icon'); | |
| 424 | + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped | |
| 425 | + echo yatra_stored_picker_icon_markup($icon_data, 'tag', 'category-icon'); | |
| 371 | 426 | } else { |
| 372 | 427 | echo '<svg width="14" height="14" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H4a1 1 0 01-1-1V4zM3 10a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H4a1 1 0 01-1-1v-6zM14 9a1 1 0 00-1 1v6a1 1 0 001 1h2a1 1 0 001-1v-6a1 1 0 00-1-1h-2z" clip-rule="evenodd" /></svg>'; |
| 373 | 428 | } |
| 374 | 429 | } else { |
| @@ -392,9 +447,9 @@ | ||
| 392 | 447 | <div class="yatra-trip-card-price"> |
| 393 | 448 | <span class="yatra-trip-price"> |
| 394 | 449 | <?php if ($pricing['has_price']): ?> |
| 395 | 450 | <?php echo esc_html($pricing['price_prefix'] . $pricing['current_price']); ?> |
| 396 | - <?php if ($pricing['has_discount'] && !empty($pricing['original_price'])): ?> | |
| 451 | + <?php if (!empty($yatra_dp_flags['show_original_price']) && $pricing['has_discount'] && !empty($pricing['original_price'])): ?> | |
| 397 | 452 | <span class="yatra-original-price"><?php echo esc_html($pricing['original_price']); ?></span> |
| 398 | 453 | <?php endif; ?> |
| 399 | 454 | <?php else: ?> |
| 400 | 455 | <?php esc_html_e('Contact for pricing', 'yatra'); ?> |
| @@ -405,8 +460,17 @@ | ||
| 405 | 460 | <a href="<?php echo esc_url($permalink); ?>" class="yatra-btn yatra-btn-primary yatra-archive-card-cta yatra-card-view-btn"> |
| 406 | 461 | <?php echo function_exists('yatra_archive_listing_cta_icon_markup') ? yatra_archive_listing_cta_icon_markup($yatra_view_details_icon_slug, 'file-text') : yatra_svg_icon('file-text', 'yatra-btn-icon'); ?> |
| 407 | 462 | <span><?php esc_html_e('View Details', 'yatra'); ?></span> |
| 408 | 463 | </a> |
| 464 | + <?php endif; ?> | |
| 465 | + <?php if (!empty($yatra_listing_urgency)) : ?> | |
| 466 | + <div class="yatra-trip-listing-dp-urgency" style="width:100%;margin-top:8px;"> | |
| 467 | + <?php foreach ($yatra_listing_urgency as $yatra_urg_line) : ?> | |
| 468 | + <div style="background-color:#fef3c7;color:#92400e;padding:6px 8px;border-radius:6px;font-size:12px;line-height:1.35;margin-top:4px;"> | |
| 469 | + <?php echo esc_html((string) $yatra_urg_line); ?> | |
| 470 | + </div> | |
| 471 | + <?php endforeach; ?> | |
| 472 | + </div> | |
| 409 | 473 | <?php endif; ?> |
| 410 | 474 | </div> |
| 411 | 475 | </div> |
| 412 | 476 | </div> |