<?php
/**
 * Name: Redirects Manager
 * Description: Manage 301 and 302 redirects with pattern matching and wildcard support to handle URL changes, fix broken links, or redirect old pages automatically
 * Category: Utilities
 * Icon: -
 * UseCases: [
 *   {
 *     "title": "SEO-Friendly Redirects",
 *     "description": "Maintain SEO value when changing URLs by setting up proper 301 redirects."
 *   },
 *   {
 *     "title": "Broken Link Management",
 *     "description": "Fix broken links and improve user experience by redirecting old URLs to new content."
 *   },
 *   {
 *     "title": "Site Migration",
 *     "description": "Handle URL structure changes during site migrations with wildcard pattern matching."
 *   }
 * ]
 * WhereToFind: {
 *   "location": "Switchboard → Redirects Manager",
 *   "url": "admin.php?page=switchboard-redirects",
 *   "instructions": "View all redirects with stats, add new redirects, and track redirect hits",
 *   "newTab": false
 * }
 * Added: 2025-01-15
 * Tags: redirects, 301, 302, seo, urls, links
 */

// Prevent direct access
if (!defined('ABSPATH')) exit;

class SwitchboardRedirectsManager {

    private $table_name;

    public function __construct() {
        global $wpdb;
        $this->table_name = $wpdb->prefix . 'switchboard_redirects';

        // Create table if it doesn't exist
        $this->maybe_create_table();

        // Core hooks
        add_action('template_redirect', array($this, 'handle_redirects'), 1);
        add_action('admin_menu', array($this, 'add_admin_menu'));

        // Enqueue admin scripts
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));

        // AJAX handlers
        add_action('wp_ajax_switchboard_redirects_get_stats', array($this, 'ajax_get_stats'));
        add_action('wp_ajax_switchboard_redirects_get_all', array($this, 'ajax_get_all'));
        add_action('wp_ajax_switchboard_redirects_create', array($this, 'ajax_create'));
        add_action('wp_ajax_switchboard_redirects_update', array($this, 'ajax_update'));
        add_action('wp_ajax_switchboard_redirects_toggle', array($this, 'ajax_toggle'));
        add_action('wp_ajax_switchboard_redirects_delete', array($this, 'ajax_delete'));
        add_action('wp_ajax_switchboard_redirects_bulk_delete', array($this, 'ajax_bulk_delete'));
        add_action('wp_ajax_switchboard_redirects_get_pages', array($this, 'ajax_get_pages'));
    }

    /**
     * Check and create table if it doesn't exist
     */
    private function maybe_create_table() {
        global $wpdb;
        $table_exists = $wpdb->get_var("SHOW TABLES LIKE '{$this->table_name}'");

        if ($table_exists != $this->table_name) {
            $this->create_table();
        }
    }

    /**
     * Create redirects table
     */
    private function create_table() {
        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE IF NOT EXISTS {$this->table_name} (
            id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            source_url varchar(500) NOT NULL,
            target_url varchar(500) NOT NULL,
            redirect_type varchar(3) DEFAULT '301',
            match_type varchar(20) DEFAULT 'exact',
            is_active tinyint(1) DEFAULT 1,
            hit_count bigint(20) UNSIGNED DEFAULT 0,
            last_hit datetime DEFAULT NULL,
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            KEY source_url (source_url(191)),
            KEY is_active (is_active),
            KEY hit_count (hit_count)
        ) $charset_collate;";

        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql);
    }

    /**
     * Add admin menu
     */
    public function add_admin_menu() {
        add_submenu_page(
            'switchboard',
            'Redirects',
            'Redirects',
            'manage_options',
            'switchboard-redirects',
            array($this, 'render_admin_page')
        );
    }

    /**
     * Enqueue admin assets
     */
    public function enqueue_admin_assets($hook) {
        // Check if we're on the redirects manager page
        $is_redirects_page = (
            (isset($_GET['page']) && $_GET['page'] === 'switchboard-redirects') ||
            strpos($hook, 'switchboard-redirects') !== false
        );

        if (!$is_redirects_page) {
            return;
        }

        // Enqueue the main Switchboard admin CSS (contains all sb-mp-* and sb-sp-* classes)
        if (defined('SWITCHBOARD_URL') && defined('SWITCHBOARD_VERSION')) {
            wp_enqueue_style(
                'switchboard-admin',
                SWITCHBOARD_URL . 'switchboard-admin.css',
                [],
                SWITCHBOARD_VERSION
            );
        }

        // Ensure jQuery is loaded
        wp_enqueue_script('jquery');
    }

    /**
     * Render admin page
     */
    public function render_admin_page() {
        global $wpdb;

        // Get stats
        $total_redirects = $wpdb->get_var("SELECT COUNT(*) FROM {$this->table_name}");
        $active_redirects = $wpdb->get_var("SELECT COUNT(*) FROM {$this->table_name} WHERE is_active = 1");
        $total_hits = $wpdb->get_var("SELECT SUM(hit_count) FROM {$this->table_name}");
        $hits_today = $wpdb->get_var(
            "SELECT SUM(hit_count) FROM {$this->table_name} WHERE DATE(last_hit) = CURDATE()"
        );

        // Get top performing redirects
        $top_redirects = $wpdb->get_results(
            "SELECT id, source_url, target_url, hit_count, created_at FROM {$this->table_name}
            WHERE is_active = 1 ORDER BY hit_count DESC LIMIT 5"
        );

        // Get recent redirects
        $recent_redirects = $wpdb->get_results(
            "SELECT id, source_url, target_url, hit_count, created_at FROM {$this->table_name}
            ORDER BY created_at DESC LIMIT 5"
        );

        ?>
        <div class="wrap sb-module-wrap">
            <!-- Header -->
            <div class="sb-module-header">
                <div class="sb-module-header-left">
                    <svg class="sb-module-title-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"></path>
                    </svg>
                    <div>
                        <h1 class="sb-module-title">
                            <?php esc_html_e('Redirects Manager', 'wpswitchboard'); ?>
                            <span class="switchboard-badge">SWITCHBOARD</span>
                        </h1>
                        <p class="sb-module-subtitle"><?php esc_html_e('Manage URL redirects and track performance', 'wpswitchboard'); ?></p>
                    </div>
                </div>
                <div class="sb-module-header-right">
                    <a href="https://docs.wpswitchboard.com/modules/utilities/redirects-manager" target="_blank" class="sb-module-help-link">
                        <span class="sb-module-help-link-icon dashicons dashicons-editor-help"></span>
                        Help
                    </a>
                    <input type="search" id="redirects-search" class="sb-module-search-input" placeholder="<?php esc_attr_e('Search redirects...', 'wpswitchboard'); ?>" style="min-width: 250px;">
                    <button type="button" id="add-redirect-btn" class="sb-module-button sb-module-button-primary sb-module-button-icon-text">
                        <span class="dashicons dashicons-plus-alt"></span>
                        <?php esc_html_e('Add Redirect', 'wpswitchboard'); ?>
                    </button>
                </div>
            </div>

            <!-- Main Content -->
            <div class="sb-module-container">
            <!-- Stats Cards -->
            <div class="sb-module-stats">
                <div class="sb-module-stat-card">
                    <div class="sb-module-stat-label"><?php esc_html_e('Total Redirects', 'wpswitchboard'); ?></div>
                    <div class="sb-module-stat-content">
                        <div class="sb-module-stat-value"><?php echo number_format($total_redirects ?: 0); ?></div>
                    </div>
                </div>

                <div class="sb-module-stat-card">
                    <div class="sb-module-stat-label"><?php esc_html_e('Active Redirects', 'wpswitchboard'); ?></div>
                    <div class="sb-module-stat-content">
                        <div class="sb-module-stat-value"><?php echo number_format($active_redirects ?: 0); ?></div>
                    </div>
                </div>

                <div class="sb-module-stat-card">
                    <div class="sb-module-stat-label"><?php esc_html_e('Total Hits', 'wpswitchboard'); ?></div>
                    <div class="sb-module-stat-content">
                        <div class="sb-module-stat-value"><?php echo number_format($total_hits ?: 0); ?></div>
                    </div>
                </div>

                <div class="sb-module-stat-card">
                    <div class="sb-module-stat-label"><?php esc_html_e('Hits Today', 'wpswitchboard'); ?></div>
                    <div class="sb-module-stat-content">
                        <div class="sb-module-stat-value"><?php echo number_format($hits_today ?: 0); ?></div>
                    </div>
                </div>
            </div>

            <!-- Two Column Layout -->
            <div class="sb-module-layout-2col" style="grid-template-columns: 1fr 1fr !important;">
                <!-- Top Performing -->
                <div class="sb-module-card">
                    <div class="sb-module-card-header">
                        <h2 class="sb-module-card-title"><?php esc_html_e('Top Performing Redirects', 'wpswitchboard'); ?></h2>
                    </div>
                    <div class="sb-module-card-body">
                        <?php if (!empty($top_redirects)): ?>
                            <div class="sb-module-table-wrapper">
                                <table class="sb-module-table">
                                    <thead>
                                        <tr>
                                            <th><?php esc_html_e('Source URL', 'wpswitchboard'); ?></th>
                                            <th style="width: 80px;"><?php esc_html_e('Hits', 'wpswitchboard'); ?></th>
                                            <th style="width: 120px; white-space: nowrap;"><?php esc_html_e('Action', 'wpswitchboard'); ?></th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <?php foreach ($top_redirects as $redirect): ?>
                                            <tr>
                                                <td title="<?php echo esc_attr($redirect->source_url); ?>">
                                                    <div style="display: flex; align-items: center; gap: 8px;">
                                                        <span><?php echo esc_html(strlen($redirect->source_url) > 40 ? substr($redirect->source_url, 0, 40) . '...' : $redirect->source_url); ?></span>
                                                        <a href="<?php echo esc_url($redirect->source_url); ?>" target="_blank" title="<?php esc_attr_e('Visit and test redirect', 'wpswitchboard'); ?>" style="color: #64748b;">
                                                            <span class="dashicons dashicons-external"></span>
                                                        </a>
                                                    </div>
                                                </td>
                                                <td><?php echo number_format($redirect->hit_count); ?></td>
                                                <td style="white-space: nowrap;">
                                                    <button type="button" class="sb-module-button sb-module-button-secondary sb-module-button-sm edit-redirect" data-id="<?php echo $redirect->id; ?>" style="white-space: nowrap;"><?php esc_html_e('Edit', 'wpswitchboard'); ?></button>
                                                </td>
                                            </tr>
                                        <?php endforeach; ?>
                                    </tbody>
                                </table>
                            </div>
                        <?php else: ?>
                            <div class="sb-module-empty">
                                <p class="sb-module-empty-desc"><?php esc_html_e('No redirects yet', 'wpswitchboard'); ?></p>
                            </div>
                        <?php endif; ?>
                    </div>
                </div>

                <!-- Recent Redirects -->
                <div class="sb-module-card">
                    <div class="sb-module-card-header">
                        <h2 class="sb-module-card-title"><?php esc_html_e('Recently Added', 'wpswitchboard'); ?></h2>
                    </div>
                    <div class="sb-module-card-body">
                        <?php if (!empty($recent_redirects)): ?>
                            <div class="sb-module-table-wrapper">
                                <table class="sb-module-table">
                                    <thead>
                                        <tr>
                                            <th><?php esc_html_e('Source URL', 'wpswitchboard'); ?></th>
                                            <th style="width: 80px;"><?php esc_html_e('Hits', 'wpswitchboard'); ?></th>
                                            <th style="width: 120px; white-space: nowrap;"><?php esc_html_e('Action', 'wpswitchboard'); ?></th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <?php foreach ($recent_redirects as $redirect): ?>
                                            <tr>
                                                <td title="<?php echo esc_attr($redirect->source_url); ?>">
                                                    <div style="display: flex; align-items: center; gap: 8px;">
                                                        <span><?php echo esc_html(strlen($redirect->source_url) > 40 ? substr($redirect->source_url, 0, 40) . '...' : $redirect->source_url); ?></span>
                                                        <a href="<?php echo esc_url($redirect->source_url); ?>" target="_blank" title="<?php esc_attr_e('Visit and test redirect', 'wpswitchboard'); ?>" style="color: #64748b;">
                                                            <span class="dashicons dashicons-external"></span>
                                                        </a>
                                                    </div>
                                                </td>
                                                <td><?php echo number_format($redirect->hit_count); ?></td>
                                                <td style="white-space: nowrap;">
                                                    <button type="button" class="sb-module-button sb-module-button-secondary sb-module-button-sm edit-redirect" data-id="<?php echo $redirect->id; ?>" style="white-space: nowrap;"><?php esc_html_e('Edit', 'wpswitchboard'); ?></button>
                                                </td>
                                            </tr>
                                        <?php endforeach; ?>
                                    </tbody>
                                </table>
                            </div>
                        <?php else: ?>
                            <div class="sb-module-empty">
                                <p class="sb-module-empty-desc"><?php esc_html_e('No redirects yet', 'wpswitchboard'); ?></p>
                            </div>
                        <?php endif; ?>
                    </div>
                </div>
            </div>

            <!-- All Redirects Table -->
            <div class="sb-module-card" style="margin-top: 24px;">
                <div class="sb-module-card-header">
                    <div class="sb-module-card-header-left">
                        <h2 class="sb-module-card-title"><?php esc_html_e('All Redirects', 'wpswitchboard'); ?></h2>
                    </div>
                    <div class="sb-module-card-header-right">
                        <select name="action" id="bulk-action-selector-top" class="sb-module-select" style="min-width: 150px;">
                            <option value="-1"><?php esc_html_e('Bulk Actions', 'wpswitchboard'); ?></option>
                            <option value="delete"><?php esc_html_e('Delete', 'wpswitchboard'); ?></option>
                            <option value="activate"><?php esc_html_e('Activate', 'wpswitchboard'); ?></option>
                            <option value="deactivate"><?php esc_html_e('Deactivate', 'wpswitchboard'); ?></option>
                        </select>
                        <button type="button" id="doaction" class="sb-module-button sb-module-button-secondary sb-module-button-sm"><?php esc_html_e('Apply', 'wpswitchboard'); ?></button>
                    </div>
                </div>
                <div class="sb-module-card-body" style="padding: 0;">
                    <div class="sb-module-table-wrapper">
                        <table class="sb-module-table" id="redirects-table">
                            <thead>
                                <tr>
                                    <th style="width: 40px;">
                                        <input type="checkbox" id="cb-select-all" class="sb-module-checkbox">
                                    </th>
                                    <th class="sortable" data-column="source_url" style="width: 25%;">
                                        <?php esc_html_e('Source URL', 'wpswitchboard'); ?> <span class="sort-indicator"></span>
                                    </th>
                                    <th class="sortable" data-column="target_url" style="width: 25%;">
                                        <?php esc_html_e('Target URL', 'wpswitchboard'); ?> <span class="sort-indicator"></span>
                                    </th>
                                    <th style="width: 10%;"><?php esc_html_e('Type', 'wpswitchboard'); ?></th>
                                    <th class="sortable" data-column="hit_count" style="width: 8%;">
                                        <?php esc_html_e('Hits', 'wpswitchboard'); ?> <span class="sort-indicator"></span>
                                    </th>
                                    <th style="width: 10%;"><?php esc_html_e('Status', 'wpswitchboard'); ?></th>
                                    <th class="sortable" data-column="created_at" style="width: 12%;">
                                        <?php esc_html_e('Created', 'wpswitchboard'); ?> <span class="sort-indicator"></span>
                                    </th>
                                    <th style="width: 10%;"><?php esc_html_e('Actions', 'wpswitchboard'); ?></th>
                                </tr>
                            </thead>
                            <tbody id="redirects-tbody">
                                <tr>
                                    <td colspan="8" class="sb-module-empty">
                                        <div class="sb-module-empty-icon"><span class="dashicons dashicons-clock"></span></div>
                                        <p class="sb-module-empty-desc"><?php esc_html_e('Loading redirects...', 'wpswitchboard'); ?></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>

        <!-- Add/Edit Modal -->
        <div id="redirect-modal" class="sb-module-modal" style="display: none;">
            <div class="sb-module-modal-backdrop"></div>
            <div class="sb-module-modal-content sb-module-modal-md">
                <div class="sb-module-modal-header">
                    <h2 id="modal-title" class="sb-module-modal-title"><?php esc_html_e('Add Redirect', 'wpswitchboard'); ?></h2>
                    <button type="button" class="sb-module-modal-close">&times;</button>
                </div>
                <div class="sb-module-modal-body">
                    <input type="hidden" id="redirect-id">

                    <div class="sb-sp-field-horizontal" style="margin-bottom: 16px;">
                        <div class="sb-sp-field-horizontal-left">
                            <label for="source-url" class="sb-sp-label"><?php esc_html_e('Source URL (From)', 'wpswitchboard'); ?> <span class="required">*</span></label>
                            <p class="sb-sp-description"><?php esc_html_e('Enter the path to redirect FROM (e.g., /old-page or /products/*). Only paths from same domain are allowed.', 'wpswitchboard'); ?></p>
                        </div>
                        <div>
                            <input type="text" id="source-url" class="sb-module-input" placeholder="/old-page">
                            <div class="page-selector-wrapper" style="margin-top: 8px;">
                                <input type="search" id="source-page-search" class="sb-module-input page-search-input" placeholder="<?php esc_attr_e('Or search to select existing content...', 'wpswitchboard'); ?>">
                                <div id="source-page-results" class="page-results" style="display: none;"></div>
                            </div>
                        </div>
                    </div>

                    <div class="sb-sp-field-horizontal" style="margin-bottom: 16px;">
                        <div class="sb-sp-field-horizontal-left">
                            <label for="target-url" class="sb-sp-label"><?php esc_html_e('Target URL (To)', 'wpswitchboard'); ?> <span class="required">*</span></label>
                            <p class="sb-sp-description"><?php esc_html_e('Enter the full URL to redirect TO', 'wpswitchboard'); ?></p>
                        </div>
                        <div>
                            <input type="text" id="target-url" class="sb-module-input" placeholder="https://example.com/new-page">
                            <div class="page-selector-wrapper" style="margin-top: 8px;">
                                <input type="search" id="target-page-search" class="sb-module-input page-search-input" placeholder="<?php esc_attr_e('Or search to select existing content...', 'wpswitchboard'); ?>">
                                <div id="target-page-results" class="page-results" style="display: none;"></div>
                            </div>
                        </div>
                    </div>

                    <div class="sb-sp-field-horizontal" style="margin-bottom: 16px;">
                        <div class="sb-sp-field-horizontal-left">
                            <label for="redirect-type" class="sb-sp-label"><?php esc_html_e('Redirect Type', 'wpswitchboard'); ?></label>
                            <p class="sb-sp-description"><?php esc_html_e('301 for SEO, 302 for temporary changes', 'wpswitchboard'); ?></p>
                        </div>
                        <select id="redirect-type" class="sb-module-select">
                            <option value="301">301 - <?php esc_html_e('Permanent', 'wpswitchboard'); ?></option>
                            <option value="302">302 - <?php esc_html_e('Temporary', 'wpswitchboard'); ?></option>
                        </select>
                    </div>

                    <div class="sb-sp-field-horizontal" style="margin-bottom: 16px;">
                        <div class="sb-sp-field-horizontal-left">
                            <label for="match-type" class="sb-sp-label">
                                <?php esc_html_e('Match Type', 'wpswitchboard'); ?>
                                <span class="dashicons dashicons-info" id="match-type-info" style="color: var(--primary-500); cursor: help; font-size: 16px;" title="<?php esc_attr_e('Learn about match types', 'wpswitchboard'); ?>"></span>
                            </label>
                            <p class="sb-sp-description match-type-desc">
                                <span class="exact-desc"><?php esc_html_e('Matches exact path only', 'wpswitchboard'); ?></span>
                                <span class="wildcard-desc" style="display: none;"><?php esc_html_e('Use * for pattern matching (e.g., /blog/*)', 'wpswitchboard'); ?></span>
                            </p>
                        </div>
                        <select id="match-type" class="sb-module-select">
                            <option value="exact"><?php esc_html_e('Exact Match', 'wpswitchboard'); ?></option>
                            <option value="wildcard"><?php esc_html_e('Wildcard Pattern (*)', 'wpswitchboard'); ?></option>
                        </select>
                    </div>

                    <!-- Advanced Match Type Info (collapsible) -->
                    <div class="sb-module-form-group sb-sp-section sb-sp-mt-2 hidden" id="match-type-help">
                        <h4 class="sb-sp-heading-sm"><?php esc_html_e('Match Type Guide', 'wpswitchboard'); ?></h4>
                        <div class="sb-sp-text-sm">
                            <p class="sb-sp-mb-2"><strong><?php esc_html_e('Exact Match:', 'wpswitchboard'); ?></strong> <?php esc_html_e('Redirects only when the URL path matches exactly.', 'wpswitchboard'); ?></p>
                            <p class="sb-sp-mb-2 sb-sp-pl-4 sb-sp-text-muted"><?php esc_html_e('Example:', 'wpswitchboard'); ?> <code>/old-page</code> <?php esc_html_e('only matches', 'wpswitchboard'); ?> <code>/old-page</code></p>

                            <p class="sb-sp-my-2 sb-sp-border-t sb-sp-pt-2"><strong><?php esc_html_e('Wildcard Pattern (*):', 'wpswitchboard'); ?></strong> <?php esc_html_e('Matches multiple URLs using the * wildcard.', 'wpswitchboard'); ?></p>
                            <p class="sb-sp-mb-1 sb-sp-pl-4 sb-sp-text-muted"><?php esc_html_e('Example:', 'wpswitchboard'); ?> <code>/blog/*</code> <?php esc_html_e('matches:', 'wpswitchboard'); ?></p>
                            <ul class="sb-sp-list sb-sp-text-muted">
                                <li><code>/blog/post-1</code></li>
                                <li><code>/blog/category/tech</code></li>
                                <li><code>/blog/anything</code></li>
                            </ul>
                        </div>
                    </div>

                    <div class="sb-sp-field-horizontal" style="margin-bottom: 16px;">
                        <div class="sb-sp-field-horizontal-left">
                            <label class="sb-sp-label"><?php esc_html_e('Active', 'wpswitchboard'); ?></label>
                            <p class="sb-sp-description"><?php esc_html_e('Uncheck to disable this redirect temporarily', 'wpswitchboard'); ?></p>
                        </div>
                        <label class="sb-module-toggle">
                            <input type="checkbox" id="is-active" checked>
                            <span class="sb-module-toggle-slider"></span>
                        </label>
                    </div>
                </div>
                <div class="sb-module-modal-footer">
                    <button type="button" class="sb-module-button sb-module-button-secondary modal-cancel"><?php esc_html_e('Cancel', 'wpswitchboard'); ?></button>
                    <button type="button" id="save-redirect-btn" class="sb-module-button sb-module-button-primary">
                        <?php esc_html_e('Save Redirect', 'wpswitchboard'); ?>
                    </button>
                </div>
            </div>
        </div>

        <script>
        jQuery(document).ready(function($) {
            const RedirectsManager = {
                orderBy: 'created_at',
                order: 'DESC',
                search: '',
                sourceSearchTimeout: null,
                targetSearchTimeout: null,

                init: function() {
                    this.bindEvents();
                    this.loadRedirects();
                },

                bindEvents: function() {
                    const self = this;

                    // Search
                    let searchTimeout;
                    $('#redirects-search').on('input', function() {
                        clearTimeout(searchTimeout);
                        searchTimeout = setTimeout(function() {
                            self.search = $('#redirects-search').val();
                            self.loadRedirects();
                        }, 500);
                    });

                    // Add redirect button
                    $('#add-redirect-btn').on('click', function() {
                        self.openModal();
                    });

                    // Close modal function
                    const closeModal = function() {
                        $('#redirect-modal').removeClass('show');
                        setTimeout(function() {
                            $('#redirect-modal').hide();
                        }, 200); // Match CSS transition duration
                    };

                    // Ensure modal is hidden on load
                    $('#redirect-modal').hide().removeClass('show');

                    // Close modal on close button and cancel button
                    $(document).on('click', '#redirect-modal .sb-module-modal-close, #redirect-modal .modal-cancel', function(e) {
                        e.preventDefault();
                        e.stopPropagation();
                        closeModal();
                    });

                    // Close modal on backdrop click
                    $(document).on('click', '#redirect-modal .sb-module-modal-backdrop', function(e) {
                        e.preventDefault();
                        e.stopPropagation();
                        closeModal();
                    });

                    // Close modal on ESC key
                    $(document).on('keydown', function(e) {
                        if (e.key === 'Escape' && $('#redirect-modal').is(':visible')) {
                            closeModal();
                        }
                    });

                    // Prevent modal content clicks from closing modal
                    $(document).on('click', '#redirect-modal .sb-module-modal-content', function(e) {
                        e.stopPropagation();
                    });

                    // Source page search
                    $('#source-page-search').on('input', function() {
                        clearTimeout(self.sourceSearchTimeout);
                        const query = $(this).val();

                        if (query.length >= 2) {
                            self.sourceSearchTimeout = setTimeout(function() {
                                self.searchPages(query, 'source');
                            }, 300);
                        } else {
                            $('#source-page-results').hide().empty();
                        }
                    });

                    $('#source-page-search').on('focus', function() {
                        const query = $(this).val();
                        if (query.length >= 2) {
                            self.searchPages(query, 'source');
                        }
                    });

                    // Target page search
                    $('#target-page-search').on('input', function() {
                        clearTimeout(self.targetSearchTimeout);
                        const query = $(this).val();

                        if (query.length >= 2) {
                            self.targetSearchTimeout = setTimeout(function() {
                                self.searchPages(query, 'target');
                            }, 300);
                        } else {
                            $('#target-page-results').hide().empty();
                        }
                    });

                    $('#target-page-search').on('focus', function() {
                        const query = $(this).val();
                        if (query.length >= 2) {
                            self.searchPages(query, 'target');
                        }
                    });

                    // Close dropdowns when clicking outside
                    $(document).on('click', function(e) {
                        if (!$(e.target).closest('.page-selector-wrapper').length) {
                            $('.page-results').hide();
                        }
                    });

                    // Match type change
                    $('#match-type').on('change', function() {
                        const matchType = $(this).val();
                        if (matchType === 'exact') {
                            $('.exact-desc').show();
                            $('.wildcard-desc').hide();
                        } else {
                            $('.exact-desc').hide();
                            $('.wildcard-desc').show();
                        }
                    });

                    // Match type info toggle
                    $('#match-type-info').on('click', function() {
                        $('#match-type-help').slideToggle();
                    });

                    // Source URL domain filtering
                    $('#source-url').on('blur', function() {
                        self.filterSourceUrl();
                    });

                    // Save redirect
                    $('#save-redirect-btn').on('click', function() {
                        self.saveRedirect();
                    });

                    // Edit redirect
                    $(document).on('click', '.edit-redirect', function() {
                        const id = $(this).data('id');
                        self.editRedirect(id);
                    });

                    // Delete redirect
                    $(document).on('click', '.delete-redirect', function() {
                        if (confirm('Are you sure you want to delete this redirect?')) {
                            const id = $(this).data('id');
                            self.deleteRedirect(id);
                        }
                    });

                    // Toggle active
                    $(document).on('change', '.toggle-active', function() {
                        const $toggle = $(this);
                        const id = $toggle.data('id');
                        const active = $toggle.is(':checked') ? 1 : 0;

                        self.toggleActive(id, active);
                    });

                    // Sorting
                    $(document).on('click', '#redirects-table th.sortable', function() {
                        const column = $(this).data('column');
                        if (self.orderBy === column) {
                            self.order = self.order === 'DESC' ? 'ASC' : 'DESC';
                        } else {
                            self.orderBy = column;
                            self.order = 'DESC';
                        }
                        self.loadRedirects();
                    });

                    // Select all
                    $('#cb-select-all').on('change', function() {
                        $('.redirect-checkbox').prop('checked', $(this).is(':checked'));
                    });

                    // Bulk actions
                    $('#doaction').on('click', function() {
                        const action = $('#bulk-action-selector-top').val();
                        if (action === '-1') return;

                        const selected = $('.redirect-checkbox:checked').map(function() {
                            return $(this).val();
                        }).get();

                        if (selected.length === 0) {
                            alert('Please select at least one redirect');
                            return;
                        }

                        if (action === 'delete') {
                            if (confirm('Are you sure you want to delete ' + selected.length + ' redirect(s)?')) {
                                self.bulkDelete(selected);
                            }
                        }
                    });
                },

                searchPages: function(query, field) {
                    const self = this;
                    const resultsDiv = field === 'source' ? '#source-page-results' : '#target-page-results';

                    $.post(ajaxurl, {
                        action: 'switchboard_redirects_get_pages',
                        nonce: '<?php echo wp_create_nonce('switchboard_redirects'); ?>',
                        search: query
                    }, function(response) {
                        if (response.success && response.data.length > 0) {
                            self.renderPageResults(response.data, field, resultsDiv);
                        } else {
                            $(resultsDiv).html('<div class="page-results-empty">No results found</div>').show();
                        }
                    });
                },

                renderPageResults: function(items, field, resultsDiv) {
                    const self = this;
                    const $results = $(resultsDiv);
                    $results.empty();

                    items.forEach(function(item) {
                        const typeClass = 'type-' + item.type_key;
                        const $item = $('<div class="page-result-item">');

                        $item.html(`
                            <div class="page-result-title">${item.title}</div>
                            <div class="page-result-meta">
                                <span class="page-result-path">${item.path}</span>
                                <span class="page-result-type ${typeClass}">${item.type}</span>
                            </div>
                        `);

                        $item.on('click', function() {
                            if (field === 'source') {
                                $('#source-url').val(item.path);
                                $('#source-page-search').val('');
                            } else {
                                $('#target-url').val(item.url);
                                $('#target-page-search').val('');
                            }
                            $results.hide();
                        });

                        $results.append($item);
                    });

                    $results.show();
                },

                filterSourceUrl: function() {
                    const sourceUrl = $('#source-url').val().trim();
                    if (!sourceUrl) return;

                    try {
                        // If it's a full URL, extract only the path
                        if (sourceUrl.startsWith('http://') || sourceUrl.startsWith('https://')) {
                            const url = new URL(sourceUrl);
                            const currentDomain = window.location.hostname;

                            // Only allow same domain
                            if (url.hostname === currentDomain) {
                                $('#source-url').val(url.pathname);
                            } else {
                                alert('Source URL must be from the same domain. Only the path is allowed.');
                                $('#source-url').val('');
                            }
                        } else {
                            // Ensure it starts with /
                            if (!sourceUrl.startsWith('/')) {
                                $('#source-url').val('/' + sourceUrl);
                            }
                        }
                    } catch (e) {
                        // If parsing fails, ensure it starts with /
                        if (!sourceUrl.startsWith('/')) {
                            $('#source-url').val('/' + sourceUrl);
                        }
                    }
                },

                openModal: function(data = null) {
                    if (data) {
                        $('#modal-title').text('Edit Redirect');
                        $('#redirect-id').val(data.id);
                        $('#source-url').val(data.source_url);
                        $('#target-url').val(data.target_url);
                        $('#redirect-type').val(data.redirect_type);
                        $('#match-type').val(data.match_type);
                        $('#is-active').prop('checked', data.is_active == 1);
                    } else {
                        $('#modal-title').text('Add Redirect');
                        $('#redirect-id').val('');
                        $('#source-url').val('');
                        $('#target-url').val('');
                        $('#redirect-type').val('301');
                        $('#match-type').val('exact');
                        $('#is-active').prop('checked', true);
                    }
                    $('#redirect-modal').show();
                    setTimeout(function() {
                        $('#redirect-modal').addClass('show');
                    }, 10); // Small delay to trigger CSS transition
                },

                saveRedirect: function() {
                    const id = $('#redirect-id').val();
                    const data = {
                        action: id ? 'switchboard_redirects_update' : 'switchboard_redirects_create',
                        nonce: '<?php echo wp_create_nonce('switchboard_redirects'); ?>',
                        id: id,
                        source_url: $('#source-url').val(),
                        target_url: $('#target-url').val(),
                        redirect_type: $('#redirect-type').val(),
                        match_type: $('#match-type').val(),
                        is_active: $('#is-active').is(':checked') ? 1 : 0
                    };

                    $.post(ajaxurl, data, function(response) {
                        if (response.success) {
                            $('#redirect-modal').removeClass('show');
                            setTimeout(function() {
                                $('#redirect-modal').hide();
                            }, 200); // Match CSS transition duration
                            RedirectsManager.loadRedirects();
                        } else {
                            alert(response.data || 'Failed to save redirect');
                        }
                    });
                },

                loadRedirects: function() {
                    const self = this;
                    $.post(ajaxurl, {
                        action: 'switchboard_redirects_get_all',
                        nonce: '<?php echo wp_create_nonce('switchboard_redirects'); ?>',
                        orderby: self.orderBy,
                        order: self.order,
                        search: self.search
                    }, function(response) {
                        if (response.success) {
                            self.renderRedirects(response.data);
                            self.updateSortIndicators();
                        } else {
                            console.error('Failed to load redirects:', response);
                            $('#redirects-tbody').html('<tr><td colspan="8" class="sb-module-empty"><div class="sb-module-empty-icon"></div><p class="sb-module-empty-desc">Error loading redirects. Check console for details.</p></td></tr>');
                        }
                    }).fail(function(xhr, status, error) {
                        console.error('AJAX error:', status, error, xhr.responseText);
                        $('#redirects-tbody').html('<tr><td colspan="8" class="sb-module-empty"><div class="sb-module-empty-icon"></div><p class="sb-module-empty-desc">AJAX Error: ' + error + '</p></td></tr>');
                    });
                },

                renderRedirects: function(redirects) {
                    const tbody = $('#redirects-tbody');
                    tbody.empty();

                    if (!redirects || redirects.length === 0) {
                        tbody.html('<tr><td colspan="8" class="sb-module-empty"><div class="sb-module-empty-icon"></div><p class="sb-module-empty-desc">No redirects found</p></td></tr>');
                        return;
                    }

                    redirects.forEach(function(redirect, index) {
                        const row = $('<tr>');

                        // Checkbox
                        row.append(`<td style="width: 40px;"><input type="checkbox" class="sb-module-checkbox redirect-checkbox" value="${redirect.id}"></td>`);

                        // Source URL with visit link
                        const sourceUrlHtml = `
                            <div style="display: flex; align-items: center; gap: 8px;">
                                <code class="sb-sp-code">${redirect.source_url}</code>
                                <a href="${redirect.source_url}" target="_blank" title="Visit and test redirect" style="color: #64748b;">
                                    <span class="dashicons dashicons-external"></span>
                                </a>
                            </div>
                        `;
                        row.append(`<td>${sourceUrlHtml}</td>`);

                        // Target URL
                        row.append(`<td><code class="sb-sp-code">${redirect.target_url}</code></td>`);

                        // Type
                        row.append(`<td><span class="sb-mp-badge">${redirect.redirect_type}</span> ${redirect.match_type}</td>`);

                        // Hits
                        row.append(`<td style="font-weight: 600;">${redirect.hit_count || 0}</td>`);

                        // Status with toggle switch
                        const isActive = redirect.is_active == 1;
                        const statusHtml = `
                            <label class="sb-mp-toggle">
                                <input type="checkbox" class="toggle-active" data-id="${redirect.id}" ${isActive ? 'checked' : ''}>
                                <span class="sb-mp-toggle-slider"></span>
                            </label>
                        `;
                        row.append(`<td>${statusHtml}</td>`);

                        // Created
                        const date = new Date(redirect.created_at);
                        row.append(`<td class="sb-sp-text-muted">${date.toLocaleDateString()}</td>`);

                        // Actions
                        row.append(`
                            <td>
                                <div style="display: flex; gap: 8px; align-items: center;">
                                    <button type="button" class="sb-module-button sb-module-button-secondary sb-module-button-sm edit-redirect" data-id="${redirect.id}">Edit</button>
                                    <button type="button" class="sb-module-button sb-module-button-danger sb-module-button-sm delete-redirect" data-id="${redirect.id}">Delete</button>
                                </div>
                            </td>
                        `);

                        tbody.append(row);
                    });
                },

                updateSortIndicators: function() {
                    $('#redirects-table th.sortable').removeClass('active asc desc');
                    const th = $('#redirects-table th[data-column="' + this.orderBy + '"]');
                    th.addClass('active');
                    th.addClass(this.order.toLowerCase());
                },

                editRedirect: function(id) {
                    const self = this;
                    $.post(ajaxurl, {
                        action: 'switchboard_redirects_get_all',
                        nonce: '<?php echo wp_create_nonce('switchboard_redirects'); ?>'
                    }, function(response) {
                        if (response.success) {
                            const redirect = response.data.find(r => r.id == id);
                            if (redirect) {
                                self.openModal(redirect);
                            }
                        }
                    });
                },

                deleteRedirect: function(id) {
                    $.post(ajaxurl, {
                        action: 'switchboard_redirects_delete',
                        nonce: '<?php echo wp_create_nonce('switchboard_redirects'); ?>',
                        id: id
                    }, function(response) {
                        if (response.success) {
                            RedirectsManager.loadRedirects();
                        }
                    });
                },

                toggleActive: function(id, active) {
                    $.post(ajaxurl, {
                        action: 'switchboard_redirects_toggle',
                        nonce: '<?php echo wp_create_nonce('switchboard_redirects'); ?>',
                        id: id,
                        is_active: active
                    }, function(response) {
                        if (!response.success) {
                            // If failed, reload to get correct state
                            RedirectsManager.loadRedirects();
                        }
                    });
                },

                bulkDelete: function(ids) {
                    $.post(ajaxurl, {
                        action: 'switchboard_redirects_bulk_delete',
                        nonce: '<?php echo wp_create_nonce('switchboard_redirects'); ?>',
                        ids: ids
                    }, function(response) {
                        if (response.success) {
                            RedirectsManager.loadRedirects();
                        }
                    });
                }
            };

            RedirectsManager.init();
        });
        </script>
        <?php
    }

    /**
     * Handle redirects on template_redirect
     */
    public function handle_redirects() {
        if (is_admin()) {
            return;
        }

        global $wpdb;

        // SECURITY FIX: Sanitize REQUEST_URI
        $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '/';
        $parsed_url = parse_url($request_uri);
        $path = isset($parsed_url['path']) ? $parsed_url['path'] : '/';

        // Get all active redirects
        $redirects = $wpdb->get_results(
            "SELECT * FROM {$this->table_name} WHERE is_active = 1 ORDER BY match_type ASC, id DESC"
        );

        foreach ($redirects as $redirect) {
            $match = false;

            if ($redirect->match_type === 'exact') {
                // BUG FIX: Normalize trailing slashes to prevent /about != /about/ mismatch
                $normalized_path = rtrim($path, '/');
                $normalized_source = rtrim($redirect->source_url, '/');
                // Handle homepage case - empty string should match /
                $normalized_path = $normalized_path === '' ? '/' : $normalized_path;
                $normalized_source = $normalized_source === '' ? '/' : $normalized_source;
                $match = ($normalized_path === $normalized_source);
            } elseif ($redirect->match_type === 'wildcard') {
                $pattern = str_replace('*', '(.*)', preg_quote($redirect->source_url, '/'));
                $pattern = '/^' . $pattern . '$/i';
                $match = preg_match($pattern, $path);
            }

            if ($match) {
                // SECURITY FIX: Validate redirect URL before redirecting
                $target_url = $redirect->target_url;

                // Only allow http/https protocols
                if (!preg_match('/^https?:\/\//i', $target_url)) {
                    // If it's a relative URL, make it absolute
                    $target_url = home_url($target_url);
                }

                // Validate that it's a safe URL
                $validated_url = esc_url_raw($target_url, array('http', 'https'));
                if (empty($validated_url)) {
                    continue; // Skip invalid URLs
                }

                // Update hit count and last hit
                $wpdb->query($wpdb->prepare(
                    "UPDATE {$this->table_name} SET hit_count = hit_count + 1, last_hit = NOW() WHERE id = %d",
                    $redirect->id
                ));

                $redirect_type = ($redirect->redirect_type === '302') ? 302 : 301;
                wp_safe_redirect($validated_url, $redirect_type);
                exit;
            }
        }
    }

    /**
     * AJAX: Get stats
     */
    public function ajax_get_stats() {
        check_ajax_referer('switchboard_redirects', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error('Permission denied');
        }

        global $wpdb;

        $stats = array(
            'total' => $wpdb->get_var("SELECT COUNT(*) FROM {$this->table_name}"),
            'active' => $wpdb->get_var("SELECT COUNT(*) FROM {$this->table_name} WHERE is_active = 1"),
            'total_hits' => $wpdb->get_var("SELECT SUM(hit_count) FROM {$this->table_name}"),
            'hits_today' => $wpdb->get_var("SELECT SUM(hit_count) FROM {$this->table_name} WHERE DATE(last_hit) = CURDATE()")
        );

        wp_send_json_success($stats);
    }

    /**
     * AJAX: Get all redirects
     */
    public function ajax_get_all() {
        check_ajax_referer('switchboard_redirects', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error('Permission denied');
        }

        global $wpdb;

        $orderby = isset($_POST['orderby']) ? sanitize_text_field($_POST['orderby']) : 'created_at';
        $order = isset($_POST['order']) ? sanitize_text_field($_POST['order']) : 'DESC';
        $search = isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '';

        // Validate orderby column (SECURITY: Whitelist to prevent SQL injection)
        $allowed_columns = array('source_url', 'target_url', 'hit_count', 'created_at');
        if (!in_array($orderby, $allowed_columns, true)) {
            $orderby = 'created_at';
        }

        // Validate order direction (SECURITY: Strict validation)
        $order = strtoupper($order) === 'ASC' ? 'ASC' : 'DESC';

        $where = '';
        if (!empty($search)) {
            $where = $wpdb->prepare(" WHERE source_url LIKE %s OR target_url LIKE %s",
                '%' . $wpdb->esc_like($search) . '%',
                '%' . $wpdb->esc_like($search) . '%'
            );
        }

        // BUG FIX: Removed redundant prepare() call - $orderby and $order are already whitelisted
        $query = "SELECT * FROM {$this->table_name} {$where} ORDER BY {$orderby} {$order}";

        $redirects = $wpdb->get_results($query, ARRAY_A);

        // SECURITY FIX: Don't expose database errors to users
        if ($wpdb->last_error) {
            error_log('Redirects Manager Database Error: ' . $wpdb->last_error);
            wp_send_json_error('An error occurred while fetching redirects');
        }

        wp_send_json_success($redirects);
    }

    /**
     * AJAX: Create redirect
     */
    public function ajax_create() {
        check_ajax_referer('switchboard_redirects', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error('Permission denied');
        }

        $source_url = sanitize_text_field($_POST['source_url']);
        $target_url = esc_url_raw($_POST['target_url']);
        $redirect_type = sanitize_text_field($_POST['redirect_type']);
        $match_type = sanitize_text_field($_POST['match_type']);
        $is_active = intval($_POST['is_active']);

        if (empty($source_url) || empty($target_url)) {
            wp_send_json_error('Source and target URLs are required');
        }

        // Ensure source URL starts with /
        if (substr($source_url, 0, 1) !== '/') {
            $source_url = '/' . $source_url;
        }

        global $wpdb;

        $result = $wpdb->insert(
            $this->table_name,
            array(
                'source_url' => $source_url,
                'target_url' => $target_url,
                'redirect_type' => $redirect_type,
                'match_type' => $match_type,
                'is_active' => $is_active
            ),
            array('%s', '%s', '%s', '%s', '%d')
        );

        if ($result) {
            wp_send_json_success('Redirect created successfully');
        } else {
            wp_send_json_error('Failed to create redirect');
        }
    }

    /**
     * AJAX: Update redirect
     */
    public function ajax_update() {
        check_ajax_referer('switchboard_redirects', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error('Permission denied');
        }

        $id = intval($_POST['id']);
        $source_url = sanitize_text_field($_POST['source_url']);
        $target_url = esc_url_raw($_POST['target_url']);
        $redirect_type = sanitize_text_field($_POST['redirect_type']);
        $match_type = sanitize_text_field($_POST['match_type']);
        $is_active = intval($_POST['is_active']);

        // Ensure source URL starts with /
        if (substr($source_url, 0, 1) !== '/') {
            $source_url = '/' . $source_url;
        }

        global $wpdb;

        $result = $wpdb->update(
            $this->table_name,
            array(
                'source_url' => $source_url,
                'target_url' => $target_url,
                'redirect_type' => $redirect_type,
                'match_type' => $match_type,
                'is_active' => $is_active
            ),
            array('id' => $id),
            array('%s', '%s', '%s', '%s', '%d'),
            array('%d')
        );

        if ($result !== false) {
            wp_send_json_success('Redirect updated successfully');
        } else {
            wp_send_json_error('Failed to update redirect');
        }
    }

    /**
     * AJAX: Toggle active status
     */
    public function ajax_toggle() {
        check_ajax_referer('switchboard_redirects', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error('Permission denied');
        }

        $id = intval($_POST['id']);
        $is_active = intval($_POST['is_active']);

        global $wpdb;

        $result = $wpdb->update(
            $this->table_name,
            array('is_active' => $is_active),
            array('id' => $id),
            array('%d'),
            array('%d')
        );

        if ($result !== false) {
            wp_send_json_success();
        } else {
            wp_send_json_error('Failed to toggle status');
        }
    }

    /**
     * AJAX: Delete redirect
     */
    public function ajax_delete() {
        check_ajax_referer('switchboard_redirects', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error('Permission denied');
        }

        $id = intval($_POST['id']);

        global $wpdb;

        $result = $wpdb->delete(
            $this->table_name,
            array('id' => $id),
            array('%d')
        );

        if ($result) {
            wp_send_json_success('Redirect deleted successfully');
        } else {
            wp_send_json_error('Failed to delete redirect');
        }
    }

    /**
     * AJAX: Bulk delete redirects
     */
    public function ajax_bulk_delete() {
        check_ajax_referer('switchboard_redirects', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error('Permission denied');
        }

        $ids = isset($_POST['ids']) ? array_map('intval', $_POST['ids']) : array();

        if (empty($ids)) {
            wp_send_json_error('No redirects selected');
        }

        global $wpdb;

        $placeholders = implode(',', array_fill(0, count($ids), '%d'));
        $query = "DELETE FROM {$this->table_name} WHERE id IN ($placeholders)";

        $result = $wpdb->query($wpdb->prepare($query, $ids));

        if ($result) {
            wp_send_json_success('Redirects deleted successfully');
        } else {
            wp_send_json_error('Failed to delete redirects');
        }
    }

    /**
     * AJAX: Get pages for dropdown
     */
    public function ajax_get_pages() {
        check_ajax_referer('switchboard_redirects', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error('Permission denied');
        }

        $search = isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '';
        $items = array();

        // Get all public post types
        $post_types = get_post_types(array('public' => true), 'objects');
        $post_type_names = array();
        foreach ($post_types as $post_type) {
            if (!in_array($post_type->name, array('attachment'))) {
                $post_type_names[] = $post_type->name;
            }
        }

        // Build query args
        $query_args = array(
            'post_type' => $post_type_names,
            'post_status' => 'publish',
            'posts_per_page' => 50,
            'orderby' => 'title',
            'order' => 'ASC'
        );

        // Add search if provided
        if (!empty($search)) {
            $query_args['s'] = $search;
        }

        // Get posts
        $query = new WP_Query($query_args);

        if ($query->have_posts()) {
            while ($query->have_posts()) {
                $query->the_post();
                $post_type_obj = get_post_type_object(get_post_type());
                $items[] = array(
                    'id' => get_the_ID(),
                    'title' => get_the_title(),
                    'url' => get_permalink(),
                    'path' => parse_url(get_permalink(), PHP_URL_PATH),
                    'type' => $post_type_obj->labels->singular_name,
                    'type_key' => get_post_type()
                );
            }
            wp_reset_postdata();
        }

        // Get categories
        $cat_args = array(
            'taxonomy' => 'category',
            'hide_empty' => false,
            'number' => 20
        );
        if (!empty($search)) {
            $cat_args['search'] = $search;
        }

        $categories = get_terms($cat_args);
        if (!is_wp_error($categories) && !empty($categories)) {
            foreach ($categories as $cat) {
                $cat_link = get_term_link($cat);
                if (!is_wp_error($cat_link)) {
                    $items[] = array(
                        'id' => $cat->term_id,
                        'title' => $cat->name,
                        'url' => $cat_link,
                        'path' => parse_url($cat_link, PHP_URL_PATH),
                        'type' => 'Category',
                        'type_key' => 'category'
                    );
                }
            }
        }

        // Get tags
        $tag_args = array(
            'taxonomy' => 'post_tag',
            'hide_empty' => false,
            'number' => 20
        );
        if (!empty($search)) {
            $tag_args['search'] = $search;
        }

        $tags = get_terms($tag_args);
        if (!is_wp_error($tags) && !empty($tags)) {
            foreach ($tags as $tag) {
                $tag_link = get_term_link($tag);
                if (!is_wp_error($tag_link)) {
                    $items[] = array(
                        'id' => $tag->term_id,
                        'title' => $tag->name,
                        'url' => $tag_link,
                        'path' => parse_url($tag_link, PHP_URL_PATH),
                        'type' => 'Tag',
                        'type_key' => 'tag'
                    );
                }
            }
        }

        // Limit total results
        $items = array_slice($items, 0, 50);

        wp_send_json_success($items);
    }

    /**
     * Register data locations for cleanup system
     */
    public function register_data_locations() {
        return array(
            'options' => array(),
            'option_patterns' => array(),
            'tables' => array('switchboard_redirects'),
            'post_meta' => array(),
            'user_meta' => array(),
        );
    }
}

// Initialize and register with data system
$switchboard_instance = new SwitchboardRedirectsManager();
Switchboard_Data_Registry::get_instance()->auto_register($switchboard_instance, __FILE__);
