'array', 'sanitize_callback' => array($this, 'sanitize_api_settings'), 'default' => array(), ) ); } /** * Clean and sanitize incoming API engine settings array. */ public function sanitize_api_settings($input) { $sanitized = array(); if (isset($input['active_provider'])) { $sanitized['active_provider'] = sanitize_key($input['active_provider']); } if (isset($input['microsoft_region'])) { $sanitized['microsoft_region'] = sanitize_text_field($input['microsoft_region']); } $prompt_keys = array('openai_custom_prompt', 'anthropic_custom_prompt', 'grok_custom_prompt', 'gemini_custom_prompt'); foreach ($prompt_keys as $key) { if (isset($input[$key])) { $sanitized[$key] = sanitize_textarea_field($input[$key]); } } $key_fields = array('deepl_key', 'google_key', 'lecto_key', 'microsoft_key', 'openai_key', 'anthropic_key', 'grok_key', 'gemini_key', 'openai_model', 'anthropic_model', 'grok_model', 'gemini_model'); foreach ($key_fields as $field) { if (isset($input[$field])) { $sanitized[$field] = sanitize_text_field(trim($input[$field])); } } return $sanitized; } /** * Registers structural parent node space alongside synchronized submenus. * Re-ordered based on user priority and simplified for intermediate clarity. */ public function register_admin_workspace() { $capability = 'manage_options'; // Main Parent Menu Node add_menu_page( esc_html__('AF Translate – AI Automated Translation Studio for WordPress', 'af-translate'), esc_html__('AF Translate', 'af-translate'), $capability, 'af-translate', array($this, 'render_workspace_router'), 'dashicons-translation', 65 ); // 1. Dashboard (The central hub, matches parent slug to avoid duplicates) add_submenu_page( 'af-translate', esc_html__('AF Translate Dashboard', 'af-translate'), esc_html__('Dashboard', 'af-translate'), $capability, 'af-translate', array($this, 'render_workspace_router') ); // 2. Translate Plugins (Highest priority search intent) add_submenu_page( 'af-translate', esc_html__('Translate Installed Plugins', 'af-translate'), esc_html__('Translate Plugins', 'af-translate'), $capability, 'af-translate-plugins', array($this, 'render_workspace_router') ); // 3. Translate Themes (Second highest priority search intent) add_submenu_page( 'af-translate', esc_html__('Translate Installed Themes', 'af-translate'), esc_html__('Translate Themes', 'af-translate'), $capability, 'af-translate-themes', array($this, 'render_workspace_router') ); // 4. Translate WordPress Core (Lower frequency utility task) add_submenu_page( 'af-translate', esc_html__('Translate WordPress Core System', 'af-translate'), esc_html__('WordPress Core', 'af-translate'), $capability, 'af-translate-core', array($this, 'render_workspace_router') ); // 5. Site Languages (Informational configuration screen) add_submenu_page( 'af-translate', esc_html__('Manage Localized Site Languages', 'af-translate'), esc_html__('Site Languages', 'af-translate'), $capability, 'af-translate-languages', array($this, 'render_workspace_router') ); // 6. AI Settings (Setup/Configuration - standard placement at the bottom) add_submenu_page( 'af-translate', esc_html__('AI Engine Settings & API Keys', 'af-translate'), esc_html__('AI Settings', 'af-translate'), $capability, 'af-translate-ai-connecter', array($this, 'render_workspace_router') ); } /** * Register and Enqueue Dashboard Assets * Fully synchronized with chunked UI pagination constraints. * * @param string $hook The current admin page hook suffix. */ public function af_translate_enqueue_bulk_engine_assets($hook) { if (false === strpos($hook, 'af-translate')) { return; } $settings = get_option('af_translate_api_settings', array()); $default_provider = isset($settings['active_provider']) ? sanitize_key($settings['active_provider']) : 'none'; $engine_manifest = array( 'deepl' => __('DeepL Pro / Free Translator', 'af-translate'), 'google' => __('Google Translate Cloud v2 API', 'af-translate'), 'lecto' => __('Lecto AI Translation Engine', 'af-translate'), 'microsoft' => __('Microsoft Cognitive Translator v3', 'af-translate'), 'openai' => __('OpenAI Core Engines (GPT-4o / Mini)', 'af-translate'), 'anthropic' => __('Anthropic LLM Array (Claude 3.5 Sonnet)', 'af-translate'), 'grok' => __('xAI Enterprise Core (Grok 4)', 'af-translate'), 'gemini' => __('Google Gemini Flash / Pro Multimodal', 'af-translate'), ); $available_providers = array(); foreach ($engine_manifest as $slug => $label) { $key_field = ('microsoft' === $slug) ? 'microsoft_key' : $slug . '_key'; if (! empty($settings[$key_field])) { $available_providers[] = array( 'slug' => $slug, 'label' => $label ); } } // Prepare the baseline configuration array for Free version $bulk_settings = array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('af_translate_secure_action'), 'available_providers' => $available_providers, 'default_provider' => $default_provider, 'settings_url' => admin_url('admin.php?page=af-translate-ai-connecter'), 'strings' => array( 'cancel' => __('Cancel', 'af-translate'), 'run_batch' => __('Execute Run', 'af-translate'), 'initiating' => __('Analyzing translation matrix blocks...', 'af-translate'), 'processing' => __('Translating chunk packages via AI engine...', 'af-translate'), 'select_engine' => __('Select AI Provider', 'af-translate'), 'preview_loaded' => __('Bulk Translation Preview Loaded!', 'af-translate'), 'configure_title' => __('Configure AI Bulk Engine Run', 'af-translate'), 'filter_constraints' => __('Target Filter Constraints', 'af-translate'), 'translate_empty' => __('Translate Empty Tracks Only (Recommended)', 'af-translate'), 'translate_all' => __('Translate All Strings (Overwrite Existing)', 'af-translate'), 'no_keys_title' => __('AI API Keys Required', 'af-translate'), 'no_keys_desc' => __('No active AI translation engines were found. Please configure your API keys in the setup dashboard to unlock bulk translations.', 'af-translate'), 'go_to_setup' => __('Go to AI Setup', 'af-translate'), 'configure_btn' => __('Configure API Keys', 'af-translate'), 'consulting_ai' => __('Consulting AI models...', 'af-translate'), ) ); /** * EXTENSIBILITY BRIDGE HOOK * Allows the Pro version to intercept the configurations and inject calculation trees or toggle enable_preflight. */ $bulk_settings = apply_filters('af_translate_bulk_settings', $bulk_settings); wp_enqueue_script( 'af-translate-bulk-engine', AF_TRANSLATE_URL . 'assets/js/ai-translate-bulk.js', array('jquery'), AF_TRANSLATE_VERSION, true ); wp_localize_script('af-translate-bulk-engine', 'afTranslateBulkSettings', $bulk_settings); wp_enqueue_script( 'af-translate-workbench-engine', AF_TRANSLATE_URL . 'assets/js/ai-translate-workbench.js', array('jquery', 'af-translate-bulk-engine'), AF_TRANSLATE_VERSION, true ); } /** * Directs administrative action requests and maps layout states. */ public function render_workspace_router() { if (! current_user_can('manage_options')) { wp_die(esc_html__('Security Exception: You do not have sufficient permissions to access this page.', 'af-translate')); } // phpcs:ignore WordPress.Security.NonceVerification.Recommended $current_page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : 'af-translate'; $tab = 'overview'; if ('af-translate-plugins' === $current_page) { $tab = 'plugins'; } elseif ('af-translate-themes' === $current_page) { $tab = 'themes'; } elseif ('af-translate-core' === $current_page) { $tab = 'wordpress'; } elseif ('af-translate-languages' === $current_page) { $tab = 'languages'; } elseif ('af-translate-ai-connecter' === $current_page) { $tab = 'settings'; } else { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $tab = isset($_GET['tab']) ? sanitize_key(wp_unslash($_GET['tab'])) : 'overview'; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended $view = isset($_GET['view']) ? sanitize_key(wp_unslash($_GET['view'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $type = isset($_GET['type']) ? sanitize_key(wp_unslash($_GET['type'])) : 'theme'; echo '
%s %s