<?php
/**
 * Plugin Name: ContentZavod
 * Plugin URI: https://newsai.fittin.ru/
 * Description: Content factory for SEO acceleration and traffic increase
 * Version: 2.5.0
 * Author: Fittin
 * Author URI: https://contentzavod.fittin.ru
 * License: GPLv2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: contentzavod
 * Domain Path: /languages
 */

// Защита от прямого доступа
if (!defined('ABSPATH')) {
    exit;
}

class ContentZavod_Proxy {
    
    /**
     * Версия плагина
     */
    private const VERSION = '2.5.0';

    /**
     * URL API для получения контента
     */
    private const API_BASE_URL = 'https://ainews-back.fittin.ru';
    
    /**
     * Префикс URL для перехвата
     */
    private const URL_PREFIX = 'contentzavod';
    
    /**
     * Ключ для хранения API токена в настройках
     */
    private const OPTION_API_TOKEN = 'contentzavod_api_token';

    /**
     * IndexNow API endpoint (общий для Bing, Yandex, Seznam, Naver)
     */
    private const INDEXNOW_API_URL = 'https://api.indexnow.org/indexnow';

    /**
     * Ключ для хранения IndexNow ключа верификации
     */
    private const OPTION_INDEXNOW_KEY = 'contentzavod_indexnow_key';

    /**
     * Ключ для хранения списка отправленных URL
     */
    private const OPTION_INDEXNOW_SUBMITTED_URLS = 'contentzavod_indexnow_submitted_urls';

    /**
     * Ключ для хранения времени последней проверки
     */
    private const OPTION_INDEXNOW_LAST_CHECK = 'contentzavod_indexnow_last_check';

    /**
     * Ключ для хранения статуса последней проверки
     */
    private const OPTION_INDEXNOW_LAST_STATUS = 'contentzavod_indexnow_last_status';

    /**
     * Ключ для хранения общего количества отправленных URL
     */
    private const OPTION_INDEXNOW_SUBMITTED_COUNT = 'contentzavod_indexnow_submitted_count';

    /**
     * Имя WP cron хука для IndexNow
     */
    public const CRON_HOOK = 'contentzavod_indexnow_cron';

    /**
     * Конструктор класса
     */
    public function __construct() {
        // Используем более высокий приоритет (99), чтобы выполняться после других плагинов
        add_action('init', array($this, 'add_rewrite_rules'), 99);
        
        // Обрабатываем запросы ОЧЕНЬ РАНО (приоритет 1), до других плагинов
        add_action('template_redirect', array($this, 'handle_proxy_request'), 1);
        
        // Дополнительная ранняя проверка на уровне parse_request
        add_action('parse_request', array($this, 'early_sitemap_check'), 1);
        
        add_filter('query_vars', array($this, 'add_query_vars'), 99);
        
        // Автоматически добавляем sitemap в robots.txt
        add_filter('robots_txt', array($this, 'add_sitemap_to_robots'), 999, 2);
        
        // Добавляем страницу настроек в админ-панель
        add_action('admin_menu', array($this, 'add_admin_menu'));
        add_action('admin_init', array($this, 'register_settings'));
        
        // Добавляем стили для админ-панели
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_styles'));
        
        // Добавляем ссылку на настройки на странице плагинов
        add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'add_settings_link'));
        
        // Показываем уведомление об ошибке, если токен не настроен
        add_action('admin_notices', array($this, 'show_api_token_notice'));

        // IndexNow: регистрируем callback для cron задачи
        add_action(self::CRON_HOOK, array($this, 'indexnow_cron_run'));
    }
    
    /**
     * Добавляет правила перезаписи URL
     */
    public function add_rewrite_rules() {
        // Правило для contentzavod-sitemap.xml (не конфликтует с sitemap.xml)
        add_rewrite_rule(
            '^' . self::URL_PREFIX . '-sitemap\.xml$',
            'index.php?contentzavod_sitemap=1',
            'top'
        );
        
        // Правило для главной страницы contentzavod (список всех новостей)
        add_rewrite_rule(
            '^' . self::URL_PREFIX . '/?$',
            'index.php?contentzavod_all_news=1',
            'top'
        );
        
        // Правило для отдельных страниц контента с /view/
        add_rewrite_rule(
            '^' . self::URL_PREFIX . '/view/(.+)/?$',
            'index.php?contentzavod_path=$matches[1]',
            'top'
        );
        
        // Правило для страниц тегов: /contentzavod/tag/{slug}
        add_rewrite_rule(
            '^' . self::URL_PREFIX . '/tag/([^/]+)/?$',
            'index.php?contentzavod_tag=$matches[1]',
            'top'
        );

        // Правило для IndexNow key verification file: /{key}.txt
        $indexnow_key = get_option(self::OPTION_INDEXNOW_KEY, '');
        if (!empty($indexnow_key)) {
            add_rewrite_rule(
                '^' . preg_quote($indexnow_key, '#') . '\.txt$',
                'index.php?contentzavod_indexnow_key=1',
                'top'
            );
        }
    }
    
    /**
     * Добавляет переменные запроса
     */
    public function add_query_vars($vars) {
        $vars[] = 'contentzavod_path';
        $vars[] = 'contentzavod_sitemap';
        $vars[] = 'contentzavod_all_news';
        $vars[] = 'contentzavod_tag';
        $vars[] = 'contentzavod_indexnow_key';
        return $vars;
    }
    
    /**
     * Ранняя проверка запроса sitemap (до других плагинов)
     * Обрабатывает запрос напрямую, минуя WordPress routing
     */
    public function early_sitemap_check() {
        $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
        
        // Проверяем, это запрос к contentzavod-sitemap.xml
        if (preg_match('#^/?' . self::URL_PREFIX . '-sitemap\.xml#', $request_uri)) {
            $this->serve_sitemap_directly();
            exit; // Принудительно завершаем выполнение
        }
        
        // Проверяем, это запрос к главной странице contentzavod (список всех новостей)
        // Поддерживаем как /contentzavod, так и /contentzavod/ и с query (?page=2 и т.п.)
        $path_only = parse_url($request_uri, PHP_URL_PATH);
        if ($path_only === '/' . self::URL_PREFIX || 
            $path_only === '/' . self::URL_PREFIX . '/') {
            $this->serve_all_news_page();
            exit; // Принудительно завершаем выполнение
        }
        
        // Ранняя обработка страницы тега: /contentzavod/tag/{slug}[?page=..]
        if (preg_match('#^/?' . self::URL_PREFIX . '/tag/([^/]+)/?$#', $path_only, $m)) {
            $tag_slug = sanitize_text_field($m[1]);
            $this->serve_tag_page($tag_slug);
            exit;
        }

        // IndexNow key verification file: /{key}.txt
        $indexnow_key = get_option(self::OPTION_INDEXNOW_KEY, '');
        if (!empty($indexnow_key) && $path_only === '/' . $indexnow_key . '.txt') {
            $this->serve_indexnow_key_file();
            exit;
        }
    }
    
    /**
     * Обрабатывает проксированный запрос
     */
    public function handle_proxy_request() {
        $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
        
        // IndexNow key verification file
        $is_indexnow_key = get_query_var('contentzavod_indexnow_key');
        if ($is_indexnow_key) {
            $this->serve_indexnow_key_file();
            return;
        }

        // Проверяем запрос sitemap
        $is_sitemap = get_query_var('contentzavod_sitemap');
        if ($is_sitemap) {
            $this->handle_sitemap_request();
            return;
        }
        
        // Проверяем запрос страницы со всеми новостями
        $is_all_news = get_query_var('contentzavod_all_news');
        if ($is_all_news) {
            $this->serve_all_news_page();
            return;
        }
        
        // Проверяем запрос страницы тега
        $tag_slug = get_query_var('contentzavod_tag');
        if (!empty($tag_slug)) {
            $this->serve_tag_page(sanitize_text_field($tag_slug));
            return;
        }
        
        // Дополнительная проверка для главной страницы через REQUEST_URI
        if ($request_uri === '/' . self::URL_PREFIX || $request_uri === '/' . self::URL_PREFIX . '/') {
            $this->serve_all_news_page();
            return;
        }
        
        $path = get_query_var('contentzavod_path');
        
        // Если это не наш запрос, пропускаем (не мешаем другим плагинам)
        if (empty($path)) {
            return;
        }
        
        // Дополнительная проверка: обрабатываем только URL начинающиеся с /contentzavod/view/
        if (strpos($request_uri, '/' . self::URL_PREFIX . '/view/') !== 0 && 
            strpos($request_uri, '/' . self::URL_PREFIX . '-sitemap.xml') !== 0) {
            return;
        }
        
        // Получаем API токен из настроек
        $api_token = get_option(self::OPTION_API_TOKEN);
        
        if (empty($api_token)) {
            wp_die(esc_html__('Error: API token not configured. Go to Settings → ContentZavod to configure.', 'contentzavod'));
            return;
        }
        
        // Формируем URL для API запроса
        $target_url = 'https://ainews-back.fittin.ru/public/content/' . $api_token . '/view/' . $path;
        
        // Получаем контент
        $response = wp_remote_get($target_url, array(
            'timeout' => 30,
            'sslverify' => true,
            'headers' => array(
                'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            )
        ));
        
        if (is_wp_error($response)) {
            /* translators: %s: error message */
            wp_die(sprintf(esc_html__('Error getting content: %s', 'contentzavod'), esc_html($response->get_error_message())));
            return;
        }
        
        $status_code = wp_remote_retrieve_response_code($response);
        
        if ($status_code !== 200) {
            status_header($status_code);
            /* translators: %s: HTTP status code */
            wp_die(sprintf(esc_html__('Error: page not found (code %s)', 'contentzavod'), esc_html($status_code)));
            return;
        }
        
        $response_body = wp_remote_retrieve_body($response);
        $content_type = wp_remote_retrieve_header($response, 'content-type');
        
        // API возвращает JSON с полем html_content
        if (strpos($content_type, 'application/json') !== false) {
            $data = json_decode($response_body, true);
            
            if (isset($data['html_content']) && !empty($data['html_content'])) {
                $content = $data['html_content'];
            } else {
                wp_die(esc_html__('Error: content not found in API response', 'contentzavod'));
                return;
            }
        } else {
            // Если вдруг API вернул HTML напрямую
            $content = $response_body;
        }
        
        // Обрабатываем HTML контент (заменяем ссылки если нужно)
        $content = $this->process_html_content($content, $path);
        
        // Устанавливаем заголовки
        header('Content-Type: text/html; charset=utf-8');
        
        // Выводим контент
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- HTML content from trusted API
        echo $content;
        exit;
    }
    
    /**
     * Обрабатывает HTML контент: заменяет относительные ссылки
     * 
     * @param string $html HTML контент
     * @param string $current_path Текущий путь
     * @return string Обработанный HTML
     */
    private function process_html_content($html, $current_path) {
        $site_url = home_url();
        $source_url = 'https://ainews-back.fittin.ru';
        
        // Заменяем абсолютные ссылки на источник
        $html = str_replace(
            $source_url . '/' . self::URL_PREFIX . '/',
            $site_url . '/' . self::URL_PREFIX . '/',
            $html
        );
        
        // Обрабатываем относительные ссылки в атрибутах href
        $html = preg_replace_callback(
            '/href=["\'](?!http|\/\/|#|mailto:|tel:)([^"\']+)["\']/i',
            function($matches) use ($source_url) {
                $url = $matches[1];
                // Если ссылка начинается с /, это абсолютный путь от корня
                if (strpos($url, '/') === 0) {
                    return 'href="' . $source_url . $url . '"';
                }
                // Иначе это относительный путь
                return 'href="' . $source_url . '/' . $url . '"';
            },
            $html
        );
        
        // Обрабатываем относительные ссылки в атрибутах src (изображения, скрипты)
        $html = preg_replace_callback(
            '/src=["\'](?!http|\/\/|data:)([^"\']+)["\']/i',
            function($matches) use ($source_url) {
                $url = $matches[1];
                // Если ссылка начинается с /, это абсолютный путь от корня
                if (strpos($url, '/') === 0) {
                    return 'src="' . $source_url . $url . '"';
                }
                // Иначе это относительный путь
                return 'src="' . $source_url . '/' . $url . '"';
            },
            $html
        );
        
        // Обрабатываем srcset для адаптивных изображений
        $html = preg_replace_callback(
            '/srcset=["\']([^"\']+)["\']/i',
            function($matches) use ($source_url) {
                $srcset = $matches[1];
                // Разбиваем srcset на отдельные элементы
                $items = explode(',', $srcset);
                $processed_items = array();
                
                foreach ($items as $item) {
                    $item = trim($item);
                    // Разделяем URL и дескриптор (например, "image.jpg 2x")
                    $parts = preg_split('/\s+/', $item);
                    $url = $parts[0];
                    
                    // Пропускаем абсолютные URL
                    if (preg_match('/^(http|\/\/|data:)/', $url)) {
                        $processed_items[] = $item;
                        continue;
                    }
                    
                    // Обрабатываем относительные URL
                    if (strpos($url, '/') === 0) {
                        $parts[0] = $source_url . $url;
                    } else {
                        $parts[0] = $source_url . '/' . $url;
                    }
                    
                    $processed_items[] = implode(' ', $parts);
                }
                
                return 'srcset="' . implode(', ', $processed_items) . '"';
            },
            $html
        );
        
        // Обрабатываем CSS ссылки (link rel="stylesheet")
        $html = preg_replace_callback(
            '/<link([^>]*?)href=["\'](?!http|\/\/)([^"\']+)["\']([^>]*?)>/i',
            function($matches) use ($source_url) {
                $before = $matches[1];
                $url = $matches[2];
                $after = $matches[3];
                
                if (strpos($url, '/') === 0) {
                    $full_url = $source_url . $url;
                } else {
                    $full_url = $source_url . '/' . $url;
                }
                
                return '<link' . $before . 'href="' . $full_url . '"' . $after . '>';
            },
            $html
        );
        
        // Обрабатываем inline стили с url()
        $html = preg_replace_callback(
            '/url\(["\']?(?!http|\/\/|data:)([^"\')\s]+)["\']?\)/i',
            function($matches) use ($source_url) {
                $url = $matches[1];
                
                if (strpos($url, '/') === 0) {
                    return 'url("' . $source_url . $url . '")';
                }
                return 'url("' . $source_url . '/' . $url . '")';
            },
            $html
        );
        
        return $html;
    }
    
    /**
     * Обрабатывает запрос sitemap.xml
     */
    private function handle_sitemap_request() {
        $this->serve_sitemap_directly();
    }
    
    /**
     * Напрямую отдаёт sitemap, минуя другие плагины
     */
    private function serve_sitemap_directly() {
        // Очищаем буфер вывода сразу
        while (ob_get_level()) {
            ob_end_clean();
        }
        
        // Получаем API токен из настроек
        $api_token = get_option(self::OPTION_API_TOKEN);
        
        if (empty($api_token)) {
            status_header(500);
            header('Content-Type: application/xml; charset=utf-8');
            echo '<?xml version="1.0" encoding="UTF-8"?>';
            echo '<error><message>API token not configured</message><help>Please configure API token in WordPress admin panel: Settings → ContentZavod</help></error>';
            exit;
        }
        
        $target_url = 'https://ainews-back.fittin.ru/public/content/' . $api_token . '/sitemap.xml';
        
        // Получаем sitemap
        $response = wp_remote_get($target_url, array(
            'timeout' => 30,
            'sslverify' => true,
            'headers' => array(
                'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            )
        ));
        
        if (is_wp_error($response)) {
            status_header(500);
            header('Content-Type: application/xml; charset=utf-8');
            echo '<?xml version="1.0" encoding="UTF-8"?>';
            echo '<error><message>Sitemap not available</message><details>' . esc_html($response->get_error_message()) . '</details><url>' . esc_html($target_url) . '</url></error>';
            exit;
        }
        
        $status_code = wp_remote_retrieve_response_code($response);
        
        if ($status_code !== 200) {
            status_header($status_code);
            header('Content-Type: application/xml; charset=utf-8');
            echo '<?xml version="1.0" encoding="UTF-8"?>';
            echo '<error><message>Sitemap not found</message><status>' . esc_html($status_code) . '</status><url>' . esc_html($target_url) . '</url><response>' . esc_html(wp_remote_retrieve_body($response)) . '</response></error>';
            exit;
        }
        
        $content = wp_remote_retrieve_body($response);
        
        // Проверяем, что контент не пустой
        if (empty($content)) {
            status_header(500);
            header('Content-Type: application/xml; charset=utf-8');
            echo '<?xml version="1.0" encoding="UTF-8"?>';
            echo '<error><message>Empty sitemap response</message><url>' . esc_html($target_url) . '</url></error>';
            exit;
        }
        
        // Обрабатываем XML: заменяем URL источника на URL нашего сайта
        $content = $this->process_sitemap_content($content);
        
        // Устанавливаем заголовки
        status_header(200);
        header('Content-Type: application/xml; charset=utf-8');
        header('X-Robots-Tag: noindex, follow');
        header('Cache-Control: no-cache, must-revalidate'); // Отключаем кэш для отладки
        header('X-ContentZavod-Debug: sitemap');
        
        // Выводим контент
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- XML content from trusted API
        echo $content;
        exit; // Принудительно завершаем выполнение
    }
    
    /**
     * Обрабатывает содержимое sitemap: заменяет URL
     * 
     * @param string $xml XML содержимое sitemap
     * @return string Обработанный XML
     */
    private function process_sitemap_content($xml) {
        $site_url = home_url();
        
        // Заменяем URL источника на URL нашего сайта
        // Пример: https://ainews-back.fittin.ru/public/content/{token}/view/slug -> https://lifeexpert.top/contentzavod/view/slug
        $xml = preg_replace(
            '#https://ainews-back\.fittin\.ru/public/content/[^/]+/view/#',
            $site_url . '/' . self::URL_PREFIX . '/view/',
            $xml
        );
        
        return $xml;
    }
    
    /**
     * Отдаёт страницу со всеми новостями
     */
    private function serve_all_news_page() {
        // Очищаем буфер вывода сразу
        while (ob_get_level()) {
            ob_end_clean();
        }
        
        // Получаем API токен из настроек
        $api_token = get_option(self::OPTION_API_TOKEN);
        
        if (empty($api_token)) {
            status_header(500);
            header('Content-Type: text/html; charset=utf-8');
            $settings_url = esc_url(admin_url('options-general.php?page=contentzavod-settings'));
            echo '<!DOCTYPE html><html><head><meta charset="utf-8"><title>' . esc_html__('Configuration Error', 'contentzavod') . '</title></head><body>';
            echo '<h1>' . esc_html__('Configuration Error', 'contentzavod') . '</h1>';
            echo '<p>' . esc_html__('API token not configured. Go to Settings → ContentZavod to configure.', 'contentzavod') . '</p>';
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Static HTML with pre-escaped URL
            echo '<p><a href="' . $settings_url . '">' . esc_html__('Go to settings', 'contentzavod') . '</a></p>';
            echo '</body></html>';
            exit;
        }
        
        // Формируем URL для API запроса
        $target_url = 'https://ainews-back.fittin.ru/public/content/' . $api_token . '/all-news-page';
        
        // Прокидываем поддерживаемые query-параметры (пагинация)
        $allowed_params = array();
        if (isset($_GET['page'])) {
            $page = absint($_GET['page']);
            if ($page > 0) {
                $allowed_params['page'] = $page;
            }
        }
        if (!empty($allowed_params)) {
            $target_url = add_query_arg($allowed_params, $target_url);
        }
        
        // Получаем страницу со списком новостей
        $response = wp_remote_get($target_url, array(
            'timeout' => 30,
            'sslverify' => true,
            'headers' => array(
                'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            )
        ));
        
        if (is_wp_error($response)) {
            status_header(500);
            header('Content-Type: text/html; charset=utf-8');
            echo '<!DOCTYPE html><html><head><meta charset="utf-8"><title>' . esc_html__('Connection Error', 'contentzavod') . '</title></head><body>';
            echo '<h1>' . esc_html__('Connection Error', 'contentzavod') . '</h1>';
            /* translators: %s: error message */
            echo '<p>' . sprintf(esc_html__('Failed to get news list: %s', 'contentzavod'), esc_html($response->get_error_message())) . '</p>';
            echo '<p>URL: ' . esc_html($target_url) . '</p>';
            echo '</body></html>';
            exit;
        }
        
        $status_code = wp_remote_retrieve_response_code($response);
        
        if ($status_code !== 200) {
            status_header($status_code);
            header('Content-Type: text/html; charset=utf-8');
            /* translators: %s: HTTP status code */
            echo '<!DOCTYPE html><html><head><meta charset="utf-8"><title>' . sprintf(esc_html__('Error %s', 'contentzavod'), esc_html($status_code)) . '</title></head><body>';
            /* translators: %s: HTTP status code */
            echo '<h1>' . sprintf(esc_html__('Error %s', 'contentzavod'), esc_html($status_code)) . '</h1>';
            echo '<p>' . esc_html__('Page not found.', 'contentzavod') . '</p>';
            echo '<p>URL: ' . esc_html($target_url) . '</p>';
            echo '</body></html>';
            exit;
        }
        
        $content = wp_remote_retrieve_body($response);
        
        // Проверяем, что контент не пустой
        if (empty($content)) {
            status_header(500);
            header('Content-Type: text/html; charset=utf-8');
            echo '<!DOCTYPE html><html><head><meta charset="utf-8"><title>' . esc_html__('Empty Response', 'contentzavod') . '</title></head><body>';
            echo '<h1>' . esc_html__('Empty Response', 'contentzavod') . '</h1>';
            echo '<p>' . esc_html__('Server returned empty response.', 'contentzavod') . '</p>';
            echo '<p>URL: ' . esc_html($target_url) . '</p>';
            echo '</body></html>';
            exit;
        }
        
        // Обрабатываем HTML контент (заменяем ссылки)
        $processed = $this->process_all_news_html($content);
        
        // Проверяем, что обработка не убила контент
        if (empty($processed) && !empty($content)) {
            $processed = $content; // Используем оригинальный контент
        }
        
        $content = $processed;
        
        // Устанавливаем заголовки
        status_header(200);
        header('Content-Type: text/html; charset=utf-8');
        header('Cache-Control: public, max-age=1800'); // Кэш на 30 минут
        
        // Выводим контент
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- HTML content from trusted API
        echo $content;
        exit;
    }
    
    /**
     * Обрабатывает HTML страницы со всеми новостями
     * 
     * @param string $html HTML контент
     * @return string Обработанный HTML
     */
    private function process_all_news_html($html) {
        // Если HTML пустой, возвращаем как есть
        if (empty($html)) {
            return $html;
        }
        
        $site_url = home_url();
        
        // Заменяем ссылки на статьи, чтобы они вели на наш сайт
        // Пример: /public/content/{token}/view/{slug} -> /contentzavod/view/{slug}
        $result = preg_replace_callback(
            '#href=["\'](?:https://ainews-back\.fittin\.ru)?/public/content/[^/]+/view/([^"\']+)["\']#i',
            function($matches) use ($site_url) {
                $slug = $matches[1];
                return 'href="' . $site_url . '/' . self::URL_PREFIX . '/view/' . $slug . '"';
            },
            $html
        );
        
        // Проверяем, что preg_replace_callback не вернул null
        if ($result !== null) {
            $html = $result;
        }
        
        // Заменяем ссылки пагинации главной: all-news-page[?page=..] -> /contentzavod[?page=..]
        $result = preg_replace_callback(
            '#href=["\'](?:https://ainews-back\.fittin\.ru)?/public/content/[^/]+/all-news-page(\?[^"\']*)?["\']#i',
            function($matches) use ($site_url) {
                $query = '';
                if (!empty($matches[1])) {
                    // сохраняем только page
                    $parsed = array();
                    parse_str(ltrim($matches[1], '?'), $parsed);
                    $qs = array();
                    if (isset($parsed['page']) && (int)$parsed['page'] > 0) {
                        $qs['page'] = (int)$parsed['page'];
                    }
                    if (!empty($qs)) {
                        $query = '?' . http_build_query($qs);
                    }
                }
                return 'href="' . $site_url . '/' . self::URL_PREFIX . '/' . $query . '"';
            },
            $html
        );
        if ($result !== null) {
            $html = $result;
        }
        
        // Заменяем ссылки на теги (вариант /tag/{slug})
        $result = preg_replace_callback(
            '#href=["\'](?:https://ainews-back\.fittin\.ru)?/public/content/[^/]+/tag/([^"\'/\?]+)(\?[^"\']*)?["\']#i',
            function($matches) use ($site_url) {
                $slug = $matches[1];
                $query = '';
                if (!empty($matches[2])) {
                    $parsed = array();
                    parse_str(ltrim($matches[2], '?'), $parsed);
                    $qs = array();
                    if (isset($parsed['page']) && (int)$parsed['page'] > 0) {
                        $qs['page'] = (int)$parsed['page'];
                    }
                    if (!empty($qs)) {
                        $query = '?' . http_build_query($qs);
                    }
                }
                return 'href="' . $site_url . '/' . self::URL_PREFIX . '/tag/' . $slug . $query . '"';
            },
            $html
        );
        if ($result !== null) {
            $html = $result;
        }
        
        // Заменяем ссылки на теги (вариант all-news-page?tag=slug)
        $result = preg_replace_callback(
            '#href=["\'](?:https://ainews-back\.fittin\.ru)?/public/content/[^/]+/all-news-page\?([^"\']*)["\']#i',
            function($matches) use ($site_url) {
                $params = array();
                parse_str($matches[1], $params);
                if (empty($params['tag'])) {
                    return 'href="' . $site_url . '/' . self::URL_PREFIX . '/"';
                }
                $slug = $params['tag'];
                $qs = array();
                if (isset($params['page']) && (int)$params['page'] > 0) {
                    $qs['page'] = (int)$params['page'];
                }
                $query = !empty($qs) ? ('?' . http_build_query($qs)) : '';
                return 'href="' . $site_url . '/' . self::URL_PREFIX . '/tag/' . $slug . $query . '"';
            },
            $html
        );
        if ($result !== null) {
            $html = $result;
        }
        
        // Заменяем абсолютные ссылки на ресурсы (изображения, CSS, JS)
        $result = preg_replace_callback(
            '#(src|href)=["\'](?!http|//|data:|\\#)([^"\']+)["\']#i',
            function($matches) {
                $attr = $matches[1];
                $url = $matches[2];
                
                // Если ссылка начинается с /, это абсолютный путь от корня
                if (strpos($url, '/') === 0) {
                    return $attr . '="https://ainews-back.fittin.ru' . $url . '"';
                }
                
                return $attr . '="https://ainews-back.fittin.ru/' . $url . '"';
            },
            $html
        );
        
        // Проверяем, что preg_replace_callback не вернул null
        if ($result !== null) {
            $html = $result;
        }
        
        return $html;
    }
    
    /**
     * Отдаёт страницу тега со списком новостей
     * 
     * @param string $tag_slug Слаг тега
     */
    private function serve_tag_page($tag_slug) {
        // Очищаем буфер вывода сразу
        while (ob_get_level()) {
            ob_end_clean();
        }
        
        // Получаем API токен из настроек
        $api_token = get_option(self::OPTION_API_TOKEN);
        
        if (empty($api_token)) {
            status_header(500);
            header('Content-Type: text/html; charset=utf-8');
            $settings_url = esc_url(admin_url('options-general.php?page=contentzavod-settings'));
            echo '<!DOCTYPE html><html><head><meta charset="utf-8"><title>' . esc_html__('Configuration Error', 'contentzavod') . '</title></head><body>';
            echo '<h1>' . esc_html__('Configuration Error', 'contentzavod') . '</h1>';
            echo '<p>' . esc_html__('API token not configured. Go to Settings → ContentZavod to configure.', 'contentzavod') . '</p>';
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Static HTML with pre-escaped URL
            echo '<p><a href="' . $settings_url . '">' . esc_html__('Go to settings', 'contentzavod') . '</a></p>';
            echo '</body></html>';
            exit;
        }
        
        // Базовый URL для страницы тега
        $target_url = 'https://ainews-back.fittin.ru/public/content/' . $api_token . '/tag/' . rawurlencode(sanitize_text_field($tag_slug));
        // Поддержка пагинации ?page=..
        if (isset($_GET['page'])) {
            $page = absint($_GET['page']);
            if ($page > 0) {
                $target_url = add_query_arg(array('page' => $page), $target_url);
            }
        }
        
        // Получаем страницу со списком новостей по тегу
        $response = wp_remote_get($target_url, array(
            'timeout' => 30,
            'sslverify' => true,
            'headers' => array(
                'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            )
        ));
        
        if (is_wp_error($response)) {
            status_header(500);
            header('Content-Type: text/html; charset=utf-8');
            echo '<!DOCTYPE html><html><head><meta charset="utf-8"><title>' . esc_html__('Connection Error', 'contentzavod') . '</title></head><body>';
            echo '<h1>' . esc_html__('Connection Error', 'contentzavod') . '</h1>';
            /* translators: %s: error message */
            echo '<p>' . sprintf(esc_html__('Failed to get news list: %s', 'contentzavod'), esc_html($response->get_error_message())) . '</p>';
            echo '<p>URL: ' . esc_html($target_url) . '</p>';
            echo '</body></html>';
            exit;
        }
        
        $status_code = wp_remote_retrieve_response_code($response);
        
        if ($status_code !== 200) {
            status_header($status_code);
            header('Content-Type: text/html; charset=utf-8');
            /* translators: %s: HTTP status code */
            echo '<!DOCTYPE html><html><head><meta charset="utf-8"><title>' . sprintf(esc_html__('Error %s', 'contentzavod'), esc_html($status_code)) . '</title></head><body>';
            /* translators: %s: HTTP status code */
            echo '<h1>' . sprintf(esc_html__('Error %s', 'contentzavod'), esc_html($status_code)) . '</h1>';
            echo '<p>' . esc_html__('Page not found.', 'contentzavod') . '</p>';
            echo '<p>URL: ' . esc_html($target_url) . '</p>';
            echo '</body></html>';
            exit;
        }
        
        $content = wp_remote_retrieve_body($response);
        
        // Проверяем, что контент не пустой
        if (empty($content)) {
            status_header(500);
            header('Content-Type: text/html; charset=utf-8');
            echo '<!DOCTYPE html><html><head><meta charset="utf-8"><title>' . esc_html__('Empty Response', 'contentzavod') . '</title></head><body>';
            echo '<h1>' . esc_html__('Empty Response', 'contentzavod') . '</h1>';
            echo '<p>' . esc_html__('Server returned empty response.', 'contentzavod') . '</p>';
            echo '<p>URL: ' . esc_html($target_url) . '</p>';
            echo '</body></html>';
            exit;
        }
        
        // Обрабатываем HTML контент (заменяем ссылки)
        $processed = $this->process_all_news_html($content);
        if (empty($processed) && !empty($content)) {
            $processed = $content;
        }
        $content = $processed;
        
        // Устанавливаем заголовки
        status_header(200);
        header('Content-Type: text/html; charset=utf-8');
        header('Cache-Control: public, max-age=1800'); // Кэш на 30 минут
        
        // Выводим контент
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- HTML content from trusted API
        echo $content;
        exit;
    }
    
    // =========================================================================
    // IndexNow: методы для уведомления поисковых систем о новом контенте
    // =========================================================================

    /**
     * Отдаёт файл верификации IndexNow ключа
     */
    private function serve_indexnow_key_file() {
        $key = get_option(self::OPTION_INDEXNOW_KEY, '');

        if (empty($key)) {
            status_header(404);
            exit;
        }

        status_header(200);
        header('Content-Type: text/plain; charset=utf-8');
        header('Cache-Control: public, max-age=86400');
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- hex string
        echo $key;
        exit;
    }

    /**
     * WP cron callback: загружает sitemap, сравнивает URL, отправляет новые в IndexNow
     */
    public function indexnow_cron_run() {
        $api_token    = get_option(self::OPTION_API_TOKEN, '');
        $indexnow_key = get_option(self::OPTION_INDEXNOW_KEY, '');

        if (empty($api_token) || empty($indexnow_key)) {
            update_option(self::OPTION_INDEXNOW_LAST_CHECK, time());
            update_option(self::OPTION_INDEXNOW_LAST_STATUS, 'skipped: missing api_token or indexnow_key');
            return;
        }

        update_option(self::OPTION_INDEXNOW_LAST_CHECK, time());

        // 1. Загружаем sitemap XML
        $sitemap_url = self::API_BASE_URL . '/public/content/' . rawurlencode($api_token) . '/sitemap.xml';
        $response = wp_remote_get($sitemap_url, array(
            'timeout'   => 30,
            'sslverify' => true,
            'headers'   => array(
                'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            ),
        ));

        if (is_wp_error($response)) {
            update_option(self::OPTION_INDEXNOW_LAST_STATUS, 'api_error: ' . $response->get_error_message());
            return;
        }

        $code = wp_remote_retrieve_response_code($response);
        if ($code !== 200) {
            update_option(self::OPTION_INDEXNOW_LAST_STATUS, 'api_error: HTTP ' . $code);
            return;
        }

        $xml = wp_remote_retrieve_body($response);
        if (empty($xml)) {
            update_option(self::OPTION_INDEXNOW_LAST_STATUS, 'api_error: empty sitemap');
            return;
        }

        // 2. Парсим URL из sitemap
        $sitemap_urls = $this->indexnow_parse_sitemap_urls($xml);
        if (empty($sitemap_urls)) {
            update_option(self::OPTION_INDEXNOW_LAST_STATUS, 'no_urls_in_sitemap');
            return;
        }

        // 3. Сравниваем с ранее отправленными
        $submitted = get_option(self::OPTION_INDEXNOW_SUBMITTED_URLS, array());
        if (!is_array($submitted)) {
            $submitted = array();
        }
        $new_urls = array_values(array_diff($sitemap_urls, $submitted));

        if (empty($new_urls)) {
            update_option(self::OPTION_INDEXNOW_LAST_STATUS, 'no_new_urls');
            return;
        }

        // 4. Отправляем новые URL в IndexNow
        $result = $this->indexnow_submit_urls($new_urls, $indexnow_key);

        if (is_wp_error($result)) {
            update_option(self::OPTION_INDEXNOW_LAST_STATUS, 'api_error: ' . $result->get_error_message());
            return;
        }

        // 5. Сохраняем результат (ограничиваем список до 2000 последних URL)
        $submitted = array_merge($submitted, $new_urls);
        if (count($submitted) > 2000) {
            $submitted = array_slice($submitted, -2000);
        }
        update_option(self::OPTION_INDEXNOW_SUBMITTED_URLS, $submitted);

        $count = (int) get_option(self::OPTION_INDEXNOW_SUBMITTED_COUNT, 0);
        update_option(self::OPTION_INDEXNOW_SUBMITTED_COUNT, $count + count($new_urls));
        update_option(self::OPTION_INDEXNOW_LAST_STATUS, 'ok: submitted ' . count($new_urls) . ' url(s)');
    }

    /**
     * Парсит URL из sitemap XML и переписывает на локальный домен
     *
     * @param string $xml Содержимое sitemap XML
     * @return array Массив локальных URL
     */
    private function indexnow_parse_sitemap_urls($xml) {
        $prev = libxml_use_internal_errors(true);
        $doc  = simplexml_load_string($xml);
        libxml_clear_errors();
        libxml_use_internal_errors($prev);

        if ($doc === false) {
            return array();
        }

        $site_url = home_url();
        $urls     = array();

        foreach ($doc->url as $url_node) {
            $loc = (string) $url_node->loc;
            if (empty($loc)) {
                continue;
            }
            // Переписываем URL API на локальный домен (пропускаем URL, не совпавшие с паттерном)
            $local = preg_replace(
                '#https://ainews-back\.fittin\.ru/public/content/[^/]+/view/#',
                $site_url . '/' . self::URL_PREFIX . '/view/',
                $loc,
                -1,
                $count
            );
            if (!empty($local) && $count > 0) {
                $urls[] = $local;
            }
        }

        return array_unique($urls);
    }

    /**
     * Отправляет пакет URL в IndexNow API
     *
     * @param array  $urls Массив URL для отправки
     * @param string $key  IndexNow ключ верификации
     * @return true|WP_Error
     */
    private function indexnow_submit_urls($urls, $key) {
        $host         = wp_parse_url(home_url(), PHP_URL_HOST);
        $key_location = home_url('/' . $key . '.txt');

        $payload = wp_json_encode(array(
            'host'        => $host,
            'key'         => $key,
            'keyLocation' => $key_location,
            'urlList'     => array_values($urls),
        ));

        $response = wp_remote_post(self::INDEXNOW_API_URL, array(
            'timeout'   => 30,
            'sslverify' => true,
            'headers'   => array(
                'Content-Type' => 'application/json; charset=utf-8',
                'User-Agent'   => 'ContentZavod/' . self::VERSION . '; WordPress/' . get_bloginfo('version'),
            ),
            'body' => $payload,
        ));

        if (is_wp_error($response)) {
            return $response;
        }

        $code = wp_remote_retrieve_response_code($response);

        // 200 = обработано, 202 = принято к обработке
        if ($code === 200 || $code === 202) {
            return true;
        }

        return new WP_Error(
            'indexnow_http_error',
            sprintf(
                __('IndexNow API returned HTTP %1$d: %2$s', 'contentzavod'),
                $code,
                wp_remote_retrieve_body($response)
            )
        );
    }

    /**
     * Добавляет sitemap в robots.txt автоматически
     *
     * @param string $output Содержимое robots.txt
     * @param bool $public Публичен ли сайт
     * @return string Обновлённое содержимое robots.txt
     */
    public function add_sitemap_to_robots($output, $public) {
        // Добавляем sitemap только если сайт публичный
        if ($public) {
            $sitemap_url = home_url('/' . self::URL_PREFIX . '-sitemap.xml');
            
            // Проверяем, не добавлен ли уже этот sitemap
            if (strpos($output, $sitemap_url) === false) {
                $output .= "\nSitemap: " . $sitemap_url . "\n";
            }
        }
        
        return $output;
    }
    
    /**
     * Подключает стили для админ-панели
     */
    public function enqueue_admin_styles($hook) {
        // Загружаем стили только на странице настроек плагина
        if ($hook !== 'settings_page_contentzavod-settings') {
            return;
        }
        
        // Добавляем inline стили для страницы настроек
        $custom_css = '
            .wrap h2 {
                margin-top: 20px;
            }
            .wrap code {
                background: #f0f0f1;
                padding: 2px 6px;
                border-radius: 3px;
            }
        ';
        wp_add_inline_style('common', $custom_css);
    }
    
    /**
     * Показывает уведомление в админ-панели, если API токен не настроен
     */
    public function show_api_token_notice() {
        // Проверяем, настроен ли API токен
        $api_token = get_option(self::OPTION_API_TOKEN, '');
        
        // Если токен настроен, ничего не показываем
        if (!empty($api_token)) {
            return;
        }
        
        // Получаем текущий экран
        $screen = get_current_screen();
        
        // Не показываем уведомление на странице настроек плагина (там уже есть предупреждение)
        if ($screen && $screen->id === 'settings_page_contentzavod-settings') {
            return;
        }
        
        // Формируем URL настроек
        $settings_url = admin_url('options-general.php?page=contentzavod-settings');
        
        // Показываем уведомление об ошибке
        ?>
        <div class="notice notice-error is-dismissible">
            <p>
                <strong>ContentZavod:</strong> 
                <?php echo esc_html__('Plugin not configured! To use the plugin, you need to enter an API token.', 'contentzavod'); ?>
                <a href="<?php echo esc_url($settings_url); ?>"><?php echo esc_html__('Go to settings', 'contentzavod'); ?></a>
            </p>
        </div>
        <?php
    }
    
    /**
     * Добавляет ссылку "Настройки" на странице плагинов
     * 
     * @param array $links Существующие ссылки
     * @return array Обновлённый массив ссылок
     */
    public function add_settings_link($links) {
        $settings_link = '<a href="' . admin_url('options-general.php?page=contentzavod-settings') . '">' . esc_html__('Settings', 'contentzavod') . '</a>';
        array_unshift($links, $settings_link);
        return $links;
    }
    
    /**
     * Добавляет пункт меню в админ-панель
     */
    public function add_admin_menu() {
        add_options_page(
            __('ContentZavod Settings', 'contentzavod'),  // Заголовок страницы
            __('ContentZavod', 'contentzavod'),           // Название в меню
            'manage_options',                             // Права доступа
            'contentzavod-settings',                      // Slug страницы
            array($this, 'render_settings_page')          // Функция отрисовки
        );
    }
    
    /**
     * Регистрирует настройки плагина
     */
    public function register_settings() {
        register_setting(
            'contentzavod_settings_group',  // Группа настроек
            self::OPTION_API_TOKEN,          // Название опции
            array(
                'type' => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'default' => ''
            )
        );
        
        add_settings_section(
            'contentzavod_main_section',              // ID секции
            __('Main Settings', 'contentzavod'),      // Заголовок секции
            array($this, 'render_section_info'),      // Callback для описания
            'contentzavod-settings'                   // Страница
        );
        
        add_settings_field(
            'contentzavod_api_token_field',           // ID поля
            __('API Token', 'contentzavod'),          // Название поля
            array($this, 'render_api_token_field'),   // Callback для отрисовки
            'contentzavod-settings',                  // Страница
            'contentzavod_main_section'               // Секция
        );

        // IndexNow секция
        add_settings_section(
            'contentzavod_indexnow_section',
            __('IndexNow Settings', 'contentzavod'),
            array($this, 'render_indexnow_section_info'),
            'contentzavod-settings'
        );
    }

    /**
     * Отрисовывает информацию о секции настроек
     */
    public function render_section_info() {
        echo '<p>' . esc_html__('Enter your API token to access ContentZavod content.', 'contentzavod') . '</p>';
        echo '<p>' . esc_html__('You can get an API token in your personal account at', 'contentzavod') . ' <a href="https://contentzavod.fittin.ru" target="_blank">contentzavod.fittin.ru</a></p>';
    }
    
    /**
     * Отрисовывает поле для ввода API токена
     */
    public function render_api_token_field() {
        $api_token = get_option(self::OPTION_API_TOKEN, '');
        ?>
        <input 
            type="text" 
            name="<?php echo esc_attr(self::OPTION_API_TOKEN); ?>" 
            value="<?php echo esc_attr($api_token); ?>" 
            class="regular-text"
            placeholder="<?php echo esc_attr__('Enter your API token', 'contentzavod'); ?>"
        />
        <p class="description">
            <?php echo esc_html__('API token for content access. Format: character string.', 'contentzavod'); ?>
        </p>
        <?php
    }

    /**
     * Отрисовывает секцию IndexNow на странице настроек
     */
    public function render_indexnow_section_info() {
        $key              = get_option(self::OPTION_INDEXNOW_KEY, '');
        $last_check       = (int) get_option(self::OPTION_INDEXNOW_LAST_CHECK, 0);
        $last_status      = get_option(self::OPTION_INDEXNOW_LAST_STATUS, __('Never run', 'contentzavod'));
        $submitted_count  = (int) get_option(self::OPTION_INDEXNOW_SUBMITTED_COUNT, 0);
        $key_url          = !empty($key) ? home_url('/' . $key . '.txt') : '';
        $last_check_fmt   = $last_check > 0
            ? date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $last_check)
            : __('Never', 'contentzavod');

        echo '<p>' . esc_html__('IndexNow automatically notifies search engines about new content URLs found in your sitemap.', 'contentzavod') . '</p>';

        echo '<table class="form-table"><tbody>';

        // Ключ
        echo '<tr><th scope="row">' . esc_html__('IndexNow Key:', 'contentzavod') . '</th><td>';
        if (!empty($key)) {
            echo '<code>' . esc_html($key) . '</code>';
            echo ' &mdash; <a href="' . esc_url($key_url) . '" target="_blank">' . esc_html__('Verify key file', 'contentzavod') . '</a>';
        } else {
            echo '<em>' . esc_html__('Not generated yet. Re-activate the plugin to generate.', 'contentzavod') . '</em>';
        }
        echo '</td></tr>';

        // URL файла ключа
        echo '<tr><th scope="row">' . esc_html__('Key Location URL:', 'contentzavod') . '</th>';
        echo '<td>' . (!empty($key_url) ? '<code>' . esc_html($key_url) . '</code>' : '&mdash;') . '</td></tr>';

        // Последняя проверка
        echo '<tr><th scope="row">' . esc_html__('Last Check:', 'contentzavod') . '</th>';
        echo '<td>' . esc_html($last_check_fmt) . '</td></tr>';

        // Статус
        echo '<tr><th scope="row">' . esc_html__('Last Status:', 'contentzavod') . '</th>';
        echo '<td><code>' . esc_html($last_status) . '</code></td></tr>';

        // Количество отправленных URL
        echo '<tr><th scope="row">' . esc_html__('Total URLs Submitted:', 'contentzavod') . '</th>';
        echo '<td><strong>' . esc_html((string) $submitted_count) . '</strong></td></tr>';

        echo '</tbody></table>';
    }

    /**
     * Отрисовывает страницу настроек
     */
    public function render_settings_page() {
        // Проверяем права доступа
        if (!current_user_can('manage_options')) {
            return;
        }
        
        // Получаем текущий API токен
        $api_token = get_option(self::OPTION_API_TOKEN, '');
        $is_configured = !empty($api_token);
        
        ?>
        <div class="wrap">
            <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
            
            <?php if ($is_configured): ?>
                <div class="notice notice-success">
                    <p><strong><?php echo esc_html__('✅ API token configured! Plugin is ready to use.', 'contentzavod'); ?></strong></p>
                </div>
            <?php else: ?>
                <div class="notice notice-warning">
                    <p><strong><?php echo esc_html__('⚠️ API token not configured. Please enter API token below.', 'contentzavod'); ?></strong></p>
                </div>
            <?php endif; ?>
            
            <form method="post" action="options.php">
                <?php
                settings_fields('contentzavod_settings_group');
                do_settings_sections('contentzavod-settings');
                submit_button(__('Save Settings', 'contentzavod'));
                ?>
            </form>
            
            <hr>
            
            <h2><?php echo esc_html__('Plugin Information', 'contentzavod'); ?></h2>
            <table class="form-table">
                <tr>
                    <th scope="row"><?php echo esc_html__('Plugin Version:', 'contentzavod'); ?></th>
                    <td><strong><?php echo esc_html(self::VERSION); ?></strong></td>
                </tr>
                <tr>
                    <th scope="row"><?php echo esc_html__('Sitemap URL:', 'contentzavod'); ?></th>
                    <td>
                        <code><?php echo esc_html(home_url('/' . self::URL_PREFIX . '-sitemap.xml')); ?></code>
                        <?php if ($is_configured): ?>
                            <br><a href="<?php echo esc_url(home_url('/' . self::URL_PREFIX . '-sitemap.xml')); ?>" target="_blank"><?php echo esc_html__('Open sitemap', 'contentzavod'); ?></a>
                        <?php endif; ?>
                    </td>
                </tr>
                <tr>
                    <th scope="row"><?php echo esc_html__('Main News Page:', 'contentzavod'); ?></th>
                    <td>
                        <code><?php echo esc_html(home_url('/' . self::URL_PREFIX . '/')); ?></code>
                        <?php if ($is_configured): ?>
                            <br><a href="<?php echo esc_url(home_url('/' . self::URL_PREFIX . '/')); ?>" target="_blank"><?php echo esc_html__('Open page', 'contentzavod'); ?></a>
                        <?php endif; ?>
                    </td>
                </tr>
            </table>
            
            <hr>
            
            <h2><?php echo esc_html__('How to Use', 'contentzavod'); ?></h2>
            <ol>
                <li><?php echo esc_html__('Get an API token in your personal account at', 'contentzavod'); ?> <a href="https://contentzavod.fittin.ru" target="_blank">contentzavod.fittin.ru</a></li>
                <li><?php echo esc_html__('Enter the API token in the field above and click "Save Settings"', 'contentzavod'); ?></li>
                <li><?php echo esc_html__('Go to Settings → Permalinks and click "Save" (updates rewrite rules)', 'contentzavod'); ?></li>
                <li><?php echo esc_html__('Done! Content will be available at:', 'contentzavod'); ?> <code><?php echo esc_html(home_url('/' . self::URL_PREFIX . '/')); ?></code></li>
            </ol>
            
            <hr>
            
            <h2><?php echo esc_html__('Testing', 'contentzavod'); ?></h2>
            <?php if ($is_configured): ?>
                <p><?php echo esc_html__('Check plugin functionality:', 'contentzavod'); ?></p>
                <ul>
                    <li><a href="<?php echo esc_url(home_url('/' . self::URL_PREFIX . '-sitemap.xml')); ?>" target="_blank"><?php echo esc_html__('Open sitemap', 'contentzavod'); ?></a></li>
                    <li><a href="<?php echo esc_url(home_url('/' . self::URL_PREFIX . '/')); ?>" target="_blank"><?php echo esc_html__('Open main news page', 'contentzavod'); ?></a></li>
                    <li><a href="<?php echo esc_url(home_url('/robots.txt')); ?>" target="_blank"><?php echo esc_html__('Check robots.txt', 'contentzavod'); ?></a></li>
                </ul>
            <?php else: ?>
                <p><em><?php echo esc_html__('First configure the API token for testing.', 'contentzavod'); ?></em></p>
            <?php endif; ?>
            
            <hr>
            
            <h2><?php echo esc_html__('Support', 'contentzavod'); ?></h2>
            <p>
                <strong><?php echo esc_html__('Website:', 'contentzavod'); ?></strong> <a href="https://contentzavod.fittin.ru" target="_blank">contentzavod.fittin.ru</a><br>
                <strong><?php echo esc_html__('Documentation:', 'contentzavod'); ?></strong> <a href="https://contentzavod.fittin.ru" target="_blank">contentzavod.fittin.ru</a>
            </p>
        </div>
        <?php
    }
}

// Инициализация плагина
// Используем приоритет 20, чтобы загружаться после большинства плагинов (включая XML Sitemap)
function contentzavod_proxy_init() {
    new ContentZavod_Proxy();
}
add_action('plugins_loaded', 'contentzavod_proxy_init', 20);

/**
 * Активация плагина
 */
function contentzavod_proxy_activate() {
    // Генерируем IndexNow ключ при первой активации (до add_rewrite_rules, чтобы правило было зарегистрировано)
    if (empty(get_option('contentzavod_indexnow_key', ''))) {
        update_option('contentzavod_indexnow_key', bin2hex(random_bytes(16)));
    }

    // Добавляем правила перезаписи (включая IndexNow key file)
    $plugin = new ContentZavod_Proxy();
    $plugin->add_rewrite_rules();

    // Регистрируем ежечасную cron задачу для IndexNow
    if (!wp_next_scheduled(ContentZavod_Proxy::CRON_HOOK)) {
        wp_schedule_event(time(), 'hourly', ContentZavod_Proxy::CRON_HOOK);
    }

    // Сбрасываем правила перезаписи
    flush_rewrite_rules();
}
register_activation_hook(__FILE__, 'contentzavod_proxy_activate');

/**
 * Деактивация плагина
 */
function contentzavod_proxy_deactivate() {
    // Удаляем cron задачу IndexNow
    wp_clear_scheduled_hook(ContentZavod_Proxy::CRON_HOOK);

    // Сбрасываем правила перезаписи
    flush_rewrite_rules();
}
register_deactivation_hook(__FILE__, 'contentzavod_proxy_deactivate');

