PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
← All changes | app/Services/EmailTemplateDefaults.php +312 -11 3.0.4 → 3.0.16 View file →
@@ -16,13 +16,15 @@
16 16 * @return array<string, string>
17 17 */
18 18 public static function settingsOptionDefaults(): array
19 19 {
20 - return [
20 + $defaults = [
21 21 'email_tpl_booking_subject' => '✈️ [{{site_name}}] Booking update · {{booking_reference}}',
22 22 'email_tpl_booking_body' => self::htmlBookingCustomer(),
23 23 'email_tpl_payment_subject' => '✅ [{{site_name}}] Payment received · {{booking_reference}}',
24 24 'email_tpl_payment_body' => self::htmlPaymentCustomer(),
25 + 'email_tpl_partial_payment_subject' => '💳 [{{site_name}}] Part payment received · {{booking_reference}}',
26 + 'email_tpl_partial_payment_body' => self::htmlPartialPaymentCustomer(),
25 27 'email_tpl_cancellation_subject' => '📋 [{{site_name}}] Booking cancelled · {{booking_reference}}',
26 28 'email_tpl_cancellation_body' => self::htmlCancellationCustomer(),
27 29 'email_tpl_reminder_subject' => '🗓️ [{{site_name}}] Your trip is coming up · {{booking_reference}}',
28 30 'email_tpl_reminder_body' => self::htmlReminderCustomer(),
@@ -35,8 +37,22 @@
35 37 'email_tpl_trip_consent_subject' => '📝 [{{site_name}}] Action required · {{form_name}}',
36 38 'email_tpl_trip_consent_body' => self::htmlTripConsentRequest(),
37 39 'email_tpl_customer_verification_subject' => '✉️ [{{site_name}}] Verify your email address',
38 40 'email_tpl_customer_verification_body' => self::htmlCustomerEmailVerification(),
41 + // Guest-checkout verification (distinct from account registration above).
42 + // Subject mirrors the render's hardcoded fallback; body reuses the
43 + // customer-verification HTML so the email is identical until an operator
44 + // customizes it. Registering these keys here is required so the settings
45 + // save accepts them (SettingsController whitelists by default_settings)
46 + // and the admin template editor pre-fills them.
47 + 'email_tpl_guest_verification_subject' => '✉️ [{{site_name}}] Verify your email to complete your booking',
48 + 'email_tpl_guest_verification_body' => self::htmlCustomerEmailVerification(),
49 + // Account email change: confirmation link to the NEW address, and a
50 + // security notice to the OLD address once the change is confirmed.
51 + 'email_tpl_account_email_change_subject' => '✉️ [{{site_name}}] Confirm your new email address',
52 + 'email_tpl_account_email_change_body' => self::htmlAccountEmailChangeRequest(),
53 + 'email_tpl_account_email_changed_subject' => '🔔 [{{site_name}}] Your email address was changed',
54 + 'email_tpl_account_email_changed_body' => self::htmlAccountEmailChanged(),
39 55 'email_tpl_booking_completed_subject' => '🌟 [{{site_name}}] Thanks for traveling · {{booking_reference}}',
40 56 'email_tpl_booking_completed_body' => self::htmlTripCompleted(),
41 57 'email_tpl_booking_expired_customer_subject' => '⏱️ [{{site_name}}] Booking expired · {{booking_reference}}',
42 58 'email_tpl_booking_expired_customer_body' => self::htmlBookingExpiredCustomer(),
@@ -64,8 +80,26 @@
64 80 'email_tpl_abandoned_booking_recovery_second_body' => self::htmlAbandonedBookingRecoverySecond(),
65 81 'email_tpl_abandoned_booking_recovery_final_subject' => '⚠️ [{{site_name}}] Final reminder: complete your booking',
66 82 'email_tpl_abandoned_booking_recovery_final_body' => self::htmlAbandonedBookingRecoveryFinal(),
67 83 ];
84 +
85 + // Every template also gets an opt-in Bcc / Cc option, derived from its
86 + // own subject key so the two lists can never drift apart (and so a
87 + // template type added later picks them up for free). Empty by default:
88 + // no address configured means no copy is sent and nothing changes for
89 + // existing sites. Registered here because this array doubles as the
90 + // whitelist of settings the REST API will persist.
91 + foreach (array_keys($defaults) as $key) {
92 + if (substr($key, -8) !== '_subject') {
93 + continue;
94 + }
95 +
96 + $base = substr($key, 0, -8);
97 + $defaults[$base . '_bcc'] = '';
98 + $defaults[$base . '_cc'] = '';
99 + }
100 +
101 + return $defaults;
68 102 }
69 103
70 104 /**
71 105 * Full subject + body for Pro system templates (DB). Null = no bundled default for that key.
@@ -98,8 +132,12 @@
98 132 'booking_cancelled' => [
99 133 'subject' => '📋 Booking cancelled · {{booking_reference}}',
100 134 'body' => self::htmlCancellationCustomer(),
101 135 ],
136 + 'admin_booking_cancelled' => [
137 + 'subject' => '📋 Booking cancelled · {{booking_reference}} (#{{booking_id}})',
138 + 'body' => self::htmlAdminBookingCancelled(),
139 + ],
102 140 'booking_completed' => [
103 141 'subject' => '🌟 Thanks for traveling with us · {{booking_reference}}',
104 142 'body' => self::htmlTripCompleted(),
105 143 ],
@@ -106,8 +144,16 @@
106 144 'payment_received' => [
107 145 'subject' => '✅ Payment received · {{booking_reference}}',
108 146 'body' => self::htmlPaymentCustomer(),
109 147 ],
148 + 'admin_payment_received' => [
149 + 'subject' => '✅ Payment received · {{booking_reference}} (#{{booking_id}})',
150 + 'body' => self::htmlAdminPaymentReceived(),
151 + ],
152 + 'partial_payment_received' => [
153 + 'subject' => '💳 Part payment received · {{booking_reference}}',
154 + 'body' => self::htmlPartialPaymentCustomer(),
155 + ],
110 156 'payment_reminder' => [
111 157 'subject' => '💳 Payment reminder · {{booking_reference}}',
112 158 'body' => self::htmlPaymentReminder(),
113 159 ],
@@ -138,8 +184,24 @@
138 184 'customer_email_verification' => [
139 185 'subject' => '✉️ [{{site_name}}] Verify your email address',
140 186 'body' => self::htmlCustomerEmailVerification(),
141 187 ],
188 + 'guest_email_verification' => [
189 + // Guest-checkout verification reuses the customer-verification
190 + // body — the flow is identical (click a magic link to prove
191 + // ownership) and the booking-specific copy is injected at
192 + // send-time via {{intro_paragraph}} / {{footer_note}}.
193 + 'subject' => '✉️ [{{site_name}}] Verify your email to complete your booking',
194 + 'body' => self::htmlCustomerEmailVerification(),
195 + ],
196 + 'account_email_change_request' => [
197 + 'subject' => '✉️ [{{site_name}}] Confirm your new email address',
198 + 'body' => self::htmlAccountEmailChangeRequest(),
199 + ],
200 + 'account_email_changed' => [
201 + 'subject' => '🔔 [{{site_name}}] Your email address was changed',
202 + 'body' => self::htmlAccountEmailChanged(),
203 + ],
142 204 'booking_expired_customer' => [
143 205 'subject' => '⏱️ [{{site_name}}] Booking expired · {{booking_reference}}',
144 206 'body' => self::htmlBookingExpiredCustomer(),
145 207 ],
@@ -225,8 +287,9 @@
225 287 }));
226 288
227 289 $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">'
228 290 . sprintf(
291 + /* translators: %s: customer name */
229 292 esc_html__('Hello %s,', 'yatra'),
230 293 $name
231 294 )
232 295 . '</p>'
@@ -262,9 +325,13 @@
262 325 return $row['value'] !== '';
263 326 }));
264 327
265 328 $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">'
266 - . sprintf(esc_html__('Dear %s,', 'yatra'), $name)
329 + . sprintf(
330 + /* translators: %s: customer name */
331 + esc_html__('Dear %s,', 'yatra'),
332 + $name
333 + )
267 334 . '</p>'
268 335 . '<p style="margin:0 0 8px;color:#475569;">'
269 336 . esc_html__('We’ve received your payment — thank you! Here’s a quick summary.', 'yatra')
270 337 . '</p>'
@@ -279,10 +346,61 @@
279 346 );
280 347 }
281 348
282 349 /**
350 + * Part-payment received — a balance is still outstanding.
351 + *
352 + * Wording differs from the full-payment email on purpose: it confirms what
353 + * was received AND states what is still owed, which is the whole reason this
354 + * template is separate.
355 + *
283 356 * @param array<string, string> $v
284 357 */
358 + public static function fallbackTransactionalPartialPayment(array $v): string
359 + {
360 + // Null-coalescing rather than `?:` so this renders cleanly even when a
361 + // caller passes a sparse variable set — this fallback runs on sites that
362 + // upgraded before the template's body option was seeded.
363 + $name = esc_html(
364 + ($v['customer_first_name'] ?? '') ?: ($v['customer_name'] ?? '') ?: __('Customer', 'yatra')
365 + );
366 + $site = esc_html($v['site_name'] ?? get_bloginfo('name'));
367 + $rows = array_values(array_filter([
368 + ['label' => __('Booking reference', 'yatra'), 'value' => esc_html($v['booking_reference'] ?? '')],
369 + ['label' => __('Amount received', 'yatra'), 'value' => esc_html($v['payment_amount_formatted'] ?? '')],
370 + ['label' => __('Paid so far', 'yatra'), 'value' => esc_html($v['amount_paid_formatted'] ?? '')],
371 + ['label' => __('Balance remaining', 'yatra'), 'value' => esc_html($v['amount_due_formatted'] ?? '')],
372 + ['label' => __('Booking total', 'yatra'), 'value' => esc_html($v['total_amount_formatted'] ?? '')],
373 + ['label' => __('Method', 'yatra'), 'value' => esc_html($v['payment_method'] ?? '')],
374 + ['label' => __('Transaction ID', 'yatra'), 'value' => esc_html($v['transaction_id'] ?? '')],
375 + ], static function (array $row): bool {
376 + return $row['value'] !== '';
377 + }));
378 +
379 + $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">'
380 + . sprintf(
381 + /* translators: %s: customer name */
382 + esc_html__('Dear %s,', 'yatra'),
383 + $name
384 + )
385 + . '</p>'
386 + . '<p style="margin:0 0 8px;color:#475569;">'
387 + . esc_html__('Thank you — we’ve received your part payment. Your booking is not yet paid in full, so the remaining balance is shown below.', 'yatra')
388 + . '</p>'
389 + . EmailTemplateLayout::detailCard($rows);
390 +
391 + return EmailTemplateLayout::customer(
392 + '💳',
393 + __('Part payment received', 'yatra'),
394 + $inner,
395 + $site,
396 + __('Payment update', 'yatra')
397 + );
398 + }
399 +
400 + /**
401 + * @param array<string, string> $v
402 + */
285 403 public static function fallbackTransactionalCancellation(array $v): string
286 404 {
287 405 $name = esc_html($v['customer_first_name'] ?: $v['customer_name'] ?: __('Customer', 'yatra'));
288 406 $site = esc_html($v['site_name'] ?? get_bloginfo('name'));
@@ -294,9 +412,13 @@
294 412 return $row['value'] !== '';
295 413 }));
296 414
297 415 $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">'
298 - . sprintf(esc_html__('Hello %s,', 'yatra'), $name)
416 + . sprintf(
417 + /* translators: %s: customer name */
418 + esc_html__('Hello %s,', 'yatra'),
419 + $name
420 + )
299 421 . '</p>'
300 422 . '<p style="margin:0 0 20px;color:#475569;">'
301 423 . esc_html__('Your booking has been cancelled as requested. If you have questions, just reply to this email.', 'yatra')
302 424 . '</p>'
@@ -336,9 +458,13 @@
336 458 $rows = array_merge($rows, $balanceRow);
337 459 }
338 460
339 461 $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">'
340 - . sprintf(esc_html__('Dear %s,', 'yatra'), $name)
462 + . sprintf(
463 + /* translators: %s: customer name */
464 + esc_html__('Dear %s,', 'yatra'),
465 + $name
466 + )
341 467 . '</p>'
342 468 . '<p style="margin:0 0 20px;color:#475569;">'
343 469 . ($days !== ''
344 470 ? sprintf(
@@ -392,9 +518,13 @@
392 518 : '';
393 519
394 520 $inner = $testBlock
395 521 . '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">'
396 - . sprintf(esc_html__('Hello %s,', 'yatra'), $recipient)
522 + . sprintf(
523 + /* translators: %s: customer name */
524 + esc_html__('Hello %s,', 'yatra'),
525 + $recipient
526 + )
397 527 . '</p>'
398 528 . '<p style="margin:0 0 20px;color:#475569;">'
399 529 . sprintf(
400 530 /* translators: %s: consent form title */
@@ -446,9 +576,13 @@
446 576 . $expiryInner
447 577 . '</div>';
448 578
449 579 $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">'
450 - . sprintf(esc_html__('Hello %s,', 'yatra'), $first)
580 + . sprintf(
581 + /* translators: %s: customer name */
582 + esc_html__('Hello %s,', 'yatra'),
583 + $first
584 + )
451 585 . '</p>'
452 586 . ($intro !== '' ? '<p style="margin:0 0 20px;color:#475569;">' . $intro . '</p>' : '')
453 587 . EmailTemplateLayout::button($link, __('Verify email address', 'yatra'))
454 588 . $expiry
@@ -467,8 +601,90 @@
467 601 );
468 602 }
469 603
470 604 /**
605 + * Fallback HTML for the account email-change confirmation (empty saved template).
606 + *
607 + * @param array<string, string> $v
608 + */
609 + public static function fallbackTransactionalAccountEmailChangeRequest(array $v): string
610 + {
611 + $firstRaw = (string) ($v['customer_first_name'] ?? '');
612 + if ($firstRaw === '') {
613 + $firstRaw = (string) ($v['customer_name'] ?? '');
614 + }
615 + $first = esc_html($firstRaw !== '' ? $firstRaw : __('there', 'yatra'));
616 + $site = esc_html($v['site_name'] ?? get_bloginfo('name'));
617 + $link = esc_url((string) ($v['verification_link'] ?? home_url('/')));
618 + $newEmail = esc_html((string) ($v['new_email'] ?? ''));
619 + $intro = isset($v['intro_paragraph']) ? esc_html((string) $v['intro_paragraph']) : '';
620 + $footer = isset($v['footer_note']) ? esc_html((string) $v['footer_note']) : '';
621 +
622 + $newBlock = $newEmail !== ''
623 + ? '<div style="margin:0 0 20px;padding:12px 16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:10px;font-size:14px;color:#475569;">'
624 + . esc_html__('New email address:', 'yatra') . ' <strong>' . $newEmail . '</strong></div>'
625 + : '';
626 +
627 + $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">'
628 + . sprintf(/* translators: %s: customer name */ esc_html__('Hello %s,', 'yatra'), $first)
629 + . '</p>'
630 + . ($intro !== '' ? '<p style="margin:0 0 20px;color:#475569;">' . $intro . '</p>' : '')
631 + . $newBlock
632 + . EmailTemplateLayout::button($link, __('Confirm email change', 'yatra'))
633 + . ($footer !== '' ? '<p style="margin:24px 0 0;font-size:14px;color:#64748b;">' . $footer . '</p>' : '')
634 + . '<p style="margin:20px 0 0;font-size:13px;color:#64748b;">'
635 + . esc_html__('If the button does not work, copy this link into your browser:', 'yatra')
636 + . '</p>'
637 + . '<p style="margin:8px 0 0;font-size:13px;word-break:break-all;"><a href="' . $link . '" style="color:#0d9488;">' . $link . '</a></p>';
638 +
639 + return EmailTemplateLayout::customer(
640 + '✉️',
641 + __('Confirm your new email', 'yatra'),
642 + $inner,
643 + $site,
644 + __('Account security', 'yatra')
645 + );
646 + }
647 +
648 + /**
649 + * Fallback HTML for the "email changed" security notice (empty saved template).
650 + *
651 + * @param array<string, string> $v
652 + */
653 + public static function fallbackTransactionalAccountEmailChanged(array $v): string
654 + {
655 + $firstRaw = (string) ($v['customer_first_name'] ?? '');
656 + if ($firstRaw === '') {
657 + $firstRaw = (string) ($v['customer_name'] ?? '');
658 + }
659 + $first = esc_html($firstRaw !== '' ? $firstRaw : __('there', 'yatra'));
660 + $site = esc_html($v['site_name'] ?? get_bloginfo('name'));
661 + $newEmail = esc_html((string) ($v['new_email'] ?? ''));
662 + $intro = isset($v['intro_paragraph']) ? esc_html((string) $v['intro_paragraph']) : '';
663 + $footer = isset($v['footer_note']) ? esc_html((string) $v['footer_note']) : '';
664 +
665 + $newBlock = $newEmail !== ''
666 + ? '<div style="margin:0 0 20px;padding:12px 16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:10px;font-size:14px;color:#475569;">'
667 + . esc_html__('New email address:', 'yatra') . ' <strong>' . $newEmail . '</strong></div>'
668 + : '';
669 +
670 + $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">'
671 + . sprintf(/* translators: %s: customer name */ esc_html__('Hello %s,', 'yatra'), $first)
672 + . '</p>'
673 + . ($intro !== '' ? '<p style="margin:0 0 20px;color:#475569;">' . $intro . '</p>' : '')
674 + . $newBlock
675 + . ($footer !== '' ? '<p style="margin:24px 0 0;font-size:14px;color:#64748b;">' . $footer . '</p>' : '');
676 +
677 + return EmailTemplateLayout::customer(
678 + '🔔',
679 + __('Your email address was changed', 'yatra'),
680 + $inner,
681 + $site,
682 + __('Account security', 'yatra')
683 + );
684 + }
685 +
686 + /**
471 687 * Fallback HTML for admin new-booking notice (empty saved template).
472 688 *
473 689 * @param array<string, string> $v
474 690 */
@@ -560,9 +776,9 @@
560 776 ['label' => __('Phone', 'yatra'), 'value' => esc_html($v['customer_phone'] ?? '')],
561 777 ['label' => __('Trip', 'yatra'), 'value' => esc_html($v['trip_name'] ?? '')],
562 778 ['label' => __('Travel date', 'yatra'), 'value' => esc_html($v['travel_date'] ?? '')],
563 779 ['label' => __('Travelers', 'yatra'), 'value' => esc_html($v['travelers_count'] ?? '')],
564 - ['label' => __('Total', 'yatra'), 'value' => trim(esc_html($v['total_amount_formatted'] ?? '') . ' ' . esc_html($v['currency'] ?? ''))],
780 + ['label' => __('Total', 'yatra'), 'value' => esc_html($v['total_amount_formatted'] ?? '')],
565 781 ['label' => __('Booking status', 'yatra'), 'value' => esc_html($v['booking_status'] ?? '')],
566 782 ['label' => __('Payment status', 'yatra'), 'value' => esc_html($v['payment_status'] ?? '')],
567 783 ], static function (array $row): bool {
568 784 return trim((string) ($row['value'] ?? '')) !== '';
@@ -707,9 +923,9 @@
707 923 ['label' => 'Phone', 'value' => '{{customer_phone}}'],
708 924 ['label' => 'Trip', 'value' => '{{trip_name}}'],
709 925 ['label' => 'Travel date', 'value' => '{{travel_date}}'],
710 926 ['label' => 'Travelers', 'value' => '{{travelers_count}}'],
711 - ['label' => 'Total', 'value' => '{{total_amount_formatted}} {{currency}}'],
927 + ['label' => 'Total', 'value' => '{{total_amount_formatted}}'],
712 928 ['label' => 'Booking status', 'value' => '{{booking_status}}'],
713 929 ['label' => 'Payment status', 'value' => '{{payment_status}}'],
714 930 ])
715 931 . '<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:28px 0 0;"><tr>'
@@ -750,8 +966,35 @@
750 966 'Payment received'
751 967 );
752 968 }
753 969
970 + /**
971 + * Editor pre-fill for the part-payment template ({{merge tags}} intact).
972 + */
973 + private static function htmlPartialPaymentCustomer(): string
974 + {
975 + $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">Dear {{customer_name}},</p>'
976 + . '<p style="margin:0 0 20px;color:#475569;">'
977 + . esc_html__('Thank you — we’ve received your part payment. The remaining balance for your booking is shown below.', 'yatra')
978 + . '</p>'
979 + . EmailTemplateLayout::detailCard([
980 + ['label' => 'Booking reference', 'value' => '{{booking_reference}}'],
981 + ['label' => 'Amount received', 'value' => '{{payment_amount_formatted}}'],
982 + ['label' => 'Paid so far', 'value' => '{{amount_paid_formatted}}'],
983 + ['label' => 'Balance remaining', 'value' => '{{amount_due_formatted}}'],
984 + ['label' => 'Booking total', 'value' => '{{total_amount_formatted}}'],
985 + ['label' => 'Method', 'value' => '{{payment_method}}'],
986 + ]);
987 +
988 + return EmailTemplateLayout::customer(
989 + '💳',
990 + 'Part payment received',
991 + $inner,
992 + '{{site_name}}',
993 + 'Payment update'
994 + );
995 + }
996 +
754 997 private static function htmlCancellationCustomer(): string
755 998 {
756 999 $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">Hello {{customer_name}},</p>'
757 1000 . '<p style="margin:0 0 20px;color:#475569;">'
@@ -883,8 +1126,55 @@
883 1126 __('Account verification', 'yatra')
884 1127 );
885 1128 }
886 1129
1130 + private static function htmlAccountEmailChangeRequest(): string
1131 + {
1132 + $cta = '<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:28px 0;"><tr>'
1133 + . '<td style="border-radius:10px;background:#0d9488;">'
1134 + . '<a href="{{verification_link}}" style="display:inline-block;padding:14px 28px;font-family:\'Segoe UI\',Roboto,Arial,sans-serif;font-size:15px;font-weight:600;color:#ffffff;text-decoration:none;border-radius:10px;">'
1135 + . esc_html__('Confirm email change', 'yatra')
1136 + . '</a></td></tr></table>';
1137 +
1138 + $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">Hello {{customer_first_name}},</p>'
1139 + . '<p style="margin:0 0 20px;color:#475569;">{{intro_paragraph}}</p>'
1140 + . '<div style="margin:0 0 20px;padding:12px 16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:10px;font-size:14px;color:#475569;">'
1141 + . esc_html__('New email address:', 'yatra') . ' <strong>{{new_email}}</strong>'
1142 + . '</div>'
1143 + . $cta
1144 + . '<p style="margin:24px 0 0;font-size:14px;color:#64748b;">{{footer_note}}</p>'
1145 + . '<p style="margin:20px 0 0;font-size:13px;color:#64748b;">'
1146 + . esc_html__('If the button does not work, copy this link into your browser:', 'yatra')
1147 + . '</p>'
1148 + . '<p style="margin:8px 0 0;font-size:13px;word-break:break-all;"><a href="{{verification_link}}" style="color:#0d9488;">{{verification_link}}</a></p>';
1149 +
1150 + return EmailTemplateLayout::customer(
1151 + '✉️',
1152 + __('Confirm your new email', 'yatra'),
1153 + $inner,
1154 + '{{site_name}}',
1155 + __('Account security', 'yatra')
1156 + );
1157 + }
1158 +
1159 + private static function htmlAccountEmailChanged(): string
1160 + {
1161 + $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">Hello {{customer_first_name}},</p>'
1162 + . '<p style="margin:0 0 20px;color:#475569;">{{intro_paragraph}}</p>'
1163 + . '<div style="margin:0 0 20px;padding:12px 16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:10px;font-size:14px;color:#475569;">'
1164 + . esc_html__('New email address:', 'yatra') . ' <strong>{{new_email}}</strong>'
1165 + . '</div>'
1166 + . '<p style="margin:24px 0 0;font-size:14px;color:#64748b;">{{footer_note}}</p>';
1167 +
1168 + return EmailTemplateLayout::customer(
1169 + '🔔',
1170 + __('Your email address was changed', 'yatra'),
1171 + $inner,
1172 + '{{site_name}}',
1173 + __('Account security', 'yatra')
1174 + );
1175 + }
1176 +
887 1177 private static function htmlPaymentReminder(): string
888 1178 {
889 1179 $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">Hello {{customer_name}},</p>'
890 1180 . '<p style="margin:0 0 20px;color:#475569;">'
@@ -1053,20 +1343,31 @@
1053 1343 }
1054 1344
1055 1345 private static function htmlScheduledPaymentReminder(): string
1056 1346 {
1347 + // "Pay your balance now" CTA. The href is the {{balance_payment_url}}
1348 + // merge tag (a secure, guest-accessible balance link supplied by Pro
1349 + // Scheduled Payments); it is built manually rather than via
1350 + // EmailTemplateLayout::button() because that esc_url()s the href, which
1351 + // would strip the merge-tag braces. Pro passes an already-escaped URL.
1352 + $cta = '<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:28px 0;"><tr>'
1353 + . '<td style="border-radius:10px;background:#0d9488;">'
1354 + . '<a href="{{balance_payment_url}}" style="display:inline-block;padding:14px 28px;font-family:\'Segoe UI\',Roboto,Arial,sans-serif;font-size:15px;font-weight:600;color:#ffffff;text-decoration:none;border-radius:10px;">'
1355 + . esc_html__('Pay your balance now', 'yatra') . '</a></td></tr></table>';
1356 +
1057 1357 $inner = '<p style="margin:0 0 16px;font-size:17px;color:#0f172a;">Hello {{customer_first_name}},</p>'
1058 1358 . '<p style="margin:0 0 20px;color:#475569;">'
1059 - . esc_html__('This is a reminder that a scheduled payment is coming up for your booking.', 'yatra')
1359 + . esc_html__('This is a reminder that the remaining balance for your booking is coming up.', 'yatra')
1060 1360 . '</p>'
1061 1361 . EmailTemplateLayout::detailCard([
1062 1362 ['label' => 'Reference', 'value' => '{{booking_reference}}'],
1063 1363 ['label' => 'Amount', 'value' => '{{scheduled_amount_formatted}}'],
1064 - ['label' => 'Scheduled date', 'value' => '{{scheduled_date_formatted}}'],
1364 + ['label' => 'Due date', 'value' => '{{scheduled_date_formatted}}'],
1065 1365 ['label' => 'Type', 'value' => '{{payment_type_label}}'],
1066 1366 ])
1367 + . $cta
1067 1368 . '<p style="margin:24px 0 0;font-size:14px;color:#64748b;">'
1068 - . esc_html__('If you need to update your payment method, contact us before the charge date.', 'yatra')
1369 + . esc_html__('If you have any questions about this payment, please contact us before the due date.', 'yatra')
1069 1370 . '</p>';
1070 1371
1071 1372 return EmailTemplateLayout::customer(
1072 1373 '💳',