PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.8
Yatra – Travel Booking & Tour Operator Software v3.0.8
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 2.0.10 All 83 releases
yatra / app / Controllers / SetupWizardController.php

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

810 lines 27.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Setup Wizard Controller
4 * Handles the one-time setup wizard for Yatra plugin
5 *
6 * @package Yatra\Controllers
7 * @since 3.0.0
8 */
9
10 namespace Yatra\Controllers;
11
12 use Yatra\Services\StatsUsage;
13 use Yatra\Helpers\CurrencyHelper;
14 use Yatra\Services\SettingsService;
15
16 defined('ABSPATH') || exit;
17
18 class SetupWizardController
19 {
20 /**
21 * Option name to track wizard completion (legacy compatibility)
22 */
23 const WIZARD_COMPLETED_OPTION = 'yatra_setup_wizard_ran';
24
25 /**
26 * Option name to track wizard redirect
27 */
28 const WIZARD_REDIRECT_OPTION = 'yatra_setup_wizard_redirect';
29
30 /**
31 * Current step
32 *
33 * @var string
34 */
35 private $step = '';
36
37 /**
38 * Steps for the setup wizard
39 *
40 * @var array
41 */
42 private $steps = array();
43
44 /**
45 * Constructor
46 */
47 public function __construct()
48 {
49 // Only register admin menu if setup wizard is enabled
50 if (apply_filters('yatra_enable_setup_wizard', true) && current_user_can('manage_options')) {
51 add_action('admin_menu', array($this, 'admin_menus'));
52 }
53
54 add_action('admin_init', array($this, 'setup_wizard'));
55
56 // Add AJAX handlers for theme actions
57 add_action('wp_ajax_yatra_install_theme', array($this, 'ajax_install_theme'));
58 add_action('wp_ajax_yatra_activate_theme', array($this, 'ajax_activate_theme'));
59 }
60
61 /**
62 * Get wizard steps
63 * Called after init to ensure translations are loaded
64 */
65 private function get_steps()
66 {
67 if (!empty($this->steps)) {
68 return $this->steps;
69 }
70
71 $this->steps = array(
72 'welcome' => array(
73 'name' => __('Welcome', 'yatra'),
74 'view' => array($this, 'setup_welcome'),
75 'handler' => array($this, 'setup_welcome_save'),
76 ),
77 'business' => array(
78 'name' => __('Business', 'yatra'),
79 'view' => array($this, 'setup_business'),
80 'handler' => array($this, 'setup_business_save'),
81 ),
82 'bookings' => array(
83 'name' => __('Bookings', 'yatra'),
84 'view' => array($this, 'setup_bookings'),
85 'handler' => array($this, 'setup_bookings_save'),
86 ),
87 'communications' => array(
88 'name' => __('Email & payments', 'yatra'),
89 'view' => array($this, 'setup_communications'),
90 'handler' => array($this, 'setup_communications_save'),
91 ),
92 'currency' => array(
93 'name' => __('Currency', 'yatra'),
94 'view' => array($this, 'setup_currency'),
95 'handler' => array($this, 'setup_currency_save'),
96 ),
97 'theme' => array(
98 'name' => __('Theme', 'yatra'),
99 'view' => array($this, 'setup_theme'),
100 'handler' => array($this, 'setup_theme_save'),
101 ),
102 'complete' => array(
103 'name' => __('Done', 'yatra'),
104 'view' => array($this, 'setup_complete'),
105 'handler' => array($this, 'setup_complete_save'),
106 ),
107 );
108
109 $this->steps = apply_filters('yatra_setup_wizard_steps', $this->steps, $this);
110
111 return $this->steps;
112 }
113
114 /**
115 * Register admin menus
116 */
117 public function admin_menus()
118 {
119 // Must stay registered in $submenu: WordPress runs user_can_access_admin_page() in menu.php
120 // before admin_init; remove_submenu_page() breaks parent resolution and causes 403 on this URL.
121 // The item is hidden from the sidebar via CSS in AdminServiceProvider.
122 add_submenu_page(
123 'yatra',
124 __('Yatra Setup Wizard', 'yatra'),
125 __('Setup wizard', 'yatra'),
126 'manage_options',
127 'yatra-setup',
128 array($this, 'setup_wizard')
129 );
130 }
131
132
133 /**
134 * Show the setup wizard
135 */
136 public function setup_wizard()
137 {
138 if (empty($_GET['page']) || 'yatra-setup' !== $_GET['page']) {
139 return;
140 }
141
142 // Handle skip setup request
143 if (isset($_GET['skip_setup']) && $_GET['skip_setup'] === '1') {
144 $this->skip_setup_wizard();
145 }
146
147 $steps = $this->get_steps();
148 $this->step = isset($_GET['step']) ? sanitize_key($_GET['step']) : current(array_keys($steps));
149
150 if (class_exists(StatsUsage::class)) {
151 $usage = StatsUsage::instance();
152 if ($this->step === 'welcome') {
153 $usage->mark_onboarding_started();
154 }
155 $usage->set_onboarding_step($this->step);
156 }
157
158 // Legacy URL: step=general → business
159 if ($this->step === 'general' && isset($steps['business'])) {
160 wp_safe_redirect(esc_url_raw($this->get_step_url('business')));
161 exit;
162 }
163
164 // Process form submission BEFORE any output
165 if (!empty($_POST['save_step'])) {
166 $save_step = sanitize_key($_POST['save_step']);
167 if ($save_step === $this->step && isset($steps[$this->step]['handler'])) {
168 call_user_func($steps[$this->step]['handler'], $this);
169 // Handler should redirect and exit, so code below won't execute
170 }
171 }
172
173 // Enqueue styles and scripts before outputting HTML
174 $this->enqueue_wizard_assets();
175
176 $this->setup_wizard_steps();
177 $this->setup_wizard_content();
178 exit;
179 }
180
181 /**
182 * Enqueue wizard assets
183 */
184 private function enqueue_wizard_assets()
185 {
186 // Enqueue setup wizard styles
187 wp_enqueue_style(
188 'yatra-setup-wizard',
189 YATRA_PLUGIN_URL . 'assets/admin/css/setup-wizard.css',
190 [],
191 YATRA_VERSION
192 );
193
194 // Enqueue setup wizard scripts
195 wp_enqueue_script(
196 'yatra-setup-wizard',
197 YATRA_PLUGIN_URL . 'assets/admin/js/setup-wizard.js',
198 ['jquery'],
199 YATRA_VERSION,
200 true
201 );
202
203 // Localize script
204 wp_localize_script('yatra-setup-wizard', 'yatraSetupWizard', [
205 'ajax_url' => admin_url('admin-ajax.php'),
206 'nonce' => wp_create_nonce('yatra_setup_wizard_nonce'),
207 'skipConfirmMessage' => __('Skip this step? Nothing on this screen will be saved—you can finish later in Yatra Settings.', 'yatra'),
208 'strings' => [
209 'confirm_leave' => __('Are you sure you want to leave the setup wizard?', 'yatra'),
210 'saving' => __('Saving...', 'yatra'),
211 'saved' => __('Saved!', 'yatra'),
212 'error' => __('Error occurred', 'yatra'),
213 ],
214 ]);
215 }
216
217 /**
218 * Get the URL for the next step
219 */
220 public function get_next_step_link()
221 {
222 $steps = $this->get_steps();
223 $keys = array_keys($steps);
224 $current_key = array_search($this->step, $keys);
225
226 if (false === $current_key) {
227 return '';
228 }
229
230 $next_key = $current_key + 1;
231
232 if (isset($keys[$next_key])) {
233 return $this->get_step_url($keys[$next_key]);
234 }
235
236 return '';
237 }
238
239 /**
240 * Get URL for a specific step
241 */
242 public function get_step_url($step)
243 {
244 return add_query_arg(
245 array(
246 'page' => 'yatra-setup',
247 'step' => $step
248 ),
249 admin_url('admin.php')
250 );
251 }
252
253 /**
254 * Setup wizard steps
255 */
256 public function setup_wizard_steps()
257 {
258 $output_steps = $this->get_steps();
259 ?>
260 <!DOCTYPE html>
261 <html <?php language_attributes(); ?>>
262 <head>
263 <meta name="viewport" content="width=device-width"/>
264 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
265 <title><?php esc_html_e('Yatra &rsaquo; Setup Wizard', 'yatra'); ?></title>
266 <?php wp_print_styles('yatra-setup-wizard'); ?>
267 <?php wp_print_scripts('jquery'); ?>
268 <?php wp_print_scripts('yatra-setup-wizard'); ?>
269 </head>
270 <body class="yatra-setup wp-core-ui">
271 <div class="yatra-setup-wrapper">
272 <ol class="yatra-setup-steps">
273 <?php
274 $step_icons = array(
275 'welcome' => '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>',
276 'business' => '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 21h18"></path><path d="M5 21V7l8-4v18"></path><path d="M19 21V11l-6-4"></path></svg>',
277 'bookings' => '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>',
278 'communications' => '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>',
279 'currency' => '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="1" x2="12" y2="23"></line><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path></svg>',
280 'theme' => '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"></path><path d="M2 17l10 5 10-5M2 12l10 5 10-5"></path></svg>',
281 'complete' => '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></path></svg>'
282 );
283
284 $ordered_keys = array_keys($output_steps);
285 foreach ($output_steps as $step_key => $step) {
286 $cur = array_search($this->step, $ordered_keys, true);
287 $pos = array_search($step_key, $ordered_keys, true);
288 $is_completed = $cur !== false && $pos !== false && $cur > $pos;
289 $icon = isset($step_icons[$step_key]) ? $step_icons[$step_key] : '';
290
291 if ($step_key === $this->step) {
292 ?>
293 <li class="active"><span class="step-icon"><?php echo $icon; ?></span><?php echo esc_html($step['name']); ?></li>
294 <?php
295 } elseif ($is_completed) {
296 ?>
297 <li class="done">
298 <a href="<?php echo esc_url($this->get_step_url($step_key)); ?>"><span class="step-icon"><?php echo $icon; ?></span><?php echo esc_html($step['name']); ?></a>
299 </li>
300 <?php
301 } else {
302 ?>
303 <li><span class="step-icon"><?php echo $icon; ?></span><?php echo esc_html($step['name']); ?></li>
304 <?php
305 }
306 }
307 ?>
308 </ol>
309 <?php
310 }
311
312 /**
313 * Setup wizard content
314 */
315 public function setup_wizard_content()
316 {
317 $steps = $this->get_steps();
318
319 echo '<div class="yatra-setup-content">';
320 if (isset($steps[$this->step]['view'])) {
321 call_user_func($steps[$this->step]['view'], $this);
322 }
323 echo '</div>';
324 echo '</div>'; // .yatra-setup-wrapper
325 ?>
326 </body>
327 </html>
328 <?php
329 }
330
331 /**
332 * Safe redirect target passed from wizard navigation links.
333 */
334 private function get_redirect_target(string $default): string
335 {
336 $redirectTo = isset($_POST['yatra_redirect_to']) ? (string) wp_unslash($_POST['yatra_redirect_to']) : '';
337 $redirectTo = $redirectTo !== '' ? esc_url_raw($redirectTo) : '';
338
339 // Only allow admin URLs on the same host.
340 if ($redirectTo !== '') {
341 $validated = wp_validate_redirect($redirectTo, '');
342 if ($validated !== '' && strpos($validated, admin_url()) === 0) {
343 return $validated;
344 }
345 }
346
347 return $default;
348 }
349
350 /**
351 * Welcome step
352 */
353 public function setup_welcome()
354 {
355 include YATRA_ABSPATH . 'templates/setup-wizard/welcome.php';
356 }
357
358 /**
359 * Save welcome step (usage opt-in) and continue to Business.
360 */
361 public function setup_welcome_save()
362 {
363 check_admin_referer('yatra-setup');
364
365 $allow_tracking = !empty($_POST['yatra_allow_usage_tracking']);
366 update_option('yatra_allow_usage_tracking', $allow_tracking);
367 if (class_exists(StatsUsage::class)) {
368 if ($allow_tracking) {
369 StatsUsage::instance()->enable(true);
370 } else {
371 StatsUsage::instance()->disable();
372 }
373 }
374
375 wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
376 exit;
377 }
378
379 /**
380 * Human-readable progress for task steps (excludes decorative copy on welcome).
381 */
382 public function get_wizard_progress_label(): string
383 {
384 $steps = $this->get_steps();
385 $keys = array_keys($steps);
386 $idx = array_search($this->step, $keys, true);
387 if ($idx === false) {
388 return '';
389 }
390
391 return sprintf(
392 /* translators: 1: current step number, 2: total steps */
393 __('Step %1$d of %2$d', 'yatra'),
394 (int) $idx + 1,
395 count($keys)
396 );
397 }
398
399 /**
400 * Business profile (company contact only).
401 */
402 public function setup_business()
403 {
404 include YATRA_ABSPATH . 'templates/setup-wizard/business.php';
405 }
406
407 /**
408 * Save business profile.
409 */
410 public function setup_business_save()
411 {
412 check_admin_referer('yatra-setup');
413
414 $settings = [
415 'company_name' => isset($_POST['company_name']) ? sanitize_text_field(wp_unslash($_POST['company_name'])) : '',
416 'company_email' => isset($_POST['company_email']) ? sanitize_email(wp_unslash($_POST['company_email'])) : '',
417 'company_phone' => isset($_POST['company_phone']) ? sanitize_text_field(wp_unslash($_POST['company_phone'])) : '',
418 ];
419
420 foreach ($settings as $key => $value) {
421 update_option('yatra_' . $key, $value);
422 }
423
424 $extra = apply_filters('yatra_setup_wizard_business_save', [], $_POST);
425 if (is_array($extra)) {
426 foreach ($extra as $optionKey => $value) {
427 if (! is_string($optionKey) || $optionKey === '') {
428 continue;
429 }
430 if (strpos($optionKey, 'yatra_') === 0) {
431 update_option($optionKey, $value);
432 } else {
433 update_option('yatra_' . $optionKey, $value);
434 }
435 }
436 }
437
438 SettingsService::reload();
439
440 wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
441 exit;
442 }
443
444 /**
445 * Booking behaviour (guest checkout, confirmations).
446 */
447 public function setup_bookings()
448 {
449 include YATRA_ABSPATH . 'templates/setup-wizard/bookings.php';
450 }
451
452 /**
453 * Save booking behaviour.
454 */
455 public function setup_bookings_save()
456 {
457 check_admin_referer('yatra-setup');
458
459 update_option('yatra_enable_guest_booking', isset($_POST['enable_guest_booking']) && $_POST['enable_guest_booking'] === 'true');
460 update_option('yatra_booking_confirmation', isset($_POST['booking_confirmation']) && $_POST['booking_confirmation'] === 'true');
461
462 $extra = apply_filters('yatra_setup_wizard_bookings_save', [], $_POST);
463 if (is_array($extra)) {
464 foreach ($extra as $optionKey => $value) {
465 if (! is_string($optionKey) || $optionKey === '') {
466 continue;
467 }
468 if (strpos($optionKey, 'yatra_') === 0) {
469 update_option($optionKey, $value);
470 } else {
471 update_option('yatra_' . $optionKey, $value);
472 }
473 }
474 }
475
476 SettingsService::reload();
477
478 wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
479 exit;
480 }
481
482 /**
483 * Email identity, notifications, payment safety.
484 */
485 public function setup_communications()
486 {
487 include YATRA_ABSPATH . 'templates/setup-wizard/communications.php';
488 }
489
490 /**
491 * Save communications & payment safety settings.
492 */
493 public function setup_communications_save()
494 {
495 check_admin_referer('yatra-setup');
496
497 $companyName = (string) SettingsService::get('company_name', '');
498 $companyEmail = (string) SettingsService::get('company_email', '');
499
500 $fromName = isset($_POST['email_from_name']) ? sanitize_text_field(wp_unslash($_POST['email_from_name'])) : '';
501 $fromEmail = isset($_POST['email_from_address']) ? sanitize_email(wp_unslash($_POST['email_from_address'])) : '';
502 if ($fromName === '') {
503 $fromName = $companyName;
504 }
505 if ($fromEmail === '') {
506 $fromEmail = $companyEmail;
507 }
508 update_option('yatra_from_name', $fromName);
509 update_option('yatra_from_email', $fromEmail);
510 update_option('yatra_email_from_name', $fromName);
511 update_option('yatra_email_from_address', $fromEmail);
512
513 update_option('yatra_payment_test_mode', isset($_POST['payment_test_mode']) && $_POST['payment_test_mode'] === 'true');
514
515 $extra = apply_filters('yatra_setup_wizard_communications_save', [], $_POST);
516 if (is_array($extra)) {
517 foreach ($extra as $optionKey => $value) {
518 if (! is_string($optionKey) || $optionKey === '') {
519 continue;
520 }
521 if (strpos($optionKey, 'yatra_') === 0) {
522 update_option($optionKey, $value);
523 } else {
524 update_option('yatra_' . $optionKey, $value);
525 }
526 }
527 }
528
529 // Back-compat: extensions that hooked the old single "general" save.
530 $legacyExtra = apply_filters('yatra_setup_wizard_general_save', [], $_POST);
531 if (is_array($legacyExtra)) {
532 foreach ($legacyExtra as $optionKey => $value) {
533 if (! is_string($optionKey) || $optionKey === '') {
534 continue;
535 }
536 if (strpos($optionKey, 'yatra_') === 0) {
537 update_option($optionKey, $value);
538 } else {
539 update_option('yatra_' . $optionKey, $value);
540 }
541 }
542 }
543
544 SettingsService::reload();
545
546 wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
547 exit;
548 }
549
550 /**
551 * Currency settings step
552 */
553 public function setup_currency()
554 {
555 include YATRA_ABSPATH . 'templates/setup-wizard/currency.php';
556 }
557
558 /**
559 * Save currency settings
560 */
561 public function setup_currency_save()
562 {
563 check_admin_referer('yatra-setup');
564
565 $currency_code = isset($_POST['currency']) ? sanitize_text_field($_POST['currency']) : 'USD';
566
567 // Validate currency exists
568 if (!CurrencyHelper::exists($currency_code)) {
569 $currency_code = 'USD'; // Fallback to USD
570 }
571
572 // Get recommended decimal places for the selected currency
573 $currency_data = CurrencyHelper::get($currency_code);
574 $recommended_decimals = $currency_data ? $currency_data['decimal_digits'] : 2;
575
576 // Use user-specified decimals or fall back to currency recommendation
577 $user_decimals = isset($_POST['decimal_places']) ? absint($_POST['decimal_places']) : $recommended_decimals;
578
579 $settings = array(
580 'yatra_currency' => $currency_code,
581 'yatra_currency_position' => isset($_POST['currency_position']) ? sanitize_text_field($_POST['currency_position']) : 'before',
582 'yatra_thousand_separator' => isset($_POST['thousand_separator']) ? sanitize_text_field($_POST['thousand_separator']) : ',',
583 'yatra_decimal_separator' => isset($_POST['decimal_separator']) ? sanitize_text_field($_POST['decimal_separator']) : '.',
584 'yatra_decimal_places' => $user_decimals,
585 );
586
587 foreach ($settings as $key => $value) {
588 update_option($key, $value);
589 }
590
591 SettingsService::reload();
592
593 wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
594 exit;
595 }
596
597 /**
598 * Theme step
599 */
600 public function setup_theme()
601 {
602 include YATRA_ABSPATH . 'templates/setup-wizard/theme.php';
603 }
604
605 /**
606 * Save theme settings
607 */
608 public function setup_theme_save()
609 {
610 check_admin_referer('yatra-setup');
611
612 // Handle theme installation if requested
613 if (isset($_POST['install_resa_theme']) && $_POST['install_resa_theme'] === 'yes') {
614 set_transient('yatra_install_resa_theme', 1, 300);
615 }
616
617 update_option('yatra_setup_wizard_theme_step_done', '1');
618 SettingsService::reload();
619
620 wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
621 exit;
622 }
623
624 /**
625 * Complete step
626 */
627 public function setup_complete()
628 {
629 include YATRA_ABSPATH . 'templates/setup-wizard/complete.php';
630 }
631
632 /**
633 * Handle complete step actions
634 */
635 public function setup_complete_save()
636 {
637 check_admin_referer('yatra-setup');
638
639 update_option(self::WIZARD_COMPLETED_OPTION, '1');
640 SettingsService::reload();
641 do_action('yatra_setup_wizard_completed');
642
643 wp_safe_redirect(admin_url('admin.php?page=yatra'));
644 exit;
645 }
646
647 /**
648 * Check if wizard is completed
649 */
650 public static function is_wizard_completed()
651 {
652 return get_option(self::WIZARD_COMPLETED_OPTION, '0') === '1';
653 }
654
655 /**
656 * Reset wizard
657 */
658 public static function reset_wizard()
659 {
660 delete_option(self::WIZARD_COMPLETED_OPTION);
661 delete_option(self::WIZARD_REDIRECT_OPTION);
662 }
663
664 /**
665 * Check if wizard should run (for debugging/testing)
666 */
667 public static function should_run_wizard()
668 {
669 return get_option(self::WIZARD_COMPLETED_OPTION, '0') !== '1' &&
670 apply_filters('yatra_enable_setup_wizard', true) &&
671 current_user_can('manage_options');
672 }
673
674 /**
675 * Handle skipping the setup wizard
676 */
677 public function skip_setup_wizard()
678 {
679 update_option('yatra_allow_usage_tracking', false);
680 if (class_exists(StatsUsage::class)) {
681 $u = StatsUsage::instance();
682 $u->patch_onboarding_meta([
683 'dropoff_step' => 'welcome',
684 'skipped_at' => time(),
685 ]);
686 if ($u->is_enabled()) {
687 $u->record_event('setup_abandoned');
688 }
689 $u->disable();
690 }
691
692 // Mark wizard as completed
693 update_option(self::WIZARD_COMPLETED_OPTION, '1');
694
695 // Redirect to admin dashboard
696 wp_safe_redirect(admin_url());
697 exit;
698 }
699
700 /**
701 * Setup wizard redirect on activation
702 */
703 public static function setup_wizard_redirect()
704 {
705 // Only redirect if not completed and redirect flag is set
706 if (get_transient(self::WIZARD_REDIRECT_OPTION)) {
707 delete_transient(self::WIZARD_REDIRECT_OPTION);
708
709 if (!self::is_wizard_completed()) {
710 wp_safe_redirect(admin_url('admin.php?page=yatra-setup'));
711 exit;
712 }
713 }
714 }
715
716 /**
717 * AJAX handler for theme installation
718 */
719 public function ajax_install_theme()
720 {
721 check_ajax_referer('yatra_theme_actions', 'nonce');
722
723 if (!current_user_can('install_themes')) {
724 wp_send_json_error('You do not have permission to install themes.');
725 }
726
727 $theme_slug = isset($_POST['theme_slug']) ? sanitize_text_field($_POST['theme_slug']) : '';
728
729 if (empty($theme_slug)) {
730 wp_send_json_error('Theme slug is required.');
731 }
732
733 // Include WordPress theme installation functions
734 if (!class_exists('Theme_Upgrader')) {
735 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
736 }
737
738 if (!class_exists('Theme_Installer_Skin')) {
739 require_once ABSPATH . 'wp-admin/includes/theme.php';
740 }
741
742 // Check if theme is already installed
743 if ($resa_theme = wp_get_theme($theme_slug)) {
744 if ($resa_theme->exists()) {
745 // Theme is already installed, just activate it
746 wp_send_json_success('Theme already installed, proceeding to activation.');
747 }
748 }
749
750 // Install the theme with aggressive output buffering
751 $original_level = ob_get_level();
752 ob_start();
753 $upgrader = new \Theme_Upgrader(new \Theme_Installer_Skin());
754 $result = $upgrader->install("https://downloads.wordpress.org/theme/resa.zip");
755
756 // Clean all output buffers
757 while (ob_get_level() > $original_level) {
758 ob_end_clean();
759 }
760
761 // Also clean any remaining output
762 if (ob_get_length() > 0) {
763 ob_clean();
764 }
765
766 if (is_wp_error($result)) {
767 wp_send_json_error($result->get_error_message());
768 }
769
770 if (!$result) {
771 wp_send_json_error('Theme installation failed.');
772 }
773
774 wp_send_json_success('Theme installed successfully.');
775 }
776
777 /**
778 * AJAX handler for theme activation
779 */
780 public function ajax_activate_theme()
781 {
782 check_ajax_referer('yatra_theme_actions', 'nonce');
783
784 if (!current_user_can('switch_themes')) {
785 wp_send_json_error('You do not have permission to activate themes.');
786 }
787
788 $theme_slug = isset($_POST['theme_slug']) ? sanitize_text_field($_POST['theme_slug']) : '';
789
790 if (empty($theme_slug)) {
791 wp_send_json_error('Theme slug is required.');
792 }
793
794 // Check if theme exists
795 $theme = wp_get_theme($theme_slug);
796 if (!$theme->exists()) {
797 wp_send_json_error('Theme is not installed.');
798 }
799
800 // Activate the theme
801 $result = switch_theme($theme_slug);
802
803 if (is_wp_error($result)) {
804 wp_send_json_error($result->get_error_message());
805 }
806
807 wp_send_json_success('Theme activated successfully.');
808 }
809 }
810