PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.3
Yatra – Travel Booking & Tour Operator Software v3.0.3
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.3, at templates/partials/booking-content.php

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