PluginProbe
Yatra – Travel Booking & Tour Operator Software / trunk
Yatra – Travel Booking & Tour Operator Software vtrunk
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 2.0.10 2.0.11 All 82 releases
yatra / app / Controllers / AuthController.php

AuthController.php in Yatra – Travel Booking & Tour Operator Software trunk, at app/Controllers/AuthController.php

725 lines 29.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Yatra\Controllers;
6
7 /**
8 * Authentication Controller
9 * Handles user registration, login, email verification for Yatra customers
10 *
11 * @package Yatra
12 */
13 class AuthController
14 {
15 /**
16 * Register REST API routes
17 */
18 public static function registerRoutes(): void
19 {
20 register_rest_route('yatra/v1', '/auth/login', [
21 'methods' => 'POST',
22 'callback' => [self::class, 'login'],
23 'permission_callback' => '__return_true',
24 ]);
25
26 register_rest_route('yatra/v1', '/auth/register', [
27 'methods' => 'POST',
28 'callback' => [self::class, 'register'],
29 'permission_callback' => '__return_true',
30 ]);
31
32 register_rest_route('yatra/v1', '/auth/resend-verification', [
33 'methods' => 'POST',
34 'callback' => [self::class, 'resendVerification'],
35 'permission_callback' => '__return_true',
36 ]);
37 }
38
39 /**
40 * Register Yatra Customer role
41 */
42 public static function registerCustomerRole(): void
43 {
44 if (!get_role('yatra_customer')) {
45 add_role(
46 'yatra_customer',
47 __('Yatra Customer', 'yatra'),
48 [
49 'read' => true,
50 'edit_posts' => false,
51 'delete_posts' => false,
52 ]
53 );
54 }
55 }
56
57 /**
58 * Block unverified users from WordPress login
59 *
60 * @param \WP_User|\WP_Error|null $user
61 * @param string $username
62 * @param string $password
63 * @return \WP_User|\WP_Error|null
64 */
65 public static function blockUnverifiedUserLogin($user, string $username, string $password)
66 {
67 if (is_wp_error($user)) {
68 return $user;
69 }
70
71 if (!($user instanceof \WP_User)) {
72 return $user;
73 }
74
75 $has_verification_token = get_user_meta($user->ID, 'yatra_verification_token', true);
76 $email_verified = get_user_meta($user->ID, 'yatra_email_verified', true);
77
78 $needs_verification = !empty($has_verification_token);
79
80 if (!$needs_verification) {
81 $meta_exists = metadata_exists('user', $user->ID, 'yatra_email_verified');
82 $needs_verification = $meta_exists && !$email_verified;
83 }
84
85 if ($needs_verification) {
86 $resend_url = add_query_arg([
87 'action' => 'yatra_resend_verification',
88 'email' => urlencode($user->user_email),
89 '_wpnonce' => wp_create_nonce('yatra_resend_verification'),
90 ], wp_login_url());
91
92 $message = sprintf(
93 /* translators: %s: resend verification link */
94 __('<strong>Error:</strong> Please verify your email address before logging in. Check your inbox for the verification link. <br><br><a href="%s">Click here to resend verification email</a>', 'yatra'),
95 esc_url($resend_url)
96 );
97
98 return new \WP_Error('email_not_verified', $message);
99 }
100
101 return $user;
102 }
103
104 /**
105 * Handle resend verification from WordPress login page
106 */
107 public static function handleWpLoginResendVerification(): void
108 {
109 if (!isset($_GET['action']) || $_GET['action'] !== 'yatra_resend_verification') {
110 return;
111 }
112
113 // Verify nonce
114 if (!isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_text_field($_GET['_wpnonce']), 'yatra_resend_verification')) {
115 wp_die(__('Your session has expired. Please go back and try again.', 'yatra'));
116 }
117
118 $email = isset($_GET['email']) ? sanitize_email(urldecode($_GET['email'])) : '';
119
120 if (empty($email) || !is_email($email)) {
121 wp_safe_redirect(add_query_arg('login_error', 'invalid_email', wp_login_url()));
122 exit;
123 }
124
125 $user = get_user_by('email', $email);
126
127 if (!$user) {
128 // Redirect with generic success message (don't reveal if email exists)
129 wp_safe_redirect(add_query_arg('checkemail', 'resent', wp_login_url()));
130 exit;
131 }
132
133 // Check if already verified
134 $email_verified = get_user_meta($user->ID, 'yatra_email_verified', true);
135 if ($email_verified === '1') {
136 wp_safe_redirect(add_query_arg('login_error', 'already_verified', wp_login_url()));
137 exit;
138 }
139
140 // Check rate limiting
141 $last_sent = get_user_meta($user->ID, 'yatra_verification_last_sent', true);
142 if ($last_sent && (time() - (int) $last_sent) < 120) {
143 $remaining = 120 - (time() - (int) $last_sent);
144 wp_safe_redirect(add_query_arg([
145 'login_error' => 'rate_limited',
146 'wait' => $remaining,
147 ], wp_login_url()));
148 exit;
149 }
150
151 // Generate new token and send email
152 $verification_token = wp_generate_password(32, false);
153 $secure_token = base64_encode($user->ID . '|' . $verification_token . '|' . time());
154 $secure_token = str_replace(['+', '/', '='], ['-', '_', ''], $secure_token);
155
156 update_user_meta($user->ID, 'yatra_verification_token', $verification_token);
157 update_user_meta($user->ID, 'yatra_verification_token_expiry', time() + (24 * 60 * 60));
158 update_user_meta($user->ID, 'yatra_verification_last_sent', time());
159
160 // Send email
161 $first_name = get_user_meta($user->ID, 'first_name', true) ?: $user->display_name;
162 self::sendVerificationEmail($user->ID, $email, $first_name, $secure_token, true);
163
164 wp_safe_redirect(add_query_arg('checkemail', 'resent', wp_login_url()));
165 exit;
166 }
167
168 /**
169 * Add custom messages to WordPress login page
170 */
171 public static function customLoginMessages(string $message): string
172 {
173 if (isset($_GET['checkemail']) && $_GET['checkemail'] === 'resent') {
174 $message = '<p class="message">' . __('A new verification link has been sent to your email address. Please check your inbox and spam folder.', 'yatra') . '</p>';
175 }
176
177 if (isset($_GET['email_verified']) && $_GET['email_verified'] === '1') {
178 $message = '<p class="message">' . __('Your email has been verified successfully! You can now log in.', 'yatra') . '</p>';
179 }
180
181 return $message;
182 }
183
184 /**
185 * Add custom error messages to WordPress login page
186 */
187 public static function customLoginErrors(\WP_Error $errors): \WP_Error
188 {
189 if (isset($_GET['login_error'])) {
190 switch ($_GET['login_error']) {
191 case 'invalid_email':
192 $errors->add('invalid_email', __('<strong>Error:</strong> Invalid email address.', 'yatra'));
193 break;
194 case 'already_verified':
195 $errors->add('already_verified', __('<strong>Notice:</strong> Your email is already verified. Please log in.', 'yatra'));
196 break;
197 case 'rate_limited':
198 $wait = isset($_GET['wait']) ? (int) $_GET['wait'] : 120;
199 $errors->add('rate_limited', sprintf(
200 /* translators: %d: number of seconds to wait */
201 __('<strong>Error:</strong> Please wait %d seconds before requesting another verification email.', 'yatra'),
202 $wait
203 ));
204 break;
205 }
206 }
207
208 return $errors;
209 }
210
211 /**
212 * Handle login request
213 */
214 public static function login(\WP_REST_Request $request): \WP_REST_Response
215 {
216 $username = sanitize_user($request->get_param('username') ?? '');
217 $password = $request->get_param('password') ?? '';
218 $remember = !empty($request->get_param('remember'));
219
220 if (empty($username) || empty($password)) {
221 return new \WP_REST_Response([
222 'success' => false,
223 'message' => __('Please enter your username/email and password.', 'yatra'),
224 ], 400);
225 }
226
227 // Get user to check verification status
228 $user_check = get_user_by('login', $username);
229 if (!$user_check) {
230 $user_check = get_user_by('email', $username);
231 }
232
233 // Check email verification for Yatra users
234 if ($user_check) {
235 $has_verification_token = get_user_meta($user_check->ID, 'yatra_verification_token', true);
236 $email_verified = get_user_meta($user_check->ID, 'yatra_email_verified', true);
237
238 if (!empty($has_verification_token)) {
239 return new \WP_REST_Response([
240 'success' => false,
241 'message' => __('Please verify your email address before logging in. Check your inbox for the verification link.', 'yatra'),
242 'needs_verification' => true,
243 'email' => $user_check->user_email,
244 ], 403);
245 }
246
247 $meta_exists = metadata_exists('user', $user_check->ID, 'yatra_email_verified');
248 if ($meta_exists && !$email_verified) {
249 return new \WP_REST_Response([
250 'success' => false,
251 'message' => __('Please verify your email address before logging in. Check your inbox for the verification link.', 'yatra'),
252 'needs_verification' => true,
253 'email' => $user_check->user_email,
254 ], 403);
255 }
256 }
257
258 // Authenticate
259 $user = wp_signon([
260 'user_login' => $username,
261 'user_password' => $password,
262 'remember' => $remember,
263 ], is_ssl());
264
265 if (is_wp_error($user)) {
266 $error_message = wp_strip_all_tags($user->get_error_message());
267 if (strpos($error_message, 'incorrect') !== false || strpos($error_message, 'Invalid') !== false) {
268 $error_message = __('Invalid username/email or password. Please try again.', 'yatra');
269 }
270 return new \WP_REST_Response([
271 'success' => false,
272 'message' => $error_message,
273 ], 401);
274 }
275
276 wp_set_current_user($user->ID);
277
278 return new \WP_REST_Response([
279 'success' => true,
280 'message' => __('Login successful! Redirecting...', 'yatra'),
281 'user_id' => $user->ID,
282 ]);
283 }
284
285 /**
286 * Handle registration request
287 */
288 public static function register(\WP_REST_Request $request): \WP_REST_Response
289 {
290 if (!\Yatra\Services\SettingsService::isEnabled('customer_registration')) {
291 return new \WP_REST_Response([
292 'success' => false,
293 'message' => __('New customer registration is disabled.', 'yatra'),
294 ], 403);
295 }
296
297 // reCAPTCHA v3 (no-op unless the registration form is protected in settings).
298 $recaptcha = \Yatra\Services\RecaptchaService::verifyForm(
299 'registration',
300 (string) ($request->get_param('recaptcha_token') ?? ''),
301 $_SERVER['REMOTE_ADDR'] ?? null
302 );
303 if (empty($recaptcha['success'])) {
304 return new \WP_REST_Response([
305 'success' => false,
306 'message' => $recaptcha['message'] ?? __('reCAPTCHA verification failed.', 'yatra'),
307 ], 400);
308 }
309
310 $first_name = sanitize_text_field($request->get_param('first_name') ?? '');
311 $last_name = sanitize_text_field($request->get_param('last_name') ?? '');
312 $email = sanitize_email($request->get_param('email') ?? '');
313 $phone = sanitize_text_field($request->get_param('phone') ?? '');
314 $password = $request->get_param('password') ?? '';
315 $confirm_password = $request->get_param('confirm_password') ?? '';
316
317 // Validation
318 if (empty($first_name)) {
319 return new \WP_REST_Response([
320 'success' => false,
321 'message' => __('Please enter your first name.', 'yatra'),
322 ], 400);
323 }
324
325 if (empty($last_name)) {
326 return new \WP_REST_Response([
327 'success' => false,
328 'message' => __('Please enter your last name.', 'yatra'),
329 ], 400);
330 }
331
332 if (empty($email) || !is_email($email)) {
333 return new \WP_REST_Response([
334 'success' => false,
335 'message' => __('Please enter a valid email address.', 'yatra'),
336 ], 400);
337 }
338
339 if (empty($password) || strlen($password) < 8) {
340 return new \WP_REST_Response([
341 'success' => false,
342 'message' => __('Password must be at least 8 characters long.', 'yatra'),
343 ], 400);
344 }
345
346 if ($password !== $confirm_password) {
347 return new \WP_REST_Response([
348 'success' => false,
349 'message' => __('Passwords do not match.', 'yatra'),
350 ], 400);
351 }
352
353 if (email_exists($email)) {
354 return new \WP_REST_Response([
355 'success' => false,
356 'message' => __('An account with this email already exists. Please login instead.', 'yatra'),
357 ], 409);
358 }
359
360 // Generate username
361 $username = sanitize_user(current(explode('@', $email)));
362 $original_username = $username;
363 $counter = 1;
364
365 while (username_exists($username)) {
366 $username = $original_username . $counter;
367 $counter++;
368 }
369
370 // Create user
371 $user_id = wp_create_user($username, $password, $email);
372
373 if (is_wp_error($user_id)) {
374 $error_message = wp_strip_all_tags($user_id->get_error_message());
375 return new \WP_REST_Response([
376 'success' => false,
377 'message' => $error_message,
378 ], 500);
379 }
380
381 // Assign Yatra Customer role
382 $user = new \WP_User($user_id);
383 $user->set_role('yatra_customer');
384
385 // Update user meta
386 wp_update_user([
387 'ID' => $user_id,
388 'first_name' => $first_name,
389 'last_name' => $last_name,
390 'display_name' => $first_name . ' ' . $last_name,
391 ]);
392
393 if (!empty($phone)) {
394 update_user_meta($user_id, 'billing_phone', $phone);
395 update_user_meta($user_id, 'phone', $phone);
396 }
397
398 // Email verification
399 update_user_meta($user_id, 'yatra_email_verified', '0');
400
401 $verification_token = wp_generate_password(32, false);
402 $secure_token = base64_encode($user_id . '|' . $verification_token . '|' . time());
403 $secure_token = str_replace(['+', '/', '='], ['-', '_', ''], $secure_token);
404
405 update_user_meta($user_id, 'yatra_verification_token', $verification_token);
406 update_user_meta($user_id, 'yatra_verification_token_expiry', time() + (24 * 60 * 60));
407
408 // Send verification email
409 self::sendVerificationEmail($user_id, $email, $first_name, $secure_token);
410
411 // Admin notification
412 wp_new_user_notification($user_id, null, 'admin');
413
414 return new \WP_REST_Response([
415 'success' => true,
416 'message' => __('Registration successful! Please check your email to verify your account before logging in.', 'yatra'),
417 'user_id' => $user_id,
418 'require_verification' => true,
419 ]);
420 }
421
422 /**
423 * Handle resend verification request
424 */
425 public static function resendVerification(\WP_REST_Request $request): \WP_REST_Response
426 {
427 $email = sanitize_email($request->get_param('email') ?? '');
428
429 if (empty($email) || !is_email($email)) {
430 return new \WP_REST_Response([
431 'success' => false,
432 'message' => __('Please enter a valid email address.', 'yatra'),
433 ], 400);
434 }
435
436 $user = get_user_by('email', $email);
437
438 if (!$user) {
439 return new \WP_REST_Response([
440 'success' => true,
441 'message' => __('If an account with this email exists and is pending verification, a new verification link has been sent.', 'yatra'),
442 ]);
443 }
444
445 $email_verified = get_user_meta($user->ID, 'yatra_email_verified', true);
446
447 if ($email_verified === '1' || $email_verified === 1 || $email_verified === true) {
448 return new \WP_REST_Response([
449 'success' => false,
450 'message' => __('This email is already verified. You can login now.', 'yatra'),
451 ], 400);
452 }
453
454 $meta_exists = metadata_exists('user', $user->ID, 'yatra_email_verified');
455 $has_verification_token = get_user_meta($user->ID, 'yatra_verification_token', true);
456
457 if (!$meta_exists && empty($has_verification_token)) {
458 return new \WP_REST_Response([
459 'success' => true,
460 'message' => __('If an account with this email exists and is pending verification, a new verification link has been sent.', 'yatra'),
461 ]);
462 }
463
464 // Rate limiting
465 $last_sent = get_user_meta($user->ID, 'yatra_verification_last_sent', true);
466 if ($last_sent && (time() - (int) $last_sent) < 120) {
467 $remaining = 120 - (time() - (int) $last_sent);
468 return new \WP_REST_Response([
469 'success' => false,
470 'message' => __('Please wait before requesting another verification email.', 'yatra'),
471 'rate_limited' => true,
472 'remaining_seconds' => $remaining,
473 ], 429);
474 }
475
476 // Generate new token
477 $verification_token = wp_generate_password(32, false);
478 $secure_token = base64_encode($user->ID . '|' . $verification_token . '|' . time());
479 $secure_token = str_replace(['+', '/', '='], ['-', '_', ''], $secure_token);
480
481 update_user_meta($user->ID, 'yatra_verification_token', $verification_token);
482 update_user_meta($user->ID, 'yatra_verification_token_expiry', time() + (24 * 60 * 60));
483 update_user_meta($user->ID, 'yatra_verification_last_sent', time());
484
485 // Send email
486 $first_name = get_user_meta($user->ID, 'first_name', true) ?: $user->display_name;
487 self::sendVerificationEmail($user->ID, $email, $first_name, $secure_token, true);
488
489 return new \WP_REST_Response([
490 'success' => true,
491 'message' => __('A new verification link has been sent to your email address. Please check your inbox.', 'yatra'),
492 ]);
493 }
494
495 /**
496 * Handle email verification
497 */
498 public static function handleEmailVerification(): void
499 {
500 $secure_token = (string) get_query_var('yatra_verify_email');
501 if ($secure_token === '' && isset($_GET['yatra_verify_email'])) {
502 $raw = wp_unslash($_GET['yatra_verify_email']);
503 $secure_token = is_string($raw) ? preg_replace('/[^a-zA-Z0-9_-]/', '', $raw) ?? '' : '';
504 }
505
506 if ($secure_token === '') {
507 self::showVerificationError(__('Invalid verification link.', 'yatra'));
508
509 return;
510 }
511
512 $previewToken = defined('YATRA_EMAIL_VERIFICATION_PREVIEW_TOKEN')
513 ? (string) YATRA_EMAIL_VERIFICATION_PREVIEW_TOKEN
514 : 'preview-verify-token';
515 if ($secure_token === $previewToken) {
516 self::showEmailVerificationPreviewNotice();
517
518 return;
519 }
520
521 // Decode token
522 $secure_token = str_replace(['-', '_'], ['+', '/'], $secure_token);
523 $decoded = base64_decode($secure_token);
524
525 if (!$decoded || strpos($decoded, '|') === false) {
526 self::showVerificationError(__('Invalid verification link.', 'yatra'));
527 return;
528 }
529
530 $parts = explode('|', $decoded);
531 if (count($parts) < 2) {
532 self::showVerificationError(__('Invalid verification link.', 'yatra'));
533 return;
534 }
535
536 $user_id = (int) $parts[0];
537 $token = $parts[1];
538
539 if ($user_id <= 0 || empty($token)) {
540 self::showVerificationError(__('Invalid verification link.', 'yatra'));
541 return;
542 }
543
544 $stored_token = get_user_meta($user_id, 'yatra_verification_token', true);
545 $token_expiry = get_user_meta($user_id, 'yatra_verification_token_expiry', true);
546
547 // Idempotent path: the token+expiry are deleted as soon as a successful
548 // verification completes (see below), so a second click on the same
549 // link previously fell into the "Invalid or expired" branch and made
550 // already-verified customers believe their account was broken. Detect
551 // the prior-success state explicitly and reuse the success page so the
552 // outcome is clear regardless of how many times the link is clicked.
553 $already_verified = get_user_meta($user_id, 'yatra_email_verified', true) === '1';
554 if ($already_verified) {
555 self::showVerificationSuccess(true);
556 return;
557 }
558
559 if (empty($stored_token) || $stored_token !== $token) {
560 self::showVerificationError(__('Invalid or expired verification link.', 'yatra'));
561 return;
562 }
563
564 if ($token_expiry && time() > (int) $token_expiry) {
565 self::showVerificationError(__('This verification link has expired. Please register again.', 'yatra'));
566 return;
567 }
568
569 // Mark as verified
570 update_user_meta($user_id, 'yatra_email_verified', '1');
571 delete_user_meta($user_id, 'yatra_verification_token');
572 delete_user_meta($user_id, 'yatra_verification_token_expiry');
573
574 self::showVerificationSuccess(false);
575 return;
576 }
577
578 /**
579 * Send verification email
580 */
581 private static function sendVerificationEmail(int $_user_id, string $email, string $first_name, string $secure_token, bool $isResend = false): void
582 {
583 $verificationUrl = function_exists('yatra_get_email_verification_url')
584 ? yatra_get_email_verification_url($secure_token)
585 : home_url('/yatra-verify-email/' . rawurlencode($secure_token) . '/');
586
587 $siteName = get_bloginfo('name');
588 $introParagraph = $isResend
589 ? sprintf(
590 /* translators: %s: site name */
591 __('You requested a new verification link for your account at %s. Click the button below to verify your email address.', 'yatra'),
592 $siteName
593 )
594 : sprintf(
595 /* translators: %s: site name */
596 __('Thank you for registering at %s. Please verify your email address to activate your account.', 'yatra'),
597 $siteName
598 );
599
600 $footerNote = $isResend
601 ? __('If you did not request this email, you can ignore it.', 'yatra')
602 : __('If you did not create this account, you can ignore this email.', 'yatra');
603
604 $expiryNoticeHtml = esc_html(
605 sprintf(
606 /* translators: %d: hours until link expiry */
607 __('This verification link expires in %d hours for your security.', 'yatra'),
608 24
609 )
610 );
611
612 \Yatra\Services\TransactionalEmailTemplateService::sendIfEnabled(
613 \Yatra\Services\TransactionalEmailTemplateService::TYPE_CUSTOMER_EMAIL_VERIFICATION,
614 $email,
615 [
616 'customer_first_name' => $first_name,
617 'customer_name' => $first_name,
618 'customer_email' => $email,
619 'verification_link' => $verificationUrl,
620 'intro_paragraph' => $introParagraph,
621 'footer_note' => $footerNote,
622 'expiry_notice_html' => $expiryNoticeHtml,
623 ]
624 );
625 }
626
627 /**
628 * Show verification error page (hard-fail dead-end with a route back home).
629 * Every string is translatable — operators run Yatra in many locales and
630 * the pre-3.0.5 hardcoded "Verification Failed" heading was untranslatable.
631 */
632 private static function showVerificationError(string $message): void
633 {
634 $heading = esc_html__('Verification Failed', 'yatra');
635 $cta = esc_html__('Go to Homepage', 'yatra');
636
637 wp_die(
638 '<div style="text-align: center; padding: 50px; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;">
639 <h1 style="color: #dc2626; margin-bottom: 20px;">' . $heading . '</h1>
640 <p style="color: #4b5563; font-size: 16px; margin-bottom: 30px;">' . esc_html($message) . '</p>
641 <a href="' . esc_url(home_url()) . '" style="display: inline-block; background: #3b82f6; color: #fff; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600;">' . $cta . '</a>
642 </div>',
643 __('Verification Failed', 'yatra'),
644 ['response' => 400]
645 );
646 }
647
648 /**
649 * Render an unambiguous "email verified" confirmation page.
650 *
651 * The pre-3.0.5 flow silently 302-redirected to the checkout URL with a
652 * `?email_verified=1` flag, relying on `booking-auth.php` to surface a
653 * one-liner notice. That notice only renders when the auth form itself
654 * renders (no booking session / logged-in user → notice never shown), so
655 * customers regularly saw "nothing happened" after clicking the link.
656 *
657 * Now we render a dedicated success page with explicit confirmation, the
658 * verified email-state, and a primary CTA back into the booking flow.
659 * Idempotent: a second click on the same link reaches `$already=true`
660 * and shows "Your email is already verified" instead of the misleading
661 * "Invalid or expired link" error.
662 *
663 * @param bool $already True when the user has already been verified by an
664 * earlier click on the same link (idempotent path).
665 */
666 private static function showVerificationSuccess(bool $already): void
667 {
668 $checkoutUrl = function_exists('yatra_get_checkout_url')
669 ? yatra_get_checkout_url()
670 : home_url('/');
671 $continueUrl = add_query_arg(['email_verified' => '1'], $checkoutUrl);
672
673 $heading = $already
674 ? esc_html__('Email Already Verified', 'yatra')
675 : esc_html__('Email Verified', 'yatra');
676 $message = $already
677 ? esc_html__('Your email address is already verified — no further action is needed. You can continue with your booking.', 'yatra')
678 : esc_html__('Your email address has been verified successfully. You can now log in and continue with your booking.', 'yatra');
679 $cta = esc_html__('Continue to Checkout', 'yatra');
680 $homeCta = esc_html__('Go to Homepage', 'yatra');
681 $title = $already
682 ? __('Email Already Verified', 'yatra')
683 : __('Email Verified', 'yatra');
684
685 // Inline-only styling so the page renders correctly regardless of
686 // theme stylesheet load order (wp_die() can fire before themes
687 // enqueue their styles).
688 $body = '<div style="text-align: center; padding: 50px 20px; max-width: 520px; margin: 0 auto; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;">'
689 . '<div style="display: inline-flex; align-items: center; justify-content: center; width: 72px; height: 72px; border-radius: 50%; background: #d1fae5; margin: 0 auto 24px;">'
690 . '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">'
691 . '<polyline points="20 6 9 17 4 12"></polyline>'
692 . '</svg>'
693 . '</div>'
694 . '<h1 style="color: #065f46; margin: 0 0 12px; font-size: 26px;">' . $heading . '</h1>'
695 . '<p style="color: #4b5563; font-size: 16px; line-height: 1.6; margin: 0 0 28px;">' . $message . '</p>'
696 . '<a href="' . esc_url($continueUrl) . '" style="display: inline-block; background: #059669; color: #fff; padding: 12px 28px; border-radius: 8px; text-decoration: none; font-weight: 600; margin-right: 8px;">' . $cta . '</a>'
697 . '<a href="' . esc_url(home_url()) . '" style="display: inline-block; color: #4b5563; padding: 12px 16px; text-decoration: none; font-weight: 500;">' . $homeCta . '</a>'
698 . '</div>';
699
700 wp_die($body, $title, ['response' => 200]);
701 }
702
703 /**
704 * Inform users that the link is only for email template previews.
705 */
706 private static function showEmailVerificationPreviewNotice(): void
707 {
708 $body = '<div style="text-align: center; padding: 50px; max-width: 520px; margin: 0 auto; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;">
709 <h1 style="color: #1e40af; margin-bottom: 16px;">' . esc_html__('Sample verification link', 'yatra') . '</h1>
710 <p style="color: #4b5563; font-size: 16px; line-height: 1.6; margin-bottom: 24px;">' . esc_html__(
711 'This URL is used only in email previews and test messages. It does not verify an account. Use the link from your real verification email to activate your account.',
712 'yatra'
713 ) . '</p>
714 <a href="' . esc_url(home_url()) . '" style="display: inline-block; background: #3b82f6; color: #fff; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600;">' . esc_html__('Go to homepage', 'yatra') . '</a>
715 </div>';
716
717 wp_die(
718 $body,
719 __('Email verification (preview)', 'yatra'),
720 ['response' => 200]
721 );
722 }
723 }
724
725