PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.9
Yatra – Travel Booking & Tour Operator Software v3.0.9
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 / single-taxonomy.php

single-taxonomy.php in Yatra – Travel Booking & Tour Operator Software 3.0.9, at templates/single-taxonomy.php

368 lines 18.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Single Taxonomy Page Template (Destination, Activity, Category)
4 * Shows trips filtered by the selected taxonomy with full filtering capabilities
5 *
6 * @package Yatra
7 */
8
9 // Prevent direct access
10 if (!defined('ABSPATH')) {
11 exit;
12 }
13
14 // Get taxonomy data from global
15 $taxonomy_data = $GLOBALS['yatra_taxonomy_data'] ?? null;
16
17 if (!$taxonomy_data) {
18 wp_die(__('No taxonomy data found', 'yatra'));
19 }
20
21 $type = $taxonomy_data->type;
22 $entity = $taxonomy_data; // Use the taxonomy object itself as entity
23
24 // Helper function to safely get array from $_GET
25 function yatra_get_filter_array($key, $sanitize_callback = 'sanitize_text_field') {
26 if (!isset($_GET[$key])) {
27 return [];
28 }
29
30 $value = $_GET[$key];
31
32 // If it's already an array, sanitize each element
33 if (is_array($value)) {
34 return array_map($sanitize_callback, $value);
35 }
36
37 // If it's a string, convert to array and sanitize
38 if (is_string($value) && !empty($value)) {
39 // Handle comma-separated values
40 $array = explode(',', $value);
41 return array_map($sanitize_callback, array_filter($array));
42 }
43
44 return [];
45 }
46
47 // Get active filters from URL parameters (same as main trip listing)
48 $active_filters = [
49 'destination' => sanitize_text_field($_GET['destination'] ?? ''),
50 'activity' => sanitize_text_field($_GET['activity'] ?? ''),
51 'price_min' => !empty($_GET['price_min']) ? intval($_GET['price_min']) : '',
52 'price_max' => !empty($_GET['price_max']) ? intval($_GET['price_max']) : '',
53 'trip_type' => sanitize_text_field($_GET['trip_type'] ?? ''),
54 'sort' => sanitize_text_field($_GET['sort'] ?? ''),
55 'difficulty' => yatra_get_filter_array('difficulty', 'intval'),
56 'rating' => yatra_get_filter_array('rating', 'intval'),
57 'categories' => yatra_get_filter_array('categories', 'intval'),
58 'destinations' => yatra_get_filter_array('destinations', 'intval'),
59 'activities' => yatra_get_filter_array('activities', 'intval'),
60 'accommodation' => yatra_get_filter_array('accommodation', 'sanitize_text_field'),
61 'included_services' => yatra_get_filter_array('included_services', 'sanitize_text_field'),
62 'special_offers' => yatra_get_filter_array('special_offers', 'sanitize_text_field'),
63 'booking_options' => yatra_get_filter_array('booking_options', 'sanitize_text_field'),
64 'age_suitability' => yatra_get_filter_array('age_suitability', 'sanitize_text_field'),
65 ];
66
67 // Get type labels
68 $type_labels = [
69 'destination' => [
70 'singular' => __('Destination', 'yatra'),
71 'plural' => __('Destinations', 'yatra'),
72 /* translators: %s: destination name (e.g. "Nepal"). */
73 'trips_title' => __('Trips in %s', 'yatra'),
74 ],
75 'activity' => [
76 'singular' => __('Activity', 'yatra'),
77 'plural' => __('Activities', 'yatra'),
78 /* translators: %s: term name (activity or category, e.g. "Hiking" or "Adventure"). */
79 'trips_title' => __('%s Trips', 'yatra'),
80 ],
81 'category' => [
82 'singular' => __('Category', 'yatra'),
83 'plural' => __('Categories', 'yatra'),
84 /* translators: %s: term name (activity or category, e.g. "Hiking" or "Adventure"). */
85 'trips_title' => __('%s Trips', 'yatra'),
86 ],
87 ];
88
89 $labels = $type_labels[$type] ?? $type_labels['category'];
90
91 // Pagination: repository + handler totals; page size from WordPress Reading (posts per page)
92 $trips = is_array($taxonomy_data->trips ?? null) ? $taxonomy_data->trips : [];
93 $per_page = isset($taxonomy_data->trips_per_page) ? (int) $taxonomy_data->trips_per_page : yatra_get_posts_per_page();
94 $total_trips = isset($taxonomy_data->trips_total) ? (int) $taxonomy_data->trips_total : count($trips);
95 $total_pages = isset($taxonomy_data->trips_pages) ? max(1, (int) $taxonomy_data->trips_pages) : ($total_trips > 0 ? (int) ceil($total_trips / max(1, $per_page)) : 1);
96 $current_page = isset($taxonomy_data->trips_current_page) ? (int) $taxonomy_data->trips_current_page : yatra_get_archive_listing_paged();
97 $current_page = min(max(1, $current_page), $total_pages);
98 $paged_trips = $trips;
99
100 // Get entity image (no external hardcoded external URL)
101 $entity_image = '';
102
103 // Prefer explicit featured_image or image when present
104 if (!empty($taxonomy_data->featured_image)) {
105 $entity_image = wp_get_attachment_url($taxonomy_data->featured_image);
106 } elseif (!empty($taxonomy_data->image)) {
107 $entity_image = $taxonomy_data->image;
108 }
109
110 // If still empty, try resolving from icon configuration (same logic as listing-destination.php)
111 if (empty($entity_image) && !empty($taxonomy_data->icon)) {
112 $icon = maybe_unserialize($taxonomy_data->icon);
113
114 if (is_array($icon)) {
115 $type = $icon['type'] ?? '';
116 $value = $icon['value'] ?? '';
117
118 if ($type === 'image' && !empty($value)) {
119 if (is_numeric($value)) {
120 $maybe_url = wp_get_attachment_image_url((int) $value, 'large');
121 if (!empty($maybe_url)) {
122 $entity_image = $maybe_url;
123 }
124 } elseif (is_string($value) && filter_var($value, FILTER_VALIDATE_URL)) {
125 $entity_image = $value;
126 }
127 } elseif (!empty($icon['url']) && filter_var($icon['url'], FILTER_VALIDATE_URL)) {
128 // Legacy format: ['url' => 'https://...']
129 $entity_image = $icon['url'];
130 } elseif (!empty($icon['id'])) {
131 // Legacy format: ['id' => attachment_id]
132 $maybe_url = wp_get_attachment_image_url((int) $icon['id'], 'large');
133 if (!empty($maybe_url)) {
134 $entity_image = $maybe_url;
135 }
136 }
137 } elseif (is_numeric($icon)) {
138 $maybe_url = wp_get_attachment_image_url((int) $icon, 'large');
139 if (!empty($maybe_url)) {
140 $entity_image = $maybe_url;
141 }
142 } elseif (is_string($icon) && filter_var($icon, FILTER_VALIDATE_URL)) {
143 $entity_image = $icon;
144 }
145 }
146
147 // Final internal placeholder fallback (no external Unsplash)
148 if (empty($entity_image)) {
149 $placeholder_src = plugins_url('assets/images/placeholder.png', dirname(__FILE__));
150 $entity_image = $placeholder_src;
151 }
152
153 yatra_get_header();
154 ?>
155
156 <div class="yatra-listing-page yatra-taxonomy-page yatra-<?php echo esc_attr($type); ?>-page">
157
158 <!-- Hero Section -->
159 <div class="yatra-taxonomy-hero"<?php echo $entity_image ? ' style="background-image: url(' . esc_url($entity_image) . ');"' : ''; ?>>
160 <div class="yatra-taxonomy-hero-overlay"></div>
161 <div class="yatra-taxonomy-hero-content">
162 <h1 class="yatra-taxonomy-title"><?php echo esc_html($taxonomy_data->name); ?></h1>
163 <?php if (!empty($taxonomy_data->description)): ?>
164 <p class="yatra-taxonomy-description"><?php echo wp_kses_post($taxonomy_data->description); ?></p>
165 <?php endif; ?>
166 <div class="yatra-taxonomy-stats">
167 <span class="yatra-taxonomy-trip-count">
168 <svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
169 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7"/>
170 </svg>
171 <?php
172 /* translators: %d: total number of trips in this taxonomy term. */
173 echo sprintf(_n('%d Trip', '%d Trips', $total_trips, 'yatra'), (int) $total_trips);
174 ?>
175 </span>
176 </div>
177 </div>
178 </div>
179
180 <div class="yatra-listing-wrapper">
181 <div class="yatra-listing-container">
182
183 <!-- Full Width Content (no sidebar) -->
184 <div class="yatra-listing-content-full">
185 <!-- Results Header -->
186 <div class="yatra-results-header">
187 <div class="yatra-results-info">
188 <h2><?php echo sprintf(esc_html($labels['trips_title']), esc_html($taxonomy_data->name)); ?></h2>
189 <p class="yatra-results-count">
190 <?php
191 $start_item = ($current_page - 1) * $per_page + 1;
192 $end_item = min($current_page * $per_page, $total_trips);
193
194 if ($total_trips > 0) {
195 echo sprintf(
196 /* 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. */
197 __('Showing <strong>%1$d-%2$d</strong> of %3$d trips (Page %4$d of %5$d)', 'yatra'),
198 $start_item,
199 $end_item,
200 $total_trips,
201 $current_page,
202 $total_pages
203 );
204 } else {
205 echo esc_html__('No trips found', 'yatra');
206 }
207 ?>
208 </p>
209 </div>
210 <div class="yatra-results-controls">
211 <div class="yatra-sort-control">
212 <label><?php echo esc_html__('Sort by:', 'yatra'); ?></label>
213 <?php
214 $current_trip_sort = isset($_GET['sort']) ? sanitize_text_field(wp_unslash((string) $_GET['sort'])) : '';
215 $sort_definitions = [
216 '' => __('Recommended', 'yatra'),
217 'most_popular' => __('Most Popular', 'yatra'),
218 'price_low' => __('Price: Low to High', 'yatra'),
219 'price_high' => __('Price: High to Low', 'yatra'),
220 'rating_high' => __('Rating: Highest', 'yatra'),
221 'duration_short' => __('Duration: Shortest', 'yatra'),
222 'duration_long' => __('Duration: Longest', 'yatra'),
223 ];
224 ?>
225 <select id="yatra-sort-filter" class="yatra-sort-filter-select">
226 <?php foreach ($sort_definitions as $sort_key => $sort_label) : ?>
227 <option value="<?php echo esc_attr(esc_url(yatra_build_current_request_sort_url($sort_key))); ?>"<?php selected($sort_key, $current_trip_sort, true); ?>><?php echo esc_html($sort_label); ?></option>
228 <?php endforeach; ?>
229 </select>
230 </div>
231 <div class="yatra-view-toggle">
232 <button class="yatra-view-btn active" data-view="grid" title="<?php echo esc_attr__('Grid View', 'yatra'); ?>">
233 <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
234 <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"/>
235 </svg>
236 </button>
237 <button class="yatra-view-btn" data-view="list" title="<?php echo esc_attr__('List View', 'yatra'); ?>">
238 <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
239 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
240 </svg>
241 </button>
242 </div>
243 </div>
244 </div>
245
246 <!-- Trip Grid -->
247 <?php if (!empty($paged_trips)): ?>
248 <div class="yatra-trip-grid" id="trip-grid">
249 <?php foreach ($paged_trips as $trip): ?>
250 <?php
251 // Convert stdClass to Trip model instance if needed for consistent data access
252 if (!($trip instanceof \Yatra\Models\Trip)) {
253 $trip = \Yatra\Models\Trip::fromStdClass($trip);
254 }
255 ?>
256 <?php include(dirname(__FILE__) . '/trip-listing-card.php'); ?>
257 <?php endforeach; ?>
258 </div>
259 <?php else: ?>
260 <div class="yatra-no-trips-found">
261 <div class="yatra-no-trips-icon">
262 <svg width="32" height="32" fill="none" stroke="currentColor" viewBox="0 0 24 24">
263 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7"/>
264 </svg>
265 </div>
266 <h3><?php echo esc_html__('No trips found', 'yatra'); ?></h3>
267 <p><?php
268 /* translators: %s: taxonomy term name (destination, activity, or category). */
269 echo sprintf(esc_html__('There are no trips available for %s at the moment. Please check back later or explore other options.', 'yatra'), esc_html($taxonomy_data->name));
270 ?></p>
271 <a href="<?php echo esc_url(home_url('/' . \Yatra\Services\SettingsService::getTripBase() . '/')); ?>" class="yatra-btn yatra-btn-primary yatra-archive-card-cta">
272 <?php echo yatra_svg_icon('globe', 'yatra-btn-icon'); ?>
273 <span><?php echo esc_html__('Browse All Trips', 'yatra'); ?></span>
274 </a>
275 </div>
276 <?php endif; ?>
277
278 <?php if ($total_pages > 1): ?>
279 <div class="yatra-listing-pagination">
280 <?php
281 $prev_page = max(1, $current_page - 1);
282 $next_page = min($total_pages, $current_page + 1);
283 ?>
284
285 <?php if ($current_page <= 1): ?>
286 <span class="yatra-pagination-btn disabled" aria-disabled="true">
287 <?php echo yatra_svg_icon('chevron-left', 'yatra-btn-icon'); ?>
288 <span><?php echo esc_html__('Previous', 'yatra'); ?></span>
289 </span>
290 <?php else: ?>
291 <a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_current_request_paged_url($prev_page)); ?>">
292 <?php echo yatra_svg_icon('chevron-left', 'yatra-btn-icon'); ?>
293 <span><?php echo esc_html__('Previous', 'yatra'); ?></span>
294 </a>
295 <?php endif; ?>
296
297 <?php
298 $range = 2;
299 for ($i = 1; $i <= $total_pages; $i++) :
300 if ($i == 1 || $i == $total_pages || ($i >= $current_page - $range && $i <= $current_page + $range)) :
301 if ($i === $current_page) :
302 ?>
303 <span class="yatra-pagination-btn active"><?php echo esc_html((string) $i); ?></span>
304 <?php
305 else :
306 ?>
307 <a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_current_request_paged_url($i)); ?>"><?php echo esc_html((string) $i); ?></a>
308 <?php
309 endif;
310 elseif ($i == $current_page - $range - 1 || $i == $current_page + $range + 1) :
311 ?>
312 <span class="yatra-pagination-ellipsis">...</span>
313 <?php
314 endif;
315 endfor;
316 ?>
317
318 <?php if ($current_page >= $total_pages): ?>
319 <span class="yatra-pagination-btn disabled" aria-disabled="true">
320 <span><?php echo esc_html__('Next', 'yatra'); ?></span>
321 <?php echo yatra_svg_icon('chevron-right', 'yatra-btn-icon'); ?>
322 </span>
323 <?php else: ?>
324 <a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_current_request_paged_url($next_page)); ?>">
325 <span><?php echo esc_html__('Next', 'yatra'); ?></span>
326 <?php echo yatra_svg_icon('chevron-right', 'yatra-btn-icon'); ?>
327 </a>
328 <?php endif; ?>
329 </div>
330 <?php endif; ?>
331
332 </div>
333 </div>
334 </div>
335 </div>
336
337 <script>
338 document.addEventListener('DOMContentLoaded', function() {
339 // Grid/list view: handled by assets/js/listing.js (per-page localStorage via grid id)
340
341 // Sort: server-side (#yatra-sort-filter + listing-filters.js).
342
343 // Make trip image area clickable via JS (preserve markup/design)
344 const imageWrappers = document.querySelectorAll('.yatra-trip-card .yatra-trip-image[data-permalink]');
345 imageWrappers.forEach(function(wrapper) {
346 wrapper.addEventListener('click', function (event) {
347 // Do not navigate when clicking the favorite button inside the image area
348 var target = event.target;
349 if (target instanceof Element && target.closest('.yatra-favorite-btn')) {
350 return;
351 }
352
353 var url = wrapper.getAttribute('data-permalink');
354 if (url) {
355 window.location.href = url;
356 }
357 });
358 });
359 });
360 </script>
361
362 <?php
363 yatra_get_footer();
364 ?>
365
366
367
368