new_name) $option_mappings = [ 'arr_processing_mode' => 'airsrefe_processing_mode', 'arr_image_source' => 'airsrefe_image_source', 'arr_plugin_language' => 'airsrefe_plugin_language', 'arr_openai_key' => 'airsrefe_openai_key', 'arr_daily_parsing_limit' => 'airsrefe_daily_parsing_limit', 'arr_generate_tags' => 'airsrefe_generate_tags', 'arr_cache_time' => 'airsrefe_cache_time', 'arr_use_original_date' => 'airsrefe_use_original_date', 'arr_model_content' => 'airsrefe_model_content', 'arr_model_title' => 'airsrefe_model_title', 'arr_model_tags' => 'airsrefe_model_tags', 'arr_model_seo' => 'airsrefe_model_seo', 'arr_model_fallback' => 'airsrefe_model_fallback', 'arr_smart_model_selection' => 'airsrefe_smart_model_selection', 'arr_content_length_threshold' => 'airsrefe_content_length_threshold', 'arr_enable_json_responses' => 'airsrefe_enable_json_responses', 'arr_daily_budget_limit' => 'airsrefe_daily_budget_limit', 'arr_enable_budget_alerts' => 'airsrefe_enable_budget_alerts', 'arr_emergency_stop_enabled' => 'airsrefe_emergency_stop_enabled', 'arr_optimize_images' => 'airsrefe_optimize_images', 'arr_image_format' => 'airsrefe_image_format', 'arr_image_compression_quality' => 'airsrefe_image_compression_quality', 'arr_max_image_width' => 'airsrefe_max_image_width', 'arr_max_image_height' => 'airsrefe_max_image_height', 'arr_image_size' => 'airsrefe_image_size', 'arr_image_quality' => 'airsrefe_image_quality', 'arr_extract_full_content' => 'airsrefe_extract_full_content', 'arr_content_extraction_method' => 'airsrefe_content_extraction_method', 'arr_min_content_length' => 'airsrefe_min_content_length', 'arr_respect_robots_txt' => 'airsrefe_respect_robots_txt', 'arr_cron_interval' => 'airsrefe_cron_interval', 'arr_feeds' => 'airsrefe_feeds', 'arr_daily_costs' => 'airsrefe_daily_costs', 'arr_prompts' => 'airsrefe_prompts', 'arr_logs' => 'airsrefe_logs', 'arr_version' => 'airsrefe_version', 'arr_cache_initialized' => 'airsrefe_cache_initialized', 'arr_cache_version' => 'airsrefe_cache_version', 'arr_block_parsing' => 'airsrefe_block_parsing', 'arr_today_parsed_count' => 'airsrefe_today_parsed_count' ]; // Migrate each option if old exists and new doesn't foreach ($option_mappings as $old_name => $new_name) { $old_value = get_option($old_name); if ($old_value !== false && get_option($new_name) === false) { update_option($new_name, $old_value); // Keep old option for backward compatibility during transition // delete_option($old_name); // Uncomment after full migration } } // Migrate transients with arr_ prefix $transient_keys = [ '_transient_arr_', '_transient_timeout_arr_' ]; foreach ($transient_keys as $prefix) { $old_transients = wp_cache_get('airsrefe_old_transients_' . $prefix, 'airsrefe_migration'); if ($old_transients === false) { // Use WordPress functions instead of direct SQL $all_options = wp_load_alloptions(); $old_transients = []; foreach ($all_options as $key => $value) { if (strpos($key, $prefix) === 0) { $old_transients[] = $key; } } wp_cache_set('airsrefe_old_transients_' . $prefix, $old_transients, 'airsrefe_migration', 3600); } foreach ($old_transients as $old_name) { $new_name = str_replace('_arr_', '_airsrefe_', $old_name); $value = get_option($old_name); if ($value !== false) { update_option($new_name, $value); } } } airsrefe_append_log('Options migration completed from arr_ to airsrefe_ prefix'); } /** * Handle plugin deactivation */ function airsrefe_plugin_deactivation() { // Clear scheduled events wp_clear_scheduled_hook('airsrefe_process_queue_batch'); wp_clear_scheduled_hook('airsrefe_queue_maintenance'); // Clear all plugin caches airsrefe_clear_all_caches(); // Flush rewrite rules flush_rewrite_rules(); // Log deactivation airsrefe_append_log('Plugin deactivated'); } /** * Create necessary database tables */ function airsrefe_create_tables() { global $wpdb; $table_name = $wpdb->prefix . 'airsrefe_feeds'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE IF NOT EXISTS $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, feed_url varchar(255) NOT NULL, feed_name varchar(255) NOT NULL, processing_mode varchar(20) DEFAULT 'simple', ai_prompt text, image_source varchar(20) DEFAULT 'none', post_category int(11) DEFAULT 0, post_status varchar(20) DEFAULT 'publish', use_original_date tinyint(1) DEFAULT 1, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY feed_url (feed_url) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } /** * Initialize caching system */ function airsrefe_initialize_caching() { // Set up cache groups if (function_exists('wp_cache_add_global_groups')) { wp_cache_add_global_groups([ 'airsrefe_plugin', 'airsrefe_daily_limits', 'airsrefe_duplicates', 'airsrefe_categories', 'airsrefe' ]); } // Initialize cache settings if (!get_option('airsrefe_cache_initialized')) { update_option('airsrefe_cache_initialized', true); update_option('airsrefe_cache_version', AIRSREFE_VERSION); } } /** * Clear all plugin caches */ function airsrefe_clear_all_caches() { // Clear object cache groups if (function_exists('wp_cache_flush_group')) { wp_cache_flush_group('airsrefe_plugin'); wp_cache_flush_group('airsrefe_daily_limits'); wp_cache_flush_group('airsrefe_duplicates'); wp_cache_flush_group('airsrefe_categories'); wp_cache_flush_group('airsrefe'); } // Clear transients using WordPress API airsrefe_clear_plugin_transients(); // Clear any remaining cache wp_cache_flush(); } /** * Clear plugin transients safely */ function airsrefe_clear_plugin_transients() { // Clear known transient patterns using WordPress functions $transient_patterns = [ 'airsrefe_feed_', 'airsrefe_ai_', 'airsrefe_cache_', 'airsrefe_daily_', 'airsrefe_duplicate_', 'airsrefe_stats_', 'airsrefe_dashboard_', 'airsrefe_processed_', 'airsrefe_attachment_', 'airsrefe_today_parsed_count' ]; foreach ($transient_patterns as $pattern) { // Try to delete common transient variations for ($i = 0; $i < 100; $i++) { // Reasonable limit $key = $pattern . $i; delete_transient($key); } // Also try without numbers delete_transient($pattern . 'list'); delete_transient($pattern . 'cache'); delete_transient($pattern . 'data'); } // Clear cache groups $cache_groups = [ 'airsrefe_rss_feeds', 'airsrefe_ai_results', 'airsrefe_cache', 'airsrefe_daily_limits', 'airsrefe_duplicates', 'airsrefe_stats' ]; foreach ($cache_groups as $group) { wp_cache_flush_group($group); } // Clear WordPress object cache wp_cache_flush(); } // WordPress 4.6+ automatically loads translations, no need for manual load_plugin_textdomain // Load custom language support add_action('init', function() { $plugin_language = get_option('airssrewriter_plugin_language', 'en'); $locale = ($plugin_language === 'uk') ? 'uk' : 'en_US'; // WordPress 4.6+ automatically loads translations, but we need custom language support if ($locale !== 'en_US') { $mo_file = dirname(__FILE__) . '/languages/' . $locale . '.mo'; if (file_exists($mo_file)) { load_textdomain('ai-rss-rewriter', $mo_file); } } }, 1); // Filter to change locale on plugin pages add_filter('locale', function($locale) { // Only process in admin context and when page parameter exists if (is_admin() && isset($_GET['page'])) { // Check if user functions are available before calling current_user_can if (function_exists('current_user_can') && function_exists('wp_get_current_user')) { // Additional check to ensure WordPress user system is loaded if (did_action('init') > 0 && current_user_can('manage_options')) { // Verify nonce for additional security $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : ''; if (wp_verify_nonce($nonce, 'ai-rss-rewriter-locale')) { $page = sanitize_text_field(wp_unslash($_GET['page'])); if (strpos($page, 'ai-rss-rewriter') !== false) { $plugin_language = get_option('airssrewriter_plugin_language', 'en'); return ($plugin_language === 'uk') ? 'uk' : 'en_US'; } } } } } return $locale; }); // Filter to force load plugin translations add_filter('gettext', function($translation, $text, $domain) { if ($domain === 'ai-rss-rewriter') { $plugin_language = get_option('airssrewriter_plugin_language', 'en'); if ($plugin_language === 'uk') { static $uk_translations = null; if ($uk_translations === null) { $uk_translations = []; $uk_file = dirname(__FILE__) . '/languages/uk.po'; if (file_exists($uk_file)) { $po_content = file_get_contents($uk_file); preg_match_all('/msgid "(.*?)"\nmsgstr "(.*?)"/s', $po_content, $matches); if (!empty($matches[1]) && !empty($matches[2])) { for ($i = 0; $i < count($matches[1]); $i++) { if (!empty($matches[2][$i])) { $uk_translations[$matches[1][$i]] = $matches[2][$i]; } } } } } if (isset($uk_translations[$text])) { return $uk_translations[$text]; } } } return $translation; }, 10, 3); // Filter to force load plugin translations (alternative method) add_filter('ngettext', function($translation, $single, $plural, $number, $domain) { if ($domain === 'ai-rss-rewriter') { $plugin_language = get_option('airssrewriter_plugin_language', 'en'); if ($plugin_language === 'uk') { static $uk_translations = null; if ($uk_translations === null) { $uk_translations = []; $uk_file = dirname(__FILE__) . '/languages/uk.po'; if (file_exists($uk_file)) { $po_content = file_get_contents($uk_file); preg_match_all('/msgid "(.*?)"\nmsgstr "(.*?)"/s', $po_content, $matches); if (!empty($matches[1]) && !empty($matches[2])) { for ($i = 0; $i < count($matches[1]); $i++) { if (!empty($matches[2][$i])) { $uk_translations[$matches[1][$i]] = $matches[2][$i]; } } } } } if ($number === 1 && isset($uk_translations[$single])) { return $uk_translations[$single]; } if ($number !== 1 && isset($uk_translations[$plural])) { return $uk_translations[$plural]; } } } return $translation; }, 10, 5); if (!function_exists('airsrefe_append_log')) { /** * Append message to plugin log * * @param string $message The message to log * @return void */ function airsrefe_append_log($message) { $log = get_option('airsrefe_log', ''); $timestamp = current_time('mysql'); $new_entry = "[$timestamp] $message\n"; $log = $new_entry . $log; if (strlen($log) > 51200) { $log = substr($log, 0, 51200) . "\n[LOG TRUNCATED]\n"; } update_option('airsrefe_log', $log); } } // Calculate processing cost for article parsing if (!function_exists('airsrefe_calculate_processing_cost')) { /** * Calculate AI processing cost based on log data * * @param array $log_data Array containing processing log data * @return float Total processing cost */ function airsrefe_calculate_processing_cost($log_data = []) { $total_cost = 0; $content_length = strlen($log_data['original'] ?? '') + strlen($log_data['unique'] ?? ''); $content_tokens = $content_length / 4; $content_cost = ($content_tokens / 1000) * 0.01; $title_cost = 0.001; $tags_cost = 0.002; $image_cost = isset($log_data['image_generated']) && $log_data['image_generated'] ? 0.04 : 0; $ai_operations_cost = 0; if (isset($log_data['ai_operations'])) { foreach ($log_data['ai_operations'] as $operation) { switch ($operation) { case 'content_rewrite': $ai_operations_cost += 0.005; break; case 'title_optimization': $ai_operations_cost += 0.002; break; case 'seo_enhancement': $ai_operations_cost += 0.003; break; case 'language_translation': $ai_operations_cost += 0.008; break; } } } $total_cost = $content_cost + $title_cost + $tags_cost + $image_cost + $ai_operations_cost; if (isset($log_data['processing_cost'])) { $total_cost = $log_data['processing_cost']; } return round($total_cost, 3); } } // Load all plugin files require_once 'includes/assets-manager.php'; require_once 'includes/prompts-manager.php'; require_once 'includes/ai-handler.php'; require_once 'includes/image-handler.php'; require_once 'includes/rss-parser.php'; require_once 'includes/admin-interface.php'; require_once 'includes/settings-handlers.php'; require_once 'includes/content-processor.php'; require_once 'includes/ajax-handlers.php'; // Initialize assets manager new AIRSREFE_Assets_Manager(); // Function moved to main activation hook $defaults = [ 'airsrefe_ce_extract_full_content' => 1, 'airsrefe_ce_content_extraction_method' => 'dom', 'feedhive_extract_full_content' => 1, 'feedhive_content_extraction_method' => 'dom', 'airsrefe_use_original_date' => 1, 'airsrefe_daily_post_limit' => 50, 'airsrefe_optimize_images' => 1, 'airsrefe_image_format' => 'webp', 'airsrefe_image_compression_quality' => 85, 'airsrefe_max_image_width' => 1792, 'airsrefe_max_image_height' => 1024, 'airsrefe_image_size' => '1792x1024', 'airsrefe_image_quality' => 'standard', 'airsrefe_model_content' => 'gpt-4o', 'airsrefe_model_title' => 'gpt-4o-mini', 'airsrefe_model_tags' => 'gpt-4o-mini', 'airsrefe_exponential_backoff' => 1, 'airsrefe_max_retry_attempts' => 3, 'airsrefe_api_timeout' => 60, ]; foreach ($defaults as $option => $value) { // Використовуємо update_option замість add_option для кращої продуктивності // update_option автоматично створює опцію, якщо вона не існує update_option($option, $value); } airsrefe_cleanup_transients(); /** * Create plugin assets in uploads directory * Validates file types and ensures secure file operations */ function airsrefe_create_assets() { // Use uploads directory instead of plugin directory $upload_dir = wp_upload_dir(); $assets_dir = $upload_dir['basedir'] . '/ai-rss-rewriter/assets'; // Validate upload directory if (!$upload_dir || isset($upload_dir['error']) && $upload_dir['error']) { airsrefe_append_log("❌ Error getting upload directory: " . ($upload_dir['error'] ?? 'Unknown error')); return false; } if (!file_exists($assets_dir)) { $created = wp_mkdir_p($assets_dir); if (!$created) { airsrefe_append_log("❌ Failed to create assets directory: " . $assets_dir); return false; } } // Create subdirectories $subdirs = [ 'css/admin', 'js/admin', 'css/frontend', 'js/frontend' ]; foreach ($subdirs as $subdir) { $subdir_path = $assets_dir . '/' . $subdir; if (!file_exists($subdir_path)) { wp_mkdir_p($subdir_path); } } // Copy all required asset files to uploads directory $source_assets = AIRSREFE_PLUGIN_DIR . 'assets/'; $assets_to_copy = [ 'admin-modern.css', 'admin-modern.js', 'admin-interface.css', 'settings-admin.js' ]; // Copy CSS files $css_files = [ 'css/admin/settings.css', 'css/admin/prompts.css' ]; // Copy JS files $js_files = [ 'js/admin/modal.js', 'js/admin/feed-management.js', 'js/admin/logs.js', 'js/admin/prompts.js', ]; // Copy original assets with validation foreach ($assets_to_copy as $asset) { $source = $source_assets . $asset; $destination = $assets_dir . '/' . $asset; // Validate file extension $allowed_extensions = ['css', 'js']; $file_extension = pathinfo($asset, PATHINFO_EXTENSION); if (!in_array($file_extension, $allowed_extensions)) { airsrefe_append_log("❌ Invalid file extension for asset: " . $asset); continue; } // Validate source file exists and is readable if (!file_exists($source) || !is_readable($source)) { airsrefe_append_log("❌ Source asset not found or not readable: " . $source); continue; } // Validate file size (max 1MB for assets) if (filesize($source) > 1024 * 1024) { airsrefe_append_log("❌ Asset file too large: " . $asset); continue; } // Create destination directory if it doesn't exist $destination_dir = dirname($destination); if (!file_exists($destination_dir)) { wp_mkdir_p($destination_dir); } if (!file_exists($destination) || filemtime($source) > filemtime($destination)) { if (copy($source, $destination)) { airsrefe_append_log("✅ Asset copied successfully: " . basename($source)); } else { $error_msg = sprintf('Failed to copy asset file: %s to %s', $source, $destination); airsrefe_append_log("❌ " . $error_msg); } } } // Copy new CSS files foreach ($css_files as $css_file) { $source = AIRSREFE_PLUGIN_DIR . 'assets/' . $css_file; $destination = $assets_dir . '/' . $css_file; // Create destination directory if it doesn't exist $destination_dir = dirname($destination); if (!file_exists($destination_dir)) { wp_mkdir_p($destination_dir); } if (file_exists($source) && (!file_exists($destination) || filemtime($source) > filemtime($destination))) { if (copy($source, $destination)) { // File copied successfully airsrefe_append_log("✅ CSS file copied successfully: " . basename($source)); } else { // Log error if copy fails $error_msg = sprintf('Failed to copy CSS file: %s to %s', $source, $destination); airsrefe_append_log("❌ " . $error_msg); } } elseif (!file_exists($source)) { // If source file doesn't exist, create it directly in uploads directory $content = ''; switch ($css_file) { case 'css/admin/settings.css': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/css/admin/settings.css'); break; case 'css/admin/prompts.css': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/css/admin/prompts.css'); break; } if ($content && file_put_contents($destination, $content)) { // File created successfully airsrefe_append_log("✅ CSS file created successfully: " . basename($destination)); } else { $error_msg = sprintf('Failed to create CSS file: %s', $destination); airsrefe_append_log("❌ " . $error_msg); } } } // Copy new JS files foreach ($js_files as $js_file) { $source = AIRSREFE_PLUGIN_DIR . 'assets/' . $js_file; $destination = $assets_dir . '/' . $js_file; // Create destination directory if it doesn't exist $destination_dir = dirname($destination); if (!file_exists($destination_dir)) { wp_mkdir_p($destination_dir); } if (file_exists($source) && (!file_exists($destination) || filemtime($source) > filemtime($destination))) { if (copy($source, $destination)) { // File copied successfully airsrefe_append_log("✅ JS file copied successfully: " . basename($source)); } else { // Log error if copy fails $error_msg = sprintf('Failed to copy JS file: %s to %s', $source, $destination); airsrefe_append_log("❌ " . $error_msg); } } elseif (!file_exists($source)) { // If source file doesn't exist, create it directly in uploads directory $content = ''; switch ($js_file) { case 'js/admin/modal.js': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/js/admin/modal.js'); break; case 'js/admin/feed-management.js': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/js/admin/feed-management.js'); break; case 'js/admin/logs.js': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/js/admin/logs.js'); break; case 'js/admin/prompts.js': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/js/admin/prompts.js'); break; } if ($content && file_put_contents($destination, $content)) { // File created successfully airsrefe_append_log("✅ JS file created successfully: " . basename($destination)); } else { $error_msg = sprintf('Failed to create JS file: %s', $destination); airsrefe_append_log("❌ " . $error_msg); } } } // Verify all assets were created successfully airsrefe_verify_assets_created($assets_dir); } function airsrefe_verify_assets_created($assets_dir) { $required_files = [ 'css/admin/settings.css', 'css/admin/prompts.css', 'js/admin/modal.js', 'js/admin/feed-management.js', 'js/admin/logs.js', 'js/admin/prompts.js', ]; $missing_files = []; foreach ($required_files as $file) { if (!file_exists($assets_dir . '/' . $file)) { $missing_files[] = $file; } } if (!empty($missing_files)) { // Try to create missing files airsrefe_create_missing_assets($assets_dir, $missing_files); } } function airsrefe_create_missing_assets($assets_dir, $missing_files) { foreach ($missing_files as $file) { $destination = $assets_dir . '/' . $file; $content = ''; // Get content based on file type switch ($file) { case 'css/admin/settings.css': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/css/admin/settings.css'); break; case 'css/admin/prompts.css': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/css/admin/prompts.css'); break; case 'js/admin/modal.js': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/js/admin/modal.js'); break; case 'js/admin/feed-management.js': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/js/admin/feed-management.js'); break; case 'js/admin/logs.js': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/js/admin/logs.js'); break; case 'js/admin/prompts.js': $content = file_get_contents(AIRSREFE_PLUGIN_DIR . 'assets/js/admin/prompts.js'); break; } if ($content && file_put_contents($destination, $content)) { $success_msg = sprintf('Created missing asset file: %s', $file); airsrefe_append_log("✅ " . $success_msg); } else { $error_msg = sprintf('Failed to create missing asset file: %s', $file); airsrefe_append_log("❌ " . $error_msg); } } } // Add function to manually recreate assets if needed function airsrefe_recreate_assets() { $upload_dir = wp_upload_dir(); $assets_dir = $upload_dir['basedir'] . '/ai-rss-rewriter/assets'; airsrefe_create_assets(); } // Add function to check if assets exist and recreate if needed function airsrefe_check_assets() { $upload_dir = wp_upload_dir(); $assets_dir = $upload_dir['basedir'] . '/ai-rss-rewriter/assets'; $required_files = [ 'css/admin/settings.css', 'css/admin/prompts.css', 'js/admin/modal.js', 'js/admin/feed-management.js', 'js/admin/logs.js', 'js/admin/prompts.js', ]; $missing_files = []; foreach ($required_files as $file) { if (!file_exists($assets_dir . '/' . $file)) { $missing_files[] = $file; } } if (!empty($missing_files)) { airsrefe_create_missing_assets($assets_dir, $missing_files); return false; } return true; } // Add function to get assets URL function airsrefe_get_assets_url() { return AIRSREFE_PLUGIN_URL . 'assets/'; } // Add function to get assets directory path function airsrefe_get_assets_dir() { return AIRSREFE_PLUGIN_DIR . 'assets/'; } // Add function to ensure assets are created on admin init add_action('admin_init', 'airsrefe_ensure_assets_exist'); function airsrefe_ensure_assets_exist() { // Check if user has admin capabilities if (!current_user_can('manage_options')) { return; } // Use WordPress function to get current screen $screen = get_current_screen(); if ($screen && isset($screen->id) && strpos($screen->id, 'ai-rss-rewriter') !== false) { airsrefe_check_assets(); } } function airsrefe_get_modern_css() { // Return the content of the external CSS file $css_file = plugin_dir_path(__FILE__) . 'assets/admin-modern.css'; if (file_exists($css_file)) { return file_get_contents($css_file); } // Fallback to basic CSS if file doesn't exist return ':root{--primary-color:#20a64f;--primary-dark:#1a8a42;--primary-light:#2db85d;--secondary-color:#f8fafc;--accent-color:#3b82f6;--text-primary:#1f2937;--text-secondary:#6b7280;--text-muted:#9ca3af;--border-color:#e5e7eb;--background:#ffffff;--background-secondary:#f9fafb;--shadow-sm:0 1px 2px 0 rgb(0 0 0 / 0.05);--shadow-md:0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);--shadow-lg:0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);--success-color:#10b981;--warning-color:#f59e0b;--error-color:#ef4444}.ai-rss-rewriter-modern-admin *{box-sizing:border-box}.ai-rss-rewriter-modern-admin{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;background:var(--background-secondary);color:var(--text-primary);line-height:1.6;margin:-20px -20px -10px -2px;min-height:100vh}.admin-container{display:flex;min-height:100vh}.sidebar{width:280px;background:var(--background);border-right:1px solid var(--border-color);box-shadow:var(--shadow-sm);position:fixed;height:100vh;overflow-y:auto;z-index:1000}.sidebar-header{padding:1.5rem;border-bottom:1px solid var(--border-color);background:var(--background)}.logo{display:flex;align-items:center;gap:.75rem;font-size:1.25rem;font-weight:700;color:var(--text-primary)}.logo-icon{width:2rem;height:2rem;background:linear-gradient(135deg,var(--primary-color),var(--primary-light));border-radius:.5rem;display:flex;align-items:center;justify-content:center;color:white;font-weight:bold}.nav-menu{padding:1rem 0}.nav-item{display:block;padding:.75rem 1.5rem;color:var(--text-secondary);text-decoration:none;transition:all .2s ease;border-left:3px solid transparent}.nav-item:hover{background:var(--secondary-color);color:var(--text-primary);border-left-color:var(--primary-color)}.nav-item.active{background:rgba(32,166,79,.1);color:var(--primary-color);border-left-color:var(--primary-color);font-weight:600}.nav-item .nav-icon{margin-right:.75rem;width:1.25rem;display:inline-block}.main-content{flex:1;display:flex;flex-direction:column;margin-left:280px}.header{background:var(--background);border-bottom:1px solid var(--border-color);padding:1rem 2rem;box-shadow:var(--shadow-sm);position:sticky;top:0;z-index:999}.header-content{display:flex;justify-content:space-between;align-items:center}.page-title{font-size:1.875rem;font-weight:700;color:var(--text-primary);margin:0}.header-actions{display:flex;gap:1rem;align-items:center}'; } function airsrefe_get_modern_js() { // Return the content of the external JavaScript file $js_file = plugin_dir_path(__FILE__) . 'assets/admin-modern.js'; if (file_exists($js_file)) { return file_get_contents($js_file); } // Fallback to inline code if file doesn't exist return 'jQuery(document).ready(function($){"use strict";const ArrModern={init:function(){this.bindEvents();this.initializeComponents();this.setupKeyboardShortcuts()},bindEvents:function(){$("#refresh-feeds").on("click",this.refreshFeeds.bind(this));$("#manual-run-all").on("click",this.runAllFeeds.bind(this));$("#bulk-select-all").on("change",this.toggleBulkSelect);$(".feed-checkbox").on("change",this.updateBulkSelection);$("#bulk-form").on("submit",this.handleBulkAction);$(document).on("click",".modal-close",this.closeModal);$(document).on("click",".modal",this.handleModalClick);$("#copy-log").on("click",this.copyLog)}};ArrModern.init();});'; } add_action('plugins_loaded', 'airsrefe_check_version'); function airsrefe_check_version() { $current_version = get_option('airsrefe_version', '0.9'); if (version_compare($current_version, AIRSREFE_VERSION, '<')) { airsrefe_migrate_from_ai_rss(); airsrefe_create_assets(); if (function_exists('airsrefe_init_default_prompts')) { airsrefe_init_default_prompts(); } update_option('airsrefe_version', AIRSREFE_VERSION); } } function airsrefe_migrate_from_ai_rss() { $migrations = [ 'ai_rss_feeds' => 'airsrefe_feeds', 'ai_rss_openai_key' => 'airsrefe_openai_key', 'ai_rss_cron_interval' => 'airsrefe_cron_interval', 'ai_rss_generate_tags' => 'airsrefe_generate_tags', 'ai_rss_image_source' => 'airsrefe_image_source', 'ai_rss_cache_time' => 'airsrefe_cache_time', 'ai_rss_log' => 'airsrefe_log', 'ai_rss_logs' => 'airsrefe_logs' ]; foreach ($migrations as $old => $new) { $value = get_option($old); if ($value !== false) { update_option($new, $value); } } airsrefe_append_log('✅ Migration from AI RSS Rewriter completed'); } function airsrefe_init_default_prompts() { if (get_option('airsrefe_prompts')) return; $prompts = [ 'content_rewrite' => [ 'name' => 'Content Rewriter', 'prompt' => 'Please rewrite this news article to make it completely unique while preserving all key information. IMPORTANT: Format your response EXACTLY as follows: Title: [Write new unique title here] Content: [Write the full rewritten article content here] ===ORIGINAL ARTICLE=== Title: "{title}" Content: {content}', 'type' => 'content', 'created' => current_time('mysql') ], 'title_generator' => [ 'name' => 'Title Generator', 'prompt' => 'Create a compelling, unique headline for this article. Respond only with the title: Original title: "{title}" Article content: "{content}"', 'type' => 'title', 'created' => current_time('mysql') ], 'tags_generator' => [ 'name' => 'Tags Generator', 'prompt' => 'Generate 5-8 relevant tags for this article. Return only the tags separated by commas, in lowercase. Title: {title} Content: {content}', 'type' => 'tags', 'created' => current_time('mysql') ], 'seo_description' => [ 'name' => 'SEO Description', 'prompt' => 'Create a compelling SEO meta description (150-160 characters) for this article: {content}', 'type' => 'seo', 'created' => current_time('mysql') ], 'image_prompt' => [ 'name' => 'Image Generator', 'prompt' => 'Create a modern, eye-catching news illustration for: "{title}". Professional, clean, news website suitable.', 'type' => 'image', 'created' => current_time('mysql') ] ]; update_option('airsrefe_prompts', $prompts); } function airsrefe_cleanup_transients() { $cache_key = 'airsrefe_transients_to_clean'; $transients_to_clean = wp_cache_get($cache_key); if ($transients_to_clean === false) { $all_options = wp_load_alloptions(); $transients_to_clean = []; foreach ($all_options as $option_name => $option_value) { if (strpos($option_name, '_transient_airsrefe_') === 0 || strpos($option_name, '_transient_timeout_airsrefe_') === 0) { $transients_to_clean[] = $option_name; } } wp_cache_set($cache_key, $transients_to_clean, '', 3600); } foreach ($transients_to_clean as $transient_name) { if (strpos($transient_name, '_transient_timeout_') === 0) { continue; } if (strpos($transient_name, '_transient_') === 0) { $transient_key = str_replace('_transient_', '', $transient_name); delete_transient($transient_key); } } wp_cache_delete($cache_key); } function airsrefe_log_activation() { $features = [ 'GD' => extension_loaded('gd') ? 'Yes' : 'No', 'WebP' => function_exists('imagewebp') ? 'Yes' : 'No' ]; airsrefe_append_log("🚀 AI RSS Rewriter activated (GD: {$features['GD']}, WebP: {$features['WebP']})"); } add_filter('plugin_action_links_' . plugin_basename(__FILE__), function($links) { array_unshift($links, 'Settings'); return $links; }); add_filter('plugin_row_meta', function($links, $file) { if ($file === plugin_basename(__FILE__)) { $links[] = 'Logs'; $links[] = 'Statistics'; } return $links; }, 10, 2); register_deactivation_hook(__FILE__, function() { wp_clear_scheduled_hook('airsrefe_auto_parse_event'); airsrefe_append_log('⛔ Plugin deactivated. All scheduled tasks cleared'); }); add_action('admin_init', function() { airsrefe_create_assets(); }); add_action('rest_api_init', function() { register_rest_route('airsrefe/v1', '/feeds', [ 'methods' => 'GET', 'callback' => function() { return new WP_REST_Response(get_option('airsrefe_feeds', []), 200); }, 'permission_callback' => function() { return current_user_can('manage_options'); } ]); register_rest_route('airsrefe/v1', '/stats', [ 'methods' => 'GET', 'callback' => function() { return airsrefe_get_stats_data(); }, 'permission_callback' => function() { return current_user_can('manage_options'); } ]); }); function airsrefe_get_stats_data() { $cache_key = 'airsrefe_stats_data'; $cached_stats = wp_cache_get($cache_key); if ($cached_stats !== false) { return new WP_REST_Response($cached_stats, 200); } $stats = []; $today_date = current_time('Y-m-d'); // Use optimized helper functions $stats['posts_today'] = airsrefe_get_processed_posts_count($today_date); // Get 30-day count using optimized approach $month_cache_key = 'airsrefe_posts_30d_' . wp_date('Y-m-d'); $posts_30d = wp_cache_get($month_cache_key); if ($posts_30d === false) { $month_posts = airsrefe_get_processed_posts([ 'date_query' => [ [ 'after' => '30 days ago', ] ] ]); $posts_30d = count($month_posts); // Cache for 30 minutes wp_cache_set($month_cache_key, $posts_30d, '', 1800); } $stats['posts_30d'] = (int) $posts_30d; $feeds = get_option('airsrefe_feeds', []); $stats['total_feeds'] = count($feeds); $stats['active_feeds'] = count(array_filter($feeds, function($feed) { return !isset($feed['enabled']) || $feed['enabled']; })); $logs = get_option('airsrefe_logs', []); $successful = count(array_filter($logs, function($log) { return $log['success'] ?? false; })); $stats['success_rate'] = count($logs) > 0 ? round(($successful / count($logs)) * 100) : 0; $daily_costs = get_option('airsrefe_daily_costs', []); $stats['today_cost'] = $daily_costs[$today_date] ?? 0.00; $stats['budget_limit'] = get_option('airsrefe_daily_budget_limit', 10.00); // Cache for 5 minutes wp_cache_set($cache_key, $stats, '', 300); return new WP_REST_Response($stats, 200); } add_action('wp_head', function() { if (is_single() && get_post_meta(get_the_ID(), '_ai-rss-rewriter_processed_date', true)) { echo '' . "\n"; } }); add_action('wp_ajax_airsrefe_get_stats', 'airsrefe_ajax_get_stats'); function airsrefe_ajax_get_stats() { if (!current_user_can('manage_options')) { wp_die(-1); } $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : ''; if (!wp_verify_nonce($nonce, 'airsrefe_ajax')) { wp_die(-1); } $stats_response = airsrefe_get_stats_data(); wp_send_json_success($stats_response->get_data()); } add_action('admin_head', function() { $current_page = ''; if (isset($_GET['page'])) { $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : ''; if (wp_verify_nonce($nonce, 'airsrefe_admin_page')) { $current_page = sanitize_text_field(wp_unslash($_GET['page'])); } } if ($current_page === 'ai-rss-rewriter') { echo '