'Unauthorized' ) ); } $test_key = sanitize_text_field( wp_unslash( $_POST['api_key'] ?? '' ) ); $test_model = sanitize_text_field( wp_unslash( $_POST['model'] ?? '' ) ); $is_connector_connected = self::is_wp_ai_connector_connected(); if ( $test_model === 'auto_wp_ai' ) { if ( ! $is_connector_connected ) { wp_send_json_error( array( 'message' => 'WordPress AI Connector has no active provider connected. Please install/connect a provider under Settings > Connectors, or select a direct AI model from the dropdown.', ) ); } $test_key = 'wp_ai_core'; } if ( empty( $test_key ) ) { $saved_settings = get_option( 'metaforge_ai_settings', array() ); if ( ! empty( $saved_settings['api_key'] ) ) { $test_key = $saved_settings['api_key']; } elseif ( $is_connector_connected ) { $test_key = 'wp_ai_core'; } else { wp_send_json_error( array( 'message' => 'Please enter an API key to test, or connect an AI provider under Settings > Connectors.' ) ); } } $clean_test_key = class_exists( 'MetaForge_APIClient' ) ? MetaForge_APIClient::decrypt_key( $test_key ) : $test_key; $trimmed_key = trim( $clean_test_key ); $model_lower = strtolower( $test_model ); // Only validate key prefixes if not testing through WordPress Core AI Client if ( $clean_test_key !== 'wp_ai_core' ) { if ( strpos( $trimmed_key, 'gsk_' ) === 0 && strpos( $model_lower, 'llama' ) === false && strpos( $model_lower, 'distill' ) === false && strpos( $model_lower, 'qwen' ) === false && strpos( $model_lower, 'gpt-oss' ) === false && strpos( $model_lower, 'groq' ) === false ) { wp_send_json_error( array( 'message' => 'This key starts with "gsk_", which is a Groq API key. Please select a Groq model from the dropdown.' ) ); } if ( ( strpos( $trimmed_key, 'AIzaSy' ) === 0 || strpos( $trimmed_key, 'AQ.' ) === 0 ) && strpos( $model_lower, 'gemini' ) === false ) { wp_send_json_error( array( 'message' => 'This key is a Google Gemini API key. Please select a Google Gemini model from the dropdown.' ) ); } if ( strpos( $trimmed_key, 'sk-ant-' ) === 0 && strpos( $model_lower, 'claude' ) === false ) { wp_send_json_error( array( 'message' => 'This key starts with "sk-ant-", which is an Anthropic Claude API key. Please select a Claude model from the dropdown.' ) ); } if ( strpos( $trimmed_key, 'sk-or-v1-' ) === 0 && strpos( $model_lower, 'openrouter' ) === false ) { wp_send_json_error( array( 'message' => 'This key starts with "sk-or-v1-", which is an OpenRouter key. Please select OpenRouter from the dropdown.' ) ); } if ( strpos( $trimmed_key, 'sk-proj-' ) === 0 && strpos( $model_lower, 'gpt' ) === false && strpos( $model_lower, 'o1' ) === false && strpos( $model_lower, 'o3' ) === false ) { wp_send_json_error( array( 'message' => 'This key starts with "sk-proj-", which is an OpenAI key. Please select an OpenAI model (e.g. GPT-4o Mini) from the dropdown.' ) ); } } // Temporarily override the saved options so the client uses the unsaved ones $filter_key = ( $clean_test_key === 'wp_ai_core' ) ? '' : $clean_test_key; add_filter( 'pre_option_metaforge_ai_settings', function () use ( $filter_key, $test_model ) { return array( 'api_key' => $filter_key, 'model' => $test_model, ); } ); // This is a dry run with minimal tokens $client = new MetaForge_APIClient(); $system = "You are a test script. Respond with exactly 'OK'."; $user = 'Test connection.'; $response = $client->generate( $system, $user, false ); if ( is_wp_error( $response ) ) { $error_data = $response->get_error_data(); $retry = isset( $error_data['retry_after'] ) ? intval( $error_data['retry_after'] ) : 0; wp_send_json_error( array( 'message' => $response->get_error_message(), 'code' => $response->get_error_code(), 'retry_after' => $retry, ) ); } wp_send_json_success( array( 'message' => 'Connection successful! Engine is ready.' ) ); } public function admin_menu() { add_submenu_page( 'metaforge', 'AI Settings', 'AI Settings', 'manage_metaforge', 'metaforge_ai_settings', array( $this, 'admin_page' ) ); } public function register_settings() { register_setting( 'metaforge_ai_settings_group', 'metaforge_ai_settings', array( $this, 'sanitize_settings' ) ); } public function sanitize_settings( $input ) { $sanitized = array(); $model = isset( $input['model'] ) ? sanitize_text_field( $input['model'] ) : 'gemini-2.0-flash'; $sanitized['model'] = $model; if ( isset( $input['api_key'] ) ) { $raw_key = sanitize_text_field( $input['api_key'] ); $sanitized['api_key'] = ! empty( $raw_key ) && class_exists( 'MetaForge_APIClient' ) ? MetaForge_APIClient::encrypt_key( $raw_key ) : $raw_key; } else { $sanitized['api_key'] = ''; } $sanitized['detect_layout'] = isset( $input['detect_layout'] ) ? '1' : '0'; $sanitized['generate_schema'] = isset( $input['generate_schema'] ) ? '1' : '0'; $sanitized['fallback_ai'] = isset( $input['fallback_ai'] ) ? '1' : '0'; return $sanitized; } public function admin_page() { if ( ! current_user_can( 'manage_metaforge' ) ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only notice query flag. if ( isset( $_GET['settings-updated'] ) && sanitize_text_field( wp_unslash( $_GET['settings-updated'] ) ) ) { add_settings_error( 'metaforge_ai_messages', 'metaforge_ai_message', 'Settings Saved Successfully', 'updated' ); } $options = get_option( 'metaforge_ai_settings', array( 'api_key' => '', 'model' => 'gemini-3.5-flash-lite', 'detect_layout' => '0', 'generate_schema' => '0', 'fallback_ai' => '0', ) ); ?>
Documentation'; MetaForge_AdminHeader::render_sub_header( 'AI Settings', '', $docs_link ); ?>

' . esc_html( $error['message'] ) . '

'; } if ( ! defined( 'AUTH_KEY' ) ) { echo '

🔒 Security Recommendation: AUTH_KEY is not explicitly set in wp-config.php. Define a unique AUTH_KEY or MetaForge_AI_API_KEY in wp-config.php for maximum API key encryption security.

'; } ?>
AI Provider API Configuration
WordPress Core AI Client Active (WordPress 7.0+)
Your site supports centralized AI providers via Settings > Connectors. If using centralized AI, ensure MetaForge is approved under Settings > Connectors (click "Edit" on your connected provider and enable the checkbox for MetaForge Engine). Direct API keys below are also fully supported as direct integrations.
Provider API Key

Connectors. When no direct API key is entered, MetaForge automatically uses your connected AI provider.', 'metaforge-engine' ); ?> Connectors →', 'metaforge-engine' ); ?>

placeholder="" />
API Key Configured

Your API key is stored securely using AES-256-CBC encryption in the database.
WordPress AI Client: Centrally managed under Settings > Connectors.
DeepSeek: Get your key at platform.deepseek.com
Google Gemini: Get a free API key at aistudio.google.com
Groq (Fast / Free Llama 3): Get a free tier key at console.groq.com
OpenAI: Get an API key at platform.openai.com
Anthropic (Claude): Get a key at console.anthropic.com
OpenRouter: Universal gateway key at openrouter.ai

AI Model Selection

Select the target AI model. Ensure your API Key corresponds to your chosen provider key.

Feature Toggles
Smart Layout Detection
Schema Generation
Fallback AI Generation