Booking Form
* Dynamic form customization requires the Dynamic Form Field module (Pro).
*
* @package Yatra
*
* Expected variables:
* - $trip_id
* - $trip_slug (optional)
* - $total_travelers
* - $deposit_required
* - $deposit_percentage
* - $partial_payment
* - $partial_payment_percentage
* - $enabled_gateways
*
* Form Configuration Structure:
* - contact_form: Lead traveler contact information (prefix: contact_)
* - emergency_contact_form: Emergency contact details (prefix: emergency_)
* - traveler_form: Individual traveler details (array format: travelers[1][field_id])
*/
if (!defined('ABSPATH')) {
exit;
}
// Check if Dynamic Form Field module is enabled (Pro feature)
$is_dynamic_form_enabled = apply_filters('yatra_dynamic_form_field_enabled', false);
// Get form configuration - returns default config if module disabled, custom config if enabled
$form_config = yatra_get_booking_form_config();
// Country list for country type fields
$countries = [
'AF' => 'Afghanistan', 'AL' => 'Albania', 'DZ' => 'Algeria', 'AR' => 'Argentina',
'AU' => 'Australia', 'AT' => 'Austria', 'BD' => 'Bangladesh', 'BE' => 'Belgium',
'BR' => 'Brazil', 'BT' => 'Bhutan', 'CA' => 'Canada', 'CN' => 'China',
'CO' => 'Colombia', 'CZ' => 'Czech Republic', 'DK' => 'Denmark', 'EG' => 'Egypt',
'FI' => 'Finland', 'FR' => 'France', 'DE' => 'Germany', 'GR' => 'Greece',
'HK' => 'Hong Kong', 'HU' => 'Hungary', 'IS' => 'Iceland', 'IN' => 'India',
'ID' => 'Indonesia', 'IE' => 'Ireland', 'IL' => 'Israel', 'IT' => 'Italy',
'JP' => 'Japan', 'KE' => 'Kenya', 'KR' => 'South Korea', 'MY' => 'Malaysia',
'MV' => 'Maldives', 'MX' => 'Mexico', 'NL' => 'Netherlands', 'NZ' => 'New Zealand',
'NP' => 'Nepal', 'NO' => 'Norway', 'PK' => 'Pakistan', 'PE' => 'Peru',
'PH' => 'Philippines', 'PL' => 'Poland', 'PT' => 'Portugal', 'RO' => 'Romania',
'RU' => 'Russia', 'SA' => 'Saudi Arabia', 'SG' => 'Singapore', 'ZA' => 'South Africa',
'ES' => 'Spain', 'LK' => 'Sri Lanka', 'SE' => 'Sweden', 'CH' => 'Switzerland',
'TW' => 'Taiwan', 'TH' => 'Thailand', 'TR' => 'Turkey', 'AE' => 'United Arab Emirates',
'GB' => 'United Kingdom', 'US' => 'United States', 'VN' => 'Vietnam'
];
/**
* Render a single form field based on configuration
*
* @param array $field Field configuration
* @param string $prefix Field name prefix (e.g., 'contact_', 'emergency_')
* @param array $countries Country list for country fields
* @param string $custom_name Optional custom field name (for array-style names like travelers[1][field_id])
* @param string $custom_id Optional custom field ID
*/
if (!function_exists('yatra_render_form_field')) {
function yatra_render_form_field($field, $prefix = '', $countries = [], $custom_name = null, $custom_id = null) {
if (empty($field['enabled'])) {
return;
}
$field_id = $custom_id ? esc_attr($custom_id) : esc_attr($prefix . $field['id']);
$field_name = $custom_name ? esc_attr($custom_name) : esc_attr($prefix . $field['id']);
$required = !empty($field['required']);
$required_attr = $required ? 'required' : '';
$required_star = $required ? '*' : '';
$prefill_value = '';
if ($custom_name === null && $prefix === 'contact_') {
global $booking;
if (isset($booking) && is_object($booking)) {
$prop = 'contact_' . ($field['id'] ?? '');
if (!empty($prop) && isset($booking->{$prop}) && $booking->{$prop} !== null && $booking->{$prop} !== '') {
$prefill_value = (string) $booking->{$prop};
}
}
}
$width_class = '';
if (!empty($field['width'])) {
switch ($field['width']) {
case 'half':
$width_class = 'yatra-field-half';
break;
case 'third':
$width_class = 'yatra-field-third';
break;
default:
$width_class = 'yatra-field-full';
}
}
$field_type = $field['type'] ?? 'text';
?>
value=""
>
value=""
>
amount_paid)) : ?>
total_amount)) : ?>
*/
$yatra_normalize_booking_arrayish = static function ($value): array {
if ($value === null || $value === false || $value === '') {
return [];
}
if (is_array($value)) {
return $value;
}
if ($value instanceof \stdClass) {
return (array) $value;
}
if (is_string($value)) {
$trim = trim($value);
if ($trim === '') {
return [];
}
$decoded = json_decode($value, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
return $decoded;
}
if (function_exists('maybe_unserialize')) {
$un = maybe_unserialize($value);
if (is_array($un)) {
return $un;
}
}
}
return [];
};
$price_types = $yatra_normalize_booking_arrayish($price_types);
$traveler_counts = $yatra_normalize_booking_arrayish($traveler_counts);
// Build traveler-to-category mapping for traveler-based pricing
$traveler_category_map = [];
if ($pricing_type === 'traveler_based' && !empty($price_types) && !empty($traveler_counts)) {
$traveler_index = 1;
foreach ($price_types as $index => $pt) {
$pt = (object) $pt;
$category_id = $pt->category_id ?? $index;
$category_label = $pt->category_label ?? __('Traveler', 'yatra');
$count = isset($traveler_counts[$category_id]) ? (int) $traveler_counts[$category_id] : 0;
for ($c = 1; $c <= $count; $c++) {
$traveler_category_map[$traveler_index] = [
'category_id' => $category_id,
'category_label' => $category_label,
'category_index' => $c,
];
$traveler_index++;
}
}
}
$price_candidates = [
isset($trip->price) ? (float) $trip->price : 0,
isset($booking->session_price) ? (float) $booking->session_price : 0,
isset($trip->sale_price) ? (float) $trip->sale_price : 0,
isset($trip->original_price) ? (float) $trip->original_price : 0,
];
$effective_trip_price = 0;
foreach ($price_candidates as $candidate) {
if ($candidate > 0) {
$effective_trip_price = $candidate;
break;
}
}
$traveler_price_rows = [];
$calculated_total = 0;
if ($pricing_type === 'traveler_based' && !empty($price_types)) {
foreach ($price_types as $index => $pt) {
$pt = (object) $pt;
$category_id = $pt->category_id ?? $index;
$category_label = $pt->category_label ?? __('Traveler', 'yatra');
$category_price = isset($pt->effective_price) ? (float) $pt->effective_price : ($pt->sale_price ?? $pt->discounted_price ?? $pt->original_price ?? 0);
$count = isset($traveler_counts[$category_id]) ? (int) $traveler_counts[$category_id] : ($index === 0 ? 1 : 0);
$subtotal = $category_price * $count;
$age_info = '';
if (isset($pt->age_min) || isset($pt->age_max)) {
if (isset($pt->age_min) && isset($pt->age_max)) {
$age_info = sprintf(__('(Age %d-%d)', 'yatra'), $pt->age_min, $pt->age_max);
} elseif (isset($pt->age_min)) {
$age_info = sprintf(__('(Age %d+)', 'yatra'), $pt->age_min);
} else {
$age_info = sprintf(__('(Up to age %d)', 'yatra'), $pt->age_max);
}
}
$traveler_price_rows[] = [
'category_id' => $category_id,
'category_label' => $category_label,
'category_price' => $category_price,
'count' => $count,
'subtotal' => $subtotal,
'age_info' => $age_info,
];
$calculated_total += $subtotal;
if ($effective_trip_price <= 0 && $category_price > 0) {
$effective_trip_price = $category_price;
}
}
}
if ($effective_trip_price <= 0) {
$effective_trip_price = 0;
}
$initial_total_amount = $calculated_total > 0
? $calculated_total
: ($effective_trip_price * max(1, (int) $total_travelers));
if ($initial_total_amount <= 0 && $effective_trip_price > 0) {
$initial_total_amount = $effective_trip_price * max(1, (int) $total_travelers);
}
$initial_due_amount = $initial_total_amount;
?>
isset($trip_id) ? (int) $trip_id : 0,
'deposit_required' => $deposit_required,
'deposit_percentage' => $deposit_percentage,
'partial_payment' => $partial_payment,
'partial_payment_percentage' => $partial_payment_percentage,
]);
$has_flexible_options = $flexible_payments_enabled && !empty($payment_method_options);
?>
getForCheckout() as $gateway) {
if (!empty($gateway['id'])) {
$display_gateways[$gateway['id']] = $gateway;
}
}
}
?>
$gateway) :
$icon = !empty($gateway['icon']) ? $gateway['icon'] : plugins_url('assets/images/payment-placeholder.png', dirname(__DIR__));
?>
' . esc_html($current_user->display_name) . ''
);
?>