# yatra/3.0.3/app/Controllers/SetupWizardController.php

Yatra – Travel Booking &amp; Tour Operator Software, version 3.0.3. 810 lines.

- Page: https://pluginprobe.com/plugins/yatra/3.0.3/code/app/Controllers/SetupWizardController.php
- Raw: https://pluginprobe.com/plugins/yatra/3.0.3/raw/app/Controllers/SetupWizardController.php
- Modified: 2026-04-21T12:58:06+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/yatra/3.0.3/code/app/Controllers/SetupWizardController.php#L10-L20`.

```php
<?php
/**
 * Setup Wizard Controller
 * Handles the one-time setup wizard for Yatra plugin
 *
 * @package Yatra\Controllers
 * @since 3.0.0
 */

namespace Yatra\Controllers;

use Yatra\Services\StatsUsage;
use Yatra\Helpers\CurrencyHelper;
use Yatra\Services\SettingsService;

defined('ABSPATH') || exit;

class SetupWizardController
{
    /**
     * Option name to track wizard completion (legacy compatibility)
     */
    const WIZARD_COMPLETED_OPTION = 'yatra_setup_wizard_ran';

    /**
     * Option name to track wizard redirect
     */
    const WIZARD_REDIRECT_OPTION = 'yatra_setup_wizard_redirect';

    /**
     * Current step
     *
     * @var string
     */
    private $step = '';

    /**
     * Steps for the setup wizard
     *
     * @var array
     */
    private $steps = array();

    /**
     * Constructor
     */
    public function __construct()
    {
        // Only register admin menu if setup wizard is enabled
        if (apply_filters('yatra_enable_setup_wizard', true) && current_user_can('manage_options')) {
            add_action('admin_menu', array($this, 'admin_menus'));
        }
        
        add_action('admin_init', array($this, 'setup_wizard'));
        
        // Add AJAX handlers for theme actions
        add_action('wp_ajax_yatra_install_theme', array($this, 'ajax_install_theme'));
        add_action('wp_ajax_yatra_activate_theme', array($this, 'ajax_activate_theme'));
    }

    /**
     * Get wizard steps
     * Called after init to ensure translations are loaded
     */
    private function get_steps()
    {
        if (!empty($this->steps)) {
            return $this->steps;
        }

        $this->steps = array(
            'welcome' => array(
                'name' => __('Welcome', 'yatra'),
                'view' => array($this, 'setup_welcome'),
                'handler' => array($this, 'setup_welcome_save'),
            ),
            'business' => array(
                'name' => __('Business', 'yatra'),
                'view' => array($this, 'setup_business'),
                'handler' => array($this, 'setup_business_save'),
            ),
            'bookings' => array(
                'name' => __('Bookings', 'yatra'),
                'view' => array($this, 'setup_bookings'),
                'handler' => array($this, 'setup_bookings_save'),
            ),
            'communications' => array(
                'name' => __('Email & payments', 'yatra'),
                'view' => array($this, 'setup_communications'),
                'handler' => array($this, 'setup_communications_save'),
            ),
            'currency' => array(
                'name' => __('Currency', 'yatra'),
                'view' => array($this, 'setup_currency'),
                'handler' => array($this, 'setup_currency_save'),
            ),
            'theme' => array(
                'name' => __('Theme', 'yatra'),
                'view' => array($this, 'setup_theme'),
                'handler' => array($this, 'setup_theme_save'),
            ),
            'complete' => array(
                'name' => __('Done', 'yatra'),
                'view' => array($this, 'setup_complete'),
                'handler' => array($this, 'setup_complete_save'),
            ),
        );

        $this->steps = apply_filters('yatra_setup_wizard_steps', $this->steps, $this);

        return $this->steps;
    }

    /**
     * Register admin menus
     */
    public function admin_menus()
    {
        // Must stay registered in $submenu: WordPress runs user_can_access_admin_page() in menu.php
        // before admin_init; remove_submenu_page() breaks parent resolution and causes 403 on this URL.
        // The item is hidden from the sidebar via CSS in AdminServiceProvider.
        add_submenu_page(
            'yatra',
            __('Yatra Setup Wizard', 'yatra'),
            __('Setup wizard', 'yatra'),
            'manage_options',
            'yatra-setup',
            array($this, 'setup_wizard')
        );
    }


    /**
     * Show the setup wizard
     */
    public function setup_wizard()
    {
        if (empty($_GET['page']) || 'yatra-setup' !== $_GET['page']) {
            return;
        }

        // Handle skip setup request
        if (isset($_GET['skip_setup']) && $_GET['skip_setup'] === '1') {
            $this->skip_setup_wizard();
        }

        $steps = $this->get_steps();
        $this->step = isset($_GET['step']) ? sanitize_key($_GET['step']) : current(array_keys($steps));

        if (class_exists(StatsUsage::class)) {
            $usage = StatsUsage::instance();
            if ($this->step === 'welcome') {
                $usage->mark_onboarding_started();
            }
            $usage->set_onboarding_step($this->step);
        }

        // Legacy URL: step=general → business
        if ($this->step === 'general' && isset($steps['business'])) {
            wp_safe_redirect(esc_url_raw($this->get_step_url('business')));
            exit;
        }

        // Process form submission BEFORE any output
        if (!empty($_POST['save_step'])) {
            $save_step = sanitize_key($_POST['save_step']);
            if ($save_step === $this->step && isset($steps[$this->step]['handler'])) {
                call_user_func($steps[$this->step]['handler'], $this);
                // Handler should redirect and exit, so code below won't execute
            }
        }

        // Enqueue styles and scripts before outputting HTML
        $this->enqueue_wizard_assets();

        $this->setup_wizard_steps();
        $this->setup_wizard_content();
        exit;
    }

    /**
     * Enqueue wizard assets
     */
    private function enqueue_wizard_assets()
    {
        // Enqueue setup wizard styles
        wp_enqueue_style(
            'yatra-setup-wizard',
            YATRA_PLUGIN_URL . 'assets/admin/css/setup-wizard.css',
            [],
            YATRA_VERSION
        );

        // Enqueue setup wizard scripts
        wp_enqueue_script(
            'yatra-setup-wizard',
            YATRA_PLUGIN_URL . 'assets/admin/js/setup-wizard.js',
            ['jquery'],
            YATRA_VERSION,
            true
        );

        // Localize script
        wp_localize_script('yatra-setup-wizard', 'yatraSetupWizard', [
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('yatra_setup_wizard_nonce'),
            'skipConfirmMessage' => __('Skip this step? Nothing on this screen will be saved—you can finish later in Yatra Settings.', 'yatra'),
            'strings' => [
                'confirm_leave' => __('Are you sure you want to leave the setup wizard?', 'yatra'),
                'saving' => __('Saving...', 'yatra'),
                'saved' => __('Saved!', 'yatra'),
                'error' => __('Error occurred', 'yatra'),
            ],
        ]);
    }

    /**
     * Get the URL for the next step
     */
    public function get_next_step_link()
    {
        $steps = $this->get_steps();
        $keys = array_keys($steps);
        $current_key = array_search($this->step, $keys);

        if (false === $current_key) {
            return '';
        }

        $next_key = $current_key + 1;

        if (isset($keys[$next_key])) {
            return $this->get_step_url($keys[$next_key]);
        }

        return '';
    }

    /**
     * Get URL for a specific step
     */
    public function get_step_url($step)
    {
        return add_query_arg(
            array(
                'page' => 'yatra-setup',
                'step' => $step
            ),
            admin_url('admin.php')
        );
    }

    /**
     * Setup wizard steps
     */
    public function setup_wizard_steps()
    {
        $output_steps = $this->get_steps();
        ?>
        <!DOCTYPE html>
        <html <?php language_attributes(); ?>>
        <head>
            <meta name="viewport" content="width=device-width"/>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
            <title><?php esc_html_e('Yatra &rsaquo; Setup Wizard', 'yatra'); ?></title>
            <?php wp_print_styles('yatra-setup-wizard'); ?>
            <?php wp_print_scripts('jquery'); ?>
            <?php wp_print_scripts('yatra-setup-wizard'); ?>
        </head>
        <body class="yatra-setup wp-core-ui">
            <div class="yatra-setup-wrapper">
                <ol class="yatra-setup-steps">
                    <?php
                    $step_icons = array(
                        '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>',
                        '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>',
                        '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>',
                        '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>',
                        '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>',
                        '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>',
                        '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>'
                    );
                    
                    $ordered_keys = array_keys($output_steps);
                    foreach ($output_steps as $step_key => $step) {
                        $cur = array_search($this->step, $ordered_keys, true);
                        $pos = array_search($step_key, $ordered_keys, true);
                        $is_completed = $cur !== false && $pos !== false && $cur > $pos;
                        $icon = isset($step_icons[$step_key]) ? $step_icons[$step_key] : '';

                        if ($step_key === $this->step) {
                            ?>
                            <li class="active"><span class="step-icon"><?php echo $icon; ?></span><?php echo esc_html($step['name']); ?></li>
                            <?php
                        } elseif ($is_completed) {
                            ?>
                            <li class="done">
                                <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>
                            </li>
                            <?php
                        } else {
                            ?>
                            <li><span class="step-icon"><?php echo $icon; ?></span><?php echo esc_html($step['name']); ?></li>
                            <?php
                        }
                    }
                    ?>
                </ol>
        <?php
    }

    /**
     * Setup wizard content
     */
    public function setup_wizard_content()
    {
        $steps = $this->get_steps();
        
        echo '<div class="yatra-setup-content">';
        if (isset($steps[$this->step]['view'])) {
            call_user_func($steps[$this->step]['view'], $this);
        }
        echo '</div>';
        echo '</div>'; // .yatra-setup-wrapper
        ?>
        </body>
        </html>
        <?php
    }

    /**
     * Safe redirect target passed from wizard navigation links.
     */
    private function get_redirect_target(string $default): string
    {
        $redirectTo = isset($_POST['yatra_redirect_to']) ? (string) wp_unslash($_POST['yatra_redirect_to']) : '';
        $redirectTo = $redirectTo !== '' ? esc_url_raw($redirectTo) : '';

        // Only allow admin URLs on the same host.
        if ($redirectTo !== '') {
            $validated = wp_validate_redirect($redirectTo, '');
            if ($validated !== '' && strpos($validated, admin_url()) === 0) {
                return $validated;
            }
        }

        return $default;
    }

    /**
     * Welcome step
     */
    public function setup_welcome()
    {
        include YATRA_ABSPATH . 'templates/setup-wizard/welcome.php';
    }

    /**
     * Save welcome step (usage opt-in) and continue to Business.
     */
    public function setup_welcome_save()
    {
        check_admin_referer('yatra-setup');

        $allow_tracking = !empty($_POST['yatra_allow_usage_tracking']);
        update_option('yatra_allow_usage_tracking', $allow_tracking);
        if (class_exists(StatsUsage::class)) {
            if ($allow_tracking) {
                StatsUsage::instance()->enable(true);
            } else {
                StatsUsage::instance()->disable();
            }
        }

        wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
        exit;
    }

    /**
     * Human-readable progress for task steps (excludes decorative copy on welcome).
     */
    public function get_wizard_progress_label(): string
    {
        $steps = $this->get_steps();
        $keys = array_keys($steps);
        $idx = array_search($this->step, $keys, true);
        if ($idx === false) {
            return '';
        }

        return sprintf(
            /* translators: 1: current step number, 2: total steps */
            __('Step %1$d of %2$d', 'yatra'),
            (int) $idx + 1,
            count($keys)
        );
    }

    /**
     * Business profile (company contact only).
     */
    public function setup_business()
    {
        include YATRA_ABSPATH . 'templates/setup-wizard/business.php';
    }

    /**
     * Save business profile.
     */
    public function setup_business_save()
    {
        check_admin_referer('yatra-setup');

        $settings = [
            'company_name' => isset($_POST['company_name']) ? sanitize_text_field(wp_unslash($_POST['company_name'])) : '',
            'company_email' => isset($_POST['company_email']) ? sanitize_email(wp_unslash($_POST['company_email'])) : '',
            'company_phone' => isset($_POST['company_phone']) ? sanitize_text_field(wp_unslash($_POST['company_phone'])) : '',
        ];

        foreach ($settings as $key => $value) {
            update_option('yatra_' . $key, $value);
        }

        $extra = apply_filters('yatra_setup_wizard_business_save', [], $_POST);
        if (is_array($extra)) {
            foreach ($extra as $optionKey => $value) {
                if (! is_string($optionKey) || $optionKey === '') {
                    continue;
                }
                if (strpos($optionKey, 'yatra_') === 0) {
                    update_option($optionKey, $value);
                } else {
                    update_option('yatra_' . $optionKey, $value);
                }
            }
        }

        SettingsService::reload();

        wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
        exit;
    }

    /**
     * Booking behaviour (guest checkout, confirmations).
     */
    public function setup_bookings()
    {
        include YATRA_ABSPATH . 'templates/setup-wizard/bookings.php';
    }

    /**
     * Save booking behaviour.
     */
    public function setup_bookings_save()
    {
        check_admin_referer('yatra-setup');

        update_option('yatra_enable_guest_booking', isset($_POST['enable_guest_booking']) && $_POST['enable_guest_booking'] === 'true');
        update_option('yatra_booking_confirmation', isset($_POST['booking_confirmation']) && $_POST['booking_confirmation'] === 'true');

        $extra = apply_filters('yatra_setup_wizard_bookings_save', [], $_POST);
        if (is_array($extra)) {
            foreach ($extra as $optionKey => $value) {
                if (! is_string($optionKey) || $optionKey === '') {
                    continue;
                }
                if (strpos($optionKey, 'yatra_') === 0) {
                    update_option($optionKey, $value);
                } else {
                    update_option('yatra_' . $optionKey, $value);
                }
            }
        }

        SettingsService::reload();

        wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
        exit;
    }

    /**
     * Email identity, notifications, payment safety.
     */
    public function setup_communications()
    {
        include YATRA_ABSPATH . 'templates/setup-wizard/communications.php';
    }

    /**
     * Save communications & payment safety settings.
     */
    public function setup_communications_save()
    {
        check_admin_referer('yatra-setup');

        $companyName = (string) SettingsService::get('company_name', '');
        $companyEmail = (string) SettingsService::get('company_email', '');

        $fromName = isset($_POST['email_from_name']) ? sanitize_text_field(wp_unslash($_POST['email_from_name'])) : '';
        $fromEmail = isset($_POST['email_from_address']) ? sanitize_email(wp_unslash($_POST['email_from_address'])) : '';
        if ($fromName === '') {
            $fromName = $companyName;
        }
        if ($fromEmail === '') {
            $fromEmail = $companyEmail;
        }
        update_option('yatra_from_name', $fromName);
        update_option('yatra_from_email', $fromEmail);
        update_option('yatra_email_from_name', $fromName);
        update_option('yatra_email_from_address', $fromEmail);

        update_option('yatra_payment_test_mode', isset($_POST['payment_test_mode']) && $_POST['payment_test_mode'] === 'true');

        $extra = apply_filters('yatra_setup_wizard_communications_save', [], $_POST);
        if (is_array($extra)) {
            foreach ($extra as $optionKey => $value) {
                if (! is_string($optionKey) || $optionKey === '') {
                    continue;
                }
                if (strpos($optionKey, 'yatra_') === 0) {
                    update_option($optionKey, $value);
                } else {
                    update_option('yatra_' . $optionKey, $value);
                }
            }
        }

        // Back-compat: extensions that hooked the old single "general" save.
        $legacyExtra = apply_filters('yatra_setup_wizard_general_save', [], $_POST);
        if (is_array($legacyExtra)) {
            foreach ($legacyExtra as $optionKey => $value) {
                if (! is_string($optionKey) || $optionKey === '') {
                    continue;
                }
                if (strpos($optionKey, 'yatra_') === 0) {
                    update_option($optionKey, $value);
                } else {
                    update_option('yatra_' . $optionKey, $value);
                }
            }
        }

        SettingsService::reload();

        wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
        exit;
    }

    /**
     * Currency settings step
     */
    public function setup_currency()
    {
        include YATRA_ABSPATH . 'templates/setup-wizard/currency.php';
    }

    /**
     * Save currency settings
     */
    public function setup_currency_save()
    {
        check_admin_referer('yatra-setup');

        $currency_code = isset($_POST['currency']) ? sanitize_text_field($_POST['currency']) : 'USD';
        
        // Validate currency exists
        if (!CurrencyHelper::exists($currency_code)) {
            $currency_code = 'USD'; // Fallback to USD
        }

        // Get recommended decimal places for the selected currency
        $currency_data = CurrencyHelper::get($currency_code);
        $recommended_decimals = $currency_data ? $currency_data['decimal_digits'] : 2;
        
        // Use user-specified decimals or fall back to currency recommendation
        $user_decimals = isset($_POST['decimal_places']) ? absint($_POST['decimal_places']) : $recommended_decimals;

        $settings = array(
            'yatra_currency' => $currency_code,
            'yatra_currency_position' => isset($_POST['currency_position']) ? sanitize_text_field($_POST['currency_position']) : 'before',
            'yatra_thousand_separator' => isset($_POST['thousand_separator']) ? sanitize_text_field($_POST['thousand_separator']) : ',',
            'yatra_decimal_separator' => isset($_POST['decimal_separator']) ? sanitize_text_field($_POST['decimal_separator']) : '.',
            'yatra_decimal_places' => $user_decimals,
        );

        foreach ($settings as $key => $value) {
            update_option($key, $value);
        }

        SettingsService::reload();

        wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
        exit;
    }

    /**
     * Theme step
     */
    public function setup_theme()
    {
        include YATRA_ABSPATH . 'templates/setup-wizard/theme.php';
    }

    /**
     * Save theme settings
     */
    public function setup_theme_save()
    {
        check_admin_referer('yatra-setup');

        // Handle theme installation if requested
        if (isset($_POST['install_resa_theme']) && $_POST['install_resa_theme'] === 'yes') {
            set_transient('yatra_install_resa_theme', 1, 300);
        }

        update_option('yatra_setup_wizard_theme_step_done', '1');
        SettingsService::reload();

        wp_safe_redirect($this->get_redirect_target((string) $this->get_next_step_link()));
        exit;
    }

    /**
     * Complete step
     */
    public function setup_complete()
    {
        include YATRA_ABSPATH . 'templates/setup-wizard/complete.php';
    }

    /**
     * Handle complete step actions
     */
    public function setup_complete_save()
    {
        check_admin_referer('yatra-setup');

        update_option(self::WIZARD_COMPLETED_OPTION, '1');
        SettingsService::reload();
        do_action('yatra_setup_wizard_completed');

        wp_safe_redirect(admin_url('admin.php?page=yatra'));
        exit;
    }

    /**
     * Check if wizard is completed
     */
    public static function is_wizard_completed()
    {
        return get_option(self::WIZARD_COMPLETED_OPTION, '0') === '1';
    }

    /**
     * Reset wizard
     */
    public static function reset_wizard()
    {
        delete_option(self::WIZARD_COMPLETED_OPTION);
        delete_option(self::WIZARD_REDIRECT_OPTION);
    }

    /**
     * Check if wizard should run (for debugging/testing)
     */
    public static function should_run_wizard()
    {
        return get_option(self::WIZARD_COMPLETED_OPTION, '0') !== '1' && 
               apply_filters('yatra_enable_setup_wizard', true) && 
               current_user_can('manage_options');
    }

    /**
     * Handle skipping the setup wizard
     */
    public function skip_setup_wizard()
    {
        update_option('yatra_allow_usage_tracking', false);
        if (class_exists(StatsUsage::class)) {
            $u = StatsUsage::instance();
            $u->patch_onboarding_meta([
                'dropoff_step' => 'welcome',
                'skipped_at' => time(),
            ]);
            if ($u->is_enabled()) {
                $u->record_event('setup_abandoned');
            }
            $u->disable();
        }

        // Mark wizard as completed
        update_option(self::WIZARD_COMPLETED_OPTION, '1');
        
        // Redirect to admin dashboard
        wp_safe_redirect(admin_url());
        exit;
    }

    /**
     * Setup wizard redirect on activation
     */
    public static function setup_wizard_redirect()
    {
        // Only redirect if not completed and redirect flag is set
        if (get_transient(self::WIZARD_REDIRECT_OPTION)) {
            delete_transient(self::WIZARD_REDIRECT_OPTION);

            if (!self::is_wizard_completed()) {
                wp_safe_redirect(admin_url('admin.php?page=yatra-setup'));
                exit;
            }
        }
    }

    /**
     * AJAX handler for theme installation
     */
    public function ajax_install_theme()
    {
        check_ajax_referer('yatra_theme_actions', 'nonce');
        
        if (!current_user_can('install_themes')) {
            wp_send_json_error('You do not have permission to install themes.');
        }
        
        $theme_slug = isset($_POST['theme_slug']) ? sanitize_text_field($_POST['theme_slug']) : '';
        
        if (empty($theme_slug)) {
            wp_send_json_error('Theme slug is required.');
        }
        
        // Include WordPress theme installation functions
        if (!class_exists('Theme_Upgrader')) {
            require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
        }
        
        if (!class_exists('Theme_Installer_Skin')) {
            require_once ABSPATH . 'wp-admin/includes/theme.php';
        }
        
        // Check if theme is already installed
        if ($resa_theme = wp_get_theme($theme_slug)) {
            if ($resa_theme->exists()) {
                // Theme is already installed, just activate it
                wp_send_json_success('Theme already installed, proceeding to activation.');
            }
        }
        
        // Install the theme with aggressive output buffering
        $original_level = ob_get_level();
        ob_start();
        $upgrader = new \Theme_Upgrader(new \Theme_Installer_Skin());
        $result = $upgrader->install("https://downloads.wordpress.org/theme/resa.zip");
        
        // Clean all output buffers
        while (ob_get_level() > $original_level) {
            ob_end_clean();
        }
        
        // Also clean any remaining output
        if (ob_get_length() > 0) {
            ob_clean();
        }
        
        if (is_wp_error($result)) {
            wp_send_json_error($result->get_error_message());
        }
        
        if (!$result) {
            wp_send_json_error('Theme installation failed.');
        }
        
        wp_send_json_success('Theme installed successfully.');
    }
    
    /**
     * AJAX handler for theme activation
     */
    public function ajax_activate_theme()
    {
        check_ajax_referer('yatra_theme_actions', 'nonce');
        
        if (!current_user_can('switch_themes')) {
            wp_send_json_error('You do not have permission to activate themes.');
        }
        
        $theme_slug = isset($_POST['theme_slug']) ? sanitize_text_field($_POST['theme_slug']) : '';
        
        if (empty($theme_slug)) {
            wp_send_json_error('Theme slug is required.');
        }
        
        // Check if theme exists
        $theme = wp_get_theme($theme_slug);
        if (!$theme->exists()) {
            wp_send_json_error('Theme is not installed.');
        }
        
        // Activate the theme
        $result = switch_theme($theme_slug);
        
        if (is_wp_error($result)) {
            wp_send_json_error($result->get_error_message());
        }
        
        wp_send_json_success('Theme activated successfully.');
    }
}

```
