PluginProbe
Yatra – Travel Booking & Tour Operator Software / trunk
Yatra – Travel Booking & Tour Operator Software vtrunk
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 / single-trip.php

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

196 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Single Trip Template - Clean Version
4 *
5 * Industry-standard trip single page design following Laravel patterns.
6 * Uses global $trip object (similar to WordPress $post).
7 * All data comes from SingleTripController - no business logic in template.
8 *
9 * @package Yatra
10 * @global object $trip Trip data object (set by AppServiceProvider)
11 */
12
13 // Prevent direct access
14 if (!defined('ABSPATH')) {
15 exit;
16 }
17
18 // Access global $trip object (similar to WordPress $post)
19 global $trip;
20
21 // Bail if no trip data - return proper 404
22 if (!$trip) {
23 global $wp_query;
24 $wp_query->set_404();
25 status_header(404);
26 get_template_part(404);
27 exit;
28 }
29
30 // Document title and meta tags are handled by Yatra\Managers\SEOManager (document_title + wp_head).
31
32 yatra_get_header();
33
34 // Calculate pricing data using helper functions
35 $pricing_data = yatra_single_trip_calculate_base_price($trip);
36 $base_price = $pricing_data['base_price'];
37 $has_availability = $pricing_data['has_availability'];
38 $has_traveler_pricing = $pricing_data['has_traveler_pricing'];
39 $pricing_type = $pricing_data['pricing_type'];
40
41 // Prepare variables for templates
42 $destinations = isset($trip->destinations) ? $trip->destinations : [];
43 $activities = isset($trip->activities) ? $trip->activities : [];
44 $trip_categories = isset($trip->trip_categories) ? $trip->trip_categories : [];
45
46 // Set up global itinerary gallery data for modal (simple URL array like hero)
47 global $yatra_itinerary_gallery_images;
48 $yatra_itinerary_gallery_images = [];
49 $itinerary_days = $trip->getItineraryDays();
50 if (!empty($itinerary_days)) {
51 foreach ($itinerary_days as $day) {
52 if (!empty($day['entries'])) {
53 foreach ($day['entries'] as $entry) {
54 // Add gallery images
55 if (!empty($entry['gallery']) && is_array($entry['gallery'])) {
56 foreach ($entry['gallery'] as $media) {
57 // Always use full-size URL for gallery popup
58 $yatra_itinerary_gallery_images[] = $media['url'] ?? '';
59 }
60 }
61 // Add video thumbnail
62 if (!empty($entry['video_url'])) {
63 $video_url = esc_url($entry['video_url']);
64 $video_id = '';
65 $thumbnail_url = '';
66
67 // Extract video ID and thumbnail
68 if (strpos($video_url, 'youtube.com') !== false || strpos($video_url, 'youtu.be') !== false) {
69 // YouTube thumbnail extraction
70 preg_match('/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/shorts\/|youtube\.com\/live\/)([^&\n?#\/]+)/', $video_url, $matches);
71 $video_id = $matches[1] ?? '';
72 $thumbnail_url = "https://img.youtube.com/vi/{$video_id}/maxresdefault.jpg";
73 } elseif (strpos($video_url, 'vimeo.com') !== false) {
74 // Vimeo thumbnail extraction
75 preg_match('#vimeo\.com\/.*?(\d+)#', $video_url, $matches);
76 $video_id = $matches[1] ?? '';
77 if ($video_id) {
78 // Get Vimeo thumbnail via oEmbed API
79 $oembed_url = "https://vimeo.com/api/oembed.json?url=" . urlencode($video_url);
80 $response = wp_remote_get($oembed_url);
81 if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
82 $body = wp_remote_retrieve_body($response);
83 $data = json_decode($body, true);
84 if ($data && isset($data['thumbnail_url'])) {
85 $thumbnail_url = $data['thumbnail_url'];
86 }
87 }
88
89 // Fallback if API fails
90 if (empty($thumbnail_url)) {
91 $thumbnail_url = 'https://i.vimeocdn.com/video/' . $video_id . '_640.jpg';
92 }
93 }
94 }
95
96 if ($thumbnail_url) {
97 $yatra_itinerary_gallery_images[] = $thumbnail_url;
98 }
99 }
100 }
101 }
102 }
103 }
104 ?>
105
106 <!-- Flatpickr CSS -->
107 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
108 <!-- Flatpickr JS -->
109 <script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
110
111 <!-- Trip pricing/availability for JS: merged in wp_localize_script (yatra-trip) so apiUrl/nonce/wishlist are not overwritten. -->
112 <script>
113 window.yatraVars = {
114 nonce: '<?php echo wp_create_nonce('wp_rest'); ?>'
115 };
116 </script>
117
118 <!-- Downloads JavaScript -->
119 <?php
120 $downloads = $trip->getDownloadableItems();
121 if (!empty($downloads)):
122 ?>
123 <script src="<?php echo esc_url(plugin_dir_url(dirname(__FILE__)) . 'assets/js/api-helper.js'); ?>"></script>
124 <script src="<?php echo esc_url(plugin_dir_url(dirname(__FILE__)) . 'assets/js/downloads-list.js'); ?>"></script>
125 <?php endif; ?>
126
127 <div class="yatra-single-trip">
128
129 <!-- Hero Section -->
130 <?php yatra_get_template('partials/single-trip/hero', ['trip' => $trip, 'base_price' => $base_price]); ?>
131
132 <!-- Category, Activity, Destination Tags -->
133 <?php if (!empty($trip_categories) || !empty($activities) || !empty($destinations)): ?>
134 <?php yatra_get_template('partials/single-trip/tags', ['trip' => $trip, 'trip_categories' => $trip_categories, 'activities' => $activities, 'destinations' => $destinations]); ?>
135 <?php endif; ?>
136
137 <!-- Quick Facts Bar -->
138 <?php yatra_get_template('partials/single-trip/quick-facts', ['trip' => $trip]); ?>
139
140 <!-- Trip Attributes -->
141 <?php
142 $attributes = $trip->getAttributes();
143 if (!empty($attributes)):
144 ?>
145 <?php yatra_get_template('partials/single-trip/trip-attributes', ['trip' => $trip]); ?>
146 <?php endif; ?>
147
148 <!-- Sticky Navigation Bar -->
149 <?php yatra_get_template('partials/single-trip/sticky-nav', ['trip' => $trip, 'base_price' => $base_price, 'has_availability' => $has_availability, 'has_traveler_pricing' => $has_traveler_pricing]); ?>
150
151 <!-- Hero Gallery Modal -->
152 <?php yatra_get_template('partials/single-trip/gallery-modal', ['trip' => $trip]); ?>
153
154 <!-- Itinerary Gallery Modal -->
155 <?php yatra_get_template('partials/single-trip/itinerary-gallery-modal', ['trip' => $trip]); ?>
156
157 <!-- Main Container -->
158 <div class="yatra-trip-container">
159 <!-- Main Content -->
160 <div class="yatra-trip-main">
161 <!-- Dynamic Frontend Tabs -->
162 <?php \Yatra\Controllers\SingleTripController::renderFrontendTabs($trip); ?>
163 </div>
164
165 <!-- Sidebar - Booking Card -->
166 <?php yatra_get_template('partials/single-trip/content-sidebar', ['trip' => $trip, 'has_availability' => $has_availability, 'has_traveler_pricing' => $has_traveler_pricing, 'base_price' => $base_price, 'pricing_type' => $pricing_type]); ?>
167 </div>
168
169 <!-- Reviews Section - Full Width (before similar trips for social proof) -->
170 <?php if (yatra_reviews_enabled()): ?>
171 <?php yatra_get_template('partials/single-trip/reviews', ['trip' => $trip]); ?>
172 <?php endif; ?>
173
174 <!-- Similar Trips Section -->
175 <?php
176 $similar_trips = $trip->getSimilarTrips();
177 if (!empty($similar_trips)):
178 ?>
179 <?php yatra_get_template('partials/single-trip/similar-trips', ['trip' => $trip]); ?>
180 <?php endif; ?>
181 </div>
182
183 <!-- Mobile Sticky Sidebar -->
184 <?php yatra_get_template('partials/single-trip/sticky-sidebar', [
185 'trip' => $trip,
186 'has_availability' => $has_availability,
187 'has_traveler_pricing' => $has_traveler_pricing,
188 'base_price' => $base_price,
189 'pricing_type' => $pricing_type
190 ]); ?>
191
192 <!-- Enquiry Modal -->
193 <?php yatra_get_template('partials/single-trip/enquiry-modal', ['trip' => $trip]); ?>
194
195 <?php yatra_get_footer(); ?>
196