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-form-fields.php

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

855 lines 37.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Booking Form Fields Partial
4 *
5 * Renders form fields based on configuration from Settings -> Booking Form
6 * Dynamic form customization requires the Dynamic Form Field module (Pro).
7 *
8 * @package Yatra
9 *
10 * Expected variables:
11 * - $trip_id
12 * - $trip_slug (optional)
13 * - $total_travelers
14 * - $deposit_required
15 * - $deposit_percentage
16 * - $partial_payment
17 * - $partial_payment_percentage
18 * - $enabled_gateways
19 *
20 * Form Configuration Structure:
21 * - contact_form: Lead traveler contact information (prefix: contact_)
22 * - emergency_contact_form: Emergency contact details (prefix: emergency_)
23 * - traveler_form: Individual traveler details (array format: travelers[1][field_id])
24 */
25
26 if (!defined('ABSPATH')) {
27 exit;
28 }
29
30 // Check if Dynamic Form Field module is enabled (Pro feature)
31 $is_dynamic_form_enabled = apply_filters('yatra_dynamic_form_field_enabled', false);
32
33 // Get form configuration - returns default config if module disabled, custom config if enabled
34 $form_config = yatra_get_booking_form_config();
35
36
37 // Country list for country type fields
38 $countries = [
39 'AF' => 'Afghanistan', 'AL' => 'Albania', 'DZ' => 'Algeria', 'AR' => 'Argentina',
40 'AU' => 'Australia', 'AT' => 'Austria', 'BD' => 'Bangladesh', 'BE' => 'Belgium',
41 'BR' => 'Brazil', 'BT' => 'Bhutan', 'CA' => 'Canada', 'CN' => 'China',
42 'CO' => 'Colombia', 'CZ' => 'Czech Republic', 'DK' => 'Denmark', 'EG' => 'Egypt',
43 'FI' => 'Finland', 'FR' => 'France', 'DE' => 'Germany', 'GR' => 'Greece',
44 'HK' => 'Hong Kong', 'HU' => 'Hungary', 'IS' => 'Iceland', 'IN' => 'India',
45 'ID' => 'Indonesia', 'IE' => 'Ireland', 'IL' => 'Israel', 'IT' => 'Italy',
46 'JP' => 'Japan', 'KE' => 'Kenya', 'KR' => 'South Korea', 'MY' => 'Malaysia',
47 'MV' => 'Maldives', 'MX' => 'Mexico', 'NL' => 'Netherlands', 'NZ' => 'New Zealand',
48 'NP' => 'Nepal', 'NO' => 'Norway', 'PK' => 'Pakistan', 'PE' => 'Peru',
49 'PH' => 'Philippines', 'PL' => 'Poland', 'PT' => 'Portugal', 'RO' => 'Romania',
50 'RU' => 'Russia', 'SA' => 'Saudi Arabia', 'SG' => 'Singapore', 'ZA' => 'South Africa',
51 'ES' => 'Spain', 'LK' => 'Sri Lanka', 'SE' => 'Sweden', 'CH' => 'Switzerland',
52 'TW' => 'Taiwan', 'TH' => 'Thailand', 'TR' => 'Turkey', 'AE' => 'United Arab Emirates',
53 'GB' => 'United Kingdom', 'US' => 'United States', 'VN' => 'Vietnam'
54 ];
55
56 /**
57 * Render a single form field based on configuration
58 *
59 * @param array $field Field configuration
60 * @param string $prefix Field name prefix (e.g., 'contact_', 'emergency_')
61 * @param array $countries Country list for country fields
62 * @param string $custom_name Optional custom field name (for array-style names like travelers[1][field_id])
63 * @param string $custom_id Optional custom field ID
64 */
65 if (!function_exists('yatra_render_form_field')) {
66 function yatra_render_form_field($field, $prefix = '', $countries = [], $custom_name = null, $custom_id = null) {
67 if (empty($field['enabled'])) {
68 return;
69 }
70
71 $field_id = $custom_id ? esc_attr($custom_id) : esc_attr($prefix . $field['id']);
72 $field_name = $custom_name ? esc_attr($custom_name) : esc_attr($prefix . $field['id']);
73 $required = !empty($field['required']);
74 $required_attr = $required ? 'required' : '';
75 $required_star = $required ? '<span class="required">*</span>' : '';
76
77 $prefill_value = '';
78 if ($custom_name === null && $prefix === 'contact_') {
79 global $booking;
80 if (isset($booking) && is_object($booking)) {
81 $prop = 'contact_' . ($field['id'] ?? '');
82 if (!empty($prop) && isset($booking->{$prop}) && $booking->{$prop} !== null && $booking->{$prop} !== '') {
83 $prefill_value = (string) $booking->{$prop};
84 }
85 }
86 }
87
88 $width_class = '';
89 if (!empty($field['width'])) {
90 switch ($field['width']) {
91 case 'half':
92 $width_class = 'yatra-field-half';
93 break;
94 case 'third':
95 $width_class = 'yatra-field-third';
96 break;
97 default:
98 $width_class = 'yatra-field-full';
99 }
100 }
101 $field_type = $field['type'] ?? 'text';
102 ?>
103 <div class="yatra-form-group <?php echo esc_attr($width_class); ?> <?php echo $field_type === 'checkbox' ? 'yatra-form-group--checkbox' : ''; ?>">
104 <?php if ($field_type !== 'checkbox') : ?>
105 <label for="<?php echo $field_id; ?>">
106 <?php echo esc_html($field['label']); ?> <?php echo $required_star; ?>
107 </label>
108 <?php endif; ?>
109 <?php
110 switch ($field['type']) {
111 case 'checkbox':
112 $is_checked = ($prefill_value === '1' || $prefill_value === 'on' || $prefill_value === 'true');
113 ?>
114 <label for="<?php echo $field_id; ?>" class="yatra-inline-checkbox-label">
115 <input
116 type="checkbox"
117 id="<?php echo $field_id; ?>"
118 name="<?php echo $field_name; ?>"
119 value="1"
120 <?php checked($is_checked, true, false); ?>
121 <?php echo $required_attr; ?>
122 />
123 <span><?php echo esc_html($field['label']); ?><?php echo $required_star; ?></span>
124 </label>
125 <?php
126 break;
127 case 'select':
128 ?>
129 <select id="<?php echo $field_id; ?>" name="<?php echo $field_name; ?>" <?php echo $required_attr; ?>>
130 <option value=""><?php echo esc_html($field['placeholder'] ?? 'Select...'); ?></option>
131 <?php if (!empty($field['options'])) : ?>
132 <?php foreach ($field['options'] as $option) : ?>
133 <option value="<?php echo esc_attr($option['value']); ?>" <?php echo selected($prefill_value, (string) ($option['value'] ?? ''), false); ?>>
134 <?php echo esc_html($option['label']); ?>
135 </option>
136 <?php endforeach; ?>
137 <?php endif; ?>
138 </select>
139 <?php
140 break;
141
142 case 'country':
143 ?>
144 <select id="<?php echo $field_id; ?>" name="<?php echo $field_name; ?>" <?php echo $required_attr; ?>>
145 <option value=""><?php echo esc_html($field['placeholder'] ?? 'Select Country'); ?></option>
146 <?php foreach ($countries as $code => $name) : ?>
147 <option value="<?php echo esc_attr($code); ?>" <?php echo selected($prefill_value, (string) $code, false); ?>>
148 <?php echo esc_html($name); ?>
149 </option>
150 <?php endforeach; ?>
151 </select>
152 <?php
153 break;
154
155 case 'textarea':
156 ?>
157 <textarea
158 id="<?php echo $field_id; ?>"
159 name="<?php echo $field_name; ?>"
160 placeholder="<?php echo esc_attr($field['placeholder'] ?? ''); ?>"
161 <?php echo $required_attr; ?>
162 rows="3"
163 ><?php echo esc_textarea($prefill_value); ?></textarea>
164 <?php
165 break;
166
167 case 'date':
168 $min_attr = '';
169 ?>
170 <input
171 type="date"
172 id="<?php echo $field_id; ?>"
173 name="<?php echo $field_name; ?>"
174 <?php echo $min_attr; ?>
175 <?php echo $required_attr; ?>
176 value="<?php echo esc_attr($prefill_value); ?>"
177 >
178 <?php
179 break;
180
181 default: // text, email, tel, number
182 ?>
183 <input
184 type="<?php echo esc_attr($field['type']); ?>"
185 id="<?php echo $field_id; ?>"
186 name="<?php echo $field_name; ?>"
187 placeholder="<?php echo esc_attr($field['placeholder'] ?? ''); ?>"
188 <?php echo $required_attr; ?>
189 value="<?php echo esc_attr($prefill_value); ?>"
190 >
191 <?php
192 break;
193 }
194 ?>
195 </div>
196 <?php
197 }
198 } // End function_exists check for yatra_render_form_field
199
200 /**
201 * Render a form section with all its fields
202 */
203 if (!function_exists('yatra_render_form_section')) {
204 function yatra_render_form_section($section_config, $prefix = '', $countries = []) {
205 if (isset($section_config['enabled']) && !$section_config['enabled']) {
206 return;
207 }
208
209 $fields = $section_config['fields'] ?? [];
210
211 // Sort fields by order
212 usort($fields, function($a, $b) {
213 return ($a['order'] ?? 0) - ($b['order'] ?? 0);
214 });
215
216 // Group fields by section (for subsections like dietary)
217 $grouped_fields = [];
218 $current_section = null;
219
220 foreach ($fields as $field) {
221 if (!empty($field['enabled'])) {
222 $section = $field['section'] ?? 'main';
223 if (!isset($grouped_fields[$section])) {
224 $grouped_fields[$section] = [];
225 }
226 $grouped_fields[$section][] = $field;
227 }
228 }
229 ?>
230 <div class="yatra-booking-section">
231 <h2 class="yatra-section-title"><?php echo esc_html($section_config['title'] ?? ''); ?></h2>
232 <?php if (!empty($section_config['description'])) : ?>
233 <p class="yatra-section-description"><?php echo esc_html($section_config['description']); ?></p>
234 <?php endif; ?>
235
236 <?php foreach ($grouped_fields as $section_key => $section_fields) : ?>
237 <?php if ($section_key !== 'main') : ?>
238 <div class="yatra-traveler-subsection">
239 <h4 class="yatra-subsection-title">
240 <?php
241 switch ($section_key) {
242 case 'passport':
243 esc_html_e('Additional details', 'yatra');
244 break;
245 case 'dietary_medical':
246 esc_html_e('Dietary & Medical Requirements', 'yatra');
247 break;
248 default:
249 echo esc_html(ucwords(str_replace('_', ' ', $section_key)));
250 }
251 ?>
252 </h4>
253 <?php endif; ?>
254
255 <div class="yatra-form-row">
256 <?php foreach ($section_fields as $field) : ?>
257 <?php yatra_render_form_field($field, $prefix, $countries); ?>
258 <?php endforeach; ?>
259 </div>
260
261 <?php if ($section_key !== 'main') : ?>
262 </div>
263 <?php endif; ?>
264 <?php endforeach; ?>
265 </div>
266 <?php
267 }
268 } // End function_exists check for yatra_render_form_section
269 ?>
270
271 <!-- Hidden Fields -->
272 <input type="hidden" name="trip_id" value="<?php echo esc_attr($trip_id); ?>">
273 <?php if (!empty($trip_slug)) : ?>
274 <input type="hidden" name="trip_slug" value="<?php echo esc_attr($trip_slug); ?>">
275 <?php endif; ?>
276
277 <?php if ($is_remaining_payment) : ?>
278 <input type="hidden" name="is_remaining_payment" value="1">
279 <?php if (!empty($existing_booking_id)) : ?>
280 <input type="hidden" name="existing_booking_id" value="<?php echo esc_attr($existing_booking_id); ?>">
281 <?php endif; ?>
282 <?php if (!empty($booking_reference)) : ?>
283 <input type="hidden" name="booking_reference" value="<?php echo esc_attr($booking_reference); ?>">
284 <?php endif; ?>
285 <?php if ($remaining_amount !== null) : ?>
286 <input type="hidden" name="remaining_amount" value="<?php echo esc_attr($remaining_amount); ?>">
287 <?php endif; ?>
288 <?php if (!empty($booking->amount_paid)) : ?>
289 <input type="hidden" name="amount_paid" value="<?php echo esc_attr($booking->amount_paid); ?>">
290 <?php endif; ?>
291 <?php if (!empty($booking->total_amount)) : ?>
292 <input type="hidden" name="total_amount" value="<?php echo esc_attr($booking->total_amount); ?>">
293 <?php endif; ?>
294 <?php endif; ?>
295
296 <?php if (!$is_remaining_payment) : ?>
297 <!-- Contact Form Section -->
298 <?php
299 $contact_config = $form_config['contact_form'] ?? [];
300 if (!empty($contact_config)) {
301 yatra_render_form_section($contact_config, 'contact_', $countries);
302 }
303 ?>
304
305 <!-- Emergency Contact Section -->
306 <?php
307 $emergency_config = $form_config['emergency_contact_form'] ?? [];
308 if (!empty($emergency_config) && (!isset($emergency_config['enabled']) || $emergency_config['enabled'])) {
309 yatra_render_form_section($emergency_config, 'emergency_', $countries);
310 }
311 ?>
312
313 <!-- Traveler Information Section -->
314 <?php
315 $traveler_config = $form_config['traveler_form'] ?? [];
316 ?>
317 <?php endif; ?>
318
319 <?php
320 $traveler_config = $form_config['traveler_form'] ?? [];
321 $traveler_count = isset($total_travelers) ? max(1, (int)$total_travelers) : 1;
322
323 // Check if we have traveler-based pricing info
324 $pricing_type = isset($pricing_type) ? $pricing_type : 'regular';
325 $price_types = isset($price_types) ? $price_types : [];
326 $traveler_counts = isset($traveler_counts) ? $traveler_counts : [];
327
328 /**
329 * Coerce JSON / serialized / object values to a list for foreach-safe iteration.
330 *
331 * @param mixed $value
332 * @return array<int|string, mixed>
333 */
334 $yatra_normalize_booking_arrayish = static function ($value): array {
335 if ($value === null || $value === false || $value === '') {
336 return [];
337 }
338 if (is_array($value)) {
339 return $value;
340 }
341 if ($value instanceof \stdClass) {
342 return (array) $value;
343 }
344 if (is_string($value)) {
345 $trim = trim($value);
346 if ($trim === '') {
347 return [];
348 }
349 $decoded = json_decode($value, true);
350 if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
351 return $decoded;
352 }
353 if (function_exists('maybe_unserialize')) {
354 $un = maybe_unserialize($value);
355 if (is_array($un)) {
356 return $un;
357 }
358 }
359 }
360
361 return [];
362 };
363
364 $price_types = $yatra_normalize_booking_arrayish($price_types);
365 $traveler_counts = $yatra_normalize_booking_arrayish($traveler_counts);
366
367 // Build traveler-to-category mapping for traveler-based pricing
368 $traveler_category_map = [];
369 if ($pricing_type === 'traveler_based' && !empty($price_types) && !empty($traveler_counts)) {
370 $traveler_index = 1;
371 foreach ($price_types as $index => $pt) {
372 $pt = (object) $pt;
373 $category_id = $pt->category_id ?? $index;
374 $category_label = $pt->category_label ?? __('Traveler', 'yatra');
375 $count = isset($traveler_counts[$category_id]) ? (int) $traveler_counts[$category_id] : 0;
376
377 for ($c = 1; $c <= $count; $c++) {
378 $traveler_category_map[$traveler_index] = [
379 'category_id' => $category_id,
380 'category_label' => $category_label,
381 'category_index' => $c,
382 ];
383 $traveler_index++;
384 }
385 }
386 }
387
388 $price_candidates = [
389 isset($trip->price) ? (float) $trip->price : 0,
390 isset($booking->session_price) ? (float) $booking->session_price : 0,
391 isset($trip->sale_price) ? (float) $trip->sale_price : 0,
392 isset($trip->original_price) ? (float) $trip->original_price : 0,
393 ];
394
395 $effective_trip_price = 0;
396 foreach ($price_candidates as $candidate) {
397 if ($candidate > 0) {
398 $effective_trip_price = $candidate;
399 break;
400 }
401 }
402
403 $traveler_price_rows = [];
404 $calculated_total = 0;
405
406 if ($pricing_type === 'traveler_based' && !empty($price_types)) {
407 foreach ($price_types as $index => $pt) {
408 $pt = (object) $pt;
409 $category_id = $pt->category_id ?? $index;
410 $category_label = $pt->category_label ?? __('Traveler', 'yatra');
411 $category_price = isset($pt->effective_price) ? (float) $pt->effective_price : ($pt->sale_price ?? $pt->discounted_price ?? $pt->original_price ?? 0);
412 $count = isset($traveler_counts[$category_id]) ? (int) $traveler_counts[$category_id] : ($index === 0 ? 1 : 0);
413 $subtotal = $category_price * $count;
414
415 $age_info = '';
416 if (isset($pt->age_min) || isset($pt->age_max)) {
417 if (isset($pt->age_min) && isset($pt->age_max)) {
418 $age_info = sprintf(__('(Age %d-%d)', 'yatra'), $pt->age_min, $pt->age_max);
419 } elseif (isset($pt->age_min)) {
420 $age_info = sprintf(__('(Age %d+)', 'yatra'), $pt->age_min);
421 } else {
422 $age_info = sprintf(__('(Up to age %d)', 'yatra'), $pt->age_max);
423 }
424 }
425
426 $traveler_price_rows[] = [
427 'category_id' => $category_id,
428 'category_label' => $category_label,
429 'category_price' => $category_price,
430 'count' => $count,
431 'subtotal' => $subtotal,
432 'age_info' => $age_info,
433 ];
434
435 $calculated_total += $subtotal;
436
437 if ($effective_trip_price <= 0 && $category_price > 0) {
438 $effective_trip_price = $category_price;
439 }
440 }
441 }
442
443 if ($effective_trip_price <= 0) {
444 $effective_trip_price = 0;
445 }
446
447 $initial_total_amount = $calculated_total > 0
448 ? $calculated_total
449 : ($effective_trip_price * max(1, (int) $total_travelers));
450
451 if ($initial_total_amount <= 0 && $effective_trip_price > 0) {
452 $initial_total_amount = $effective_trip_price * max(1, (int) $total_travelers);
453 }
454
455 $initial_due_amount = $initial_total_amount;
456
457 ?>
458
459 <?php if (!empty($traveler_config) && !$is_remaining_payment) : ?>
460 <div class="yatra-booking-section">
461 <h2 class="yatra-section-title"><?php echo esc_html($traveler_config['title'] ?? __('Traveler Information', 'yatra')); ?></h2>
462 <?php if (!empty($traveler_config['description'])) : ?>
463 <p class="yatra-section-description"><?php echo esc_html($traveler_config['description']); ?></p>
464 <?php endif; ?>
465
466 <div id="yatra-travelers-container">
467 <?php
468 $traveler_fields = $traveler_config['fields'] ?? [];
469 usort($traveler_fields, function($a, $b) {
470 return ($a['order'] ?? 0) - ($b['order'] ?? 0);
471 });
472
473 // Group fields by section
474 $grouped_traveler_fields = [];
475 foreach ($traveler_fields as $field) {
476 if (!empty($field['enabled'])) {
477 $section = $field['section'] ?? 'main';
478 if (!isset($grouped_traveler_fields[$section])) {
479 $grouped_traveler_fields[$section] = [];
480 }
481 $grouped_traveler_fields[$section][] = $field;
482 }
483 }
484
485 for ($i = 1; $i <= $traveler_count; $i++) :
486 // Determine traveler label based on category if traveler-based pricing
487 if (!empty($traveler_category_map[$i])) {
488 $category_info = $traveler_category_map[$i];
489 $category_label = $category_info['category_label'];
490 $category_index = $category_info['category_index'];
491 $traveler_label = sprintf(__('%s %d', 'yatra'), $category_label, $category_index);
492 if ($i === 1) {
493 $traveler_label .= ' (' . __('Lead Traveler', 'yatra') . ')';
494 }
495 } else {
496 $traveler_label = ($i === 1) ? __('Traveler 1 (Lead Traveler)', 'yatra') : sprintf(__('Traveler %d', 'yatra'), $i);
497 }
498 ?>
499 <div class="yatra-traveler-form" data-traveler-index="<?php echo esc_attr($i); ?>" <?php if (!empty($traveler_category_map[$i])): ?>data-category-id="<?php echo esc_attr($traveler_category_map[$i]['category_id']); ?>" data-category-label="<?php echo esc_attr($traveler_category_map[$i]['category_label']); ?>"<?php endif; ?>>
500 <div class="yatra-traveler-header">
501 <h3 class="yatra-traveler-title"><?php echo esc_html($traveler_label); ?></h3>
502 <?php if ($i > 1) : ?>
503 <span class="yatra-traveler-note"><?php esc_html_e('Additional traveler', 'yatra'); ?></span>
504 <?php endif; ?>
505 </div>
506
507 <?php foreach ($grouped_traveler_fields as $section_key => $section_fields) : ?>
508 <?php if ($section_key !== 'main') : ?>
509 <div class="yatra-traveler-subsection">
510 <h4 class="yatra-subsection-title">
511 <?php
512 switch ($section_key) {
513 case 'passport':
514 esc_html_e('Additional details', 'yatra');
515 break;
516 case 'dietary_medical':
517 esc_html_e('Dietary & Medical Requirements', 'yatra');
518 break;
519 default:
520 echo esc_html(ucwords(str_replace('_', ' ', $section_key)));
521 }
522 ?>
523 </h4>
524 <?php endif; ?>
525
526 <div class="yatra-form-row">
527 <?php foreach ($section_fields as $field) :
528 $field_id = "traveler-{$i}-" . esc_attr($field['id']);
529 $field_name = "travelers[{$i}][" . esc_attr($field['id']) . "]";
530 yatra_render_form_field($field, '', $countries, $field_name, $field_id);
531 endforeach; ?>
532 </div>
533
534 <?php if ($section_key !== 'main') : ?>
535 </div>
536 <?php endif; ?>
537 <?php endforeach; ?>
538 </div>
539 <?php endfor; ?>
540 </div>
541 </div>
542 <?php endif; ?>
543
544 <!-- Payment Method Section -->
545 <?php
546 /**
547 * Filter to check if flexible payments module is enabled (Pro feature)
548 * When enabled, deposit and partial payment options will be available
549 */
550 $flexible_payments_enabled = apply_filters('yatra_flexible_payments_enabled', false);
551
552 /**
553 * Filter to get payment method options
554 * Pro module can add deposit/partial payment options via this filter
555 */
556 $payment_method_options = apply_filters('yatra_payment_method_options', [], [
557 'deposit_required' => $deposit_required,
558 'deposit_percentage' => $deposit_percentage,
559 'partial_payment' => $partial_payment,
560 'partial_payment_percentage' => $partial_payment_percentage,
561 ]);
562
563 $has_flexible_options = $flexible_payments_enabled && !empty($payment_method_options);
564 ?>
565 <?php if (!$is_remaining_payment && $has_flexible_options) : ?>
566 <div class="yatra-booking-section">
567 <h2 class="yatra-section-title"><?php esc_html_e('Payment Method', 'yatra'); ?></h2>
568
569 <div class="yatra-payment-methods">
570 <label class="yatra-payment-option">
571 <input type="radio" name="payment_method" value="full" checked>
572 <span class="yatra-payment-label">
573 <strong><?php esc_html_e('Pay in Full', 'yatra'); ?></strong>
574 <span><?php esc_html_e('Pay the total amount now', 'yatra'); ?></span>
575 </span>
576 </label>
577
578 <?php foreach ($payment_method_options as $option_key => $option) : ?>
579 <label class="yatra-payment-option">
580 <input type="radio" name="payment_method" value="<?php echo esc_attr($option['value']); ?>">
581 <span class="yatra-payment-label">
582 <strong><?php echo esc_html($option['label']); ?></strong>
583 <span><?php echo esc_html($option['description']); ?></span>
584 </span>
585 </label>
586 <?php endforeach; ?>
587 </div>
588 </div>
589 <?php endif; ?>
590
591 <!-- Payment Gateway Section -->
592 <?php
593 // Always use the live registry list (same as BookingPageHandler). Do not intersect with $enabled_gateways
594 // from older templates/sessions — that caused only stale gateways (e.g. Pay Later) to show.
595 $display_gateways = [];
596 if (class_exists('Yatra\PaymentGateways\PaymentGatewayRegistry')) {
597 $registry = \Yatra\PaymentGateways\PaymentGatewayRegistry::getInstance();
598 foreach ($registry->getForCheckout() as $gateway) {
599 if (!empty($gateway['id'])) {
600 $display_gateways[$gateway['id']] = $gateway;
601 }
602 }
603 }
604 ?>
605 <?php if (!empty($display_gateways)) : ?>
606 <div class="yatra-booking-section">
607 <h2 class="yatra-section-title"><?php esc_html_e('Select Payment Gateway', 'yatra'); ?></h2>
608
609 <div class="yatra-gateway-options">
610 <?php
611 $first = true;
612 foreach ($display_gateways as $gateway_id => $gateway) :
613 $icon = !empty($gateway['icon']) ? $gateway['icon'] : plugins_url('assets/images/payment-placeholder.png', dirname(__DIR__));
614 ?>
615 <div class="yatra-gateway-option-wrapper">
616 <label class="yatra-gateway-option">
617 <input type="radio" name="payment_gateway" value="<?php echo esc_attr($gateway_id); ?>" <?php checked($first); ?>>
618 <span class="yatra-gateway-icon-wrap">
619 <img src="<?php echo esc_url($icon ?? ''); ?>" alt="<?php echo esc_attr($gateway['title'] ?? ''); ?>" class="yatra-gateway-icon">
620 </span>
621 <span class="yatra-gateway-content">
622 <strong class="yatra-gateway-title"><?php echo esc_html($gateway['title']); ?></strong>
623 <span class="yatra-gateway-desc"><?php echo esc_html($gateway['description']); ?></span>
624 <?php if (empty($gateway['is_configured'])) : ?>
625 <span class="yatra-gateway-desc yatra-gateway-setup-required"><?php esc_html_e('Setup incomplete — finish configuration under Yatra → Settings → Payment, or choose another method.', 'yatra'); ?></span>
626 <?php endif; ?>
627 </span>
628 </label>
629 <div class="yatra-gateway-extra" id="yatra-gateway-extra-<?php echo esc_attr($gateway_id); ?>" data-gateway="<?php echo esc_attr($gateway_id); ?>"></div>
630 </div>
631 <?php
632 $first = false;
633 endforeach;
634 ?>
635 </div>
636 </div>
637 <?php endif; ?>
638
639 <?php if (!$is_remaining_payment) : ?>
640 <!-- Special Requests -->
641 <div class="yatra-booking-section">
642 <h2 class="yatra-section-title"><?php esc_html_e('Special Requests', 'yatra'); ?></h2>
643 <p class="yatra-section-description"><?php esc_html_e('Any special requests or notes for your trip (optional)', 'yatra'); ?></p>
644
645 <div class="yatra-form-group yatra-field-full">
646 <textarea
647 id="special-requests"
648 name="special_requests"
649 rows="4"
650 placeholder="<?php esc_attr_e('E.g., dietary requirements, accessibility needs, celebration requests...', 'yatra'); ?>"
651 ></textarea>
652 </div>
653 </div>
654 <?php endif; ?>
655
656 <!-- Account Creation Section (only for guests) -->
657 <?php
658 $allow_guest_checkout = \Yatra\Services\SettingsService::isEnabled('allow_guest_checkout');
659 $require_login = \Yatra\Services\SettingsService::isEnabled('require_login');
660
661 // Show account section if user is not logged in
662 if (!is_user_logged_in() && !$is_remaining_payment) :
663 ?>
664 <div class="yatra-booking-section yatra-account-section">
665 <h2 class="yatra-section-title"><?php esc_html_e('Account', 'yatra'); ?></h2>
666
667 <?php if ($require_login) : ?>
668 <!-- Login Required Message -->
669 <div class="yatra-login-required-notice" style="background: #fef3c7; border: 1px solid #f59e0b; padding: 16px; border-radius: 8px; margin-bottom: 16px;">
670 <div style="display: flex; align-items: flex-start; gap: 12px;">
671 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#d97706" stroke-width="2" style="flex-shrink: 0;">
672 <circle cx="12" cy="12" r="10"></circle>
673 <line x1="12" y1="8" x2="12" y2="12"></line>
674 <line x1="12" y1="16" x2="12.01" y2="16"></line>
675 </svg>
676 <div>
677 <p style="font-weight: 600; color: #92400e; margin: 0 0 8px 0;"><?php esc_html_e('Login Required', 'yatra'); ?></p>
678 <p style="color: #a16207; margin: 0 0 12px 0; font-size: 14px;">
679 <?php esc_html_e('You must be logged in to complete this booking. Please log in or create an account.', 'yatra'); ?>
680 </p>
681 <a href="<?php echo esc_url(wp_login_url(get_permalink())); ?>" class="yatra-login-btn" style="display: inline-flex; align-items: center; gap: 8px; padding: 10px 20px; background: #3b82f6; color: #fff; text-decoration: none; border-radius: 6px; font-weight: 500; font-size: 14px;">
682 <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
683 <path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path>
684 <polyline points="10 17 15 12 10 7"></polyline>
685 <line x1="15" y1="12" x2="3" y2="12"></line>
686 </svg>
687 <?php esc_html_e('Log In', 'yatra'); ?>
688 </a>
689 <span style="margin: 0 12px; color: #a16207;"><?php esc_html_e('or', 'yatra'); ?></span>
690 <a href="<?php echo esc_url(wp_registration_url()); ?>" style="color: #3b82f6; text-decoration: none; font-weight: 500;">
691 <?php esc_html_e('Create an Account', 'yatra'); ?>
692 </a>
693 </div>
694 </div>
695 </div>
696 <input type="hidden" name="login_required" value="1">
697
698 <?php elseif (!$allow_guest_checkout) : ?>
699 <!-- Account Required - Must Create Account -->
700 <p class="yatra-section-description" style="margin-bottom: 16px;">
701 <?php esc_html_e('Please create an account to complete your booking. This allows you to manage your bookings and receive important updates.', 'yatra'); ?>
702 </p>
703
704 <div class="yatra-form-row">
705 <div class="yatra-form-group yatra-field-half">
706 <label for="account_password">
707 <?php esc_html_e('Password', 'yatra'); ?> <span class="required">*</span>
708 </label>
709 <input type="password" id="account_password" name="account_password" required minlength="8"
710 placeholder="<?php esc_attr_e('Minimum 8 characters', 'yatra'); ?>">
711 </div>
712 <div class="yatra-form-group yatra-field-half">
713 <label for="account_password_confirm">
714 <?php esc_html_e('Confirm Password', 'yatra'); ?> <span class="required">*</span>
715 </label>
716 <input type="password" id="account_password_confirm" name="account_password_confirm" required minlength="8"
717 placeholder="<?php esc_attr_e('Re-enter password', 'yatra'); ?>">
718 </div>
719 </div>
720 <p class="yatra-field-hint" style="font-size: 13px; color: #6b7280; margin-top: 8px;">
721 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display: inline-block; vertical-align: middle; margin-right: 4px;">
722 <circle cx="12" cy="12" r="10"></circle>
723 <path d="M12 16v-4"></path>
724 <path d="M12 8h.01"></path>
725 </svg>
726 <?php esc_html_e('Your email address will be used as your username.', 'yatra'); ?>
727 </p>
728 <input type="hidden" name="create_account" value="1">
729
730 <?php else : ?>
731 <!-- Guest Checkout Allowed - Optional Account Creation -->
732 <p class="yatra-section-description" style="margin-bottom: 16px;">
733 <?php esc_html_e('Create an account to easily manage your bookings and receive travel updates.', 'yatra'); ?>
734 </p>
735
736 <label class="yatra-checkbox-label" style="margin-bottom: 16px;">
737 <input type="checkbox" name="create_account" id="create-account" value="1">
738 <span><?php esc_html_e('Create an account for easier booking management', 'yatra'); ?></span>
739 </label>
740
741 <div class="yatra-account-fields" id="yatra-account-fields" style="display: none;">
742 <div class="yatra-form-row">
743 <div class="yatra-form-group yatra-field-half">
744 <label for="account_password">
745 <?php esc_html_e('Password', 'yatra'); ?> <span class="required">*</span>
746 </label>
747 <input type="password" id="account_password" name="account_password" minlength="8"
748 placeholder="<?php esc_attr_e('Minimum 8 characters', 'yatra'); ?>">
749 </div>
750 <div class="yatra-form-group yatra-field-half">
751 <label for="account_password_confirm">
752 <?php esc_html_e('Confirm Password', 'yatra'); ?> <span class="required">*</span>
753 </label>
754 <input type="password" id="account_password_confirm" name="account_password_confirm" minlength="8"
755 placeholder="<?php esc_attr_e('Re-enter password', 'yatra'); ?>">
756 </div>
757 </div>
758 <p class="yatra-field-hint" style="font-size: 13px; color: #6b7280; margin-top: 8px;">
759 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display: inline-block; vertical-align: middle; margin-right: 4px;">
760 <circle cx="12" cy="12" r="10"></circle>
761 <path d="M12 16v-4"></path>
762 <path d="M12 8h.01"></path>
763 </svg>
764 <?php esc_html_e('Your email address will be used as your username.', 'yatra'); ?>
765 </p>
766 </div>
767 <?php endif; ?>
768 </div>
769 <?php elseif (!is_user_logged_in()) : ?>
770 <!-- User is logged in -->
771 <div class="yatra-booking-section yatra-logged-in-notice">
772 <div style="display: flex; align-items: center; gap: 12px; padding: 12px 16px; background: #ecfdf5; border: 1px solid #10b981; border-radius: 8px;">
773 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="2">
774 <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
775 <polyline points="22 4 12 14.01 9 11.01"></polyline>
776 </svg>
777 <div>
778 <span style="font-weight: 500; color: #065f46;">
779 <?php
780 $current_user = wp_get_current_user();
781 printf(
782 /* translators: %s: User display name */
783 esc_html__('Logged in as %s', 'yatra'),
784 '<strong>' . esc_html($current_user->display_name) . '</strong>'
785 );
786 ?>
787 </span>
788 <a href="<?php echo esc_url(wp_logout_url(get_permalink())); ?>" style="margin-left: 12px; color: #059669; font-size: 13px;">
789 <?php esc_html_e('Log out', 'yatra'); ?>
790 </a>
791 </div>
792 </div>
793 </div>
794 <?php endif; ?>
795
796 <!-- Terms & Conditions -->
797 <div class="yatra-booking-section">
798 <div class="yatra-terms-container">
799 <?php
800 $termsPageId = 0;
801 $privacyPageId = 0;
802 if (class_exists('\\Yatra\\Services\\SettingsService')) {
803 $termsPageId = \Yatra\Services\SettingsService::getInt('terms_page_id', 0);
804 $privacyPageId = \Yatra\Services\SettingsService::getInt('privacy_policy_page_id', 0);
805 } else {
806 $termsPageId = (int) get_option('yatra_terms_page_id', 0);
807 $privacyPageId = (int) get_option('yatra_privacy_policy_page_id', 0);
808 }
809
810 $termsUrl = $termsPageId > 0 ? get_permalink($termsPageId) : '';
811 $privacyUrl = $privacyPageId > 0 ? get_permalink($privacyPageId) : '';
812 if ($privacyUrl === '' && function_exists('get_privacy_policy_url')) {
813 $privacyUrl = (string) get_privacy_policy_url();
814 }
815 ?>
816
817 <label class="yatra-checkbox-label">
818 <input type="checkbox" name="accept_terms" id="accept-terms" required>
819 <span>
820 <?php
821 printf(
822 /* translators: %s: Terms and Conditions link */
823 esc_html__('I have read and agree to the %s', 'yatra'),
824 $termsUrl
825 ? '<a href="' . esc_url($termsUrl) . '" target="_blank" rel="noopener noreferrer">' . esc_html__('Terms and Conditions', 'yatra') . '</a>'
826 : '<span>' . esc_html__('Terms and Conditions', 'yatra') . '</span>'
827 );
828 ?>
829 <span class="required">*</span>
830 </span>
831 </label>
832
833 <label class="yatra-checkbox-label">
834 <input type="checkbox" name="accept_privacy" id="accept-privacy" required>
835 <span>
836 <?php
837 printf(
838 /* translators: %s: Privacy Policy link */
839 esc_html__('I agree to the %s and consent to my data being processed', 'yatra'),
840 $privacyUrl
841 ? '<a href="' . esc_url($privacyUrl) . '" target="_blank" rel="noopener noreferrer">' . esc_html__('Privacy Policy', 'yatra') . '</a>'
842 : '<span>' . esc_html__('Privacy Policy', 'yatra') . '</span>'
843 );
844 ?>
845 <span class="required">*</span>
846 </span>
847 </label>
848
849 <label class="yatra-checkbox-label">
850 <input type="checkbox" name="subscribe_newsletter" id="subscribe-newsletter">
851 <span><?php esc_html_e('Subscribe to our newsletter for travel tips and exclusive offers', 'yatra'); ?></span>
852 </label>
853 </div>
854 </div>
855