PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.15
Yatra – Travel Booking & Tour Operator Software v3.0.15
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 2.0.10 All 83 releases
yatra / templates / listing-destination.php

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

334 lines 18.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Destination Listing Template
4 *
5 * Lists all published destinations from the Yatra destinations table
6 * using the DestinationService. This replaces the previous static
7 * dummy-data implementation.
8 *
9 * @package Yatra
10 */
11
12 // Prevent direct access
13 if (!defined('ABSPATH')) {
14 exit;
15 }
16
17 // Load DestinationService from plugin namespace
18 if (!class_exists('Yatra\\Services\\DestinationService')) {
19 // If the service is not available for some reason, bail gracefully.
20 yatra_get_header();
21 echo '<p>' . esc_html__('Destination service is not available.', 'yatra') . '</p>';
22 yatra_get_footer();
23 return;
24 }
25
26 $destination_service = new \Yatra\Services\DestinationService();
27
28 // Fetch published destinations with stats (including trips_count, avg_rating, starting_price)
29 $destinations = $destination_service->getPublishedWithStats();
30
31 // Apply simple server-side sorting and pagination for UX.
32 $sort = isset($_GET['yatra_sort']) ? sanitize_text_field(wp_unslash($_GET['yatra_sort'])) : 'rating_desc';
33
34 if (!empty($destinations) && is_array($destinations)) {
35 yatra_sort_archive_listing_stats_rows($destinations, $sort);
36 }
37
38 $per_page = yatra_get_posts_per_page();
39 $current_page = yatra_get_archive_listing_paged();
40 $total_items = is_array($destinations) ? count($destinations) : 0;
41 $total_pages = $total_items > 0 ? (int) ceil($total_items / $per_page) : 1;
42 $current_page = min($current_page, $total_pages);
43
44 $offset = ($current_page - 1) * $per_page;
45 $paged_destinations = $total_items > 0 ? array_slice($destinations, $offset, $per_page) : [];
46
47 $yatra_browse_start = $total_items > 0 ? $offset + 1 : 0;
48 $yatra_browse_end = $total_items > 0 ? min($offset + $per_page, $total_items) : 0;
49 $yatra_browse_line = function_exists('yatra_archive_browse_results_line')
50 ? yatra_archive_browse_results_line(
51 $yatra_browse_start,
52 $yatra_browse_end,
53 $total_items,
54 $current_page,
55 $total_pages,
56 __('destinations', 'yatra')
57 )
58 : '';
59
60 $GLOBALS['yatra_archive_browse_pagination'] = [
61 'current_page' => (int) $current_page,
62 'total_pages' => (int) $total_pages,
63 ];
64
65 yatra_get_header();
66 ?>
67
68 <style>
69 .yatra-destination-icon-wrapper svg {
70 width: 100% !important;
71 height: 100% !important;
72 max-width: none !important;
73 max-height: none !important;
74 min-width: 100%;
75 min-height: 100%;
76 }
77 </style>
78
79 <div class="yatra-listing-page yatra-destination-listing">
80 <div class="yatra-listing-wrapper">
81 <main id="yatra-primary" class="yatra-listing-main">
82 <div class="yatra-listing-container">
83
84 <!-- Page Header -->
85 <div class="yatra-destination-header">
86 <div class="yatra-destination-header-content">
87 <h1><?php esc_html_e('All Destinations', 'yatra'); ?></h1>
88 <p class="yatra-archive-listing-lede"><?php esc_html_e('Pick a place, then open it to see trips that visit there. Cards show trip count and typical pricing when available.', 'yatra'); ?></p>
89 <?php if ($yatra_browse_line !== '') : ?>
90 <p class="yatra-archive-listing-results" role="status"><?php echo esc_html($yatra_browse_line); ?></p>
91 <?php endif; ?>
92 </div>
93 <div class="yatra-results-controls">
94 <div class="yatra-sort-control">
95 <label><?php esc_html_e('Sort by:', 'yatra'); ?></label>
96 <select onchange="if (this.value) window.location.href=this.value;">
97 <?php
98 $options = [
99 'rating_desc' => __('Most Popular', 'yatra'),
100 'trips_desc' => __('Most Trips', 'yatra'),
101 'name_asc' => __('Name: A-Z', 'yatra'),
102 'name_desc' => __('Name: Z-A', 'yatra'),
103 ];
104 foreach ($options as $value => $label) {
105 $url = yatra_build_archive_listing_sort_url($value);
106 $selected = $sort === $value ? 'selected' : '';
107 echo '<option value="' . esc_attr($url) . '" ' . $selected . '>' . esc_html($label) . '</option>';
108 }
109 ?>
110 </select>
111 </div>
112 <div class="yatra-view-toggle">
113 <button class="yatra-view-btn active" data-view="grid" type="button" title="<?php esc_attr_e('Grid View', 'yatra'); ?>">
114 <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
115 <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"/>
116 </svg>
117 </button>
118 <button class="yatra-view-btn" data-view="list" type="button" title="<?php esc_attr_e('List View', 'yatra'); ?>">
119 <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
120 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
121 </svg>
122 </button>
123 </div>
124 </div>
125 </div>
126
127 <!-- Destination Grid -->
128 <div class="yatra-destination-grid" id="destination-grid">
129 <?php if (!empty($paged_destinations)) : ?>
130 <?php
131 ?>
132
133 <?php foreach ($paged_destinations as $destination) : ?>
134 <?php
135 // Destination is a stdClass from repository
136 $name = isset($destination->name) ? $destination->name : '';
137 $description = isset($destination->description) ? $destination->description : '';
138
139 // Resolve image/icon from the stored icon field when possible.
140 $image_url = '';
141 $icon_class = '';
142 if (!empty($destination->icon)) {
143 $icon = maybe_unserialize($destination->icon);
144
145 if (is_array($icon)) {
146 // Handle both newer format ['type' => 'icon', 'value' => 'footprint']
147 // and older format [0 => 'icon', 1 => 'footprint']
148 $type = $icon['type'] ?? $icon[0] ?? '';
149 $value = $icon['value'] ?? $icon[1] ?? '';
150
151 if ($type === 'image' && !empty($value)) {
152 if (is_numeric($value)) {
153 $maybe_url = wp_get_attachment_image_url((int) $value, 'large');
154 if (!empty($maybe_url)) {
155 $image_url = $maybe_url;
156 }
157 } elseif (is_string($value) && filter_var($value, FILTER_VALIDATE_URL)) {
158 $image_url = $value;
159 }
160 } elseif ($type === 'icon' && !empty($value) && is_string($value)) {
161 // Store icon name so yatra_svg_icon() can render the same SVG
162 // icon as used in the React admin (e.g. 'footprint').
163 $icon_class = $value;
164 } elseif (!empty($icon['url']) && filter_var($icon['url'], FILTER_VALIDATE_URL)) {
165 // Legacy format: ['url' => 'https://...']
166 $image_url = $icon['url'];
167 } elseif (!empty($icon['id'])) {
168 // Legacy format: ['id' => attachment_id]
169 $maybe_url = wp_get_attachment_image_url((int) $icon['id'], 'large');
170 if (!empty($maybe_url)) {
171 $image_url = $maybe_url;
172 }
173 }
174 } elseif (is_numeric($icon)) {
175 $maybe_url = wp_get_attachment_image_url((int) $icon, 'large');
176 if (!empty($maybe_url)) {
177 $image_url = $maybe_url;
178 }
179 } elseif (is_string($icon) && filter_var($icon, FILTER_VALIDATE_URL)) {
180 $image_url = $icon;
181 }
182 }
183
184 // Basic stats: only use real DB fields when present; do not fake numbers.
185 $has_avg_rating = isset($destination->avg_rating) && (float) $destination->avg_rating > 0;
186 $avg_rating = $has_avg_rating ? (float) $destination->avg_rating : 0.0;
187
188 $has_trips_count = isset($destination->trips_count) && (int) $destination->trips_count > 0;
189 $trips_count = $has_trips_count ? (int) $destination->trips_count : 0;
190
191 $starting_price_raw = isset($destination->starting_price)
192 ? (float) $destination->starting_price
193 : 0.0;
194 $has_starting_price = $starting_price_raw > 0;
195
196 // Use core helper to format price with correct currency symbol & settings.
197 $starting_price = $has_starting_price
198 ? yatra_format_price($starting_price_raw)
199 : '';
200
201 // Build permalink
202 $permalink = function_exists('yatra_get_destination_permalink')
203 ? yatra_get_destination_permalink($destination->id ?? $destination)
204 : '';
205 ?>
206 <div class="yatra-destination-card">
207 <div class="yatra-destination-image">
208 <?php if (!empty($image_url)) : ?>
209 <img src="<?php echo esc_url($image_url); ?>" alt="<?php echo esc_attr($name); ?>">
210 <?php elseif (!empty($icon_class)) : ?>
211 <div class="yatra-destination-icon-wrapper" aria-hidden="true" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%); color: #4b5563;">
212 <?php echo yatra_svg_icon($icon_class, 'yatra-destination-icon'); ?>
213 </div>
214 <?php else : ?>
215 <?php
216 // Static placeholder image inside the plugin assets.
217 $placeholder_src = plugins_url('assets/images/placeholder.png', dirname(__FILE__));
218 ?>
219 <img src="<?php echo esc_url($placeholder_src); ?>" alt="<?php echo esc_attr__('Yatra placeholder', 'yatra'); ?>">
220 <?php endif; ?>
221 <div class="yatra-destination-overlay">
222 <h3><?php echo esc_html($name); ?></h3>
223 </div>
224 </div>
225 <div class="yatra-destination-content">
226 <?php if (!empty($description)) : ?>
227 <p class="yatra-archive-card-excerpt"><?php echo esc_html(wp_trim_words(wp_strip_all_tags((string) $description), 28)); ?></p>
228 <?php endif; ?>
229 <?php if ($has_avg_rating || $has_trips_count || $has_starting_price) : ?>
230 <div class="yatra-destination-stats">
231 <?php if ($has_avg_rating) : ?>
232 <div class="yatra-destination-stat">
233 <svg width="16" height="16" fill="#fbbf24" viewBox="0 0 24 24">
234 <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"/>
235 </svg>
236 <span><?php echo esc_html(number_format($avg_rating, 1)); ?></span>
237 </div>
238 <?php endif; ?>
239
240 <?php if ($has_trips_count) : ?>
241 <div class="yatra-destination-stat">
242 <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
243 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>
244 </svg>
245 <span><?php echo esc_html($trips_count); ?> <?php echo esc_html__('Trips', 'yatra'); ?></span>
246 </div>
247 <?php endif; ?>
248
249 <?php if ($has_starting_price) : ?>
250 <div class="yatra-destination-stat">
251 <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
252 <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 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
253 </svg>
254 <span><?php echo esc_html__('From ', 'yatra') . esc_html($starting_price); ?></span>
255 </div>
256 <?php endif; ?>
257 </div>
258 <?php endif; ?>
259 <?php if (!empty($permalink)) : ?>
260 <a class="yatra-btn yatra-btn-primary yatra-archive-card-cta" href="<?php echo esc_url($permalink); ?>">
261 <?php echo yatra_archive_listing_cta_icon_markup($icon_class, 'map-pin'); ?>
262 <span><?php echo esc_html__('Explore Destination', 'yatra'); ?></span>
263 </a>
264 <?php endif; ?>
265 </div>
266 </div>
267 <?php endforeach; ?>
268 <?php else : ?>
269 <p class="yatra-no-destinations">
270 <?php echo esc_html__('No destinations found. Please add destinations from the Yatra admin panel.', 'yatra'); ?>
271 </p>
272 <?php endif; ?>
273 </div>
274
275 <!-- Pagination -->
276 <?php if ($total_pages > 1) : ?>
277 <div class="yatra-listing-pagination">
278 <?php
279 $prev_page = max(1, $current_page - 1);
280 $next_page = min($total_pages, $current_page + 1);
281 ?>
282 <?php if ($current_page <= 1) : ?>
283 <span class="yatra-pagination-btn disabled" aria-disabled="true">
284 <?php echo yatra_svg_icon('chevron-left', 'yatra-btn-icon'); ?>
285 <span><?php esc_html_e('Previous', 'yatra'); ?></span>
286 </span>
287 <?php else : ?>
288 <a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_archive_listing_url($prev_page)); ?>">
289 <?php echo yatra_svg_icon('chevron-left', 'yatra-btn-icon'); ?>
290 <span><?php esc_html_e('Previous', 'yatra'); ?></span>
291 </a>
292 <?php endif; ?>
293 <?php
294 $range = 2;
295 for ($i = 1; $i <= $total_pages; $i++) :
296 if ($i == 1 || $i == $total_pages || ($i >= $current_page - $range && $i <= $current_page + $range)) :
297 if ($i === $current_page) :
298 ?>
299 <span class="yatra-pagination-btn active"><?php echo esc_html((string) $i); ?></span>
300 <?php
301 else :
302 ?>
303 <a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_archive_listing_url($i)); ?>"><?php echo esc_html((string) $i); ?></a>
304 <?php
305 endif;
306 elseif ($i == $current_page - $range - 1 || $i == $current_page + $range + 1) :
307 ?>
308 <span class="yatra-pagination-ellipsis">...</span>
309 <?php
310 endif;
311 endfor;
312 ?>
313 <?php if ($current_page >= $total_pages) : ?>
314 <span class="yatra-pagination-btn disabled" aria-disabled="true">
315 <span><?php esc_html_e('Next', 'yatra'); ?></span>
316 <?php echo yatra_svg_icon('chevron-right', 'yatra-btn-icon'); ?>
317 </span>
318 <?php else : ?>
319 <a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_archive_listing_url($next_page)); ?>">
320 <span><?php esc_html_e('Next', 'yatra'); ?></span>
321 <?php echo yatra_svg_icon('chevron-right', 'yatra-btn-icon'); ?>
322 </a>
323 <?php endif; ?>
324 </div>
325 <?php endif; ?>
326 </div>
327 </main>
328 </div>
329 </div>
330
331 <?php
332 yatra_get_footer();
333 ?>
334