PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.8
Yatra – Travel Booking & Tour Operator Software v3.0.8
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
yatra / templates / trip-listing-card.php

trip-listing-card.php in Yatra – Travel Booking & Tour Operator Software 3.0.8, at templates/trip-listing-card.php

619 lines 25.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Reusable Trip Listing Card Template
4 *
5 * This template uses Trip model getter methods for clean, reusable data access
6 * All trip-related data comes from the Trip model methods
7 *
8 * @package Yatra
9 * @var \Yatra\Models\Trip $trip The trip model object with getter methods
10 */
11
12 // Prevent direct access
13 if (!defined('ABSPATH')) {
14 exit;
15 }
16
17 // Ensure we have a trip object
18 if (!isset($trip) || !is_object($trip)) {
19 return;
20 }
21
22 // Convert stdClass to Trip model instance if needed
23 if (!($trip instanceof \Yatra\Models\Trip)) {
24 // Preserve review data before conversion
25 $original_reviews = $trip->reviews ?? null;
26 $original_average_rating = $trip->avg_rating ?? null;
27 $original_review_count = $trip->reviews_count ?? null;
28
29 $trip = \Yatra\Models\Trip::fromStdClass($trip);
30
31 // Restore review data after conversion
32 if ($original_reviews !== null) {
33 $trip->reviews = $original_reviews;
34 }
35 if ($original_average_rating !== null) {
36 $trip->avg_rating = $original_average_rating;
37 }
38 if ($original_review_count !== null) {
39 $trip->reviews_count = $original_review_count;
40 }
41 }
42
43
44 // Get all trip data using Trip model getter methods
45 $title = $trip->getTitle();
46 $duration = $trip->getDuration();
47 $difficulty = $trip->getDifficulty();
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
69 $reviews = $trip->reviews ?? [];
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);
82 }
83 }
84
85 $rating = [
86 'average_rating' => $average_rating,
87 'review_count' => $review_count,
88 'formatted_rating' => number_format($average_rating, 1),
89 'has_rating' => $average_rating > 0 && $review_count > 0,
90 ];
91 if (function_exists('yatra_trip_listing_card_rating_data')) {
92 $rating = array_merge($rating, yatra_trip_listing_card_rating_data($trip, $rating));
93 }
94
95 $pricing = $trip->getPricing();
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 }
118 $image = $trip->getImage();
119 $permalink = $trip->getPermalink();
120 $destinations = $trip->getDestinations();
121 $categories = $trip->getCategories();
122 $activities = $trip->getActivities();
123
124 if (function_exists('yatra_trip_listing_filter_classification_duplicates')) {
125 [$destinations, $activities, $categories] = yatra_trip_listing_filter_classification_duplicates(
126 $destinations,
127 $activities,
128 $categories,
129 $trip
130 );
131 }
132
133 $starting_loc = method_exists($trip, 'getStartingLocation') ? $trip->getStartingLocation() : ($trip->starting_location ?? null);
134 $ending_loc = $trip->ending_location ?? null;
135 $starting_loc = is_string($starting_loc) ? trim($starting_loc) : '';
136 $ending_loc = is_string($ending_loc) ? trim($ending_loc) : '';
137 $yatra_card_location_line = '';
138 if ($starting_loc !== '' && $ending_loc !== '' && $starting_loc !== $ending_loc) {
139 $yatra_card_location_line = function_exists('yatra_format_trip_listing_route_line')
140 ? yatra_format_trip_listing_route_line($starting_loc, $ending_loc)
141 : $starting_loc . ' → ' . $ending_loc;
142 } elseif ($starting_loc !== '') {
143 $yatra_card_location_line = $starting_loc;
144 } elseif ($ending_loc !== '') {
145 $yatra_card_location_line = $ending_loc;
146 }
147
148 $yatra_traveler_type_labels = function_exists('yatra_trip_listing_traveler_type_labels_for_card')
149 ? yatra_trip_listing_traveler_type_labels_for_card($trip)
150 : [];
151
152 $yatra_trip_type_label = function_exists('yatra_trip_listing_trip_type_label')
153 ? yatra_trip_listing_trip_type_label($trip->trip_type ?? null)
154 : '';
155 $yatra_primary_category = !empty($categories[0]) ? $categories[0] : null;
156 $yatra_categories_additional = [];
157 foreach ($categories as $yatra_cat_row) {
158 if ($yatra_primary_category && isset($yatra_cat_row->id, $yatra_primary_category->id)
159 && (int) $yatra_cat_row->id === (int) $yatra_primary_category->id) {
160 continue;
161 }
162 $yatra_categories_additional[] = $yatra_cat_row;
163 }
164
165 $yatra_view_details_icon_slug = function_exists('yatra_trip_listing_card_cta_icon_slug')
166 ? yatra_trip_listing_card_cta_icon_slug($categories, $destinations, $difficulty)
167 : '';
168
169 // Check for group discounts availability
170 $has_group_discounts = false;
171 $group_discount_summary = '';
172 try {
173 // Call the group discount API to check availability
174 $api_url = rest_url('yatra/v1/discounts/group-discounts');
175 $response = wp_remote_post($api_url, [
176 'method' => 'GET',
177 'body' => [
178 'trip_ids' => [$trip->id]
179 ],
180 'headers' => [
181 'Content-Type' => 'application/json',
182 ],
183 ]);
184
185 if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
186 $data = json_decode(wp_remote_retrieve_body($response), true);
187 if (isset($data[$trip->id]) && $data[$trip->id]['has_group_discounts']) {
188 $has_group_discounts = true;
189 $group_discount_summary = $data[$trip->id]['summary'];
190 }
191 }
192 } catch (Exception $e) {
193 // Silently fail if API call fails - don't break the page
194 $has_group_discounts = false;
195 }
196 ?>
197
198 <div class="yatra-trip-card">
199 <div class="yatra-trip-card-image">
200 <?php if (!empty($permalink)): ?>
201 <a href="<?php echo esc_url($permalink); ?>" class="yatra-trip-image-link">
202 <img src="<?php echo esc_url($image['url']); ?>" alt="<?php echo esc_attr($image['alt']); ?>">
203 </a>
204 <?php else: ?>
205 <img src="<?php echo esc_url($image['url']); ?>" alt="<?php echo esc_attr($image['alt']); ?>">
206 <?php endif; ?>
207 <?php if ($discount['has_discount'] && !empty($yatra_dp_flags['show_savings_badge'])): ?>
208 <div class="yatra-discount-badge">
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 ?>
216 </div>
217 <?php endif; ?>
218 <?php if ($has_group_discounts): ?>
219 <div class="yatra-group-discount-badge" title="<?php echo esc_attr($group_discount_summary); ?>">
220 <svg width="12" height="12" fill="currentColor" viewBox="0 0 20 20">
221 <path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
222 </svg>
223 <?php esc_html_e('Group Discounts', 'yatra'); ?>
224 </div>
225 <?php endif; ?>
226 <?php if (function_exists('yatra_wishlist_enabled') && yatra_wishlist_enabled()) : ?>
227 <button type="button" class="yatra-favorite-btn" data-trip-id="<?php echo esc_attr($trip->id); ?>" title="<?php esc_attr_e('Save to wishlist', 'yatra'); ?>" aria-label="<?php esc_attr_e('Save to wishlist', 'yatra'); ?>">
228 <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
229 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
230 </svg>
231 </button>
232 <?php endif; ?>
233 <!-- Difficulty level overlay on bottom-right -->
234 <?php if ($difficulty['has_difficulty'] && (!empty($difficulty['icon_picker']) || !empty($difficulty['icon']))): ?>
235 <div class="yatra-difficulty-overlay">
236 <?php
237 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
238 echo yatra_stored_picker_icon_markup($difficulty['icon_picker'] ?? null, 'mountain', 'difficulty-icon');
239 ?>
240 <?php echo ' ' . esc_html($difficulty['level']); ?>
241 </div>
242 <?php endif; ?>
243 </div>
244 <div class="yatra-trip-content">
245 <?php if ($yatra_card_location_line !== '' || !empty($destinations)) : ?>
246 <div class="yatra-trip-destinations" role="group" aria-label="<?php esc_attr_e('Trip location', 'yatra'); ?>">
247 <svg class="location-icon" width="14" height="14" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
248 <path fill-rule="evenodd" d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" clip-rule="evenodd" />
249 </svg>
250 <?php if ($yatra_card_location_line !== '') : ?>
251 <span class="yatra-trip-card-location-text"><?php echo esc_html($yatra_card_location_line); ?></span>
252 <?php else : ?>
253 <?php
254 $destination_links = [];
255 foreach ($destinations as $destination) {
256 if (empty($destination->name)) {
257 continue;
258 }
259 $destination_permalink = function_exists('yatra_get_destination_permalink')
260 ? yatra_get_destination_permalink($destination)
261 : '#';
262 $destination_links[] = '<a href="' . esc_url($destination_permalink) . '" class="destination-link">' . esc_html($destination->name) . '</a>';
263 }
264 echo implode(', ', $destination_links);
265 ?>
266 <?php endif; ?>
267 </div>
268 <?php endif; ?>
269
270 <h3 class="yatra-trip-title">
271 <?php if (!empty($permalink)): ?>
272 <a href="<?php echo esc_url($permalink); ?>" class="yatra-trip-title-link"><?php echo esc_html($title); ?></a>
273 <?php else: ?>
274 <?php echo esc_html($title); ?>
275 <?php endif; ?>
276 </h3>
277
278 <?php if ($yatra_trip_type_label !== '' || $yatra_primary_category) : ?>
279 <div class="yatra-trip-card-meta">
280 <?php if ($yatra_trip_type_label !== '') : ?>
281 <span class="yatra-trip-type-chip"><?php echo esc_html($yatra_trip_type_label); ?></span>
282 <?php endif; ?>
283 <?php if ($yatra_primary_category && !empty($yatra_primary_category->name)) : ?>
284 <?php
285 $pc_link = function_exists('yatra_get_category_permalink')
286 ? yatra_get_category_permalink($yatra_primary_category)
287 : '';
288 ?>
289 <?php if ($pc_link !== '') : ?>
290 <a class="yatra-trip-primary-category-chip" href="<?php echo esc_url($pc_link); ?>"><?php echo esc_html($yatra_primary_category->name); ?></a>
291 <?php else : ?>
292 <span class="yatra-trip-primary-category-chip yatra-trip-primary-category-chip--text"><?php echo esc_html($yatra_primary_category->name); ?></span>
293 <?php endif; ?>
294 <?php endif; ?>
295 </div>
296 <?php endif; ?>
297
298 <!-- Short Description -->
299 <?php
300 $short_desc = $trip->getShortDescription();
301 if (!empty($short_desc)):
302 ?>
303 <p class="yatra-trip-short-description">
304 <?php echo \Yatra\Helpers\FormatHelper::sanitizeQuillHtml($short_desc); ?>
305 </p>
306 <?php endif; ?>
307
308 <!-- Trip Stats Row: scannable decision cues (duration, rating, group, difficulty, optional bookings) -->
309 <div class="yatra-trip-stats-row">
310 <?php if ($duration['has_duration']) : ?>
311 <div class="yatra-trip-stat">
312 <div class="yatra-stat-icon duration">
313 <?php echo yatra_svg_icon('calendar', ''); ?>
314 </div>
315 <div class="yatra-stat-content">
316 <span class="yatra-stat-value"><?php echo esc_html($duration['formatted']); ?></span>
317 <span class="yatra-stat-label"><?php esc_html_e('Duration', 'yatra'); ?></span>
318 </div>
319 </div>
320 <?php endif; ?>
321
322 <?php if (!empty($rating['has_rating'])) : ?>
323 <div class="yatra-trip-stat">
324 <div class="yatra-stat-icon rating">
325 <?php echo yatra_svg_icon('star', ''); ?>
326 </div>
327 <div class="yatra-stat-content">
328 <span class="yatra-stat-value"><?php echo esc_html($rating['formatted_rating']); ?></span>
329 <span class="yatra-stat-label">
330 <?php
331 printf(
332 /* translators: %d: number of reviews */
333 esc_html(_n('%d review', '%d reviews', (int) $rating['review_count'], 'yatra')),
334 (int) $rating['review_count']
335 );
336 ?>
337 </span>
338 </div>
339 </div>
340 <?php endif; ?>
341
342 <?php if (!empty($trip->min_travelers) || !empty($trip->max_travelers)) : ?>
343 <div class="yatra-trip-stat">
344 <div class="yatra-stat-icon group">
345 <?php echo yatra_svg_icon('users', ''); ?>
346 </div>
347 <div class="yatra-stat-content">
348 <span class="yatra-stat-value">
349 <?php
350 $min_travelers = $trip->min_travelers ?? 1;
351 $max_travelers = $trip->max_travelers ?? 20;
352 echo esc_html($min_travelers . '-' . $max_travelers);
353 ?>
354 </span>
355 <span class="yatra-stat-label"><?php esc_html_e('Group size', 'yatra'); ?></span>
356 </div>
357 </div>
358 <?php endif; ?>
359
360 <?php if (!empty($difficulty['has_difficulty']) && empty($difficulty['icon']) && empty($difficulty['icon_picker'])) : ?>
361 <div class="yatra-trip-stat">
362 <div class="yatra-stat-icon difficulty">
363 <?php echo yatra_svg_icon('mountain', ''); ?>
364 </div>
365 <div class="yatra-stat-content">
366 <span class="yatra-stat-value"><?php echo esc_html($difficulty['level']); ?></span>
367 <span class="yatra-stat-label"><?php esc_html_e('Difficulty', 'yatra'); ?></span>
368 </div>
369 </div>
370 <?php endif; ?>
371
372 <?php if (apply_filters('yatra_trip_listing_card_show_bookings_count', false, $trip) && !empty($trip->bookings_count) && (int) $trip->bookings_count > 0) : ?>
373 <div class="yatra-trip-stat">
374 <div class="yatra-stat-icon bookings">
375 <svg width="14" height="14" fill="currentColor" viewBox="0 0 20 20">
376 <path fill-rule="evenodd" d="M3 1a1 1 0 000 2h1.22l.305 1.222a.997.997 0 00.01.042l1.358 5.43-.893.892C3.74 11.846 4.632 14 6.414 14H15a1 1 0 000-2H6.414l1-1H14a1 1 0 00.894-.553l3-6A1 1 0 0017 3H6.28l-.31-1.243A1 1 0 005 1H3zM16 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM6.5 18a1.5 1.5 0 100-3 1.5 1.5 0 000 3z" clip-rule="evenodd" />
377 </svg>
378 </div>
379 <div class="yatra-stat-content">
380 <span class="yatra-stat-value"><?php echo esc_html((string) (int) $trip->bookings_count); ?></span>
381 <span class="yatra-stat-label"><?php esc_html_e('Bookings', 'yatra'); ?></span>
382 </div>
383 </div>
384 <?php endif; ?>
385 </div>
386
387 <?php if (!empty($yatra_traveler_type_labels)) : ?>
388 <div class="yatra-trip-traveler-types" role="group" aria-label="<?php esc_attr_e('Traveler types', 'yatra'); ?>">
389 <svg class="yatra-trip-traveler-types-icon" width="14" height="14" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
390 <path fill-rule="evenodd" d="M4 4a2 2 0 00-2 2v8a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2H4zm2 2h8v2H6V6zm0 4h5v2H6v-2z" clip-rule="evenodd" />
391 </svg>
392 <div class="yatra-trip-traveler-types-inner">
393 <span class="yatra-trip-traveler-types-label"><?php esc_html_e('Traveler types', 'yatra'); ?></span>
394 <span class="yatra-trip-traveler-types-pills">
395 <?php foreach ($yatra_traveler_type_labels as $ttl) : ?>
396 <span class="yatra-traveler-tier-pill"><?php echo esc_html($ttl); ?></span>
397 <?php endforeach; ?>
398 </span>
399 </div>
400 </div>
401 <?php endif; ?>
402
403
404 <!-- Activities Only -->
405 <?php if (!empty($activities)) : ?>
406 <div class="yatra-trip-activities" role="group" aria-label="<?php esc_attr_e('Activities', 'yatra'); ?>">
407 <?php foreach (array_slice($activities, 0, 3) as $activity) : ?>
408 <a href="<?php echo esc_url(yatra_get_activity_permalink($activity)); ?>" class="yatra-tag activity-tag">
409 <?php echo esc_html($activity->name); ?>
410 </a>
411 <?php endforeach; ?>
412 </div>
413 <?php endif; ?>
414
415 <!-- Additional trip categories (primary chip is under title) -->
416 <?php if (!empty($yatra_categories_additional)) : ?>
417 <div class="yatra-trip-categories-compact" role="group" aria-label="<?php esc_attr_e('More categories', 'yatra'); ?>">
418 <div class="yatra-category-icon">
419 <?php
420 $first_category = $yatra_categories_additional[0];
421 if (!empty($first_category->icon)) {
422 $icon_data = maybe_unserialize($first_category->icon);
423 if (is_array($icon_data) && isset($icon_data['type']) && $icon_data['type'] === 'icon' && !empty($icon_data['value'])) {
424 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
425 echo yatra_stored_picker_icon_markup($icon_data, 'tag', 'category-icon');
426 } else {
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>';
428 }
429 } else {
430 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>';
431 }
432 ?>
433 </div>
434 <span class="yatra-categories-text">
435 <?php
436 $category_links = [];
437 foreach ($yatra_categories_additional as $category) {
438 $category_links[] = '<a href="' . esc_url(yatra_get_category_permalink($category)) . '" class="yatra-category-link">' . esc_html($category->name) . '</a>';
439 }
440 echo implode(', ', $category_links);
441 ?>
442 </span>
443 </div>
444 <?php endif; ?>
445
446 <div class="yatra-trip-footer">
447 <div class="yatra-trip-card-price">
448 <span class="yatra-trip-price">
449 <?php if ($pricing['has_price']): ?>
450 <?php echo esc_html($pricing['price_prefix'] . $pricing['current_price']); ?>
451 <?php if (!empty($yatra_dp_flags['show_original_price']) && $pricing['has_discount'] && !empty($pricing['original_price'])): ?>
452 <span class="yatra-original-price"><?php echo esc_html($pricing['original_price']); ?></span>
453 <?php endif; ?>
454 <?php else: ?>
455 <?php esc_html_e('Contact for pricing', 'yatra'); ?>
456 <?php endif; ?>
457 </span>
458 </div>
459 <?php if (!empty($permalink)) : ?>
460 <a href="<?php echo esc_url($permalink); ?>" class="yatra-btn yatra-btn-primary yatra-archive-card-cta yatra-card-view-btn">
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'); ?>
462 <span><?php esc_html_e('View Details', 'yatra'); ?></span>
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>
473 <?php endif; ?>
474 </div>
475 </div>
476 </div>
477
478 <style>
479 .yatra-trip-short-description {
480 color: #64748b;
481 font-size: 0.875rem;
482 line-height: 1.5;
483 margin: 8px 0 12px 0;
484 display: -webkit-box;
485 -webkit-line-clamp: 2;
486 -webkit-box-orient: vertical;
487 overflow: hidden;
488 text-overflow: ellipsis;
489 }
490
491 /* Trip Stats Row */
492 .yatra-trip-stats-row {
493 display: flex;
494 flex-wrap: wrap;
495 gap: 16px;
496 margin: 12px 0;
497 padding: 12px 0;
498 }
499
500 .yatra-trip-stat {
501 display: flex;
502 align-items: center;
503 gap: 8px;
504 min-width: 0;
505 flex: 1;
506 }
507
508 .yatra-stat-icon {
509 display: flex;
510 align-items: center;
511 justify-content: center;
512 width: 28px;
513 height: 28px;
514 border-radius: 6px;
515 flex-shrink: 0;
516 }
517
518 .yatra-stat-icon.duration {
519 background: #dbeafe;
520 color: #1e40af;
521 }
522
523 .yatra-stat-icon.difficulty {
524 background: #fef3c7;
525 color: #d97706;
526 }
527
528 .yatra-stat-icon.group {
529 background: #dcfce7;
530 color: #166534;
531 }
532
533 .yatra-stat-icon.bookings {
534 background: #fce7f3;
535 color: #be185d;
536 }
537
538 .yatra-stat-content {
539 display: flex;
540 flex-direction: column;
541 min-width: 0;
542 flex: 1;
543 }
544
545 .yatra-stat-value {
546 font-size: 0.875rem;
547 font-weight: 600;
548 color: #1f2937;
549 line-height: 1.2;
550 }
551
552 .yatra-stat-label {
553 font-size: 0.75rem;
554 color: #6b7280;
555 line-height: 1.2;
556 margin-top: 2px;
557 }
558
559 /* Rating Row */
560 .yatra-trip-rating-row {
561 display: flex;
562 align-items: center;
563 gap: 12px;
564 margin: 12px 0;
565 }
566
567 .yatra-rating-stars {
568 display: flex;
569 align-items: center;
570 gap: 4px;
571 }
572
573 .yatra-rating-value {
574 font-weight: 600;
575 color: #1f2937;
576 font-size: 0.875rem;
577 }
578
579 .yatra-reviews-count {
580 font-size: 0.75rem;
581 color: #6b7280;
582 }
583
584 /* Responsive design */
585 @media (max-width: 768px) {
586 .yatra-trip-stats-row {
587 gap: 12px;
588 }
589
590 .yatra-trip-stat {
591 min-width: calc(50% - 6px);
592 }
593
594 .yatra-stat-icon {
595 width: 24px;
596 height: 24px;
597 }
598
599 .yatra-stat-value {
600 font-size: 0.8rem;
601 }
602
603 .yatra-stat-label {
604 font-size: 0.7rem;
605 }
606 }
607
608 @media (max-width: 480px) {
609 .yatra-trip-stats-row {
610 flex-direction: column;
611 gap: 8px;
612 }
613
614 .yatra-trip-stat {
615 min-width: 100%;
616 }
617 }
618 </style>
619