| 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 |
// Scoped to the trip being booked, so a field or section limited to certain |
| 35 |
// trips (Pro) is neither rendered nor required here. |
| 36 |
$form_config = yatra_get_booking_form_config(!empty($trip_id) ? (int) $trip_id : null); |
| 37 |
|
| 38 |
|
| 39 |
// Country list — pulls from the canonical FormatHelper source so every |
| 40 |
// dropdown (admin, public booking, Pro modules) shows the same full |
| 41 |
// ISO-3166-1 list. Operators that want a "popular countries" subset |
| 42 |
// or custom ordering apply the `yatra_countries_list` filter. |
| 43 |
$countries = \Yatra\Helpers\FormatHelper::getCountries(); |
| 44 |
|
| 45 |
/** |
| 46 |
* Render a single form field based on configuration |
| 47 |
* |
| 48 |
* @param array $field Field configuration |
| 49 |
* @param string $prefix Field name prefix (e.g., 'contact_', 'emergency_') |
| 50 |
* @param array $countries Country list for country fields |
| 51 |
* @param string $custom_name Optional custom field name (for array-style names like travelers[1][field_id]) |
| 52 |
* @param string $custom_id Optional custom field ID |
| 53 |
*/ |
| 54 |
if (!function_exists('yatra_render_form_field')) { |
| 55 |
function yatra_render_form_field($field, $prefix = '', $countries = [], $custom_name = null, $custom_id = null) { |
| 56 |
if (empty($field['enabled'])) { |
| 57 |
return; |
| 58 |
} |
| 59 |
|
| 60 |
// Display-only text block: render admin-authored content (safe HTML) at this |
| 61 |
// position between fields. It is NOT an input — no label, name, value or |
| 62 |
// required handling — so it submits nothing and is never validated. |
| 63 |
if (($field['type'] ?? '') === 'text_block') { |
| 64 |
$tb_width = 'yatra-field-full'; |
| 65 |
if (($field['width'] ?? '') === 'half') { |
| 66 |
$tb_width = 'yatra-field-half'; |
| 67 |
} elseif (($field['width'] ?? '') === 'third') { |
| 68 |
$tb_width = 'yatra-field-third'; |
| 69 |
} |
| 70 |
?> |
| 71 |
<div class="yatra-form-group yatra-form-text-block <?php echo esc_attr($tb_width); ?>" data-applies-to="<?php echo esc_attr($field['applies_to'] ?? 'all'); ?>"> |
| 72 |
<?php echo wpautop(wp_kses_post(yatra_translate_form_string($field['content'] ?? ''))); ?> |
| 73 |
</div> |
| 74 |
<?php |
| 75 |
return; |
| 76 |
} |
| 77 |
|
| 78 |
$field_id = $custom_id ? esc_attr($custom_id) : esc_attr($prefix . $field['id']); |
| 79 |
$field_name = $custom_name ? esc_attr($custom_name) : esc_attr($prefix . $field['id']); |
| 80 |
$required = !empty($field['required']); |
| 81 |
$required_attr = $required ? 'required' : ''; |
| 82 |
$required_star = $required ? '<span class="required">*</span>' : ''; |
| 83 |
|
| 84 |
$prefill_value = ''; |
| 85 |
if ($custom_name === null && $prefix === 'contact_') { |
| 86 |
global $booking; |
| 87 |
if (isset($booking) && is_object($booking)) { |
| 88 |
$prop = 'contact_' . ($field['id'] ?? ''); |
| 89 |
if (!empty($prop) && isset($booking->{$prop}) && $booking->{$prop} !== null && $booking->{$prop} !== '') { |
| 90 |
$prefill_value = (string) $booking->{$prop}; |
| 91 |
} |
| 92 |
} |
| 93 |
} |
| 94 |
|
| 95 |
$width_class = ''; |
| 96 |
if (!empty($field['width'])) { |
| 97 |
switch ($field['width']) { |
| 98 |
case 'half': |
| 99 |
$width_class = 'yatra-field-half'; |
| 100 |
break; |
| 101 |
case 'third': |
| 102 |
$width_class = 'yatra-field-third'; |
| 103 |
break; |
| 104 |
default: |
| 105 |
$width_class = 'yatra-field-full'; |
| 106 |
} |
| 107 |
} |
| 108 |
$field_type = $field['type'] ?? 'text'; |
| 109 |
?> |
| 110 |
<div class="yatra-form-group <?php echo esc_attr($width_class); ?> <?php echo $field_type === 'checkbox' ? 'yatra-form-group--checkbox' : ''; ?>" data-applies-to="<?php echo esc_attr($field['applies_to'] ?? 'all'); ?>"> |
| 111 |
<?php if ($field_type !== 'checkbox') : ?> |
| 112 |
<label for="<?php echo $field_id; ?>"> |
| 113 |
<?php echo esc_html(yatra_translate_form_string($field['label'])); ?> <?php echo $required_star; ?> |
| 114 |
</label> |
| 115 |
<?php endif; ?> |
| 116 |
<?php |
| 117 |
switch ($field['type']) { |
| 118 |
case 'checkbox': |
| 119 |
$is_checked = ($prefill_value === '1' || $prefill_value === 'on' || $prefill_value === 'true'); |
| 120 |
?> |
| 121 |
<label for="<?php echo $field_id; ?>" class="yatra-inline-checkbox-label"> |
| 122 |
<input |
| 123 |
type="checkbox" |
| 124 |
id="<?php echo $field_id; ?>" |
| 125 |
name="<?php echo $field_name; ?>" |
| 126 |
value="1" |
| 127 |
<?php checked($is_checked, true, false); ?> |
| 128 |
<?php echo $required_attr; ?> |
| 129 |
/> |
| 130 |
<span><?php echo esc_html(yatra_translate_form_string($field['label'])); ?><?php echo $required_star; ?></span> |
| 131 |
</label> |
| 132 |
<?php |
| 133 |
break; |
| 134 |
case 'select': |
| 135 |
?> |
| 136 |
<select id="<?php echo $field_id; ?>" name="<?php echo $field_name; ?>" <?php echo $required_attr; ?>> |
| 137 |
<option value=""><?php echo esc_html(yatra_translate_form_string($field['placeholder'] ?? '') ?: __('Select...', 'yatra')); ?></option> |
| 138 |
<?php if (!empty($field['options'])) : ?> |
| 139 |
<?php foreach ($field['options'] as $option) : ?> |
| 140 |
<option value="<?php echo esc_attr($option['value']); ?>" <?php echo selected($prefill_value, (string) ($option['value'] ?? ''), false); ?>> |
| 141 |
<?php echo esc_html(yatra_translate_form_string($option['label'] ?? '')); ?> |
| 142 |
</option> |
| 143 |
<?php endforeach; ?> |
| 144 |
<?php endif; ?> |
| 145 |
</select> |
| 146 |
<?php |
| 147 |
break; |
| 148 |
|
| 149 |
case 'country': |
| 150 |
// Flag base is handed to the field (same contract as the phone |
| 151 |
// widget) so country-select.js can build flag URLs without |
| 152 |
// knowing the plugin URL. The select still renders and submits |
| 153 |
// normally — the widget is a progressive enhancement over it. |
| 154 |
$country_flag_base = \defined('YATRA_PLUGIN_URL') ? YATRA_PLUGIN_URL . 'assets/img/flags/' : ''; |
| 155 |
?> |
| 156 |
<select id="<?php echo $field_id; ?>" name="<?php echo $field_name; ?>" <?php echo $required_attr; ?> |
| 157 |
data-yatra-country-select |
| 158 |
data-flag-base="<?php echo esc_url($country_flag_base); ?>"> |
| 159 |
<option value=""><?php echo esc_html(yatra_translate_form_string($field['placeholder'] ?? '') ?: __('Select Country', 'yatra')); ?></option> |
| 160 |
<?php foreach ($countries as $code => $name) : ?> |
| 161 |
<option value="<?php echo esc_attr($code); ?>" <?php echo selected($prefill_value, (string) $code, false); ?>> |
| 162 |
<?php echo esc_html($name); ?> |
| 163 |
</option> |
| 164 |
<?php endforeach; ?> |
| 165 |
</select> |
| 166 |
<?php |
| 167 |
break; |
| 168 |
|
| 169 |
case 'textarea': |
| 170 |
?> |
| 171 |
<textarea |
| 172 |
id="<?php echo $field_id; ?>" |
| 173 |
name="<?php echo $field_name; ?>" |
| 174 |
placeholder="<?php echo esc_attr(yatra_translate_form_string($field['placeholder'] ?? '')); ?>" |
| 175 |
<?php echo $required_attr; ?> |
| 176 |
rows="3" |
| 177 |
><?php echo esc_textarea($prefill_value); ?></textarea> |
| 178 |
<?php |
| 179 |
break; |
| 180 |
|
| 181 |
case 'date': |
| 182 |
$min_attr = ''; |
| 183 |
// Date-of-birth-style fields are bounded to today and flagged so |
| 184 |
// booking.js can upgrade them to a picker with fast year jumping |
| 185 |
// (a native date popup steps one month at a time). The class is |
| 186 |
// the JS hook; if JS/flatpickr is unavailable the input stays a |
| 187 |
// working native <input type="date">. |
| 188 |
$is_dob = (stripos($field_id, 'birth') !== false || stripos($field_id, 'dob') !== false |
| 189 |
|| stripos($field_name, 'birth') !== false || stripos($field_name, 'dob') !== false); |
| 190 |
$dob_attr = $is_dob ? ' data-yatra-dob="1" max="' . esc_attr(date('Y-m-d')) . '"' : ''; |
| 191 |
// Native date inputs ignore the placeholder, but once booking.js |
| 192 |
// upgrades the field to a flatpickr text input the placeholder is |
| 193 |
// what keeps it visually consistent with the other text fields |
| 194 |
// (otherwise it renders blank). Use the field's own placeholder |
| 195 |
// when set, else a format hint matching flatpickr's Y-m-d output. |
| 196 |
$date_placeholder = !empty($field['placeholder']) |
| 197 |
? yatra_translate_form_string($field['placeholder']) |
| 198 |
: 'YYYY-MM-DD'; |
| 199 |
?> |
| 200 |
<input |
| 201 |
type="date" |
| 202 |
class="yatra-js-date" |
| 203 |
id="<?php echo $field_id; ?>" |
| 204 |
name="<?php echo $field_name; ?>" |
| 205 |
placeholder="<?php echo esc_attr($date_placeholder); ?>" |
| 206 |
<?php echo $min_attr; ?> |
| 207 |
<?php echo $dob_attr; ?> |
| 208 |
<?php echo $required_attr; ?> |
| 209 |
value="<?php echo esc_attr($prefill_value); ?>" |
| 210 |
> |
| 211 |
<?php |
| 212 |
break; |
| 213 |
|
| 214 |
default: // text, email, tel, number |
| 215 |
// Phone (tel) fields get the international country-code widget |
| 216 |
// UNLESS it has been explicitly disabled in the (Pro) form |
| 217 |
// builder. A missing key means ON, so every existing form and |
| 218 |
// customized field keeps the widget without needing a re-save. |
| 219 |
$is_phone_widget = (($field['type'] ?? '') === 'tel') |
| 220 |
&& (!array_key_exists('show_country_code', $field) || !empty($field['show_country_code'])); |
| 221 |
|
| 222 |
if ($is_phone_widget) { |
| 223 |
// Split the stored value for display: an international value |
| 224 |
// ("+9779806015400") is parsed into country + national part; |
| 225 |
// a legacy bare number is left in the number box under the |
| 226 |
// default country (never rewritten on display). |
| 227 |
$pv = (string) $prefill_value; |
| 228 |
$detected = \Yatra\Helpers\FormatHelper::detectPhoneCountry($pv); |
| 229 |
if ($detected !== null) { |
| 230 |
$p_iso = $detected['iso']; |
| 231 |
$p_dial = $detected['dial']; |
| 232 |
$p_national = $detected['national']; |
| 233 |
} else { |
| 234 |
$p_iso = \Yatra\Helpers\FormatHelper::getDefaultPhoneCountry(); |
| 235 |
$p_dial = \Yatra\Helpers\FormatHelper::getDialingCode($p_iso); |
| 236 |
$p_national = $pv; |
| 237 |
} |
| 238 |
|
| 239 |
// Companion hidden field holding the chosen ISO. Array-style |
| 240 |
// names (travelers[0][phone]) become travelers[0][phone_country]; |
| 241 |
// the server combines dial code + national number on submit. |
| 242 |
if (preg_match('/^(.*)\[([^\]]+)\]$/', $field_name, $mm)) { |
| 243 |
$companion_name = $mm[1] . '[' . $mm[2] . '_country]'; |
| 244 |
} else { |
| 245 |
$companion_name = $field_name . '_country'; |
| 246 |
} |
| 247 |
|
| 248 |
$flag_base = \defined('YATRA_PLUGIN_URL') ? YATRA_PLUGIN_URL . 'assets/img/flags/' : ''; |
| 249 |
?> |
| 250 |
<div class="yatra-phone-field" data-yatra-phone |
| 251 |
data-default-iso="<?php echo esc_attr($p_iso); ?>" |
| 252 |
data-flag-base="<?php echo esc_url($flag_base); ?>"> |
| 253 |
<button type="button" class="yatra-phone-country" aria-haspopup="listbox" aria-expanded="false" |
| 254 |
aria-label="<?php esc_attr_e('Select country dialing code', 'yatra'); ?>"> |
| 255 |
<img class="yatra-phone-flag" src="<?php echo esc_url($flag_base . strtolower($p_iso) . '.svg'); ?>" |
| 256 |
alt="" width="22" height="16" loading="lazy"> |
| 257 |
<span class="yatra-phone-dial">+<?php echo esc_html($p_dial); ?></span> |
| 258 |
<span class="yatra-phone-caret" aria-hidden="true"></span> |
| 259 |
</button> |
| 260 |
<input |
| 261 |
type="tel" |
| 262 |
class="yatra-phone-number" |
| 263 |
id="<?php echo $field_id; ?>" |
| 264 |
name="<?php echo $field_name; ?>" |
| 265 |
value="<?php echo esc_attr($p_national); ?>" |
| 266 |
placeholder="<?php echo esc_attr(yatra_translate_form_string($field['placeholder'] ?? '')); ?>" |
| 267 |
inputmode="tel" |
| 268 |
autocomplete="tel-national" |
| 269 |
<?php echo $required_attr; ?> |
| 270 |
> |
| 271 |
<input type="hidden" class="yatra-phone-iso" |
| 272 |
name="<?php echo esc_attr($companion_name); ?>" |
| 273 |
value="<?php echo esc_attr($p_iso); ?>"> |
| 274 |
</div> |
| 275 |
<?php |
| 276 |
} else { |
| 277 |
?> |
| 278 |
<input |
| 279 |
type="<?php echo esc_attr($field['type']); ?>" |
| 280 |
id="<?php echo $field_id; ?>" |
| 281 |
name="<?php echo $field_name; ?>" |
| 282 |
placeholder="<?php echo esc_attr(yatra_translate_form_string($field['placeholder'] ?? '')); ?>" |
| 283 |
<?php echo $required_attr; ?> |
| 284 |
value="<?php echo esc_attr($prefill_value); ?>" |
| 285 |
> |
| 286 |
<?php |
| 287 |
} |
| 288 |
break; |
| 289 |
} |
| 290 |
?> |
| 291 |
</div> |
| 292 |
<?php |
| 293 |
} |
| 294 |
} // End function_exists check for yatra_render_form_field |
| 295 |
|
| 296 |
/** |
| 297 |
* Render a form section with all its fields |
| 298 |
*/ |
| 299 |
if (!function_exists('yatra_render_form_section')) { |
| 300 |
function yatra_render_form_section($section_config, $prefix = '', $countries = []) { |
| 301 |
if (isset($section_config['enabled']) && !$section_config['enabled']) { |
| 302 |
return; |
| 303 |
} |
| 304 |
|
| 305 |
$fields = $section_config['fields'] ?? []; |
| 306 |
|
| 307 |
// Sort fields by order |
| 308 |
usort($fields, function($a, $b) { |
| 309 |
return ($a['order'] ?? 0) - ($b['order'] ?? 0); |
| 310 |
}); |
| 311 |
|
| 312 |
// Group fields by section (for subsections like dietary) |
| 313 |
$grouped_fields = []; |
| 314 |
$current_section = null; |
| 315 |
|
| 316 |
foreach ($fields as $field) { |
| 317 |
if (!empty($field['enabled'])) { |
| 318 |
$section = $field['section'] ?? 'main'; |
| 319 |
if (!isset($grouped_fields[$section])) { |
| 320 |
$grouped_fields[$section] = []; |
| 321 |
} |
| 322 |
$grouped_fields[$section][] = $field; |
| 323 |
} |
| 324 |
} |
| 325 |
?> |
| 326 |
<div class="yatra-booking-section"> |
| 327 |
<h2 class="yatra-section-title"><?php echo esc_html(yatra_translate_form_string($section_config['title'] ?? '')); ?></h2> |
| 328 |
<?php if (!empty($section_config['description'])) : ?> |
| 329 |
<p class="yatra-section-description"><?php echo esc_html(yatra_translate_form_string($section_config['description'])); ?></p> |
| 330 |
<?php endif; ?> |
| 331 |
|
| 332 |
<?php foreach ($grouped_fields as $section_key => $section_fields) : ?> |
| 333 |
<?php if ($section_key !== 'main') : ?> |
| 334 |
<div class="yatra-traveler-subsection"> |
| 335 |
<h4 class="yatra-subsection-title"> |
| 336 |
<?php |
| 337 |
switch ($section_key) { |
| 338 |
case 'passport': |
| 339 |
esc_html_e('Additional details', 'yatra'); |
| 340 |
break; |
| 341 |
case 'dietary_medical': |
| 342 |
esc_html_e('Dietary & Medical Requirements', 'yatra'); |
| 343 |
break; |
| 344 |
default: |
| 345 |
echo esc_html(ucwords(str_replace('_', ' ', $section_key))); |
| 346 |
} |
| 347 |
?> |
| 348 |
</h4> |
| 349 |
<?php endif; ?> |
| 350 |
|
| 351 |
<div class="yatra-form-row"> |
| 352 |
<?php foreach ($section_fields as $field) : ?> |
| 353 |
<?php yatra_render_form_field($field, $prefix, $countries); ?> |
| 354 |
<?php endforeach; ?> |
| 355 |
</div> |
| 356 |
|
| 357 |
<?php if ($section_key !== 'main') : ?> |
| 358 |
</div> |
| 359 |
<?php endif; ?> |
| 360 |
<?php endforeach; ?> |
| 361 |
</div> |
| 362 |
<?php |
| 363 |
} |
| 364 |
} // End function_exists check for yatra_render_form_section |
| 365 |
?> |
| 366 |
|
| 367 |
<!-- Hidden Fields --> |
| 368 |
<input type="hidden" name="trip_id" value="<?php echo esc_attr($trip_id); ?>"> |
| 369 |
<?php if (!empty($trip_slug)) : ?> |
| 370 |
<input type="hidden" name="trip_slug" value="<?php echo esc_attr($trip_slug); ?>"> |
| 371 |
<?php endif; ?> |
| 372 |
|
| 373 |
<?php if ($is_remaining_payment) : ?> |
| 374 |
<input type="hidden" name="is_remaining_payment" value="1"> |
| 375 |
<?php if (!empty($existing_booking_id)) : ?> |
| 376 |
<input type="hidden" name="existing_booking_id" value="<?php echo esc_attr($existing_booking_id); ?>"> |
| 377 |
<?php endif; ?> |
| 378 |
<?php if (!empty($booking_reference)) : ?> |
| 379 |
<input type="hidden" name="booking_reference" value="<?php echo esc_attr($booking_reference); ?>"> |
| 380 |
<?php endif; ?> |
| 381 |
<?php if ($remaining_amount !== null) : ?> |
| 382 |
<input type="hidden" name="remaining_amount" value="<?php echo esc_attr($remaining_amount); ?>"> |
| 383 |
<?php endif; ?> |
| 384 |
<?php if (!empty($booking->amount_paid)) : ?> |
| 385 |
<input type="hidden" name="amount_paid" value="<?php echo esc_attr($booking->amount_paid); ?>"> |
| 386 |
<?php endif; ?> |
| 387 |
<?php if (!empty($booking->total_amount)) : ?> |
| 388 |
<input type="hidden" name="total_amount" value="<?php echo esc_attr($booking->total_amount); ?>"> |
| 389 |
<?php endif; ?> |
| 390 |
<?php endif; ?> |
| 391 |
|
| 392 |
<?php if (!$is_remaining_payment) : ?> |
| 393 |
<!-- Contact Form Section --> |
| 394 |
<?php |
| 395 |
$contact_config = $form_config['contact_form'] ?? []; |
| 396 |
if (!empty($contact_config)) { |
| 397 |
yatra_render_form_section($contact_config, 'contact_', $countries); |
| 398 |
} |
| 399 |
?> |
| 400 |
|
| 401 |
<!-- Emergency Contact Section --> |
| 402 |
<?php |
| 403 |
$emergency_config = $form_config['emergency_contact_form'] ?? []; |
| 404 |
if (!empty($emergency_config) && (!isset($emergency_config['enabled']) || $emergency_config['enabled'])) { |
| 405 |
yatra_render_form_section($emergency_config, 'emergency_', $countries); |
| 406 |
} |
| 407 |
?> |
| 408 |
|
| 409 |
<!-- Traveler Information Section --> |
| 410 |
<?php |
| 411 |
$traveler_config = $form_config['traveler_form'] ?? []; |
| 412 |
?> |
| 413 |
<?php endif; ?> |
| 414 |
|
| 415 |
<?php |
| 416 |
$traveler_config = $form_config['traveler_form'] ?? []; |
| 417 |
$traveler_count = isset($total_travelers) ? max(1, (int)$total_travelers) : 1; |
| 418 |
|
| 419 |
// Check if we have traveler-based pricing info |
| 420 |
$pricing_type = isset($pricing_type) ? $pricing_type : 'regular'; |
| 421 |
$price_types = isset($price_types) ? $price_types : []; |
| 422 |
$traveler_counts = isset($traveler_counts) ? $traveler_counts : []; |
| 423 |
|
| 424 |
/** |
| 425 |
* Coerce JSON / serialized / object values to a list for foreach-safe iteration. |
| 426 |
* |
| 427 |
* @param mixed $value |
| 428 |
* @return array<int|string, mixed> |
| 429 |
*/ |
| 430 |
$yatra_normalize_booking_arrayish = static function ($value): array { |
| 431 |
if ($value === null || $value === false || $value === '') { |
| 432 |
return []; |
| 433 |
} |
| 434 |
if (is_array($value)) { |
| 435 |
return $value; |
| 436 |
} |
| 437 |
if ($value instanceof \stdClass) { |
| 438 |
return (array) $value; |
| 439 |
} |
| 440 |
if (is_string($value)) { |
| 441 |
$trim = trim($value); |
| 442 |
if ($trim === '') { |
| 443 |
return []; |
| 444 |
} |
| 445 |
$decoded = json_decode($value, true); |
| 446 |
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { |
| 447 |
return $decoded; |
| 448 |
} |
| 449 |
if (function_exists('maybe_unserialize')) { |
| 450 |
$un = maybe_unserialize($value); |
| 451 |
if (is_array($un)) { |
| 452 |
return $un; |
| 453 |
} |
| 454 |
} |
| 455 |
} |
| 456 |
|
| 457 |
return []; |
| 458 |
}; |
| 459 |
|
| 460 |
$price_types = $yatra_normalize_booking_arrayish($price_types); |
| 461 |
$traveler_counts = $yatra_normalize_booking_arrayish($traveler_counts); |
| 462 |
|
| 463 |
// Build traveler-to-category mapping for traveler-based pricing |
| 464 |
$traveler_category_map = []; |
| 465 |
if ($pricing_type === 'traveler_based' && !empty($price_types) && !empty($traveler_counts)) { |
| 466 |
$traveler_index = 1; |
| 467 |
foreach ($price_types as $index => $pt) { |
| 468 |
$pt = (object) $pt; |
| 469 |
$category_id = $pt->category_id ?? $index; |
| 470 |
$category_label = $pt->category_label ?? __('Traveler', 'yatra'); |
| 471 |
$count = isset($traveler_counts[$category_id]) ? (int) $traveler_counts[$category_id] : 0; |
| 472 |
|
| 473 |
for ($c = 1; $c <= $count; $c++) { |
| 474 |
$traveler_category_map[$traveler_index] = [ |
| 475 |
'category_id' => $category_id, |
| 476 |
'category_label' => $category_label, |
| 477 |
'category_index' => $c, |
| 478 |
]; |
| 479 |
$traveler_index++; |
| 480 |
} |
| 481 |
} |
| 482 |
} |
| 483 |
|
| 484 |
$price_candidates = [ |
| 485 |
isset($trip->price) ? (float) $trip->price : 0, |
| 486 |
isset($booking->session_price) ? (float) $booking->session_price : 0, |
| 487 |
isset($trip->sale_price) ? (float) $trip->sale_price : 0, |
| 488 |
isset($trip->original_price) ? (float) $trip->original_price : 0, |
| 489 |
]; |
| 490 |
|
| 491 |
$effective_trip_price = 0; |
| 492 |
foreach ($price_candidates as $candidate) { |
| 493 |
if ($candidate > 0) { |
| 494 |
$effective_trip_price = $candidate; |
| 495 |
break; |
| 496 |
} |
| 497 |
} |
| 498 |
|
| 499 |
$traveler_price_rows = []; |
| 500 |
$calculated_total = 0; |
| 501 |
|
| 502 |
if ($pricing_type === 'traveler_based' && !empty($price_types)) { |
| 503 |
foreach ($price_types as $index => $pt) { |
| 504 |
$pt = (object) $pt; |
| 505 |
$category_id = $pt->category_id ?? $index; |
| 506 |
$category_label = $pt->category_label ?? __('Traveler', 'yatra'); |
| 507 |
$category_price = isset($pt->effective_price) ? (float) $pt->effective_price : ($pt->sale_price ?? $pt->discounted_price ?? $pt->original_price ?? 0); |
| 508 |
$count = isset($traveler_counts[$category_id]) ? (int) $traveler_counts[$category_id] : ($index === 0 ? 1 : 0); |
| 509 |
// Single source of truth for the line amount (per-person × count, flat |
| 510 |
// per-group, or per-block group pricing). Defaults to the prior flat/ |
| 511 |
// multiply behaviour when group_overflow is absent. |
| 512 |
$pt_pricing_mode = $pt->pricing_mode ?? 'per_person'; |
| 513 |
$subtotal = \Yatra\Services\TripPricingService::categoryLineSubtotal($pt, $count, $category_price); |
| 514 |
|
| 515 |
$age_info = ''; |
| 516 |
if (isset($pt->age_min) || isset($pt->age_max)) { |
| 517 |
if (isset($pt->age_min) && isset($pt->age_max)) { |
| 518 |
/* translators: 1: minimum age, 2: maximum age. */ |
| 519 |
$age_info = sprintf(__('(Age %1$d-%2$d)', 'yatra'), $pt->age_min, $pt->age_max); |
| 520 |
} elseif (isset($pt->age_min)) { |
| 521 |
/* translators: %d: minimum age. */ |
| 522 |
$age_info = sprintf(__('(Age %d+)', 'yatra'), $pt->age_min); |
| 523 |
} else { |
| 524 |
/* translators: %d: maximum age. */ |
| 525 |
$age_info = sprintf(__('(Up to age %d)', 'yatra'), $pt->age_max); |
| 526 |
} |
| 527 |
} |
| 528 |
|
| 529 |
$traveler_price_rows[] = [ |
| 530 |
'category_id' => $category_id, |
| 531 |
'category_label' => $category_label, |
| 532 |
'category_price' => $category_price, |
| 533 |
'count' => $count, |
| 534 |
'subtotal' => $subtotal, |
| 535 |
'pricing_mode' => $pt_pricing_mode, |
| 536 |
'age_info' => $age_info, |
| 537 |
]; |
| 538 |
|
| 539 |
$calculated_total += $subtotal; |
| 540 |
|
| 541 |
if ($effective_trip_price <= 0 && $category_price > 0) { |
| 542 |
$effective_trip_price = $category_price; |
| 543 |
} |
| 544 |
} |
| 545 |
} |
| 546 |
|
| 547 |
if ($effective_trip_price <= 0) { |
| 548 |
$effective_trip_price = 0; |
| 549 |
} |
| 550 |
|
| 551 |
$initial_total_amount = $calculated_total > 0 |
| 552 |
? $calculated_total |
| 553 |
: ($effective_trip_price * max(1, (int) $total_travelers)); |
| 554 |
|
| 555 |
if ($initial_total_amount <= 0 && $effective_trip_price > 0) { |
| 556 |
$initial_total_amount = $effective_trip_price * max(1, (int) $total_travelers); |
| 557 |
} |
| 558 |
|
| 559 |
$initial_due_amount = $initial_total_amount; |
| 560 |
|
| 561 |
?> |
| 562 |
|
| 563 |
<?php |
| 564 |
// Honour the Traveler section's enable flag (Pro Dynamic Form module), mirroring |
| 565 |
// the Contact/Emergency sections. The default config has no `enabled` key, so an |
| 566 |
// un-customised/Free site treats the section as enabled and renders as before. |
| 567 |
$traveler_section_enabled = !isset($traveler_config['enabled']) || (bool) $traveler_config['enabled']; |
| 568 |
?> |
| 569 |
<?php if (!empty($traveler_config) && $traveler_section_enabled && !$is_remaining_payment) : ?> |
| 570 |
<div class="yatra-booking-section"> |
| 571 |
<h2 class="yatra-section-title"><?php echo esc_html(yatra_translate_form_string($traveler_config['title'] ?? '') ?: __('Traveler Information', 'yatra')); ?></h2> |
| 572 |
<?php if (!empty($traveler_config['description'])) : ?> |
| 573 |
<p class="yatra-section-description"><?php echo esc_html(yatra_translate_form_string($traveler_config['description'])); ?></p> |
| 574 |
<?php endif; ?> |
| 575 |
|
| 576 |
<div id="yatra-travelers-container"> |
| 577 |
<?php |
| 578 |
$traveler_fields = $traveler_config['fields'] ?? []; |
| 579 |
usort($traveler_fields, function($a, $b) { |
| 580 |
return ($a['order'] ?? 0) - ($b['order'] ?? 0); |
| 581 |
}); |
| 582 |
|
| 583 |
// Group fields by section |
| 584 |
$grouped_traveler_fields = []; |
| 585 |
foreach ($traveler_fields as $field) { |
| 586 |
if (!empty($field['enabled'])) { |
| 587 |
$section = $field['section'] ?? 'main'; |
| 588 |
if (!isset($grouped_traveler_fields[$section])) { |
| 589 |
$grouped_traveler_fields[$section] = []; |
| 590 |
} |
| 591 |
$grouped_traveler_fields[$section][] = $field; |
| 592 |
} |
| 593 |
} |
| 594 |
|
| 595 |
for ($i = 1; $i <= $traveler_count; $i++) : |
| 596 |
// Determine traveler label based on category if traveler-based pricing |
| 597 |
if (!empty($traveler_category_map[$i])) { |
| 598 |
$category_info = $traveler_category_map[$i]; |
| 599 |
$category_label = $category_info['category_label']; |
| 600 |
$category_index = $category_info['category_index']; |
| 601 |
/* translators: 1: traveler category label (e.g. Adult, Child), 2: sequential index within that category. */ |
| 602 |
$traveler_label = sprintf(__('%1$s %2$d', 'yatra'), $category_label, $category_index); |
| 603 |
if ($i === 1) { |
| 604 |
$traveler_label .= ' (' . __('Lead Traveler', 'yatra') . ')'; |
| 605 |
} |
| 606 |
} else { |
| 607 |
/* translators: %d: traveler sequence number. */ |
| 608 |
$traveler_label = ($i === 1) ? __('Traveler 1 (Lead Traveler)', 'yatra') : sprintf(__('Traveler %d', 'yatra'), $i); |
| 609 |
} |
| 610 |
|
| 611 |
// Fields targeted at the lead traveler (applies_to === 'lead') render |
| 612 |
// only for Traveler 1; everything else ('all' / unset) renders for |
| 613 |
// every traveler. Empty subsections are dropped so additional |
| 614 |
// travelers don't get an orphan heading. |
| 615 |
$traveler_grouped_fields = []; |
| 616 |
foreach ($grouped_traveler_fields as $sk => $sf) { |
| 617 |
$applicable = array_values(array_filter($sf, function ($f) use ($i) { |
| 618 |
return ($f['applies_to'] ?? 'all') !== 'lead' || $i === 1; |
| 619 |
})); |
| 620 |
if (!empty($applicable)) { |
| 621 |
$traveler_grouped_fields[$sk] = $applicable; |
| 622 |
} |
| 623 |
} |
| 624 |
?> |
| 625 |
<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; ?>> |
| 626 |
<div class="yatra-traveler-header"> |
| 627 |
<h3 class="yatra-traveler-title"><?php echo esc_html($traveler_label); ?></h3> |
| 628 |
<?php if ($i > 1) : ?> |
| 629 |
<span class="yatra-traveler-note"><?php esc_html_e('Additional traveler', 'yatra'); ?></span> |
| 630 |
<?php endif; ?> |
| 631 |
</div> |
| 632 |
|
| 633 |
<?php foreach ($traveler_grouped_fields as $section_key => $section_fields) : ?> |
| 634 |
<?php if ($section_key !== 'main') : ?> |
| 635 |
<div class="yatra-traveler-subsection"> |
| 636 |
<h4 class="yatra-subsection-title"> |
| 637 |
<?php |
| 638 |
switch ($section_key) { |
| 639 |
case 'passport': |
| 640 |
esc_html_e('Additional details', 'yatra'); |
| 641 |
break; |
| 642 |
case 'dietary_medical': |
| 643 |
esc_html_e('Dietary & Medical Requirements', 'yatra'); |
| 644 |
break; |
| 645 |
default: |
| 646 |
echo esc_html(ucwords(str_replace('_', ' ', $section_key))); |
| 647 |
} |
| 648 |
?> |
| 649 |
</h4> |
| 650 |
<?php endif; ?> |
| 651 |
|
| 652 |
<div class="yatra-form-row"> |
| 653 |
<?php foreach ($section_fields as $field) : |
| 654 |
$field_id = "traveler-{$i}-" . esc_attr($field['id']); |
| 655 |
$field_name = "travelers[{$i}][" . esc_attr($field['id']) . "]"; |
| 656 |
yatra_render_form_field($field, '', $countries, $field_name, $field_id); |
| 657 |
endforeach; ?> |
| 658 |
</div> |
| 659 |
|
| 660 |
<?php if ($section_key !== 'main') : ?> |
| 661 |
</div> |
| 662 |
<?php endif; ?> |
| 663 |
<?php endforeach; ?> |
| 664 |
</div> |
| 665 |
<?php endfor; ?> |
| 666 |
</div> |
| 667 |
</div> |
| 668 |
<?php endif; ?> |
| 669 |
|
| 670 |
<!-- Payment Method Section --> |
| 671 |
<?php |
| 672 |
/** |
| 673 |
* Filter to check if flexible payments module is enabled (Pro feature) |
| 674 |
* When enabled, deposit and partial payment options will be available |
| 675 |
*/ |
| 676 |
$flexible_payments_enabled = apply_filters('yatra_flexible_payments_enabled', false); |
| 677 |
|
| 678 |
/** |
| 679 |
* Filter to get payment method options. |
| 680 |
* |
| 681 |
* Pro module (FlexiblePayments) can add deposit/partial payment options here. |
| 682 |
* We pass `trip_id` so the Pro module can look up per-trip overrides |
| 683 |
* (trip.deposit_amount / trip.deposit_percentage) and expose the deposit |
| 684 |
* option even when the site-wide "deposit_required" flag is off — i.e. a |
| 685 |
* single trip can opt in to a custom deposit without enabling deposits for |
| 686 |
* the whole catalogue. |
| 687 |
*/ |
| 688 |
$payment_method_options = apply_filters('yatra_payment_method_options', [], [ |
| 689 |
'trip_id' => isset($trip_id) ? (int) $trip_id : 0, |
| 690 |
'deposit_required' => $deposit_required, |
| 691 |
'deposit_percentage' => $deposit_percentage, |
| 692 |
'partial_payment' => $partial_payment, |
| 693 |
'partial_payment_percentage' => $partial_payment_percentage, |
| 694 |
// Tour start (when a date is already chosen) → Pro hides deposit/partial for |
| 695 |
// tour-anchored payments when the tour is inside the balance-due window. |
| 696 |
'travel_date' => isset($booking->travel_date) ? (string) $booking->travel_date : '', |
| 697 |
]); |
| 698 |
|
| 699 |
$has_flexible_options = $flexible_payments_enabled && !empty($payment_method_options); |
| 700 |
?> |
| 701 |
<?php if (!$is_remaining_payment && $has_flexible_options) : ?> |
| 702 |
<div class="yatra-booking-section"> |
| 703 |
<h2 class="yatra-section-title"><?php esc_html_e('Payment Method', 'yatra'); ?></h2> |
| 704 |
|
| 705 |
<div class="yatra-payment-methods"> |
| 706 |
<label class="yatra-payment-option"> |
| 707 |
<input type="radio" name="payment_method" value="full" checked> |
| 708 |
<span class="yatra-payment-label"> |
| 709 |
<strong><?php esc_html_e('Pay in Full', 'yatra'); ?></strong> |
| 710 |
<span><?php esc_html_e('Pay the total amount now', 'yatra'); ?></span> |
| 711 |
</span> |
| 712 |
</label> |
| 713 |
|
| 714 |
<?php foreach ($payment_method_options as $option_key => $option) : ?> |
| 715 |
<label class="yatra-payment-option"> |
| 716 |
<input type="radio" name="payment_method" value="<?php echo esc_attr($option['value']); ?>"> |
| 717 |
<span class="yatra-payment-label"> |
| 718 |
<strong><?php echo esc_html($option['label']); ?></strong> |
| 719 |
<span><?php echo esc_html($option['description']); ?></span> |
| 720 |
</span> |
| 721 |
</label> |
| 722 |
<?php endforeach; ?> |
| 723 |
</div> |
| 724 |
</div> |
| 725 |
<?php endif; ?> |
| 726 |
|
| 727 |
<!-- Payment Gateway Section --> |
| 728 |
<?php |
| 729 |
// Always use the live registry list (same as BookingPageHandler). Do not intersect with $enabled_gateways |
| 730 |
// from older templates/sessions — that caused only stale gateways (e.g. Pay Later) to show. |
| 731 |
$display_gateways = []; |
| 732 |
if (class_exists('Yatra\PaymentGateways\PaymentGatewayRegistry')) { |
| 733 |
$registry = \Yatra\PaymentGateways\PaymentGatewayRegistry::getInstance(); |
| 734 |
foreach ($registry->getForCheckout() as $gateway) { |
| 735 |
if (!empty($gateway['id'])) { |
| 736 |
$display_gateways[$gateway['id']] = $gateway; |
| 737 |
} |
| 738 |
} |
| 739 |
} |
| 740 |
?> |
| 741 |
<?php if (!empty($display_gateways)) : ?> |
| 742 |
<div class="yatra-booking-section"> |
| 743 |
<h2 class="yatra-section-title"><?php esc_html_e('Select Payment Gateway', 'yatra'); ?></h2> |
| 744 |
|
| 745 |
<div class="yatra-gateway-options"> |
| 746 |
<?php |
| 747 |
$first = true; |
| 748 |
foreach ($display_gateways as $gateway_id => $gateway) : |
| 749 |
$icon = !empty($gateway['icon']) ? $gateway['icon'] : plugins_url('assets/images/payment-placeholder.png', dirname(__DIR__)); |
| 750 |
?> |
| 751 |
<div class="yatra-gateway-option-wrapper"> |
| 752 |
<label class="yatra-gateway-option"> |
| 753 |
<input type="radio" name="payment_gateway" value="<?php echo esc_attr($gateway_id); ?>" <?php checked($first); ?>> |
| 754 |
<span class="yatra-gateway-icon-wrap"> |
| 755 |
<img src="<?php echo esc_url($icon ?? ''); ?>" alt="<?php echo esc_attr($gateway['title'] ?? ''); ?>" class="yatra-gateway-icon"> |
| 756 |
</span> |
| 757 |
<span class="yatra-gateway-content"> |
| 758 |
<strong class="yatra-gateway-title"><?php echo esc_html($gateway['title']); ?></strong> |
| 759 |
<span class="yatra-gateway-desc"><?php echo esc_html($gateway['description']); ?></span> |
| 760 |
<?php if (empty($gateway['is_configured'])) : ?> |
| 761 |
<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> |
| 762 |
<?php endif; ?> |
| 763 |
</span> |
| 764 |
</label> |
| 765 |
<div class="yatra-gateway-extra" id="yatra-gateway-extra-<?php echo esc_attr($gateway_id); ?>" data-gateway="<?php echo esc_attr($gateway_id); ?>"></div> |
| 766 |
</div> |
| 767 |
<?php |
| 768 |
$first = false; |
| 769 |
endforeach; |
| 770 |
?> |
| 771 |
</div> |
| 772 |
</div> |
| 773 |
<?php endif; ?> |
| 774 |
|
| 775 |
<?php if (!$is_remaining_payment) : ?> |
| 776 |
<!-- Special Requests --> |
| 777 |
<div class="yatra-booking-section"> |
| 778 |
<h2 class="yatra-section-title"><?php esc_html_e('Special Requests', 'yatra'); ?></h2> |
| 779 |
<p class="yatra-section-description"><?php esc_html_e('Any special requests or notes for your trip (optional)', 'yatra'); ?></p> |
| 780 |
|
| 781 |
<div class="yatra-form-group yatra-field-full"> |
| 782 |
<textarea |
| 783 |
id="special-requests" |
| 784 |
name="special_requests" |
| 785 |
rows="4" |
| 786 |
placeholder="<?php esc_attr_e('E.g., dietary requirements, accessibility needs, celebration requests...', 'yatra'); ?>" |
| 787 |
></textarea> |
| 788 |
</div> |
| 789 |
</div> |
| 790 |
<?php endif; ?> |
| 791 |
|
| 792 |
<!-- Account Creation Section (only for guests) --> |
| 793 |
<?php |
| 794 |
$allow_guest_checkout = \Yatra\Services\SettingsService::isEnabled('allow_guest_checkout'); |
| 795 |
$require_login = \Yatra\Services\SettingsService::isEnabled('require_login'); |
| 796 |
// Account CREATION is gated by the same setting the backend enforces |
| 797 |
// (AuthController rejects registration when this is off). When registration is |
| 798 |
// disabled we never offer account-creation UI. |
| 799 |
$registration_enabled = \Yatra\Services\SettingsService::isEnabled('customer_registration'); |
| 800 |
|
| 801 |
// Show the account section only when it has something to render: login is |
| 802 |
// required, guest checkout is off (must authenticate), or registration is on |
| 803 |
// (optional/required account creation). When registration is OFF and guests are |
| 804 |
// allowed, there is nothing to show — proceed as a pure guest. |
| 805 |
if (!is_user_logged_in() && !$is_remaining_payment |
| 806 |
&& ($require_login || !$allow_guest_checkout || $registration_enabled)) : |
| 807 |
?> |
| 808 |
<div class="yatra-booking-section yatra-account-section"> |
| 809 |
<h2 class="yatra-section-title"><?php esc_html_e('Account', 'yatra'); ?></h2> |
| 810 |
|
| 811 |
<?php if ($require_login || (!$allow_guest_checkout && !$registration_enabled)) : ?> |
| 812 |
<!-- Login Required Message (login required, OR guests off with registration disabled) --> |
| 813 |
<div class="yatra-login-required-notice" style="background: #fef3c7; border: 1px solid #f59e0b; padding: 16px; border-radius: 8px; margin-bottom: 16px;"> |
| 814 |
<div style="display: flex; align-items: flex-start; gap: 12px;"> |
| 815 |
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#d97706" stroke-width="2" style="flex-shrink: 0;"> |
| 816 |
<circle cx="12" cy="12" r="10"></circle> |
| 817 |
<line x1="12" y1="8" x2="12" y2="12"></line> |
| 818 |
<line x1="12" y1="16" x2="12.01" y2="16"></line> |
| 819 |
</svg> |
| 820 |
<div> |
| 821 |
<p style="font-weight: 600; color: #92400e; margin: 0 0 8px 0;"><?php esc_html_e('Login Required', 'yatra'); ?></p> |
| 822 |
<p style="color: #a16207; margin: 0 0 12px 0; font-size: 14px;"> |
| 823 |
<?php echo $registration_enabled |
| 824 |
? esc_html__('You must be logged in to complete this booking. Please log in or create an account.', 'yatra') |
| 825 |
: esc_html__('You must be logged in to complete this booking. Please log in to continue.', 'yatra'); ?> |
| 826 |
</p> |
| 827 |
<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;"> |
| 828 |
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| 829 |
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path> |
| 830 |
<polyline points="10 17 15 12 10 7"></polyline> |
| 831 |
<line x1="15" y1="12" x2="3" y2="12"></line> |
| 832 |
</svg> |
| 833 |
<?php esc_html_e('Log In', 'yatra'); ?> |
| 834 |
</a> |
| 835 |
<?php if ($registration_enabled) : ?> |
| 836 |
<span style="margin: 0 12px; color: #a16207;"><?php esc_html_e('or', 'yatra'); ?></span> |
| 837 |
<a href="<?php echo esc_url(wp_registration_url()); ?>" style="color: #3b82f6; text-decoration: none; font-weight: 500;"> |
| 838 |
<?php esc_html_e('Create an Account', 'yatra'); ?> |
| 839 |
</a> |
| 840 |
<?php endif; ?> |
| 841 |
</div> |
| 842 |
</div> |
| 843 |
</div> |
| 844 |
<input type="hidden" name="login_required" value="1"> |
| 845 |
|
| 846 |
<?php elseif (!$allow_guest_checkout && $registration_enabled) : ?> |
| 847 |
<!-- Account Required - Must Create Account (registration enabled) --> |
| 848 |
<p class="yatra-section-description" style="margin-bottom: 16px;"> |
| 849 |
<?php esc_html_e('Please create an account to complete your booking. This allows you to manage your bookings and receive important updates.', 'yatra'); ?> |
| 850 |
</p> |
| 851 |
|
| 852 |
<div class="yatra-form-row"> |
| 853 |
<div class="yatra-form-group yatra-field-half"> |
| 854 |
<label for="account_password"> |
| 855 |
<?php esc_html_e('Password', 'yatra'); ?> <span class="required">*</span> |
| 856 |
</label> |
| 857 |
<input type="password" id="account_password" name="account_password" required minlength="8" |
| 858 |
placeholder="<?php esc_attr_e('Minimum 8 characters', 'yatra'); ?>"> |
| 859 |
</div> |
| 860 |
<div class="yatra-form-group yatra-field-half"> |
| 861 |
<label for="account_password_confirm"> |
| 862 |
<?php esc_html_e('Confirm Password', 'yatra'); ?> <span class="required">*</span> |
| 863 |
</label> |
| 864 |
<input type="password" id="account_password_confirm" name="account_password_confirm" required minlength="8" |
| 865 |
placeholder="<?php esc_attr_e('Re-enter password', 'yatra'); ?>"> |
| 866 |
</div> |
| 867 |
</div> |
| 868 |
<p class="yatra-field-hint" style="font-size: 13px; color: #6b7280; margin-top: 8px;"> |
| 869 |
<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;"> |
| 870 |
<circle cx="12" cy="12" r="10"></circle> |
| 871 |
<path d="M12 16v-4"></path> |
| 872 |
<path d="M12 8h.01"></path> |
| 873 |
</svg> |
| 874 |
<?php esc_html_e('Your email address will be used as your username.', 'yatra'); ?> |
| 875 |
</p> |
| 876 |
<input type="hidden" name="create_account" value="1"> |
| 877 |
|
| 878 |
<?php elseif ($registration_enabled) : ?> |
| 879 |
<!-- Guest Checkout Allowed - Optional Account Creation (registration enabled) --> |
| 880 |
<p class="yatra-section-description" style="margin-bottom: 16px;"> |
| 881 |
<?php esc_html_e('Create an account to easily manage your bookings and receive travel updates.', 'yatra'); ?> |
| 882 |
</p> |
| 883 |
|
| 884 |
<label class="yatra-checkbox-label" style="margin-bottom: 16px;"> |
| 885 |
<input type="checkbox" name="create_account" id="create-account" value="1"> |
| 886 |
<span><?php esc_html_e('Create an account for easier booking management', 'yatra'); ?></span> |
| 887 |
</label> |
| 888 |
|
| 889 |
<div class="yatra-account-fields" id="yatra-account-fields" style="display: none;"> |
| 890 |
<div class="yatra-form-row"> |
| 891 |
<div class="yatra-form-group yatra-field-half"> |
| 892 |
<label for="account_password"> |
| 893 |
<?php esc_html_e('Password', 'yatra'); ?> <span class="required">*</span> |
| 894 |
</label> |
| 895 |
<input type="password" id="account_password" name="account_password" minlength="8" |
| 896 |
autocomplete="new-password" |
| 897 |
placeholder="<?php esc_attr_e('Minimum 8 characters', 'yatra'); ?>"> |
| 898 |
</div> |
| 899 |
<div class="yatra-form-group yatra-field-half"> |
| 900 |
<label for="account_password_confirm"> |
| 901 |
<?php esc_html_e('Confirm Password', 'yatra'); ?> <span class="required">*</span> |
| 902 |
</label> |
| 903 |
<input type="password" id="account_password_confirm" name="account_password_confirm" minlength="8" |
| 904 |
autocomplete="new-password" |
| 905 |
placeholder="<?php esc_attr_e('Re-enter password', 'yatra'); ?>"> |
| 906 |
</div> |
| 907 |
</div> |
| 908 |
<p class="yatra-field-hint" style="font-size: 13px; color: #6b7280; margin-top: 8px;"> |
| 909 |
<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;"> |
| 910 |
<circle cx="12" cy="12" r="10"></circle> |
| 911 |
<path d="M12 16v-4"></path> |
| 912 |
<path d="M12 8h.01"></path> |
| 913 |
</svg> |
| 914 |
<?php esc_html_e('Your email address will be used as your username.', 'yatra'); ?> |
| 915 |
</p> |
| 916 |
</div> |
| 917 |
<?php endif; ?> |
| 918 |
</div> |
| 919 |
<?php elseif (is_user_logged_in()) : ?> |
| 920 |
<!-- User is logged in --> |
| 921 |
<div class="yatra-booking-section yatra-logged-in-notice"> |
| 922 |
<div style="display: flex; align-items: center; gap: 12px; padding: 12px 16px; background: #ecfdf5; border: 1px solid #10b981; border-radius: 8px;"> |
| 923 |
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="2"> |
| 924 |
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path> |
| 925 |
<polyline points="22 4 12 14.01 9 11.01"></polyline> |
| 926 |
</svg> |
| 927 |
<div> |
| 928 |
<span style="font-weight: 500; color: #065f46;"> |
| 929 |
<?php |
| 930 |
$current_user = wp_get_current_user(); |
| 931 |
printf( |
| 932 |
/* translators: %s: User display name */ |
| 933 |
esc_html__('Logged in as %s', 'yatra'), |
| 934 |
'<strong>' . esc_html($current_user->display_name) . '</strong>' |
| 935 |
); |
| 936 |
?> |
| 937 |
</span> |
| 938 |
<a href="<?php echo esc_url(wp_logout_url(get_permalink())); ?>" style="margin-left: 12px; color: #059669; font-size: 13px;"> |
| 939 |
<?php esc_html_e('Log out', 'yatra'); ?> |
| 940 |
</a> |
| 941 |
</div> |
| 942 |
</div> |
| 943 |
</div> |
| 944 |
<?php endif; ?> |
| 945 |
|
| 946 |
<!-- Terms & Conditions --> |
| 947 |
<div class="yatra-booking-section"> |
| 948 |
<div class="yatra-terms-container"> |
| 949 |
<?php |
| 950 |
$termsPageId = 0; |
| 951 |
$privacyPageId = 0; |
| 952 |
if (class_exists('\\Yatra\\Services\\SettingsService')) { |
| 953 |
$termsPageId = \Yatra\Services\SettingsService::getInt('terms_page_id', 0); |
| 954 |
$privacyPageId = \Yatra\Services\SettingsService::getInt('privacy_policy_page_id', 0); |
| 955 |
} else { |
| 956 |
$termsPageId = (int) get_option('yatra_terms_page_id', 0); |
| 957 |
$privacyPageId = (int) get_option('yatra_privacy_policy_page_id', 0); |
| 958 |
} |
| 959 |
|
| 960 |
$termsUrl = $termsPageId > 0 ? get_permalink($termsPageId) : ''; |
| 961 |
$privacyUrl = $privacyPageId > 0 ? get_permalink($privacyPageId) : ''; |
| 962 |
if ($privacyUrl === '' && function_exists('get_privacy_policy_url')) { |
| 963 |
$privacyUrl = (string) get_privacy_policy_url(); |
| 964 |
} |
| 965 |
?> |
| 966 |
|
| 967 |
<label class="yatra-checkbox-label"> |
| 968 |
<input type="checkbox" name="accept_terms" id="accept-terms" required> |
| 969 |
<span> |
| 970 |
<?php |
| 971 |
printf( |
| 972 |
/* translators: %s: Terms and Conditions link */ |
| 973 |
esc_html__('I have read and agree to the %s', 'yatra'), |
| 974 |
$termsUrl |
| 975 |
? '<a href="' . esc_url($termsUrl) . '" target="_blank" rel="noopener noreferrer">' . esc_html__('Terms and Conditions', 'yatra') . '</a>' |
| 976 |
: '<span>' . esc_html__('Terms and Conditions', 'yatra') . '</span>' |
| 977 |
); |
| 978 |
?> |
| 979 |
<span class="required">*</span> |
| 980 |
</span> |
| 981 |
</label> |
| 982 |
|
| 983 |
<label class="yatra-checkbox-label"> |
| 984 |
<input type="checkbox" name="accept_privacy" id="accept-privacy" required> |
| 985 |
<span> |
| 986 |
<?php |
| 987 |
printf( |
| 988 |
/* translators: %s: Privacy Policy link */ |
| 989 |
esc_html__('I agree to the %s and consent to my data being processed', 'yatra'), |
| 990 |
$privacyUrl |
| 991 |
? '<a href="' . esc_url($privacyUrl) . '" target="_blank" rel="noopener noreferrer">' . esc_html__('Privacy Policy', 'yatra') . '</a>' |
| 992 |
: '<span>' . esc_html__('Privacy Policy', 'yatra') . '</span>' |
| 993 |
); |
| 994 |
?> |
| 995 |
<span class="required">*</span> |
| 996 |
</span> |
| 997 |
</label> |
| 998 |
|
| 999 |
<label class="yatra-checkbox-label"> |
| 1000 |
<input type="checkbox" name="subscribe_newsletter" id="subscribe-newsletter"> |
| 1001 |
<span><?php esc_html_e('Subscribe to our newsletter for travel tips and exclusive offers', 'yatra'); ?></span> |
| 1002 |
</label> |
| 1003 |
</div> |
| 1004 |
</div> |
| 1005 |
|