PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.7
Yatra – Travel Booking & Tour Operator Software v3.0.2.7
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 / partials / booking-content.php

booking-content.php in Yatra – Travel Booking & Tour Operator Software 3.0.2.7, at templates/partials/booking-content.php

745 lines 47.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Booking Content Partial
4 *
5 * Main booking form and sidebar content - used by both:
6 * - booking.php (with header/footer)
7 * - shortcode (without header/footer)
8 *
9 * @package Yatra
10 *
11 * Expected variables from parent:
12 * - $booking (global object)
13 * - $trip
14 * - $travel_date
15 * - $total_travelers
16 * - $deposit_required
17 * - $deposit_percentage
18 * - $partial_payment
19 * - $partial_payment_percentage
20 * - $enabled_gateways
21 * - $is_remaining_payment
22 * - $remaining_amount
23 * - $existing_booking_id
24 * - $booking_reference
25 */
26
27 if (!defined('ABSPATH')) {
28 exit;
29 }
30
31 // Prepare variables for form fields partial
32 $trip_id = $trip->id;
33 $trip_slug = $trip->slug ?? '';
34 $is_remaining_payment = !empty($booking->is_remaining_payment);
35 $remaining_amount = isset($booking->remaining_amount) ? (float) $booking->remaining_amount : null;
36 $existing_booking_id = $booking->existing_booking_id ?? 0;
37 $booking_reference = $booking->booking_reference ?? '';
38 $amount_paid = isset($booking->amount_paid) ? (float) $booking->amount_paid : null;
39 $total_amount = isset($booking->total_amount) ? (float) $booking->total_amount : null;
40
41 // Check if login is required
42 $require_login = \Yatra\Services\SettingsService::get('require_login', false);
43 $allow_guest_checkout = \Yatra\Services\SettingsService::get('allow_guest_checkout', true);
44 $needs_authentication = !is_user_logged_in() && ($require_login || !$allow_guest_checkout);
45
46 // Get group discount from booking object (calculated in AppServiceProvider)
47 $group_discount = $booking->group_discount ?? null;
48 $group_discount_amount = $group_discount['amount'] ?? 0;
49 $group_discount_code = $group_discount['code'] ?? null;
50 $group_discount_label = $group_discount['label'] ?? __('Group Discount', 'yatra');
51
52 // Get pre-calculated pricing from booking object (calculated in BookingPageHandler)
53 $pricing_calculation = $booking->pricing_calculation ?? [
54 'base_amount' => 0,
55 'gross_total' => 0,
56 'final_total' => 0,
57 'amount_due' => 0,
58 'tax_calculation' => ['tax_breakdown' => [], 'total_tax_amount' => 0],
59 ];
60
61 $tax_calculation = $pricing_calculation['tax_calculation'] ?? ['tax_breakdown' => [], 'total_tax_amount' => 0];
62
63 // Use pre-calculated amounts
64 $summary_total_amount = $is_remaining_payment && !empty($total_amount)
65 ? (float) $total_amount
66 : ($pricing_calculation['final_total'] ?? 0);
67 $summary_due_amount = $is_remaining_payment && $remaining_amount !== null
68 ? (float) $remaining_amount
69 : ($pricing_calculation['amount_due'] ?? $pricing_calculation['final_total'] ?? 0);
70 ?>
71
72 <div class="yatra-booking-page">
73 <div class="yatra-booking-container">
74 <div class="yatra-booking-layout">
75 <!-- Left Side: Auth Form or Booking Form -->
76 <div class="yatra-booking-main">
77 <?php if ($needs_authentication) : ?>
78 <!-- Show Login/Registration Form -->
79 <div class="yatra-booking-header">
80 <h1><?php esc_html_e('Login Required', 'yatra'); ?></h1>
81 <p class="yatra-booking-subtitle"><?php esc_html_e('Please login or create an account to continue with your booking', 'yatra'); ?></p>
82 </div>
83
84 <?php
85 // Include the authentication form partial
86 include YATRA_PLUGIN_PATH . 'templates/partials/booking-auth.php';
87 ?>
88 <?php else : ?>
89 <!-- Show Booking Form -->
90 <div class="yatra-booking-header">
91 <h1>
92 <?php
93 if (!empty($booking->is_remaining_payment)) {
94 esc_html_e('Pay Remaining Balance', 'yatra');
95 } else {
96 esc_html_e('Complete Your Booking', 'yatra');
97 }
98 ?>
99 </h1>
100 <p class="yatra-booking-subtitle">
101 <?php
102 $reference_label = $booking_reference ? '#' . $booking_reference : '';
103
104 if ($is_remaining_payment) {
105 echo esc_html(
106 sprintf(
107 /* translators: %s booking reference */
108 __('You are paying the remaining balance for Booking %s.', 'yatra'),
109 $reference_label ?: __('(unknown reference)', 'yatra')
110 )
111 );
112 } else {
113 esc_html_e('Please fill in your details to complete the booking', 'yatra');
114 }
115 ?>
116 </p>
117 <?php if ($is_remaining_payment && !empty($remaining_amount)) : ?>
118 <div class="yatra-remaining-banner">
119 <strong><?php esc_html_e('Amount Due Now', 'yatra'); ?>:</strong>
120 <span><?php echo esc_html(yatra_format_price((float) $remaining_amount, null, false)); ?></span>
121 <?php if ($amount_paid !== null) : ?>
122 <small>
123 <?php
124 printf(
125 /* translators: %s formatted amount */
126 esc_html__('Amount already paid: %s', 'yatra'),
127 yatra_format_price((float) $amount_paid, null, false)
128 );
129 ?>
130 </small>
131 <?php endif; ?>
132 </div>
133 <?php endif; ?>
134 </div>
135
136 <!-- Booking Form -->
137 <form
138 class="yatra-booking-form"
139 id="yatra-booking-form"
140 data-payment-due="<?php echo esc_attr($summary_due_amount); ?>"
141 data-is-remaining-payment="<?php echo esc_attr($is_remaining_payment ? 'yes' : 'no'); ?>"
142 >
143 <?php
144 // Pass pricing type info to form fields partial
145 // Prefer booking pricing data, fallback to trip definition
146 $pricing_type = !empty($booking->pricing_type) ? $booking->pricing_type : ($trip->pricing_type ?? 'regular');
147 $price_types = !empty($booking->price_types) ? $booking->price_types : ($trip->price_types ?? []);
148 if (empty($pricing_type) && !empty($price_types)) {
149 $pricing_type = 'traveler_based';
150 }
151 if ($pricing_type === 'regular' && !empty($price_types)) {
152 // Infer traveler-based if price types are present but flag not set
153 $pricing_type = 'traveler_based';
154 }
155 // Ensure price_types is always the trip's price_types if booking lacks it
156 if (empty($price_types) && !empty($trip->price_types)) {
157 $price_types = $trip->price_types;
158 $pricing_type = 'traveler_based';
159 }
160 $traveler_counts = $booking->traveler_counts ?? [];
161
162 // Include shared booking form fields
163 include YATRA_PLUGIN_PATH . 'templates/partials/booking-form-fields.php';
164 ?>
165
166 <!-- Submit Button -->
167 <div class="yatra-booking-actions">
168 <button type="submit" class="yatra-booking-pay-btn" id="yatra-submit-booking">
169 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="CurrentColor" stroke-width="2">
170 <rect x="1" y="4" width="22" height="16" rx="2" ry="2"></rect>
171 <line x1="1" y1="10" x2="23" y2="10"></line>
172 </svg>
173 <span id="pay-button-text"><?php esc_html_e('Complete Booking', 'yatra'); ?></span>
174 <span id="pay-amount"><?php echo esc_html(yatra_format_price((float) ($summary_due_amount ?? 0), null, false)); ?></span>
175 </button>
176 <a href="<?php echo esc_url(home_url('/trip/' . $trip->slug)); ?>" class="yatra-booking-cancel-btn">
177 <?php esc_html_e('Cancel', 'yatra'); ?>
178 </a>
179 </div>
180 <div class="yatra-booking-form-errors" id="yatra-booking-form-errors" aria-live="polite"></div>
181
182 <input type="hidden" name="trip_price" value="<?php echo esc_attr($trip->price); ?>">
183 <input type="hidden" name="currency" value="<?php echo esc_attr(\Yatra\Services\SettingsService::getCurrency()); ?>">
184 <?php wp_nonce_field('yatra_booking_nonce', 'yatra_booking_nonce'); ?>
185 </form>
186 <?php endif; ?>
187 </div>
188
189 <!-- Right Side: Booking Summary -->
190 <div class="yatra-booking-sidebar">
191
192 <?php if ($is_remaining_payment) : ?>
193 <!-- Simplified Remaining Payment Sidebar -->
194 <div class="yatra-booking-summary yatra-remaining-summary" data-summary-total="<?php echo esc_attr($summary_total_amount); ?>" data-summary-due="<?php echo esc_attr($summary_due_amount); ?>" data-is-remaining="yes">
195 <h3><?php esc_html_e('Payment Summary', 'yatra'); ?></h3>
196
197 <!-- Booking Reference -->
198 <div class="yatra-remaining-reference">
199 <div class="yatra-reference-badge">
200 <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
201 <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
202 <polyline points="14 2 14 8 20 8"></polyline>
203 <line x1="16" y1="13" x2="8" y2="13"></line>
204 <line x1="16" y1="17" x2="8" y2="17"></line>
205 </svg>
206 <span><?php esc_html_e('Booking Reference', 'yatra'); ?></span>
207 </div>
208 <strong class="yatra-reference-value">#<?php echo esc_html($booking_reference); ?></strong>
209 </div>
210
211 <!-- Trip Info Card -->
212 <div class="yatra-remaining-trip-card">
213 <div class="yatra-remaining-trip-image">
214 <img src="<?php echo esc_url($trip->featured_image ?? ''); ?>" alt="<?php echo esc_attr($trip->title ?? ''); ?>">
215 </div>
216 <div class="yatra-remaining-trip-info">
217 <h4><?php echo esc_html($trip->title); ?></h4>
218 <div class="yatra-remaining-trip-meta">
219 <span>
220 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
221 <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
222 <line x1="16" y1="2" x2="16" y2="6"></line>
223 <line x1="8" y1="2" x2="8" y2="6"></line>
224 <line x1="3" y1="10" x2="21" y2="10"></line>
225 </svg>
226 <?php echo esc_html(date_i18n(get_option('date_format'), strtotime($travel_date))); ?>
227 </span>
228 <span>
229 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
230 <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
231 <circle cx="9" cy="7" r="4"></circle>
232 </svg>
233 <?php echo esc_html($total_travelers . ' ' . _n('traveler', 'travelers', $total_travelers, 'yatra')); ?>
234 </span>
235 </div>
236 </div>
237 </div>
238
239 <!-- Payment Breakdown -->
240 <div class="yatra-remaining-breakdown">
241 <div class="yatra-remaining-row">
242 <span><?php esc_html_e('Original Booking Total', 'yatra'); ?></span>
243 <span><?php echo esc_html(yatra_format_price((float) ($total_amount ?? 0), null, false)); ?></span>
244 </div>
245 <div class="yatra-remaining-row yatra-remaining-paid">
246 <span>
247 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
248 <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
249 <polyline points="22 4 12 14.01 9 11.01"></polyline>
250 </svg>
251 <?php esc_html_e('Amount Already Paid', 'yatra'); ?>
252 </span>
253 <span class="yatra-paid-amount"><?php echo esc_html(yatra_format_price((float) ($amount_paid ?? 0), null, false)); ?></span>
254 </div>
255 <div class="yatra-remaining-row yatra-remaining-due">
256 <span><strong><?php esc_html_e('Remaining Balance', 'yatra'); ?></strong></span>
257 <span class="yatra-due-amount"><strong><?php echo esc_html(yatra_format_price((float) ($remaining_amount ?? 0), null, false)); ?></strong></span>
258 </div>
259 </div>
260
261 <!-- Due Now Highlight -->
262 <div class="yatra-remaining-due-now">
263 <div class="yatra-due-now-label">
264 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
265 <rect x="1" y="4" width="22" height="16" rx="2" ry="2"></rect>
266 <line x1="1" y1="10" x2="23" y2="10"></line>
267 </svg>
268 <?php esc_html_e('Amount Due Now', 'yatra'); ?>
269 </div>
270 <div class="yatra-due-now-amount" id="summary-due">
271 <?php echo esc_html(yatra_format_price((float) ($remaining_amount ?? 0), null, false)); ?>
272 </div>
273 </div>
274
275 <!-- Secure Payment Badge -->
276 <div class="yatra-remaining-secure">
277 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
278 <rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
279 <path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
280 </svg>
281 <span><?php esc_html_e('Secure SSL encrypted payment', 'yatra'); ?></span>
282 </div>
283 </div>
284 <?php else : ?>
285 <!-- Regular Booking Summary -->
286 <div class="yatra-booking-summary" data-summary-total="<?php echo esc_attr($summary_total_amount); ?>" data-summary-due="<?php echo esc_attr($summary_due_amount); ?>" data-is-remaining="no">
287 <h3><?php esc_html_e('Booking Summary', 'yatra'); ?></h3>
288
289 <!-- Travel Details -->
290 <div class="yatra-summary-travel-details">
291 <?php
292 $departure_time = $booking->departure_time ?? '';
293 $is_day_trip = $booking->is_day_trip ?? false;
294 $pricing_type = $booking->pricing_type ?? 'regular';
295 $price_types = $booking->price_types ?? [];
296 $traveler_counts = $booking->traveler_counts ?? [];
297 ?>
298
299 <div class="yatra-summary-form-group">
300 <label for="travel-date"><?php esc_html_e('Travel Date', 'yatra'); ?></label>
301 <div class="yatra-summary-readonly-field">
302 <?php if ($is_day_trip && !empty($departure_time)): ?>
303 <span class="yatra-date-display"><?php echo esc_html(\Yatra\Helpers\FormatHelper::formatDate((string) $travel_date)); ?></span>
304 <span class="yatra-time-display"><?php echo esc_html(\Yatra\Helpers\FormatHelper::formatTimeForDisplay($departure_time)); ?></span>
305 <?php else: ?>
306 <?php echo esc_html(\Yatra\Helpers\FormatHelper::formatDate((string) $travel_date)); ?>
307 <?php endif; ?>
308 </div>
309 <input type="hidden" id="travel-date" name="travel_date" form="yatra-booking-form" value="<?php echo esc_attr($travel_date); ?>">
310 <?php if (!empty($departure_time)): ?>
311 <input type="hidden" name="departure_time" form="yatra-booking-form" value="<?php echo esc_attr($departure_time); ?>">
312 <?php endif; ?>
313 </div>
314
315 <?php if (!empty($trip->price_types) || (!empty($price_types) && $pricing_type === 'traveler_based')): ?>
316 <!-- Traveler-based pricing: use shared traveler selector partial -->
317 <div class="yatra-summary-form-group yatra-traveler-categories">
318 <label><?php esc_html_e('Travelers', 'yatra'); ?></label>
319 <?php
320 $traveler_rows = [];
321 foreach ($price_types as $index => $pt) {
322 $pt = (object) $pt;
323 $category_id = $pt->category_id ?? $index;
324 $category_label = $pt->category_label ?? __('Traveler', 'yatra');
325 $count = isset($traveler_counts[$category_id]) ? (int) $traveler_counts[$category_id] : ($index === 0 ? 1 : 0);
326 $category_price = isset($pt->effective_price) ? (float) $pt->effective_price : ($pt->sale_price ?? $pt->discounted_price ?? $pt->original_price ?? 0);
327 $pricing_mode = (!empty($pt->pricing_mode) && $pt->pricing_mode === 'per_group') ? 'per_group' : 'per_person';
328 $age_info = '';
329 if (isset($pt->age_min) || isset($pt->age_max)) {
330 if (isset($pt->age_min) && isset($pt->age_max)) {
331 $age_info = sprintf(__('(Age %d-%d)', 'yatra'), $pt->age_min, $pt->age_max);
332 } elseif (isset($pt->age_min)) {
333 $age_info = sprintf(__('(Age %d+)', 'yatra'), $pt->age_min);
334 } else {
335 $age_info = sprintf(__('(Up to age %d)', 'yatra'), $pt->age_max);
336 }
337 }
338 $input_id = 'traveler_' . $category_id;
339 $traveler_rows[] = [
340 'label' => $category_label,
341 'subtitle' => $age_info,
342 'price_html' => $category_price > 0 ? '<span class="yatra-quantity-price">' . yatra_format_price($category_price) . '</span>' : '',
343 'row_attrs' => [
344 'data-category-id' => $category_id,
345 'data-price' => $category_price,
346 'data-pricing-mode' => $pricing_mode,
347 ],
348 'minus_disabled' => ($index !== 0 && $count <= 0),
349 'plus_disabled' => false,
350 'minus_attrs' => [
351 'data-target' => $input_id,
352 'aria-label' => sprintf(__('Decrease %s', 'yatra'), $category_label),
353 ],
354 'plus_attrs' => [
355 'data-target' => $input_id,
356 'aria-label' => sprintf(__('Increase %s', 'yatra'), $category_label),
357 ],
358 'input_attrs' => [
359 'id' => $input_id,
360 'name' => 'travelers[' . $category_id . ']',
361 'value' => $count,
362 'min' => 0,
363 'max' => $trip->max_travelers ?: 20,
364 'data-category-label' => $category_label,
365 'data-price' => $category_price,
366 'data-pricing-mode' => $pricing_mode,
367 ],
368 ];
369 }
370 $traveler_display_text = !empty($traveler_rows) ? ($traveler_rows[0]['label'] . ' x ' . max(1, (int) $traveler_rows[0]['input_attrs']['value'])) : __('Traveler x 1', 'yatra');
371 $root_id = '';
372 $root_class = 'yatra-booking-field-select yatra-participants-select';
373 $container_attrs = [];
374 $display_id = 'participants-display';
375 $display_class = 'yatra-participants-display';
376 $display_attrs = [];
377 $dropdown_id = 'quantity-selector';
378 $dropdown_class = 'yatra-booking-quantity-selector';
379 $dropdown_attrs = [];
380 $icon_html = yatra_svg_icon('users', 'yatra-icon-sm');
381 $rows = $traveler_rows;
382 include YATRA_PLUGIN_PATH . 'templates/partials/traveler-selector.php';
383 ?>
384 </div>
385 <?php else: ?>
386 <!-- Regular pricing: Read-only display -->
387 <div class="yatra-summary-form-group">
388 <label for="number-of-travelers"><?php esc_html_e('Travelers', 'yatra'); ?></label>
389 <div class="yatra-summary-readonly-field">
390 <?php echo esc_html($total_travelers . ' ' . _n('traveler', 'travelers', $total_travelers, 'yatra')); ?>
391 </div>
392 <input type="hidden" id="number-of-travelers" name="number_of_travelers" form="yatra-booking-form" value="<?php echo esc_attr($total_travelers); ?>">
393 </div>
394 <?php endif; ?>
395 </div>
396
397 <!-- Trip Info -->
398 <div class="yatra-summary-trip">
399 <?php $trip_permalink = function_exists('yatra_get_trip_permalink') ? yatra_get_trip_permalink($trip) : ''; ?>
400 <div class="yatra-summary-image">
401 <?php if (!empty($trip_permalink)) : ?>
402 <a href="<?php echo esc_url($trip_permalink ?? ''); ?>">
403 <?php endif; ?>
404 <img src="<?php echo esc_url($trip->featured_image ?? ''); ?>" alt="<?php echo esc_attr($trip->title ?? ''); ?>">
405 <?php if (!empty($trip_permalink)) : ?>
406 </a>
407 <?php endif; ?>
408 </div>
409 <div class="yatra-summary-details">
410 <?php if (!empty($trip_permalink)) : ?>
411 <h4><a href="<?php echo esc_url($trip_permalink ?? ''); ?>"><?php echo esc_html($trip->title ?? ''); ?></a></h4>
412 <?php else : ?>
413 <h4><?php echo esc_html($trip->title); ?></h4>
414 <?php endif; ?>
415 <div class="yatra-summary-meta">
416 <?php
417 $duration_days = (int) ($trip->duration_days ?? 0);
418 $duration_nights = isset($trip->duration_nights) ? (int) $trip->duration_nights : null;
419 ?>
420 <?php if ($duration_days > 0) : ?>
421 <?php if ($duration_days <= 1) : ?>
422 <span><?php esc_html_e('Day Trip', 'yatra'); ?></span>
423 <?php else : ?>
424 <span><?php echo esc_html(yatra_format_duration($duration_days, $duration_nights)); ?></span>
425 <?php endif; ?>
426 <?php endif; ?>
427 <?php if (!empty($trip->difficulty_level)) : ?>
428 <span>•</span>
429 <span><?php echo esc_html(ucfirst($trip->difficulty_level)); ?></span>
430 <?php endif; ?>
431 </div>
432 </div>
433 </div>
434
435
436 <!-- Trip Attributes -->
437 <?php if (!empty($trip->attributes)): ?>
438 <div class="yatra-booking-attributes">
439 <h5><?php esc_html_e('Trip Features', 'yatra'); ?></h5>
440 <div class="yatra-booking-attributes-list">
441 <?php foreach ($trip->attributes as $attribute): ?>
442 <div class="yatra-booking-attribute-item">
443 <div class="yatra-booking-attribute-name">
444 <?php echo esc_html($attribute['name']); ?>
445 </div>
446 <div class="yatra-booking-attribute-value">
447 <?php
448 // Display value based on field type (simplified for booking sidebar)
449 switch ($attribute['field_type']) {
450 case 'checkbox':
451 $cb_val = $attribute['value'] ?? null;
452 $cb_options = json_decode($attribute['field_options'] ?? '[]', true);
453 if (!is_array($cb_options)) {
454 $cb_options = [];
455 }
456 if (is_array($cb_val)) {
457 $labels = [];
458 foreach ($cb_options as $opt) {
459 if (!isset($opt['value'], $opt['label'])) {
460 continue;
461 }
462 foreach ($cb_val as $v) {
463 if ((string) $v === (string) $opt['value']) {
464 $labels[] = $opt['label'];
465 break;
466 }
467 }
468 }
469 echo esc_html($labels !== [] ? implode(', ', $labels) : '—');
470 } else {
471 echo $cb_val ? esc_html__('Yes', 'yatra') : esc_html__('No', 'yatra');
472 }
473 break;
474 case 'select':
475 case 'radio':
476 $options = json_decode($attribute['field_options'] ?? '[]', true);
477 if (!is_array($options)) {
478 $options = [];
479 }
480 $selected_value = is_array($attribute['value']) ? ($attribute['value'][0] ?? null) : ($attribute['value'] ?? null);
481 $matched_label = null;
482 foreach ($options as $option) {
483 if (!is_array($option) || !isset($option['value'], $option['label'])) {
484 continue;
485 }
486 if ((string) $option['value'] === (string) $selected_value) {
487 $matched_label = (string) $option['label'];
488 break;
489 }
490 }
491 if ($matched_label !== null) {
492 echo esc_html($matched_label);
493 } elseif ($selected_value !== null && $selected_value !== '') {
494 echo esc_html((string) $selected_value);
495 } else {
496 echo esc_html('—');
497 }
498 break;
499 case 'date':
500 echo esc_html(date_i18n(get_option('date_format'), strtotime($attribute['value'])));
501 break;
502 case 'color':
503 echo '<span class="yatra-booking-color-swatch" style="background-color: ' . esc_attr($attribute['value']) . ';" title="' . esc_attr($attribute['value']) . '"></span>';
504 break;
505 case 'textarea':
506 // Truncate long text for sidebar
507 $text = wp_strip_all_tags($attribute['value']);
508 echo esc_html(substr($text, 0, 25) . (strlen($text) > 25 ? '...' : ''));
509 break;
510 case 'number':
511 echo esc_html(number_format($attribute['value'], 0));
512 break;
513 default:
514 // Truncate long text for sidebar
515 echo esc_html(substr($attribute['value'], 0, 20) . (strlen($attribute['value']) > 20 ? '...' : ''));
516 break;
517 }
518 ?>
519 </div>
520 </div>
521 <?php endforeach; ?>
522 </div>
523 </div>
524 <?php endif; ?>
525
526 <!-- Coupon Code Section -->
527 <div class="yatra-coupon-section">
528 <div class="yatra-coupon-toggle">
529 <button type="button" id="yatra-coupon-toggle-btn" class="yatra-coupon-toggle-btn">
530 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
531 <path d="M20 12v6a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-6"></path>
532 <path d="M12 2v10"></path>
533 <path d="m4.93 10.93 1.41 1.41"></path>
534 <path d="m17.66 10.93-1.41 1.41"></path>
535 <circle cx="12" cy="2" r="2"></circle>
536 </svg>
537 <?php esc_html_e('Have a coupon code?', 'yatra'); ?>
538 <svg class="yatra-coupon-chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
539 <polyline points="6 9 12 15 18 9"></polyline>
540 </svg>
541 </button>
542 </div>
543 <div class="yatra-coupon-form" id="yatra-coupon-form" style="display: none;">
544 <div class="yatra-coupon-input-group">
545 <input type="text" id="yatra-coupon-code" name="coupon_code" placeholder="<?php esc_attr_e('Enter coupon code', 'yatra'); ?>" class="yatra-coupon-input" autocomplete="off">
546 <button type="button" id="yatra-apply-coupon" class="yatra-apply-coupon-btn">
547 <?php esc_html_e('Apply', 'yatra'); ?>
548 </button>
549 </div>
550 <div id="yatra-coupon-message" class="yatra-coupon-message" style="display: none;"></div>
551 </div>
552 <!-- Applied Coupon Display -->
553 <div class="yatra-applied-coupon" id="yatra-applied-coupon" style="display: none;">
554 <div class="yatra-applied-coupon-info">
555 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
556 <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
557 <polyline points="22 4 12 14.01 9 11.01"></polyline>
558 </svg>
559 <span class="yatra-coupon-code-display"></span>
560 <span class="yatra-coupon-discount"></span>
561 </div>
562 <button type="button" id="yatra-remove-coupon" class="yatra-remove-coupon-btn" title="<?php esc_attr_e('Remove coupon', 'yatra'); ?>">
563 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
564 <line x1="18" y1="6" x2="6" y2="18"></line>
565 <line x1="6" y1="6" x2="18" y2="18"></line>
566 </svg>
567 </button>
568 </div>
569 </div>
570
571 <!-- Additional Services Section (Premium Feature) -->
572 <?php
573 /**
574 * Filter: Get additional services for this trip
575 * Allows premium modules to add extra services to the booking
576 */
577 $additional_services = apply_filters('yatra_booking_additional_services', [], $trip_id, $total_travelers, $traveler_counts ?? [], $travel_date);
578
579 // Get selected services from session (set from popup)
580 $session = yatra_get_booking_session();
581 $selected_service_ids = isset($session['additional_services']) && is_array($session['additional_services'])
582 ? array_map('intval', $session['additional_services'])
583 : [];
584
585 if (!empty($additional_services)) :
586 ?>
587 <div class="yatra-additional-services-section">
588 <div class="yatra-services-header">
589 <h4><?php esc_html_e('Additional Services', 'yatra'); ?></h4>
590 <p class="yatra-services-subtitle"><?php esc_html_e('Enhance your trip with these optional add-ons', 'yatra'); ?></p>
591 </div>
592 <div class="yatra-services-list" id="yatra-additional-services">
593 <?php foreach ($additional_services as $service) :
594 $service_id = (int) $service['id'];
595 $service_name = $service['name'];
596 $service_description = $service['description'] ?? '';
597 $service_price = (float) $service['price'];
598 $service_price_per = $service['price_per'] ?? 'person';
599 $service_image = $service['image_url'] ?? '';
600 // Check is_required - handle various formats (bool, string "1", int 1)
601 $is_required = isset($service['is_required']) && ($service['is_required'] === true || $service['is_required'] === 1 || $service['is_required'] === '1');
602 $is_included = isset($service['is_included']) && ($service['is_included'] === true || $service['is_included'] === 1 || $service['is_included'] === '1');
603 $is_selected = in_array($service_id, $selected_service_ids, false);
604
605 $price_label = yatra_format_price($service_price);
606 if ($service_price_per === 'person') {
607 $price_label .= ' ' . __('per person', 'yatra');
608 } elseif ($service_price_per === 'day') {
609 $price_label .= ' ' . __('per day', 'yatra');
610 } else {
611 $price_label .= ' ' . __('per booking', 'yatra');
612 }
613 if ($is_included) {
614 $price_label = __('Included', 'yatra');
615 }
616
617 // Determine checked and disabled states
618 $is_checked = $is_required || $is_included || $is_selected;
619 $is_disabled = $is_required || $is_included;
620 ?>
621 <div class="yatra-service-item <?php echo $is_required ? 'yatra-service-required' : ''; ?> <?php echo $is_checked ? 'yatra-service-selected' : ''; ?>"
622 data-service-id="<?php echo esc_attr($service_id); ?>"
623 data-service-price="<?php echo esc_attr($service_price); ?>"
624 data-service-price-per="<?php echo esc_attr($service_price_per); ?>"
625 data-is-required="<?php echo $is_required ? '1' : '0'; ?>">
626 <label class="yatra-service-label">
627 <input type="checkbox"
628 name="additional_services[]"
629 value="<?php echo esc_attr($service_id); ?>"
630 <?php echo $is_checked ? 'checked' : ''; ?>
631 <?php echo $is_disabled ? 'disabled' : ''; ?>
632 form="yatra-booking-form">
633 <div class="yatra-service-info">
634 <span class="yatra-service-name"><?php echo esc_html($service_name); ?></span>
635 <?php if ($service_description) : ?>
636 <span class="yatra-service-description"><?php echo esc_html($service_description); ?></span>
637 <?php endif; ?>
638 </div>
639 <span class="yatra-service-price"><?php echo esc_html($price_label); ?></span>
640 </label>
641 </div>
642 <?php endforeach; ?>
643 </div>
644 </div>
645 <?php endif; ?>
646
647
648 <!-- Price Breakdown -->
649 <div class="yatra-summary-pricing" id="yatra-summary-pricing" data-pricing-type="<?php echo esc_attr($pricing_type); ?>" data-is-remaining="<?php echo esc_attr($is_remaining_payment ? 'yes' : 'no'); ?>">
650 <!-- This section is loaded/updated via AJAX -->
651 <?php
652 // Get checkout model from booking object
653 $checkout = $booking->checkout ?? null;
654
655 // Include pricing summary template (uses $checkout model)
656 include YATRA_PLUGIN_PATH . 'templates/partials/pricing-summary.php';
657
658
659 ?>
660 </div>
661
662 <!-- Cancellation Policy -->
663 <?php if (!empty($trip->cancellation_policy)): ?>
664 <div class="yatra-summary-info yatra-cancellation-policy">
665 <h4><?php esc_html_e('Cancellation Policy', 'yatra'); ?></h4>
666 <div class="yatra-cancellation-policy-content">
667 <?php
668 // Process and display the cancellation policy as a paragraph
669 $policy_text = wp_strip_all_tags($trip->cancellation_policy);
670
671 // Truncate if too long for booking summary
672 $max_length = 200;
673 if (strlen($policy_text) > $max_length) {
674 $truncated_text = substr($policy_text, 0, $max_length);
675 // Find last complete sentence within truncation
676 $last_period = strrpos($truncated_text, '.');
677 $last_exclamation = strrpos($truncated_text, '!');
678 $last_question = strrpos($truncated_text, '?');
679
680 $last_sentence_end = max($last_period, $last_exclamation, $last_question);
681
682 if ($last_sentence_end > $max_length * 0.7) {
683 // If we have a complete sentence, end there
684 $display_text = substr($truncated_text, 0, $last_sentence_end + 1);
685 } else {
686 // Otherwise, truncate at word boundary
687 $display_text = substr($truncated_text, 0, strrpos($truncated_text, ' ')) . '...';
688 }
689 } else {
690 $display_text = $policy_text;
691 }
692
693 echo '<p>' . esc_html($display_text) . '</p>';
694
695 // Show "more" indicator if truncated
696 if (strlen($policy_text) > $max_length) {
697 echo '<p class="yatra-policy-more">';
698 echo esc_html__('Full policy available on trip details page', 'yatra');
699 echo '</p>';
700 }
701 ?>
702 </div>
703 </div>
704 <?php endif; ?>
705
706 <!-- Booking Assurance -->
707 <div class="yatra-summary-info">
708 <h4><?php esc_html_e('Booking Assurance', 'yatra'); ?></h4>
709 <ul>
710 <li>
711 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display: inline-block; vertical-align: middle; margin-right: 6px;">
712 <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
713 <polyline points="22 4 12 14.01 9 11.01"></polyline>
714 </svg>
715 <?php esc_html_e('Instant confirmation', 'yatra'); ?>
716 </li>
717 <li>
718 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display: inline-block; vertical-align: middle; margin-right: 6px;">
719 <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>
720 </svg>
721 <?php esc_html_e('24/7 customer support', 'yatra'); ?>
722 </li>
723 <li>
724 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display: inline-block; vertical-align: middle; margin-right: 6px;">
725 <rect x="1" y="4" width="22" height="16" rx="2" ry="2"></rect>
726 <line x1="1" y1="10" x2="23" y2="10"></line>
727 </svg>
728 <?php esc_html_e('Secure payment processing', 'yatra'); ?>
729 </li>
730 </ul>
731 </div>
732
733 <!-- Selected Gateway Info -->
734 <div class="yatra-gateway-info" id="yatra-gateway-info" style="display: none;">
735 <h4><?php esc_html_e('Payment Information', 'yatra'); ?></h4>
736 <div id="yatra-gateway-details"></div>
737 </div>
738 </div>
739 <?php endif; ?>
740 </div>
741 </div>
742 </div>
743 </div>
744
745