| @@ -45,8 +45,10 @@ | ||
| 45 | 45 | /** Primary brand color (hex) for trip/booking/listing frontend — see FrontendThemeCss */ |
| 46 | 46 | 'frontend_primary_color' => '#3b82f6', |
| 47 | 47 | /** Max width for Yatra trip/booking/listing containers (CSS length). Empty = theme.json / content width / filter. */ |
| 48 | 48 | 'frontend_container_max_width' => '', |
| 49 | + /** Trip listing card density: 'standard' | 'compact_mobile' | 'compact_all'. */ | |
| 50 | + 'frontend_listing_card_layout' => 'standard', | |
| 49 | 51 | |
| 50 | 52 | // Booking |
| 51 | 53 | 'booking_base' => 'book', |
| 52 | 54 | 'use_booking_page' => false, |
| @@ -55,8 +57,13 @@ | ||
| 55 | 57 | 'privacy_policy_page_id' => 0, |
| 56 | 58 | 'enable_guest_booking' => true, |
| 57 | 59 | 'booking_confirmation' => true, |
| 58 | 60 | 'auto_confirm_bookings' => false, |
| 61 | + // Auto-confirm mode: none | online | all. Default 'online' (successful | |
| 62 | + // online payment => confirmed). Behaviour is resolved via | |
| 63 | + // yatra_get_auto_confirm_mode(), which uses the stored mode when set and | |
| 64 | + // otherwise derives from the legacy auto_confirm_bookings boolean. | |
| 65 | + 'auto_confirm_mode' => 'online', | |
| 59 | 66 | 'require_login' => false, |
| 60 | 67 | 'allow_guest_checkout' => true, |
| 61 | 68 | // Hold guest bookings in `pending_verification` status until |
| 62 | 69 | // the customer clicks a magic link sent to the email they |
| @@ -74,8 +81,12 @@ | ||
| 74 | 81 | // gracefully by skipping the cancellation paragraph or |
| 75 | 82 | // falling back to the per-trip cancellation_policy. |
| 76 | 83 | 'booking_expiry_hours' => 24, |
| 77 | 84 | 'booking_reminder_days' => 3, |
| 85 | + // Storefront booking horizon in months. 12 is the value that was | |
| 86 | + // hard-coded before it became configurable, so a site that never | |
| 87 | + // touches it behaves exactly as before. See yatra_get_availability_horizon_months(). | |
| 88 | + 'availability_horizon_months' => 12, | |
| 78 | 89 | 'allow_waitlist' => true, |
| 79 | 90 | 'waitlist_auto_confirm' => false, |
| 80 | 91 | // Pro: when enabled, the single-trip date_specific mode renders a |
| 81 | 92 | // <select> of available departure dates instead of the flatpickr |
| @@ -160,9 +171,18 @@ | ||
| 160 | 171 | 'email_template_admin_scheduled_payment_failed' => true, |
| 161 | 172 | 'email_template_enquiry_received' => true, |
| 162 | 173 | 'email_template_enquiry_admin' => true, |
| 163 | 174 | 'email_template_enquiry_response' => true, |
| 164 | - 'email_template_review_request' => true, | |
| 175 | + // Off by default, unlike the other templates. A review request is the | |
| 176 | + // one transactional email that is not a response to something the | |
| 177 | + // customer just did, and several jurisdictions treat it as advertising | |
| 178 | + // rather than service mail — in Germany the BGH (VI ZR 225/17) holds it | |
| 179 | + // needs prior consent, and the existing-customer exemption in | |
| 180 | + // §7 Abs. 3 UWG does not cover it. Shipping it on would have every new | |
| 181 | + // site mailing customers for consent it has not collected, so the | |
| 182 | + // operator turns it on once they have decided how they collect it. | |
| 183 | + // Sites that already have it on are untouched. | |
| 184 | + 'email_template_review_request' => false, | |
| 165 | 185 | 'email_template_abandoned_booking_recovery_first' => true, |
| 166 | 186 | 'email_template_abandoned_booking_recovery_second' => true, |
| 167 | 187 | 'email_template_abandoned_booking_recovery_final' => true, |
| 168 | 188 | // Customer-registration gate (AuthController::register reads |
| @@ -207,9 +227,13 @@ | ||
| 207 | 227 | 'require_booking_to_review' => false, |
| 208 | 228 | 'auto_approve_reviews' => false, |
| 209 | 229 | 'enable_review_moderation' => true, |
| 210 | 230 | 'minimum_rating' => 1, |
| 211 | - 'review_reminder_days' => 7, | |
| 231 | + 'review_reminder_days' => 3, | |
| 232 | + // Never ask about a trip that ended longer ago than this. The | |
| 233 | + // reminder is anchored to the tour's end date, so a backlog of | |
| 234 | + // bookings completed late is skipped rather than mailed in bulk. | |
| 235 | + 'review_reminder_max_age_days' => 14, | |
| 212 | 236 | |
| 213 | 237 | // Tax |
| 214 | 238 | 'enable_tax' => false, |
| 215 | 239 | 'tax_rate' => 0, |
| @@ -233,8 +257,15 @@ | ||
| 233 | 257 | 'trip_category_base' => 'trip-category', |
| 234 | 258 | |
| 235 | 259 | // SEO |
| 236 | 260 | 'enable_sitemap' => true, |
| 261 | + // Which Yatra content types appear in /yatra-sitemap.xml. Defaults to | |
| 262 | + // every type, so a site that never touches this keeps today's sitemap. | |
| 263 | + 'sitemap_types' => ['archive', 'trip', 'destination', 'activity', 'category'], | |
| 264 | + // Opt-in, and deliberately separate from the list above: dropping a type | |
| 265 | + // from the sitemap is housekeeping, while noindex de-indexes pages that | |
| 266 | + // may currently rank. That should never happen as a side effect. | |
| 267 | + 'sitemap_noindex_excluded' => false, | |
| 237 | 268 | |
| 238 | 269 | // Advanced |
| 239 | 270 | 'enable_debug_mode' => false, |
| 240 | 271 | 'delete_data_on_uninstall' => false, |
| @@ -318,12 +349,17 @@ | ||
| 318 | 349 | } |
| 319 | 350 | |
| 320 | 351 | /** |
| 321 | 352 | * Get booking form configuration (merged with defaults) |
| 322 | - * | |
| 353 | + * | |
| 354 | + * @param int|null $tripId Trip being booked. When given, Pro's Dynamic Form | |
| 355 | + * Field module resolves each section's per-trip | |
| 356 | + * conditions for that trip (title, description and | |
| 357 | + * field list); without it the full config is | |
| 358 | + * returned, conditions included (the Settings editor). | |
| 323 | 359 | * @return array |
| 324 | 360 | */ |
| 325 | - public static function getBookingFormConfig(): array | |
| 361 | + public static function getBookingFormConfig(?int $tripId = null): array | |
| 326 | 362 | { |
| 327 | 363 | $saved_config = self::get('booking_form_config', []); |
| 328 | 364 | $default_config = self::getDefaultBookingFormConfig(); |
| 329 | 365 | |
| @@ -328,9 +364,9 @@ | ||
| 328 | 364 | $default_config = self::getDefaultBookingFormConfig(); |
| 329 | 365 | |
| 330 | 366 | // If no saved config, return defaults (Pro may filter) |
| 331 | 367 | if (empty($saved_config)) { |
| 332 | - return apply_filters('yatra_booking_form_config', $default_config); | |
| 368 | + return apply_filters('yatra_booking_form_config', $default_config, $tripId); | |
| 333 | 369 | } |
| 334 | 370 | |
| 335 | 371 | // Merge saved over defaults. IMPORTANT: `fields` is a positional list, |
| 336 | 372 | // so a naive array_replace_recursive() merges field-by-INDEX — which |
| @@ -420,9 +456,9 @@ | ||
| 420 | 456 | $merged[$form_type] = $saved_section; |
| 421 | 457 | } |
| 422 | 458 | } |
| 423 | 459 | |
| 424 | - return apply_filters('yatra_booking_form_config', $merged); | |
| 460 | + return apply_filters('yatra_booking_form_config', $merged, $tripId); | |
| 425 | 461 | } |
| 426 | 462 | |
| 427 | 463 | private static function isEmailIdentityKey(string $key): bool |
| 428 | 464 | { |