PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.5
Yatra – Travel Booking & Tour Operator Software v3.0.5
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.5, at templates/partials/booking-form-fields.php

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