PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.6
Yatra – Travel Booking & Tour Operator Software v3.0.6
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 / listing-trip.php

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

852 lines 57.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Trip listing template (presentation). Data is prepared in {@see TripListingPageContextFactory} and set by {@see ListingPageHandler}.
4 *
5 * @package Yatra
6 */
7
8 use Yatra\Services\TripListingService;
9
10 if (!defined('ABSPATH')) {
11 exit;
12 }
13
14 $tripListingService = new TripListingService();
15
16 $ctx = $GLOBALS['yatra_trip_listing_context'] ?? [];
17 $filter_data = $ctx['filter_data'] ?? [];
18 if ($filter_data === []) {
19 $filter_data = $tripListingService->getFilterData();
20 }
21 $yatra_trip_list = $ctx['trip_list'] ?? ($GLOBALS['yatra_trip_list'] ?? null);
22 $trips_source = $ctx['trips'] ?? [];
23 $trip_total = (int) ($ctx['total'] ?? 0);
24 $trip_total_pages = (int) ($ctx['pages'] ?? 1);
25 $trip_current_page = (int) ($ctx['current_page'] ?? 1);
26 $trip_dest_options = $ctx['destinations'] ?? [];
27 $trip_act_options = $ctx['activities'] ?? [];
28 $active_filters = $ctx['active_filters'] ?? [];
29 $yatra_listing_title = $ctx['listing_title'] ?? __('All Trips', 'yatra');
30 $current_filter_type = $ctx['taxonomy_type'] ?? '';
31 $current_filter_slug = $ctx['taxonomy_slug'] ?? '';
32 $current_filter_name = $ctx['taxonomy_name'] ?? '';
33 $yatra_results = $ctx['results'] ?? [
34 'display_total' => 0,
35 'start_item' => 0,
36 'end_item' => 0,
37 'per_page' => yatra_get_posts_per_page(),
38 ];
39 $yatra_pagination = $ctx['pagination'] ?? [
40 'total_pages' => 1,
41 'current_page' => 1,
42 'prev_url' => null,
43 'next_url' => null,
44 'items' => [],
45 ];
46 $yatra_sort_options = $ctx['sort_options'] ?? [];
47 $show_taxonomy_context = !empty($ctx['show_taxonomy_context']);
48
49 yatra_get_header();
50 ?>
51
52 <?php if ($show_taxonomy_context) : ?>
53 <div id="yatra-trip-context"
54 data-type="<?php echo esc_attr($current_filter_type); ?>"
55 data-slug="<?php echo esc_attr($current_filter_slug); ?>"
56 data-name="<?php echo esc_attr($current_filter_name); ?>"
57 style="display:none;"></div>
58 <?php endif; ?>
59
60 <div class="yatra-listing-page yatra-trip-listing" id="yatra-trip-listing-root">
61 <!-- Trip Search Shortcode - replaces hardcoded search UI -->
62 <div class="yatra-trip-listing-search-wrap">
63 <?php echo do_shortcode('[yatra_search]'); ?>
64 </div>
65
66 <div class="yatra-listing-wrapper yatra-listing-wrapper--overlay-host">
67 <div id="yatra-listing-loading-overlay" class="yatra-listing-loading-overlay" aria-hidden="true" role="status">
68 <div class="yatra-listing-loading-card">
69 <span class="yatra-listing-loading-spinner" aria-hidden="true"></span>
70 <p class="yatra-listing-loading-text"><?php esc_html_e('Updating trips…', 'yatra'); ?></p>
71 </div>
72 </div>
73 <div class="yatra-listing-container">
74
75 <!-- Results Header -->
76 <div class="yatra-results-header">
77 <div class="yatra-results-info">
78 <h1><?php echo esc_html($yatra_listing_title); ?></h1>
79 <?php if (empty($show_taxonomy_context)) : ?>
80 <p class="yatra-listing-archive-lede"><?php esc_html_e('Compare trips, filter by budget and trip style, then open a trip for full details and booking.', 'yatra'); ?></p>
81 <?php elseif (!empty($current_filter_name) || !empty($current_filter_slug)) : ?>
82 <p class="yatra-listing-archive-lede"><?php
83 printf(
84 /* translators: %s: applied taxonomy filter label (destination, activity, or category name). */
85 esc_html__('Filtered by: %s', 'yatra'),
86 esc_html($current_filter_name !== '' ? $current_filter_name : (string) $current_filter_slug)
87 );
88 ?></p>
89 <?php endif; ?>
90 <p class="yatra-results-count">
91 <?php
92 if ($yatra_results['display_total'] > 0) {
93 echo sprintf(
94 /* translators: 1: first item index on the page, 2: last item index on the page, 3: total trips, 4: current page number, 5: total page count. */
95 __('Showing <strong>%1$d-%2$d</strong> of %3$d trips (Page %4$d of %5$d)', 'yatra'),
96 (int) $yatra_results['start_item'],
97 (int) $yatra_results['end_item'],
98 (int) $yatra_results['display_total'],
99 $trip_current_page,
100 $trip_total_pages
101 );
102 } else {
103 echo esc_html__('No trips found', 'yatra');
104 }
105 ?>
106 </p>
107 </div>
108 <div class="yatra-results-controls">
109 <div class="yatra-sort-control">
110 <label><?php esc_html_e('Sort by:', 'yatra'); ?></label>
111 <?php
112 ?>
113 <select id="yatra-sort-filter" class="yatra-sort-filter-select">
114 <?php foreach ($yatra_sort_options as $sort_opt) : ?>
115 <option value="<?php echo esc_attr(esc_url($sort_opt['url'])); ?>"<?php echo !empty($sort_opt['selected']) ? ' selected="selected"' : ''; ?>>
116 <?php echo esc_html($sort_opt['label']); ?>
117 </option>
118 <?php endforeach; ?>
119 </select>
120 </div>
121 <div class="yatra-view-toggle">
122 <button class="yatra-view-btn active" data-view="grid" title="<?php esc_attr_e('Grid View', 'yatra'); ?>">
123 <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
124 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"/>
125 </svg>
126 </button>
127 <button class="yatra-view-btn" data-view="list" title="<?php esc_attr_e('List View', 'yatra'); ?>">
128 <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
129 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
130 </svg>
131 </button>
132 </div>
133 </div>
134 </div>
135
136 <div class="yatra-listing-layout">
137 <!-- Filter Sidebar - Comprehensive Filters -->
138 <aside class="yatra-filter-sidebar">
139 <div class="yatra-filter-header">
140 <h2><?php esc_html_e('Filters', 'yatra'); ?></h2>
141 <button type="button" class="yatra-clear-filters"><?php esc_html_e('Clear all', 'yatra'); ?></button>
142 </div>
143
144 <!-- Price Range -->
145 <?php
146 $price_stats = $filter_data['price_stats'] ?? $tripListingService->getPriceStats();
147
148 $min_price = $price_stats ? (int)$price_stats->min_price : 0;
149 $max_price = $price_stats ? (int)$price_stats->max_price : 10000;
150 $step = max(1, (int)($max_price / 100)); // Dynamic step based on price range
151 ?>
152 <div class="yatra-filter-section">
153 <div class="yatra-filter-title" data-toggle="price">
154 <div class="yatra-filter-title-content">
155 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
156 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/>
157 </svg>
158 <span><?php esc_html_e('Price Range', 'yatra'); ?></span>
159 </div>
160 <div class="yatra-filter-actions">
161 <span class="yatra-clear-section" data-section="price" title="<?php esc_attr_e('Clear price filters', 'yatra'); ?>">
162 <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
163 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
164 </svg>
165 </span>
166 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
167 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
168 </svg>
169 </div>
170 </div>
171 <div class="yatra-filter-content">
172 <div class="yatra-price-range">
173 <div class="yatra-price-inputs">
174 <div class="yatra-price-input-group">
175 <label class="yatra-price-input-label"><?php esc_html_e('Min Price', 'yatra'); ?></label>
176 <input type="number" name="price_min" placeholder="<?php echo $min_price; ?>" min="<?php echo $min_price; ?>" max="<?php echo $max_price; ?>" value="<?php echo !empty($active_filters['price_min']) ? esc_attr($active_filters['price_min']) : ''; ?>" id="priceMin">
177 </div>
178 <div class="yatra-price-separator">—</div>
179 <div class="yatra-price-input-group">
180 <label class="yatra-price-input-label"><?php esc_html_e('Max Price', 'yatra'); ?></label>
181 <input type="number" name="price_max" placeholder="<?php echo $max_price; ?>" min="<?php echo $min_price; ?>" max="<?php echo $max_price; ?>" value="<?php echo !empty($active_filters['price_max']) ? esc_attr($active_filters['price_max']) : ''; ?>" id="priceMax">
182 </div>
183 </div>
184 <div class="yatra-price-slider">
185 <div class="yatra-price-slider-track" aria-hidden="true"></div>
186 <div class="yatra-price-slider-range" aria-hidden="true"></div>
187 <input type="range" min="<?php echo $min_price; ?>" max="<?php echo $max_price; ?>" step="<?php echo $step; ?>" value="<?php echo !empty($active_filters['price_min']) ? esc_attr($active_filters['price_min']) : $min_price; ?>" class="yatra-range-min" id="priceRangeMin" data-default="<?php echo $min_price; ?>" data-user-set="<?php echo !empty($active_filters['price_min']) ? 'true' : 'false'; ?>">
188 <input type="range" min="<?php echo $min_price; ?>" max="<?php echo $max_price; ?>" step="<?php echo $step; ?>" value="<?php echo !empty($active_filters['price_max']) ? esc_attr($active_filters['price_max']) : $max_price; ?>" class="yatra-range-max" id="priceRangeMax" data-default="<?php echo $max_price; ?>" data-user-set="<?php echo !empty($active_filters['price_max']) ? 'true' : 'false'; ?>">
189 </div>
190 <div class="yatra-price-display"><?php echo yatra_format_price($min_price); ?> - <?php echo yatra_format_price($max_price); ?></div>
191 </div>
192 </div>
193 </div>
194
195 <!-- Trip Type Filter -->
196 <div class="yatra-filter-section">
197 <div class="yatra-filter-title" data-toggle="trip-type">
198 <div class="yatra-filter-title-content">
199 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
200 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
201 </svg>
202 <span><?php esc_html_e('Trip Type', 'yatra'); ?></span>
203 </div>
204 <div class="yatra-filter-actions">
205 <span class="yatra-clear-section" data-section="trip-type" title="<?php esc_attr_e('Clear trip type filter', 'yatra'); ?>">
206 <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
207 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
208 </svg>
209 </span>
210 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
211 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
212 </svg>
213 </div>
214 </div>
215 <div class="yatra-filter-content">
216 <div class="yatra-checkbox-group">
217 <?php
218 // Get trip type options from service
219 $trip_type_options = $filter_data['trip_types'] ?? [];
220
221 foreach ($trip_type_options as $type_option) :
222 ?>
223 <label class="yatra-checkbox-label">
224 <input type="radio" name="trip_type" value="<?php echo esc_attr($type_option->value); ?>" <?php echo ($active_filters['trip_type'] === $type_option->value) ? 'checked' : ''; ?>>
225 <span><?php echo esc_html($type_option->label); ?></span>
226 <span class="yatra-filter-count">(<?php echo (int)$type_option->count; ?>)</span>
227 </label>
228 <?php endforeach; ?>
229
230 <!-- All Types Option -->
231 <label class="yatra-checkbox-label">
232 <input type="radio" name="trip_type" value="" <?php echo empty($active_filters['trip_type']) ? 'checked' : ''; ?>>
233 <span><?php esc_html_e('All Types', 'yatra'); ?></span>
234 </label>
235 </div>
236 </div>
237 </div>
238
239 <!-- Difficulty Level -->
240 <?php
241 $difficulty_levels = $filter_data['difficulty_levels'] ?? [];
242 if (!empty($difficulty_levels)) :
243 ?>
244 <div class="yatra-filter-section">
245 <div class="yatra-filter-title" data-toggle="difficulty">
246 <div class="yatra-filter-title-content">
247 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
248 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z"/>
249 </svg>
250 <span><?php esc_html_e('Difficulty Level', 'yatra'); ?></span>
251 </div>
252 <div class="yatra-filter-actions">
253 <span class="yatra-clear-section" data-section="difficulty" title="<?php esc_attr_e('Clear difficulty filters', 'yatra'); ?>">
254 <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
255 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
256 </svg>
257 </span>
258 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
259 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
260 </svg>
261 </div>
262 </div>
263 <div class="yatra-filter-content">
264 <?php
265 $yatra_sidebar_cb_rows = [];
266 foreach ($difficulty_levels as $level) {
267 $yatra_sidebar_cb_rows[] = [
268 'value' => $level->id,
269 'label' => $level->name,
270 'count' => (int) $level->count,
271 ];
272 }
273 $yatra_sidebar_cb_input_name = 'difficulty[]';
274 $yatra_sidebar_cb_active = $active_filters['difficulty'] ?? [];
275 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
276 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
277 ?>
278 </div>
279 </div>
280 <?php endif; ?>
281
282 <!-- Rating -->
283 <div class="yatra-filter-section">
284 <div class="yatra-filter-title" data-toggle="rating">
285 <div class="yatra-filter-title-content">
286 <svg class="yatra-filter-icon" width="18" height="18" fill="#fbbf24" viewBox="0 0 24 24">
287 <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
288 </svg>
289 <span><?php esc_html_e('Rating', 'yatra'); ?></span>
290 </div>
291 <div class="yatra-filter-actions">
292 <span class="yatra-clear-section" data-section="rating" title="<?php esc_attr_e('Clear rating filters', 'yatra'); ?>">
293 <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
294 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
295 </svg>
296 </span>
297 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
298 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
299 </svg>
300 </div>
301 </div>
302 <div class="yatra-filter-content">
303 <div class="yatra-rating-filter">
304 <?php
305 $rating_options = $filter_data['ratings'] ?? [];
306
307 foreach ($rating_options as $option) :
308 // Show all rating options, even with 0 count for better UX
309 ?>
310 <label class="yatra-rating-option">
311 <input type="checkbox" name="rating[]" value="<?php echo esc_attr($option->rating); ?>" <?php echo in_array($option->rating, $active_filters['rating'] ?? []) ? 'checked' : ''; ?>>
312 <div class="yatra-stars-display">
313 <?php for ($i = 1; $i <= 5; $i++) : ?>
314 <svg class="yatra-star <?php echo $i <= $option->rating ? 'filled' : 'empty'; ?>" width="16" height="16" viewBox="0 0 24 24">
315 <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" fill="<?php echo $i <= $option->rating ? '#fbbf24' : '#e5e7eb'; ?>"/>
316 </svg>
317 <?php endfor; ?>
318 <span class="yatra-rating-label"><?php echo esc_html($option->label); ?></span>
319 <span class="yatra-filter-count">(<?php echo (int)$option->count; ?>)</span>
320 </div>
321 </label>
322 <?php endforeach; ?>
323 </div>
324 </div>
325 </div>
326
327 <!-- Trip Categories -->
328 <?php
329 $categories = $filter_data['categories'] ?? [];
330 if (!empty($categories)) :
331 ?>
332 <div class="yatra-filter-section">
333 <div class="yatra-filter-title" data-toggle="categories">
334 <div class="yatra-filter-title-content">
335 <svg class="yatra-filter-icon" width="18" height="18" fill="currentColor" viewBox="0 0 20 20">
336 <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" />
337 </svg>
338 <span><?php esc_html_e('Categories', 'yatra'); ?></span>
339 </div>
340 <div class="yatra-filter-actions">
341 <span class="yatra-clear-section" data-section="categories" title="<?php esc_attr_e('Clear category filters', 'yatra'); ?>">
342 <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
343 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
344 </svg>
345 </span>
346 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
347 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
348 </svg>
349 </div>
350 </div>
351 <div class="yatra-filter-content">
352 <?php
353 $yatra_sidebar_cb_rows = [];
354 foreach ($categories as $category) {
355 $yatra_sidebar_cb_rows[] = [
356 'value' => $category->id,
357 'label' => $category->name,
358 'count' => (int) $category->count,
359 ];
360 }
361 $yatra_sidebar_cb_input_name = 'categories[]';
362 $yatra_sidebar_cb_active = $active_filters['categories'] ?? [];
363 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
364 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
365 ?>
366 </div>
367 </div>
368 <?php endif; ?>
369
370 <!-- Destinations -->
371 <?php
372 $destinations = $filter_data['destinations'] ?? [];
373 if (!empty($destinations)) :
374 ?>
375 <div class="yatra-filter-section">
376 <div class="yatra-filter-title" data-toggle="destinations">
377 <div class="yatra-filter-title-content">
378 <svg class="yatra-filter-icon" width="18" height="18" fill="currentColor" viewBox="0 0 20 20">
379 <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" />
380 </svg>
381 <span><?php esc_html_e('Destinations', 'yatra'); ?></span>
382 </div>
383 <div class="yatra-filter-actions">
384 <span class="yatra-clear-section" data-section="destinations" title="<?php esc_attr_e('Clear destination filters', 'yatra'); ?>">
385 <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
386 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
387 </svg>
388 </span>
389 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
390 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
391 </svg>
392 </div>
393 </div>
394 <div class="yatra-filter-content">
395 <?php
396 $yatra_sidebar_cb_rows = [];
397 foreach ($destinations as $destination) {
398 $yatra_sidebar_cb_rows[] = [
399 'value' => $destination->id,
400 'label' => $destination->name,
401 'count' => (int) $destination->count,
402 ];
403 }
404 $yatra_sidebar_cb_input_name = 'destinations[]';
405 $yatra_sidebar_cb_active = $active_filters['destinations'] ?? [];
406 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
407 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
408 ?>
409 </div>
410 </div>
411 <?php endif; ?>
412
413 <!-- Activities -->
414 <?php
415 $activities = $filter_data['activities'] ?? [];
416 if (!empty($activities)) :
417 ?>
418 <div class="yatra-filter-section">
419 <div class="yatra-filter-title" data-toggle="activities">
420 <div class="yatra-filter-title-content">
421 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
422 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
423 </svg>
424 <span><?php esc_html_e('Activities', 'yatra'); ?></span>
425 </div>
426 <div class="yatra-filter-actions">
427 <span class="yatra-clear-section" data-section="activities" title="<?php esc_attr_e('Clear activity filters', 'yatra'); ?>">
428 <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
429 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
430 </svg>
431 </span>
432 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
433 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
434 </svg>
435 </div>
436 </div>
437 <div class="yatra-filter-content">
438 <?php
439 $yatra_sidebar_cb_rows = [];
440 foreach ($activities as $activity) {
441 $yatra_sidebar_cb_rows[] = [
442 'value' => $activity->id,
443 'label' => $activity->name,
444 'count' => (int) $activity->count,
445 ];
446 }
447 $yatra_sidebar_cb_input_name = 'activities[]';
448 $yatra_sidebar_cb_active = $active_filters['activities'] ?? [];
449 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
450 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
451 ?>
452 </div>
453 </div>
454 <?php endif; ?>
455
456 <!-- Accommodation Type -->
457 <?php
458 // Get accommodation types from service
459 $accommodation_types = $filter_data['accommodations'] ?? [];
460
461 if (!empty($accommodation_types)) :
462 ?>
463 <div class="yatra-filter-section">
464 <div class="yatra-filter-title" data-toggle="accommodation">
465 <div class="yatra-filter-title-content">
466 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
467 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"/>
468 </svg>
469 <span><?php esc_html_e('Accommodation', 'yatra'); ?></span>
470 </div>
471 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
472 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
473 </svg>
474 </div>
475 <div class="yatra-filter-content">
476 <?php
477 $yatra_sidebar_cb_rows = [];
478 foreach ($accommodation_types as $accommodation) {
479 $yatra_sidebar_cb_rows[] = [
480 'value' => $accommodation->name,
481 'label' => ucwords(str_replace(['_', '-'], ' ', $accommodation->name)),
482 'count' => (int) $accommodation->trip_count,
483 ];
484 }
485 $yatra_sidebar_cb_input_name = 'accommodation[]';
486 $yatra_sidebar_cb_active = $active_filters['accommodation'] ?? [];
487 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
488 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
489 ?>
490 </div>
491 </div>
492 <?php endif; ?>
493
494 <!-- Included Services -->
495 <?php
496 // Get included services from service
497 $included_services = $filter_data['included_services'] ?? [];
498
499 if (!empty($included_services)) :
500 ?>
501 <div class="yatra-filter-section">
502 <div class="yatra-filter-title" data-toggle="services">
503 <div class="yatra-filter-title-content">
504 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
505 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z"/>
506 </svg>
507 <span><?php esc_html_e('Included Services', 'yatra'); ?></span>
508 </div>
509 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
510 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
511 </svg>
512 </div>
513 <div class="yatra-filter-content">
514 <?php
515 $yatra_sidebar_cb_rows = [];
516 foreach ($included_services as $service) {
517 $yatra_sidebar_cb_rows[] = [
518 'value' => $service->service_name,
519 'label' => $service->service_name,
520 'count' => (int) $service->trip_count,
521 ];
522 }
523 $yatra_sidebar_cb_input_name = 'services[]';
524 $yatra_sidebar_cb_active = $active_filters['services'] ?? [];
525 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
526 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
527 ?>
528 </div>
529 </div>
530 <?php endif; ?>
531
532 <!-- Special Offers -->
533 <?php
534 // Get special offers from service
535 $special_offers = $filter_data['special_offers'] ?? [];
536
537 if (!empty($special_offers)) :
538 ?>
539 <div class="yatra-filter-section">
540 <div class="yatra-filter-title" data-toggle="offers">
541 <div class="yatra-filter-title-content">
542 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
543 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v13m0-13V6a2 2 0 112 2h-2zm0 0V5.5A2.5 2.5 0 109.5 8H12zm-7 4h14M5 12a2 2 0 110-4h14a2 2 0 110 4M5 12v7a2 2 0 002 2h10a2 2 0 002-2v-7"/>
544 </svg>
545 <span><?php esc_html_e('Special Offers', 'yatra'); ?></span>
546 </div>
547 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
548 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
549 </svg>
550 </div>
551 <div class="yatra-filter-content">
552 <?php
553 $yatra_sidebar_cb_rows = [];
554 foreach ($special_offers as $offer) {
555 $yatra_sidebar_cb_rows[] = [
556 'value' => $offer->value,
557 'label' => $offer->label,
558 'count' => (int) $offer->count,
559 ];
560 }
561 $yatra_sidebar_cb_input_name = 'offers[]';
562 $yatra_sidebar_cb_active = $active_filters['offers'] ?? [];
563 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
564 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
565 ?>
566 </div>
567 </div>
568 <?php endif; ?>
569
570 <!-- Booking Options -->
571 <?php
572 // Get booking options from service
573 $booking_options = $filter_data['booking_options'] ?? [];
574
575 if (!empty($booking_options)) :
576 ?>
577 <div class="yatra-filter-section">
578 <div class="yatra-filter-title" data-toggle="booking">
579 <div class="yatra-filter-title-content">
580 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
581 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
582 </svg>
583 <span><?php esc_html_e('Booking Options', 'yatra'); ?></span>
584 </div>
585 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
586 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
587 </svg>
588 </div>
589 <div class="yatra-filter-content">
590 <?php
591 $yatra_sidebar_cb_rows = [];
592 foreach ($booking_options as $option) {
593 $yatra_sidebar_cb_rows[] = [
594 'value' => $option->value,
595 'label' => $option->label,
596 'count' => (int) $option->count,
597 ];
598 }
599 $yatra_sidebar_cb_input_name = 'booking[]';
600 $yatra_sidebar_cb_active = $active_filters['booking'] ?? [];
601 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
602 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
603 ?>
604 </div>
605 </div>
606 <?php endif; ?>
607
608 <!-- Age Suitability -->
609 <?php
610 // Get age restrictions from service
611 $age_options = $filter_data['age_restrictions'] ?? [];
612
613 if (!empty($age_options)) :
614 ?>
615 <div class="yatra-filter-section">
616 <div class="yatra-filter-title" data-toggle="age">
617 <div class="yatra-filter-title-content">
618 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
619 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
620 </svg>
621 <span><?php esc_html_e('Age Suitability', 'yatra'); ?></span>
622 </div>
623 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
624 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
625 </svg>
626 </div>
627 <div class="yatra-filter-content">
628 <?php
629 $yatra_sidebar_cb_rows = [];
630 foreach ($age_options as $option) {
631 $yatra_sidebar_cb_rows[] = [
632 'value' => $option->value,
633 'label' => $option->label,
634 'count' => (int) $option->count,
635 ];
636 }
637 $yatra_sidebar_cb_input_name = 'age[]';
638 $yatra_sidebar_cb_active = $active_filters['age'] ?? [];
639 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
640 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
641 ?>
642 </div>
643 </div>
644 <?php endif; ?>
645
646 <!-- Trip Attributes Filter -->
647 <?php if (is_array($yatra_trip_list) && !empty($yatra_trip_list['attributes'])) : ?>
648 <div class="yatra-filter-section">
649 <div class="yatra-filter-title" data-toggle="trip-attributes">
650 <div class="yatra-filter-title-content">
651 <svg class="yatra-filter-icon" width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
652 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"/>
653 </svg>
654 <span><?php esc_html_e('Trip Attributes', 'yatra'); ?></span>
655 </div>
656 <div class="yatra-filter-actions">
657 <span class="yatra-clear-section" data-section="trip-attributes" title="<?php esc_attr_e('Clear trip attribute filters', 'yatra'); ?>">
658 <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
659 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
660 </svg>
661 </span>
662 <svg class="yatra-filter-arrow" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
663 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
664 </svg>
665 </div>
666 </div>
667 <div class="yatra-filter-content">
668 <?php foreach ($yatra_trip_list['attributes'] as $attribute) : ?>
669 <?php
670 $attribute_filter_name = 'attributes[' . $attribute['id'] . ']';
671 $current_values = $active_filters['attributes'][$attribute['id']] ?? [];
672
673 $field_options = [];
674 if (!empty($attribute['field_options'])) {
675 $field_options = is_array($attribute['field_options']) ?
676 $attribute['field_options'] :
677 (json_decode($attribute['field_options'], true) ?: []);
678 }
679 ?>
680
681 <div class="yatra-attribute-item">
682 <div class="yatra-attribute-label">
683 <?php if (!empty($attribute['icon'])) : ?>
684 <?php
685 $icon_data = maybe_unserialize($attribute['icon']);
686 if (is_array($icon_data) && $icon_data['type'] === 'image' && !empty($icon_data['value'])) {
687 $image_url = '';
688 if (is_numeric($icon_data['value'])) {
689 $image_url = wp_get_attachment_image_url((int) $icon_data['value'], 'thumbnail');
690 } elseif (is_string($icon_data['value']) && filter_var($icon_data['value'], FILTER_VALIDATE_URL)) {
691 $image_url = $icon_data['value'];
692 }
693 if (!empty($image_url)) {
694 echo '<img class="yatra-attribute-icon" src="' . esc_url($image_url) . '" alt="' . esc_attr($attribute['name']) . '" width="16" height="16">';
695 }
696 } elseif (is_array($icon_data) && $icon_data['type'] === 'icon' && !empty($icon_data['value'])) {
697 echo '<span class="yatra-attribute-icon">' . yatra_svg_icon($icon_data['value'], '') . '</span>';
698 }
699 ?>
700 <?php endif; ?>
701 <span class="yatra-attribute-name"><?php echo esc_html($attribute['name']); ?></span>
702 </div>
703 <div class="yatra-attribute-content">
704 <?php if (($attribute['field_type'] === 'select' || $attribute['field_type'] === 'radio') && !empty($field_options)) : ?>
705 <?php
706 $yatra_sidebar_cb_rows = [];
707 foreach ($field_options as $option) {
708 $yatra_sidebar_cb_rows[] = [
709 'value' => $option['value'],
710 'label' => $option['label'],
711 ];
712 }
713 $yatra_sidebar_cb_input_name = $attribute_filter_name . '[]';
714 $yatra_sidebar_cb_active = $current_values;
715 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
716 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
717 ?>
718
719 <?php elseif ($attribute['field_type'] === 'checkbox' && !empty($field_options)) : ?>
720 <?php
721 $yatra_sidebar_cb_rows = [];
722 foreach ($field_options as $option) {
723 $yatra_sidebar_cb_rows[] = [
724 'value' => $option['value'],
725 'label' => $option['label'],
726 ];
727 }
728 $yatra_sidebar_cb_input_name = $attribute_filter_name . '[]';
729 $yatra_sidebar_cb_active = is_array($current_values) ? $current_values : [];
730 include __DIR__ . '/partials/listing-sidebar-collapsible-checkboxes.php';
731 unset($yatra_sidebar_cb_rows, $yatra_sidebar_cb_input_name, $yatra_sidebar_cb_active);
732 ?>
733
734 <?php elseif ($attribute['field_type'] === 'checkbox') : ?>
735 <div class="yatra-checkbox-group">
736 <label class="yatra-checkbox-label">
737 <input
738 type="checkbox"
739 name="<?php echo esc_attr($attribute_filter_name); ?>"
740 value="1"
741 <?php echo in_array('1', (array) $current_values, true) ? 'checked' : ''; ?>
742 >
743 <span><?php _e('Yes', 'yatra'); ?></span>
744 </label>
745 </div>
746
747 <?php elseif ($attribute['field_type'] === 'number') : ?>
748 <div class="yatra-input-group">
749 <input
750 type="number"
751 name="<?php echo esc_attr($attribute_filter_name); ?>[min]"
752 placeholder="<?php esc_attr_e('Min', 'yatra'); ?>"
753 value="<?php echo esc_attr($current_values['min'] ?? ''); ?>"
754 class="yatra-filter-input"
755 >
756 <input
757 type="number"
758 name="<?php echo esc_attr($attribute_filter_name); ?>[max]"
759 placeholder="<?php esc_attr_e('Max', 'yatra'); ?>"
760 value="<?php echo esc_attr($current_values['max'] ?? ''); ?>"
761 class="yatra-filter-input"
762 >
763 </div>
764
765 <?php elseif ($attribute['field_type'] === 'date') : ?>
766 <div class="yatra-input-group">
767 <input
768 type="date"
769 name="<?php echo esc_attr($attribute_filter_name); ?>[from]"
770 value="<?php echo esc_attr($current_values['from'] ?? ''); ?>"
771 class="yatra-filter-input"
772 >
773 <input
774 type="date"
775 name="<?php echo esc_attr($attribute_filter_name); ?>[to]"
776 value="<?php echo esc_attr($current_values['to'] ?? ''); ?>"
777 class="yatra-filter-input"
778 >
779 </div>
780
781 <?php else : ?>
782 <input
783 type="text"
784 name="<?php echo esc_attr($attribute_filter_name); ?>"
785 placeholder="<?php esc_attr_e('Type to filter…', 'yatra'); ?>"
786 value="<?php echo esc_attr(implode(', ', $current_values)); ?>"
787 class="yatra-filter-input"
788 >
789 <?php endif; ?>
790 </div>
791 </div>
792 <?php endforeach; ?>
793 </div>
794 </div>
795 <?php endif; ?>
796
797 </aside>
798
799 <!-- Main Content Area -->
800 <main class="yatra-listing-content">
801 <?php if (count($trips_source) > 0) : ?>
802 <div class="yatra-trip-grid" id="trip-grid">
803 <?php foreach ($trips_source as $trip) : ?>
804 <!-- Use the reusable trip-listing-card.php component -->
805 <?php include(dirname(__FILE__) . '/trip-listing-card.php'); ?>
806 <?php endforeach; ?>
807 </div>
808 <?php else : ?>
809 <div class="yatra-empty-state text-center py-12">
810 <svg class="mx-auto h-8 w-8 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
811 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
812 </svg>
813 <h3 class="mt-2 text-lg font-medium text-gray-900 dark:text-gray-100"><?php esc_html_e('No trips found', 'yatra'); ?></h3>
814 <p class="mt-1 text-gray-500 dark:text-gray-400"><?php esc_html_e('Try adjusting your search or filter to find what you\'re looking for.', 'yatra'); ?></p>
815 </div>
816 <?php endif; ?>
817
818 <div class="yatra-listing-pagination yatra-listing-pagination--trip-content">
819 <?php
820 $prev_url = $yatra_pagination['prev_url'] ?? null;
821 $next_url = $yatra_pagination['next_url'] ?? null;
822 $prev_disabled = empty($prev_url);
823 $next_disabled = empty($next_url);
824 ?>
825 <a class="yatra-pagination-btn <?php echo $prev_disabled ? 'disabled' : ''; ?>" href="<?php echo $prev_disabled ? 'javascript:void(0);' : esc_url($prev_url); ?>">
826 <?php echo yatra_svg_icon('chevron-left', 'yatra-btn-icon'); ?>
827 <span><?php esc_html_e('Previous', 'yatra'); ?></span>
828 </a>
829 <?php foreach (($yatra_pagination['items'] ?? []) as $pitem) : ?>
830 <?php if (($pitem['type'] ?? '') === 'ellipsis') : ?>
831 <span class="yatra-pagination-ellipsis">...</span>
832 <?php elseif (($pitem['type'] ?? '') === 'page') : ?>
833 <a class="yatra-pagination-btn <?php echo !empty($pitem['is_current']) ? 'active' : ''; ?>" href="<?php echo esc_url((string) ($pitem['url'] ?? '')); ?>">
834 <?php echo esc_html((string) ($pitem['page'] ?? '')); ?>
835 </a>
836 <?php endif; ?>
837 <?php endforeach; ?>
838 <a class="yatra-pagination-btn <?php echo $next_disabled ? 'disabled' : ''; ?>" href="<?php echo $next_disabled ? 'javascript:void(0);' : esc_url($next_url); ?>">
839 <span><?php esc_html_e('Next', 'yatra'); ?></span>
840 <?php echo yatra_svg_icon('chevron-right', 'yatra-btn-icon'); ?>
841 </a>
842 </div>
843 </main>
844 </div>
845 </div>
846 </div>
847 </div>
848
849 <?php
850 yatra_get_footer();
851 ?>
852