| 1 |
<?php |
| 2 |
|
| 3 |
declare(strict_types=1); |
| 4 |
|
| 5 |
namespace Yatra\Services; |
| 6 |
|
| 7 |
use Yatra\Repositories\TripRepository; |
| 8 |
|
| 9 |
/** |
| 10 |
* Sample merge-tag data for email previews and tests. |
| 11 |
* Trip context: pass {@see self::forTemplateKey()} a trip ID to hydrate trip_* tags from the database. |
| 12 |
* |
| 13 |
* @see apply_filters('yatra_email_template_preview_variables', ...) |
| 14 |
* @see apply_filters('yatra_email_template_trip_variables', ...) |
| 15 |
*/ |
| 16 |
final class EmailTemplateSampleData |
| 17 |
{ |
| 18 |
/** |
| 19 |
* @param int|null $tripId Optional Yatra trip ID to merge real trip_name, trip_url, trip_id |
| 20 |
* @return array<string, string> |
| 21 |
*/ |
| 22 |
public static function forTemplateKey(string $templateKey, ?int $tripId = null): array |
| 23 |
{ |
| 24 |
$vars = self::baseSamples(); |
| 25 |
if ($tripId !== null && $tripId > 0) { |
| 26 |
$vars = self::mergeTripContext($tripId, $vars); |
| 27 |
} |
| 28 |
|
| 29 |
if ($templateKey === 'trip_consent_request') { |
| 30 |
$vars['recipient_name'] = $vars['customer_name'] ?? __('Alex Traveler', 'yatra'); |
| 31 |
$vars['form_name'] = __('Trip liability & release', 'yatra'); |
| 32 |
$vars['consent_link'] = home_url('/trip-consent/preview-token/'); |
| 33 |
$vars['expiry_notice_html'] = '<strong>' . esc_html__('This link expires soon.', 'yatra') . '</strong> ' |
| 34 |
. esc_html__('Request a new email from the operator if needed.', 'yatra'); |
| 35 |
$vars['consent_test_notice_html'] = ''; |
| 36 |
} |
| 37 |
|
| 38 |
if ($templateKey === 'customer_email_verification') { |
| 39 |
$previewTok = defined('YATRA_EMAIL_VERIFICATION_PREVIEW_TOKEN') |
| 40 |
? (string) YATRA_EMAIL_VERIFICATION_PREVIEW_TOKEN |
| 41 |
: 'preview-verify-token'; |
| 42 |
$vars['verification_link'] = function_exists('yatra_get_email_verification_url') |
| 43 |
? yatra_get_email_verification_url($previewTok) |
| 44 |
: home_url('/?yatra_verify_email=' . rawurlencode($previewTok)); |
| 45 |
$vars['intro_paragraph'] = __('Thank you for registering. Click the button below to verify your email and activate your account.', 'yatra'); |
| 46 |
$vars['footer_note'] = __('If you did not create an account, you can ignore this email.', 'yatra'); |
| 47 |
$vars['expiry_notice_html'] = esc_html( |
| 48 |
sprintf( |
| 49 |
/* translators: %d: hours until link expiry */ |
| 50 |
__('This verification link expires in %d hours for your security.', 'yatra'), |
| 51 |
24 |
| 52 |
) |
| 53 |
); |
| 54 |
} |
| 55 |
|
| 56 |
/** @var array<string, string> $filtered */ |
| 57 |
$filtered = apply_filters('yatra_email_template_preview_variables', $vars, $templateKey, $tripId); |
| 58 |
|
| 59 |
return TransactionalEmailTemplateService::mergeTemplateVariables($filtered); |
| 60 |
} |
| 61 |
|
| 62 |
/** |
| 63 |
* @return array<string, string> |
| 64 |
*/ |
| 65 |
private static function baseSamples(): array |
| 66 |
{ |
| 67 |
$currency = SettingsService::getCurrency(); |
| 68 |
$travelSample = date_i18n(get_option('date_format'), strtotime('+14 days')); |
| 69 |
$specialSample = __('Late check-in after 10pm if possible.', 'yatra'); |
| 70 |
|
| 71 |
return [ |
| 72 |
'customer_name' => __('Alex Traveler', 'yatra'), |
| 73 |
'customer_first_name' => 'Alex', |
| 74 |
'customer_last_name' => __('Traveler', 'yatra'), |
| 75 |
'customer_email' => 'alex@example.com', |
| 76 |
'customer_phone' => '+1 555 0100', |
| 77 |
'booking_reference' => 'YTR-PREVIEW-001', |
| 78 |
'booking_id' => '42', |
| 79 |
'trip_id' => '101', |
| 80 |
'trip_name' => __('Sample Mountain Trek', 'yatra'), |
| 81 |
'travel_date' => $travelSample, |
| 82 |
'travelers_count' => '2', |
| 83 |
'total_amount_formatted' => yatra_format_price(2499.0, $currency), |
| 84 |
'amount_due_formatted' => yatra_format_price(499.0, $currency), |
| 85 |
// Aliases for the same monetary values — keep the preview |
| 86 |
// consistent regardless of which spelling the template |
| 87 |
// uses ({{total_amount}} vs {{total_amount_formatted}}, |
| 88 |
// {{balance_due}} vs {{amount_due_formatted}}, etc.). |
| 89 |
'total_amount' => yatra_format_price(2499.0, $currency), |
| 90 |
'balance_due' => yatra_format_price(499.0, $currency), |
| 91 |
'amount_due' => yatra_format_price(499.0, $currency), |
| 92 |
'amount_paid' => yatra_format_price(2000.0, $currency), |
| 93 |
'amount_paid_formatted' => yatra_format_price(2000.0, $currency), |
| 94 |
'currency' => $currency, |
| 95 |
'booking_status' => __('confirmed', 'yatra'), |
| 96 |
'payment_status' => __('pending', 'yatra'), |
| 97 |
'intro_paragraph' => __('Thank you for your booking. This preview uses sample data.', 'yatra'), |
| 98 |
'details_html' => '<p><strong>' . esc_html__('Note', 'yatra') . ':</strong> ' . esc_html__('Optional line items appear here.', 'yatra') . '</p>', |
| 99 |
'footer_note' => __('We look forward to hosting you.', 'yatra'), |
| 100 |
'payment_amount_formatted' => yatra_format_price(500.0, $currency), |
| 101 |
'payment_method' => __('Credit card', 'yatra'), |
| 102 |
'transaction_id' => 'txn_preview_001', |
| 103 |
'reminder_days' => '7', |
| 104 |
'days_until_trip' => '7', |
| 105 |
'reminder_extra_html' => '<p>' . esc_html__('Reminder: check your packing list before departure.', 'yatra') . '</p>', |
| 106 |
'trip_url' => home_url('/'), |
| 107 |
'review_url' => home_url('/#reviews'), |
| 108 |
'admin_url' => admin_url('admin.php?page=yatra'), |
| 109 |
'booking_url' => home_url('/my-account/bookings/42'), |
| 110 |
'message' => __('Could you confirm whether airport pickup is included on day one?', 'yatra'), |
| 111 |
'response' => __('Hi Alex, yes — pickup is included for all guests. Safe travels!', 'yatra'), |
| 112 |
'original_message' => __('Interested in the April departure dates.', 'yatra'), |
| 113 |
'expiry_policy_note' => __('Unpaid bookings are released after the deadline.', 'yatra'), |
| 114 |
'scheduled_amount_formatted' => yatra_format_price(750.0, $currency), |
| 115 |
'scheduled_date_formatted' => date_i18n(get_option('date_format'), strtotime('+5 days')), |
| 116 |
'payment_type_label' => __('Installment', 'yatra'), |
| 117 |
'scheduled_payment_id' => '9', |
| 118 |
'balance_after_formatted' => yatra_format_price(1749.0, $currency), |
| 119 |
'failure_reason' => __('Card declined (insufficient funds).', 'yatra'), |
| 120 |
'failure_intro_html' => '<p style="margin:0;">' |
| 121 |
. esc_html__('We could not process your scheduled payment.', 'yatra') |
| 122 |
. '</p>', |
| 123 |
'failure_followup_html' => esc_html__( |
| 124 |
'Please update your payment method or contact us so we can retry before your booking is affected.', |
| 125 |
'yatra' |
| 126 |
), |
| 127 |
'recovery_intro_html' => '<p style="margin:0;">' |
| 128 |
. esc_html__('You left items in your cart — your trip is still available to book.', 'yatra') |
| 129 |
. '</p>', |
| 130 |
'recovery_reminder_label' => __('48 hours left at this price', 'yatra'), |
| 131 |
'recovery_link' => home_url('/book/preview-recovery/'), |
| 132 |
'payment_gateway' => 'stripe', |
| 133 |
'payment_gateway_label' => 'Stripe', |
| 134 |
'payment_schedule' => 'deposit', |
| 135 |
'payment_schedule_label' => __('Deposit (balance due later)', 'yatra'), |
| 136 |
'travelers_list' => "1. Alex Traveler (" . __('Lead', 'yatra') . ")\n2. Sam Guest", |
| 137 |
'travelers_list_html' => '<ul style="margin:8px 0;padding-left:20px;">' |
| 138 |
. '<li style="margin:4px 0;">Alex Traveler <span style="color:#64748b;font-size:12px;">(' . esc_html__('Lead', 'yatra') . ')</span></li>' |
| 139 |
. '<li style="margin:4px 0;">Sam Guest</li></ul>', |
| 140 |
'traveler_custom_fields_html' => '<div style="margin:12px 0 0;">' |
| 141 |
. '<p style="margin:0 0 6px;font-weight:600;">' . esc_html__('Traveler 1 — Alex Traveler', 'yatra') . '</p>' |
| 142 |
. '<table role="presentation" cellpadding="0" cellspacing="0" style="width:100%;border-collapse:collapse;">' |
| 143 |
. '<tr><td style="padding:4px 12px 4px 0;vertical-align:top;color:#64748b;width:40%;">' . esc_html__('Dietary Requirements', 'yatra') . '</td>' |
| 144 |
. '<td style="padding:4px 0;vertical-align:top;">' . esc_html__('Vegetarian', 'yatra') . '</td></tr></table></div>', |
| 145 |
'booking_custom_fields_html' => '<div style="margin:12px 0 0;">' |
| 146 |
. '<p style="margin:0 0 6px;font-weight:600;">' . esc_html__('Additional services', 'yatra') . '</p>' |
| 147 |
. '<ul style="margin:0;padding-left:20px;">' |
| 148 |
. '<li style="margin:4px 0;">' . esc_html__('Airport transfer', 'yatra') . ' — ' . esc_html(yatra_format_price(45.0, $currency)) . '</li>' |
| 149 |
. '</ul></div>', |
| 150 |
'special_requests' => $specialSample, |
| 151 |
'special_requests_html' => nl2br(esc_html($specialSample)), |
| 152 |
]; |
| 153 |
} |
| 154 |
|
| 155 |
/** |
| 156 |
* @param array<string, string> $vars |
| 157 |
* @return array<string, string> |
| 158 |
*/ |
| 159 |
private static function mergeTripContext(int $tripId, array $vars): array |
| 160 |
{ |
| 161 |
try { |
| 162 |
$repo = new TripRepository(); |
| 163 |
$trip = $repo->findWithRelations($tripId, true); |
| 164 |
if ($trip && !empty($trip->id)) { |
| 165 |
$vars['trip_id'] = (string) (int) $trip->id; |
| 166 |
if (!empty($trip->title)) { |
| 167 |
$vars['trip_name'] = (string) $trip->title; |
| 168 |
} |
| 169 |
if (!empty($trip->slug)) { |
| 170 |
$vars['trip_url'] = home_url('/' . SettingsService::getTripBase() . '/' . rawurlencode((string) $trip->slug) . '/'); |
| 171 |
} |
| 172 |
} |
| 173 |
} catch (\Throwable $e) { |
| 174 |
// Leave sample trip_* as-is |
| 175 |
} |
| 176 |
|
| 177 |
/** @var array<string, string> */ |
| 178 |
return apply_filters('yatra_email_template_trip_variables', $vars, $tripId); |
| 179 |
} |
| 180 |
|
| 181 |
public static function isPreviewableTemplateKey(string $templateKey): bool |
| 182 |
{ |
| 183 |
if (TransactionalEmailTemplateService::coreTemplateKeyToType($templateKey) !== null) { |
| 184 |
return true; |
| 185 |
} |
| 186 |
|
| 187 |
return EmailTemplateDefaults::proSystemTemplate($templateKey) !== null; |
| 188 |
} |
| 189 |
} |
| 190 |
|