| 1 |
<?php |
| 2 |
/** |
| 3 |
* Activity Listing Template |
| 4 |
* |
| 5 |
* Lists all published activities from the Yatra activities table |
| 6 |
* using the ActivityService. 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 ActivityService from plugin namespace |
| 18 |
if (!class_exists('Yatra\\Services\\ActivityService')) { |
| 19 |
// If the service is not available for some reason, bail gracefully. |
| 20 |
yatra_get_header(); |
| 21 |
echo '<p>' . esc_html__('Activity service is not available.', 'yatra') . '</p>'; |
| 22 |
yatra_get_footer(); |
| 23 |
return; |
| 24 |
} |
| 25 |
|
| 26 |
$activity_service = new \Yatra\Services\ActivityService(); |
| 27 |
|
| 28 |
// Fetch published activities with stats (including trips_count, avg_rating, starting_price) |
| 29 |
$activities = $activity_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($activities) && is_array($activities)) { |
| 35 |
yatra_sort_archive_listing_stats_rows($activities, $sort); |
| 36 |
} |
| 37 |
|
| 38 |
$per_page = yatra_get_posts_per_page(); |
| 39 |
$current_page = yatra_get_archive_listing_paged(); |
| 40 |
$total_items = is_array($activities) ? count($activities) : 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_activities = $total_items > 0 ? array_slice($activities, $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 |
__('activities', '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-activity-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-activity-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-activity-header"> |
| 86 |
<div class="yatra-activity-header-content"> |
| 87 |
<h1><?php esc_html_e('All Activities', 'yatra'); ?></h1> |
| 88 |
<p class="yatra-archive-listing-lede"><?php esc_html_e('Browse experiences (hiking, diving, sightseeing, and more). Open one to see trips built around that activity.', '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 |
<!-- Activity Grid --> |
| 128 |
<div class="yatra-activity-grid" id="activity-grid"> |
| 129 |
<?php |
| 130 |
if (!empty($paged_activities)) { |
| 131 |
foreach ($paged_activities as $activity) { |
| 132 |
// Activity is a stdClass from repository |
| 133 |
$name = isset($activity->name) ? $activity->name : ''; |
| 134 |
$description = isset($activity->description) ? $activity->description : ''; |
| 135 |
|
| 136 |
// Resolve image/icon from the stored icon field when possible. |
| 137 |
$image_url = ''; |
| 138 |
$icon_class = ''; |
| 139 |
if (!empty($activity->icon)) { |
| 140 |
$icon = maybe_unserialize($activity->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. 'camera'). |
| 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($activity->avg_rating) && (float) $activity->avg_rating > 0; |
| 183 |
$avg_rating = $has_avg_rating ? (float) $activity->avg_rating : 0.0; |
| 184 |
|
| 185 |
$has_trips_count = isset($activity->trips_count) && (int) $activity->trips_count > 0; |
| 186 |
$trips_count = $has_trips_count ? (int) $activity->trips_count : 0; |
| 187 |
|
| 188 |
$starting_price_raw = isset($activity->starting_price) |
| 189 |
? (float) $activity->starting_price |
| 190 |
: 0.0; |
| 191 |
$has_starting_price = $starting_price_raw > 0; |
| 192 |
|
| 193 |
// Use core helper to format price with correct currency symbol & settings. |
| 194 |
$starting_price = $has_starting_price |
| 195 |
? yatra_format_price($starting_price_raw) |
| 196 |
: ''; |
| 197 |
|
| 198 |
// Build permalink |
| 199 |
$permalink = function_exists('yatra_get_activity_permalink') |
| 200 |
? yatra_get_activity_permalink($activity->id ?? $activity) |
| 201 |
: ''; |
| 202 |
?> |
| 203 |
<div class="yatra-activity-card"> |
| 204 |
<div class="yatra-activity-image"> |
| 205 |
<?php if (!empty($image_url)) : ?> |
| 206 |
<img src="<?php echo esc_url($image_url); ?>" alt="<?php echo esc_attr($name); ?>"> |
| 207 |
<?php elseif (!empty($icon_class)) : ?> |
| 208 |
<div class="yatra-activity-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;"> |
| 209 |
<?php echo yatra_svg_icon($icon_class, 'yatra-activity-icon'); ?> |
| 210 |
</div> |
| 211 |
<?php else : ?> |
| 212 |
<?php |
| 213 |
// Use the placeholder image from plugin assets |
| 214 |
$placeholder_src = plugins_url('assets/images/placeholder.png', dirname(__FILE__)); |
| 215 |
?> |
| 216 |
<img src="<?php echo esc_url($placeholder_src); ?>" alt="<?php echo esc_attr__('Yatra placeholder', 'yatra'); ?>"> |
| 217 |
<?php endif; ?> |
| 218 |
</div> |
| 219 |
<div class="yatra-activity-content"> |
| 220 |
<h3><?php echo esc_html($name); ?></h3> |
| 221 |
<?php if (!empty($description)) : ?> |
| 222 |
<p class="yatra-archive-card-excerpt"><?php echo esc_html(wp_trim_words(wp_strip_all_tags((string) $description), 28)); ?></p> |
| 223 |
<?php endif; ?> |
| 224 |
<div class="yatra-activity-stats"> |
| 225 |
<?php if ($has_avg_rating) : ?> |
| 226 |
<div class="yatra-activity-stat"> |
| 227 |
<svg width="16" height="16" fill="#fbbf24" viewBox="0 0 24 24"> |
| 228 |
<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"/> |
| 229 |
</svg> |
| 230 |
<span><?php echo esc_html(number_format($avg_rating, 1)); ?></span> |
| 231 |
</div> |
| 232 |
<?php endif; ?> |
| 233 |
<?php if ($has_trips_count) : ?> |
| 234 |
<div class="yatra-activity-stat"> |
| 235 |
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| 236 |
<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"/> |
| 237 |
</svg> |
| 238 |
<span><?php echo esc_html($trips_count); ?> <?php esc_html_e('Trips', 'yatra'); ?></span> |
| 239 |
</div> |
| 240 |
<?php endif; ?> |
| 241 |
<?php if ($has_starting_price) : ?> |
| 242 |
<div class="yatra-activity-stat"> |
| 243 |
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| 244 |
<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"/> |
| 245 |
</svg> |
| 246 |
<span><?php esc_html_e('From', 'yatra'); ?> <?php echo esc_html($starting_price); ?></span> |
| 247 |
</div> |
| 248 |
<?php endif; ?> |
| 249 |
</div> |
| 250 |
<?php if (!empty($permalink)) : ?> |
| 251 |
<a class="yatra-btn yatra-btn-primary yatra-archive-card-cta" href="<?php echo esc_url($permalink); ?>"> |
| 252 |
<?php echo yatra_archive_listing_cta_icon_markup($icon_class, 'activity'); ?> |
| 253 |
<span><?php echo esc_html__('View Trips', 'yatra'); ?></span> |
| 254 |
</a> |
| 255 |
<?php endif; ?> |
| 256 |
</div> |
| 257 |
</div> |
| 258 |
<?php |
| 259 |
} |
| 260 |
} else { |
| 261 |
?> |
| 262 |
<div class="yatra-no-activities"> |
| 263 |
<p><?php esc_html_e('No activities found.', 'yatra'); ?></p> |
| 264 |
</div> |
| 265 |
<?php } ?> |
| 266 |
</div> |
| 267 |
|
| 268 |
<!-- Pagination --> |
| 269 |
<?php if ($total_pages > 1) : ?> |
| 270 |
<div class="yatra-listing-pagination"> |
| 271 |
<?php |
| 272 |
$prev_page = max(1, $current_page - 1); |
| 273 |
$next_page = min($total_pages, $current_page + 1); |
| 274 |
?> |
| 275 |
<?php if ($current_page <= 1) : ?> |
| 276 |
<span class="yatra-pagination-btn disabled" aria-disabled="true"> |
| 277 |
<?php echo yatra_svg_icon('chevron-left', 'yatra-btn-icon'); ?> |
| 278 |
<span><?php esc_html_e('Previous', 'yatra'); ?></span> |
| 279 |
</span> |
| 280 |
<?php else : ?> |
| 281 |
<a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_archive_listing_url($prev_page)); ?>"> |
| 282 |
<?php echo yatra_svg_icon('chevron-left', 'yatra-btn-icon'); ?> |
| 283 |
<span><?php esc_html_e('Previous', 'yatra'); ?></span> |
| 284 |
</a> |
| 285 |
<?php endif; ?> |
| 286 |
<?php |
| 287 |
$range = 2; |
| 288 |
for ($i = 1; $i <= $total_pages; $i++) : |
| 289 |
if ($i == 1 || $i == $total_pages || ($i >= $current_page - $range && $i <= $current_page + $range)) : |
| 290 |
if ($i === $current_page) : |
| 291 |
?> |
| 292 |
<span class="yatra-pagination-btn active"><?php echo esc_html((string) $i); ?></span> |
| 293 |
<?php |
| 294 |
else : |
| 295 |
?> |
| 296 |
<a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_archive_listing_url($i)); ?>"><?php echo esc_html((string) $i); ?></a> |
| 297 |
<?php |
| 298 |
endif; |
| 299 |
elseif ($i == $current_page - $range - 1 || $i == $current_page + $range + 1) : |
| 300 |
?> |
| 301 |
<span class="yatra-pagination-ellipsis">...</span> |
| 302 |
<?php |
| 303 |
endif; |
| 304 |
endfor; |
| 305 |
?> |
| 306 |
<?php if ($current_page >= $total_pages) : ?> |
| 307 |
<span class="yatra-pagination-btn disabled" aria-disabled="true"> |
| 308 |
<span><?php esc_html_e('Next', 'yatra'); ?></span> |
| 309 |
<?php echo yatra_svg_icon('chevron-right', 'yatra-btn-icon'); ?> |
| 310 |
</span> |
| 311 |
<?php else : ?> |
| 312 |
<a class="yatra-pagination-btn" href="<?php echo esc_url(yatra_build_archive_listing_url($next_page)); ?>"> |
| 313 |
<span><?php esc_html_e('Next', 'yatra'); ?></span> |
| 314 |
<?php echo yatra_svg_icon('chevron-right', 'yatra-btn-icon'); ?> |
| 315 |
</a> |
| 316 |
<?php endif; ?> |
| 317 |
</div> |
| 318 |
<?php endif; ?> |
| 319 |
</div> |
| 320 |
</main> |
| 321 |
</div> |
| 322 |
</div> |
| 323 |
|
| 324 |
<?php yatra_get_footer(); ?> |
| 325 |
|