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 — pulls from the canonical FormatHelper source so every
// dropdown (admin, public booking, Pro modules) shows the same full
// ISO-3166-1 list. Operators that want a "popular countries" subset
// or custom ordering apply the `yatra_countries_list` filter.
$countries = \Yatra\Helpers\FormatHelper::getCountries();
/**
* 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)) {
/* translators: 1: minimum age, 2: maximum age. */
$age_info = sprintf(__('(Age %1$d-%2$d)', 'yatra'), $pt->age_min, $pt->age_max);
} elseif (isset($pt->age_min)) {
/* translators: %d: minimum age. */
$age_info = sprintf(__('(Age %d+)', 'yatra'), $pt->age_min);
} else {
/* translators: %d: maximum age. */
$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) . ''
);
?>