PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.13
Yatra – Travel Booking & Tour Operator Software v3.0.13
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-category.php

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

344 lines 19.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Trip Category Listing Template
4 *
5 * Lists all published trip categories from the Yatra trip categories table
6 * using the TripCategoryService. 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 TripCategoryService from plugin namespace
18 if (!class_exists('Yatra\\Services\\TripCategoryService')) {
19 // If the service is not available for some reason, bail gracefully.
20 yatra_get_header();
21 echo '<p>' . esc_html__('Trip category service is not available.', 'yatra') . '</p>';
22 yatra_get_footer();
23 return;
24 }
25
26 $category_service = new \Yatra\Services\TripCategoryService();
27
28 // Fetch published categories with stats (including trips_count, avg_rating, starting_price)
29 $categories = $category_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($categories) && is_array($categories)) {
35 yatra_sort_archive_listing_stats_rows($categories, $sort);
36 }
37
38 $per_page = yatra_get_posts_per_page();
39 $current_page = yatra_get_archive_listing_paged();
40 $total_items = is_array($categories) ? count($categories) : 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_categories = $total_items > 0 ? array_slice($categories, $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 __('categories', '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-category-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-trip-category-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-category-header">
86 <div class="yatra-category-header-content">
87 <h1><?php esc_html_e('Trip Categories', 'yatra'); ?></h1>
88 <p class="yatra-archive-listing-lede"><?php esc_html_e('Browse trips by style or theme—adventure, family, luxury, and more. Open a category to find matching trips you can book.', '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 <!-- Category Grid -->
128 <div class="yatra-category-grid" id="category-grid">
129 <?php if (!empty($paged_categories)) : ?>
130 <?php foreach ($paged_categories as $category) : ?>
131 <?php
132 // Category is a stdClass from repository
133 $name = isset($category->name) ? $category->name : '';
134 $description = isset($category->description) ? $category->description : '';
135
136 // Resolve image/icon from the stored icon field when possible.
137 $image_url = '';
138 $icon_class = '';
139 if (!empty($category->icon)) {
140 $icon = maybe_unserialize($category->icon);
141
142 if (is_array($icon)) {
143 // Handle both newer format ['type' => 'icon', 'value' => 'footprint']
144 // and older format [0 => 'icon', 1 => 'footprint']
145 $type = $icon['type'] ?? $icon[0] ?? '';
146 $value = $icon['value'] ?? $icon[1] ?? '';
147
148 if ($type === 'image' && !empty($value)) {
149 if (is_numeric($value)) {
150 $maybe_url = wp_get_attachment_image_url((int) $value, 'large');
151 if (!empty($maybe_url)) {
152 $image_url = $maybe_url;
153 }
154 } elseif (is_string($value) && filter_var($value, FILTER_VALIDATE_URL)) {
155 $image_url = $value;
156 }
157 } elseif ($type === 'icon' && !empty($value) && is_string($value)) {
158 // Store icon name so yatra_svg_icon() can render the same SVG
159 // icon as used in the React admin (e.g. 'footprint').
160 $icon_class = $value;
161 } elseif (!empty($icon['url']) && filter_var($icon['url'], FILTER_VALIDATE_URL)) {
162 // Legacy format: ['url' => 'https://...']
163 $image_url = $icon['url'];
164 } elseif (!empty($icon['id'])) {
165 // Legacy format: ['id' => attachment_id]
166 $maybe_url = wp_get_attachment_image_url((int) $icon['id'], 'large');
167 if (!empty($maybe_url)) {
168 $image_url = $maybe_url;
169 }
170 }
171 } elseif (is_numeric($icon)) {
172 $maybe_url = wp_get_attachment_image_url((int) $icon, 'large');
173 if (!empty($maybe_url)) {
174 $image_url = $maybe_url;
175 }
176 } elseif (is_string($icon) && filter_var($icon, FILTER_VALIDATE_URL)) {
177 $image_url = $icon;
178 }
179 }
180
181 // Basic stats: only use real DB fields when present; do not fake numbers.
182 $has_avg_rating = isset($category->avg_rating) && (float) $category->avg_rating > 0;
183 $avg_rating = $has_avg_rating ? (float) $category->avg_rating : 0.0;
184
185 $has_trips_count = isset($category->trips_count) && (int) $category->trips_count > 0;
186 $trips_count = $has_trips_count ? (int) $category->trips_count : 0;
187
188 $starting_price_raw = isset($category->starting_price)
189 ? (float) $category->starting_price
190 : 0.0;
191 $has_starting_price = $starting_price_raw > 0;
192
193 // Apply dynamic pricing if module is enabled
194 if ($has_starting_price && apply_filters('yatra_dynamic_pricing_enabled', false)) {
195 $starting_price_raw = apply_filters('yatra_trip_display_price', $starting_price_raw, $category->id ?? 0, [
196 'departure_date' => null, // Generic display for category
197 'spots_remaining' => null,
198 ]);
199 }
200
201 // Use core helper to format price with correct currency symbol & settings.
202 $starting_price = $has_starting_price
203 ? yatra_format_price($starting_price_raw)
204 : '';
205
206 // Build permalink
207 $permalink = function_exists('yatra_get_category_permalink')
208 ? yatra_get_category_permalink($category->id ?? $category)
209 : '';
210 ?>
211 <div class="yatra-category-card">
212 <div class="yatra-category-image">
213 <?php if (!empty($image_url)) : ?>
214 <img src="<?php echo esc_url($image_url); ?>" alt="<?php echo esc_attr($name); ?>">
215 <?php elseif (!empty($icon_class)) : ?>
216 <div class="yatra-category-icon-wrapper" aria-hidden="true" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;">
217 <?php echo yatra_svg_icon($icon_class, 'yatra-category-icon'); ?>
218 </div>
219 <?php else : ?>
220 <?php
221 // Static placeholder image inside the plugin assets.
222 $placeholder_src = plugins_url('assets/images/placeholder.png', dirname(__FILE__));
223 ?>
224 <img src="<?php echo esc_url($placeholder_src); ?>" alt="<?php echo esc_attr__('Yatra placeholder', 'yatra'); ?>">
225 <?php endif; ?>
226 <div class="yatra-category-overlay">
227 <h3><?php echo esc_html($name); ?></h3>
228 </div>
229 </div>
230 <div class="yatra-category-content">
231 <?php if (!empty($description)) : ?>
232 <p class="yatra-archive-card-excerpt"><?php echo esc_html(wp_trim_words(wp_strip_all_tags((string) $description), 28)); ?></p>
233 <?php endif; ?>
234 <?php if ($has_avg_rating || $has_trips_count || $has_starting_price) : ?>
235 <div class="yatra-category-stats">
236 <?php if ($has_avg_rating) : ?>
237 <div class="yatra-category-stat">
238 <svg width="16" height="16" fill="#fbbf24" viewBox="0 0 24 24">
239 <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"/>
240 </svg>
241 <span><?php echo esc_html(number_format($avg_rating, 1)); ?></span>
242 </div>
243 <?php endif; ?>
244
245 <?php if ($has_trips_count) : ?>
246 <div class="yatra-category-stat">
247 <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
248 <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"/>
249 </svg>
250 <span><?php echo esc_html($trips_count); ?> <?php echo esc_html__('Trips', 'yatra'); ?></span>
251 </div>
252 <?php endif; ?>
253
254 <?php if ($has_starting_price) : ?>
255 <div class="yatra-category-stat">
256 <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
257 <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"/>
258 </svg>
259 <span><?php echo esc_html__('From ', 'yatra') . esc_html($starting_price); ?></span>
260 </div>
261 <?php endif; ?>
262 </div>
263 <?php endif; ?>
264 <?php if (!empty($permalink)) : ?>
265 <a class="yatra-btn yatra-btn-primary yatra-archive-card-cta" href="<?php echo esc_url($permalink); ?>">
266 <?php echo yatra_archive_listing_cta_icon_markup($icon_class, 'palette'); ?>
267 <span><?php echo esc_html__('Explore Category', 'yatra'); ?></span>
268 </a>
269 <?php else : ?>
270 <button type="button" class="yatra-btn yatra-btn-primary yatra-archive-card-cta" disabled>
271 <?php echo yatra_archive_listing_cta_icon_markup($icon_class, 'palette'); ?>
272 <span><?php echo esc_html__('Explore Category', 'yatra'); ?></span>
273 </button>
274 <?php endif; ?>
275 </div>
276 </div>
277 <?php endforeach; ?>
278 <?php else : ?>
279 <p class="yatra-no-categories">
280 <?php echo esc_html__('No categories found. Please add categories from the Yatra admin panel.', 'yatra'); ?>
281 </p>
282 <?php endif; ?>
283 </div>
284
285 <!-- Pagination -->
286 <?php if ($total_pages > 1) : ?>
287 <div class="yatra-listing-pagination">
288 <?php
289 $prev_page = max(1, $current_page - 1);
290 $next_page = min($total_pages, $current_page + 1);
291 ?>
292 <?php if ($current_page <= 1) : ?>
293 <span class="yatra-pagination-btn disabled" aria-disabled="true">
294 <?php echo yatra_svg_icon('chevron-left', 'yatra-btn-icon'); ?>
295 <span><?php esc_html_e('Previous', 'yatra'); ?></span>
296 </span>
297 <?php else : ?>
298 <a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_archive_listing_url($prev_page)); ?>">
299 <?php echo yatra_svg_icon('chevron-left', 'yatra-btn-icon'); ?>
300 <span><?php esc_html_e('Previous', 'yatra'); ?></span>
301 </a>
302 <?php endif; ?>
303 <?php
304 $range = 2;
305 for ($i = 1; $i <= $total_pages; $i++) :
306 if ($i == 1 || $i == $total_pages || ($i >= $current_page - $range && $i <= $current_page + $range)) :
307 if ($i === $current_page) :
308 ?>
309 <span class="yatra-pagination-btn active"><?php echo esc_html((string) $i); ?></span>
310 <?php
311 else :
312 ?>
313 <a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_archive_listing_url($i)); ?>"><?php echo esc_html((string) $i); ?></a>
314 <?php
315 endif;
316 elseif ($i == $current_page - $range - 1 || $i == $current_page + $range + 1) :
317 ?>
318 <span class="yatra-pagination-ellipsis">...</span>
319 <?php
320 endif;
321 endfor;
322 ?>
323 <?php if ($current_page >= $total_pages) : ?>
324 <span class="yatra-pagination-btn disabled" aria-disabled="true">
325 <span><?php esc_html_e('Next', 'yatra'); ?></span>
326 <?php echo yatra_svg_icon('chevron-right', 'yatra-btn-icon'); ?>
327 </span>
328 <?php else : ?>
329 <a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_archive_listing_url($next_page)); ?>">
330 <span><?php esc_html_e('Next', 'yatra'); ?></span>
331 <?php echo yatra_svg_icon('chevron-right', 'yatra-btn-icon'); ?>
332 </a>
333 <?php endif; ?>
334 </div>
335 <?php endif; ?>
336 </div>
337 </main>
338 </div>
339 </div>
340
341 <?php
342 yatra_get_footer();
343 ?>
344