__('Security check failed.', 'botwriter'))); } // Verify permissions if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => __('Permission denied.', 'botwriter'))); } $provider = isset($_POST['provider']) ? sanitize_text_field(wp_unslash($_POST['provider'])) : ''; $api_key = isset($_POST['api_key']) ? sanitize_text_field(wp_unslash($_POST['api_key'])) : ''; if (empty($provider)) { wp_send_json_error(array('message' => __('No provider specified.', 'botwriter'))); } if (empty($api_key)) { wp_send_json_error(array('message' => __('Please enter an API key first.', 'botwriter'))); } // Provider endpoints for testing (using /models which is free and doesn't consume tokens) $providers_config = array( // Text providers 'openai' => array( 'url' => 'https://api.openai.com/v1/models', 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, ), ), 'anthropic' => array( 'url' => 'https://api.anthropic.com/v1/models', 'headers' => array( 'x-api-key' => $api_key, 'anthropic-version' => '2023-06-01', ), ), 'google' => array( 'url' => 'https://generativelanguage.googleapis.com/v1beta/models?key=' . $api_key, 'headers' => array(), ), 'mistral' => array( 'url' => 'https://api.mistral.ai/v1/models', 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, ), ), 'groq' => array( 'url' => 'https://api.groq.com/openai/v1/models', 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, ), ), 'openrouter' => array( 'url' => 'https://openrouter.ai/api/v1/models', 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, ), ), // Image providers 'dalle' => array( 'url' => 'https://api.openai.com/v1/models', 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, ), ), 'fal' => array( 'url' => 'https://api.fal.ai/v1/models', 'headers' => array( 'Authorization' => 'Key ' . $api_key, ), ), 'replicate' => array( 'url' => 'https://api.replicate.com/v1/account', 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, ), ), 'stability' => array( 'url' => 'https://api.stability.ai/v1/user/account', 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, ), ), 'cloudflare' => array( 'url' => 'https://api.cloudflare.com/client/v4/user/tokens/verify', 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, ), ), // Gemini image uses Google text provider API key 'gemini' => array( 'url' => 'https://generativelanguage.googleapis.com/v1beta/models?key=' . $api_key, 'headers' => array(), ), ); if (!isset($providers_config[$provider])) { wp_send_json_error(array('message' => __('Unknown provider.', 'botwriter'))); } $config = $providers_config[$provider]; $ssl_verify = get_option('botwriter_sslverify', 'yes') === 'yes'; $response = wp_remote_get($config['url'], array( 'timeout' => 15, 'sslverify' => $ssl_verify, 'headers' => $config['headers'], )); if (is_wp_error($response)) { wp_send_json_error(array( 'message' => sprintf( /* translators: %s: Error message from the API */ __('Connection error: %s', 'botwriter'), $response->get_error_message() ), )); } $code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); // Check for success (200 OK) if ($code === 200) { // Extract models list $models = array(); $models_data = array(); if (isset($data['data']) && is_array($data['data'])) { $models_data = $data['data']; } elseif (isset($data['models']) && is_array($data['models'])) { $models_data = $data['models']; } // Build models array with id and name foreach ($models_data as $model) { $model_id = ''; $model_name = ''; // Different providers have different response structures if (isset($model['id'])) { $model_id = $model['id']; $model_name = isset($model['name']) ? $model['name'] : $model['id']; } elseif (isset($model['name'])) { $model_id = $model['name']; $model_name = isset($model['displayName']) ? $model['displayName'] : (isset($model['display_name']) ? $model['display_name'] : $model['name']); } // Google Gemini returns model names with "models/" prefix - remove it if (strpos($model_id, 'models/') === 0) { $model_id = substr($model_id, 7); // Remove "models/" prefix } if (strpos($model_name, 'models/') === 0) { $model_name = substr($model_name, 7); } // Filter OpenAI models: exclude non-text models if ($provider === 'openai') { $exclude_patterns = array('dall-e', 'whisper', 'tts', 'embedding', 'moderation'); $should_exclude = false; foreach ($exclude_patterns as $pattern) { if (stripos($model_id, $pattern) !== false) { $should_exclude = true; break; } } if ($should_exclude) { continue; } } // Filter Google models: only those supporting generateContent if ($provider === 'google') { $supported_methods = isset($model['supportedGenerationMethods']) ? $model['supportedGenerationMethods'] : array(); if (!in_array('generateContent', $supported_methods)) { continue; } } if (!empty($model_id)) { $models[] = array( 'id' => $model_id, 'name' => $model_name, ); } } // Sort models alphabetically by id usort($models, function($a, $b) { return strcasecmp($a['id'], $b['id']); }); $model_count = count($models); // Save models to database using our models manager if ($model_count > 0) { botwriter_update_provider_all_models($provider, $models); } $message = __('API key is valid!', 'botwriter'); if ($model_count > 0) { $message .= ' ' . sprintf( /* translators: %d: Number of models available */ _n('%d model available.', '%d models available.', $model_count, 'botwriter'), $model_count ); } wp_send_json_success(array( 'message' => $message, 'models' => $models, 'provider' => $provider, )); } // Handle error responses $error_message = __('Invalid API key.', 'botwriter'); if ($code === 401 || $code === 403) { $error_message = __('Invalid or unauthorized API key.', 'botwriter'); } elseif ($code === 429) { $error_message = __('Rate limit exceeded. Please try again later.', 'botwriter'); } elseif ($code === 500 || $code === 502 || $code === 503) { $error_message = __('Provider service temporarily unavailable.', 'botwriter'); } // Try to get error message from response if (isset($data['error']['message'])) { $error_message = sanitize_text_field($data['error']['message']); } elseif (isset($data['message'])) { $error_message = sanitize_text_field($data['message']); } wp_send_json_error(array('message' => $error_message)); } /** * AJAX handler to test model connectivity * Sends a minimal prompt to verify the model works */ function botwriter_ajax_test_model() { // Verify nonce if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'botwriter_settings_nonce')) { wp_send_json_error(array('message' => __('Security check failed.', 'botwriter'))); } // Verify permissions if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => __('Permission denied.', 'botwriter'))); } $provider = isset($_POST['provider']) ? sanitize_text_field(wp_unslash($_POST['provider'])) : ''; $model = isset($_POST['model']) ? sanitize_text_field(wp_unslash($_POST['model'])) : ''; if (empty($provider)) { wp_send_json_error(array('message' => __('No provider specified.', 'botwriter'))); } if (empty($model)) { wp_send_json_error(array('message' => __('No model specified.', 'botwriter'))); } // Get API key for provider $api_key_option = 'botwriter_' . $provider . '_api_key'; $api_key = botwriter_decrypt_api_key(get_option($api_key_option)); if (empty($api_key)) { wp_send_json_error(array('message' => __('Please configure the API key first.', 'botwriter'))); } $ssl_verify = get_option('botwriter_sslverify', 'yes') === 'yes'; $test_message = 'Say "Ready!" in one word.'; // Provider-specific API calls switch ($provider) { case 'openai': // GPT-5 and GPT-4.1 models require max_completion_tokens instead of max_tokens $is_new_model = preg_match('/^(gpt-5|gpt-4\.1|o\d)/i', $model); $token_param = $is_new_model ? 'max_completion_tokens' : 'max_tokens'; $response = wp_remote_post('https://api.openai.com/v1/chat/completions', array( 'timeout' => 30, 'sslverify' => $ssl_verify, 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ), 'body' => wp_json_encode(array( 'model' => $model, 'messages' => array( array('role' => 'user', 'content' => $test_message) ), $token_param => 10, )), )); break; case 'anthropic': $response = wp_remote_post('https://api.anthropic.com/v1/messages', array( 'timeout' => 30, 'sslverify' => $ssl_verify, 'headers' => array( 'x-api-key' => $api_key, 'anthropic-version' => '2023-06-01', 'Content-Type' => 'application/json', ), 'body' => wp_json_encode(array( 'model' => $model, 'max_tokens' => 10, 'messages' => array( array('role' => 'user', 'content' => $test_message) ), )), )); break; case 'google': $url = 'https://generativelanguage.googleapis.com/v1beta/models/' . $model . ':generateContent?key=' . $api_key; $response = wp_remote_post($url, array( 'timeout' => 30, 'sslverify' => $ssl_verify, 'headers' => array( 'Content-Type' => 'application/json', ), 'body' => wp_json_encode(array( 'contents' => array( array( 'parts' => array( array('text' => $test_message) ) ) ), 'generationConfig' => array( 'maxOutputTokens' => 10, ), )), )); break; case 'mistral': $response = wp_remote_post('https://api.mistral.ai/v1/chat/completions', array( 'timeout' => 30, 'sslverify' => $ssl_verify, 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ), 'body' => wp_json_encode(array( 'model' => $model, 'messages' => array( array('role' => 'user', 'content' => $test_message) ), 'max_tokens' => 10, )), )); break; case 'groq': $response = wp_remote_post('https://api.groq.com/openai/v1/chat/completions', array( 'timeout' => 30, 'sslverify' => $ssl_verify, 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ), 'body' => wp_json_encode(array( 'model' => $model, 'messages' => array( array('role' => 'user', 'content' => $test_message) ), 'max_tokens' => 10, )), )); break; case 'openrouter': $response = wp_remote_post('https://openrouter.ai/api/v1/chat/completions', array( 'timeout' => 30, 'sslverify' => $ssl_verify, 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', 'HTTP-Referer' => home_url(), 'X-Title' => 'BotWriter', ), 'body' => wp_json_encode(array( 'model' => $model, 'messages' => array( array('role' => 'user', 'content' => $test_message) ), 'max_tokens' => 10, )), )); break; default: wp_send_json_error(array('message' => __('Unknown provider.', 'botwriter'))); return; } if (is_wp_error($response)) { wp_send_json_error(array( 'message' => sprintf( /* translators: %s: Error message */ __('Connection error: %s', 'botwriter'), $response->get_error_message() ), )); } $code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); // Extract response text based on provider $reply = ''; if ($code === 200) { switch ($provider) { case 'openai': case 'mistral': case 'groq': case 'openrouter': $reply = $data['choices'][0]['message']['content'] ?? ''; break; case 'anthropic': $reply = $data['content'][0]['text'] ?? ''; break; case 'google': $reply = $data['candidates'][0]['content']['parts'][0]['text'] ?? ''; break; } if (!empty($reply)) { wp_send_json_success(array( 'message' => sprintf( /* translators: %s: Model response */ __('Model responded: "%s"', 'botwriter'), esc_html(trim($reply)) ), )); } else { wp_send_json_success(array('message' => __('Model is working!', 'botwriter'))); } } // Handle error responses $error_message = __('Model test failed.', 'botwriter'); if ($code === 401 || $code === 403) { $error_message = __('Invalid or unauthorized API key.', 'botwriter'); } elseif ($code === 404) { $error_message = __('Model not found. It may not be available for your account.', 'botwriter'); } elseif ($code === 429) { $error_message = __('Rate limit exceeded. Please try again later.', 'botwriter'); } elseif ($code === 500 || $code === 502 || $code === 503) { $error_message = __('Provider service temporarily unavailable.', 'botwriter'); } // Try to get error message from response if (isset($data['error']['message'])) { $error_message = sanitize_text_field($data['error']['message']); } elseif (isset($data['message'])) { $error_message = sanitize_text_field($data['message']); } wp_send_json_error(array('message' => $error_message)); } /** * AJAX handler to reset models to default */ function botwriter_ajax_reset_models() { // Verify nonce if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'botwriter_settings_nonce')) { wp_send_json_error(array('message' => __('Security check failed.', 'botwriter'))); } // Verify permissions if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => __('Permission denied.', 'botwriter'))); } // Reset models to default if (botwriter_reset_models_to_default()) { wp_send_json_success(array( 'message' => __('Models reset to defaults successfully!', 'botwriter'), )); } else { wp_send_json_error(array( 'message' => __('Failed to reset models. Please try again.', 'botwriter'), )); } } /** * AJAX handler to save individual settings */ function botwriter_ajax_save_settings() { // Verify nonce if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'botwriter_settings_nonce')) { wp_send_json_error(['message' => __('Security check failed.', 'botwriter')]); } // Verify permissions if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('Permission denied.', 'botwriter')]); } $field = isset($_POST['field']) ? sanitize_text_field(wp_unslash($_POST['field'])) : ''; $value = isset($_POST['value']) ? wp_unslash($_POST['value']) : ''; if (empty($field)) { wp_send_json_error(['message' => __('No field specified.', 'botwriter')]); } // List of allowed fields $allowed_fields = [ 'botwriter_text_provider', 'botwriter_image_provider', 'botwriter_openai_api_key', 'botwriter_anthropic_api_key', 'botwriter_google_api_key', 'botwriter_mistral_api_key', 'botwriter_groq_api_key', 'botwriter_openrouter_api_key', 'botwriter_fal_api_key', 'botwriter_replicate_api_key', 'botwriter_stability_api_key', 'botwriter_cloudflare_api_key', 'botwriter_cloudflare_account_id', 'botwriter_openai_model', 'botwriter_anthropic_model', 'botwriter_google_model', 'botwriter_mistral_model', 'botwriter_groq_model', 'botwriter_openrouter_model', 'botwriter_dalle_model', 'botwriter_gemini_image_model', 'botwriter_fal_model', 'botwriter_replicate_model', 'botwriter_stability_model', 'botwriter_cloudflare_model', 'botwriter_ai_image_size', 'botwriter_ai_image_quality', 'botwriter_ai_image_style', 'botwriter_ai_image_style_custom', 'botwriter_image_postprocess_enabled', 'botwriter_image_output_format', 'botwriter_image_max_width', 'botwriter_image_compression', 'botwriter_image_max_filesize', 'botwriter_sslverify', 'botwriter_cron_active', 'botwriter_paused_tasks', 'botwriter_tags_disabled', 'botwriter_meta_disabled', 'botwriter_image_error_continue', // SEO Translation fields 'botwriter_seo_translation_enabled', 'botwriter_seo_target_language', 'botwriter_seo_translate_title', 'botwriter_seo_translate_tags', 'botwriter_seo_translate_image', // Stock photo fields 'botwriter_stockphoto_preferred', 'botwriter_stockphoto_selection', 'botwriter_stockphoto_attribution', ]; if (!in_array($field, $allowed_fields)) { wp_send_json_error(['message' => __('Invalid field.', 'botwriter')]); } // API key fields that need encryption $api_key_fields = [ 'botwriter_openai_api_key', 'botwriter_anthropic_api_key', 'botwriter_google_api_key', 'botwriter_mistral_api_key', 'botwriter_groq_api_key', 'botwriter_openrouter_api_key', 'botwriter_fal_api_key', 'botwriter_replicate_api_key', 'botwriter_stability_api_key', 'botwriter_cloudflare_api_key', ]; if (in_array($field, $api_key_fields)) { $value = sanitize_text_field($value); if (!empty($value)) { // Special validation for OpenAI key if ($field === 'botwriter_openai_api_key') { if (strpos($value, 'sk-') !== 0) { wp_send_json_error(['message' => __('OpenAI API Key must start with "sk-".', 'botwriter')]); } } $value = botwriter_encrypt_api_key_generic($value); } } elseif ($field === 'botwriter_paused_tasks') { $value = max(2, intval($value)); } elseif ($field === 'botwriter_cron_active' || $field === 'botwriter_tags_disabled' || $field === 'botwriter_meta_disabled' || $field === 'botwriter_seo_translation_enabled' || $field === 'botwriter_seo_translate_title' || $field === 'botwriter_seo_translate_tags' || $field === 'botwriter_seo_translate_image') { $value = ($value === '1' || $value === 'true' || $value === true) ? '1' : '0'; } else { $value = sanitize_text_field($value); } // Save the option update_option($field, $value); // Handle cron activation/deactivation if ($field === 'botwriter_cron_active') { if ($value === '1') { botwriter_scheduled_events_plugin_activate(); } else { botwriter_scheduled_events_plugin_deactivate(); } } wp_send_json_success(['message' => __('Saved', 'botwriter'), 'field' => $field]); } /** * Main settings page handler */ function botwriter_settings_page_handler() { // Verify permissions if (!current_user_can('manage_options')) { wp_die(esc_html__('You do not have permission to access this page.', 'botwriter')); } // Add metabox add_meta_box( 'botwriter_settings', __('WP BotWriter Settings', 'botwriter'), 'botwriter_settings_meta_box_handler', 'botwriter_settings_page', 'normal', 'default' ); ?>

'OpenAI (GPT-5, GPT-4o)', 'anthropic' => 'Anthropic (Claude)', 'google' => 'Google (Gemini) - FREE TIER', 'mistral' => 'Mistral AI - FREE TIER', 'groq' => 'Groq (Ultra Fast) - FREE TIER', 'openrouter' => 'OpenRouter (Multiple) - FREE TIER', ]; $image_providers = [ 'dalle' => 'DALL-E (OpenAI)', 'gemini' => 'Google Gemini', 'fal' => 'Fal.ai (Flux)', 'replicate' => 'Replicate', 'stability' => 'Stability AI', 'cloudflare' => 'Cloudflare AI (FREE)', 'stockphoto' => '📷 [FREE] Stock Images', 'none' => '🚫 No Image Generation', ]; ?>

$name): $is_active = ($id === $text_provider); $render_func = 'botwriter_render_' . $id . '_settings'; ?>
' . esc_html__('Provider configuration not available.', 'botwriter') . '

'; } ?>

$name): $is_active = ($id === $image_provider); $render_func = 'botwriter_render_' . $id . '_settings'; ?>
' . esc_html__('Provider configuration not available.', 'botwriter') . '

'; } ?>

16:9

DALL-E1792×1024
Fal.ai/Flux1344×768
Stability AI1344×768
Replicate1344×768

DALL-Estandard
Fal.ai20 steps
Stability AIsd3-large
Replicate25 steps
">

%

DALL-E $0.04 - $0.08
Fal.ai $0.03 - $0.05
Stability $0.02 - $0.04
Replicate $0.003 - $0.05

'English', 'es' => 'Spanish (Español)', 'fr' => 'French (Français)', 'de' => 'German (Deutsch)', 'it' => 'Italian (Italiano)', 'pt' => 'Portuguese (Português)', 'nl' => 'Dutch (Nederlands)', 'ru' => 'Russian (Русский)', 'ja' => 'Japanese (日本語)', 'ko' => 'Korean (한국어)', 'zh' => 'Chinese (中文)', 'ar' => 'Arabic (العربية)', 'hi' => 'Hindi (हिन्दी)', 'tr' => 'Turkish (Türkçe)', 'pl' => 'Polish (Polski)', 'sv' => 'Swedish (Svenska)', 'da' => 'Danish (Dansk)', 'no' => 'Norwegian (Norsk)', 'fi' => 'Finnish (Suomi)', 'cs' => 'Czech (Čeština)', 'ro' => 'Romanian (Română)', 'hu' => 'Hungarian (Magyar)', 'el' => 'Greek (Ελληνικά)', 'th' => 'Thai (ไทย)', 'vi' => 'Vietnamese (Tiếng Việt)', 'id' => 'Indonesian (Bahasa)', 'ms' => 'Malay (Melayu)', 'uk' => 'Ukrainian (Українська)', ); ?>

get_option('botwriter_ai_image_size', 'square'), 'botwriter_ai_image_quality' => get_option('botwriter_ai_image_quality', 'medium'), 'botwriter_ai_image_style' => get_option('botwriter_ai_image_style', 'realistic'), 'botwriter_ai_image_style_custom' => get_option('botwriter_ai_image_style_custom', ''), 'botwriter_image_postprocess_enabled' => get_option('botwriter_image_postprocess_enabled', '0'), 'botwriter_image_output_format' => get_option('botwriter_image_output_format', 'webp'), 'botwriter_image_max_width' => get_option('botwriter_image_max_width', '1200'), 'botwriter_image_compression' => get_option('botwriter_image_compression', '85'), 'botwriter_image_max_filesize' => get_option('botwriter_image_max_filesize', '120'), 'botwriter_sslverify' => get_option('botwriter_sslverify', 'yes'), 'botwriter_cron_active' => get_option('botwriter_cron_active', '1'), 'botwriter_paused_tasks' => get_option('botwriter_paused_tasks', '2'), 'botwriter_tags_disabled' => get_option('botwriter_tags_disabled', '0'), 'botwriter_meta_disabled' => get_option('botwriter_meta_disabled', '0'), // SEO Translation 'botwriter_seo_translation_enabled' => get_option('botwriter_seo_translation_enabled', '0'), 'botwriter_seo_target_language' => get_option('botwriter_seo_target_language', 'en'), 'botwriter_seo_translate_title' => get_option('botwriter_seo_translate_title', '1'), 'botwriter_seo_translate_tags' => get_option('botwriter_seo_translate_tags', '1'), 'botwriter_seo_translate_image' => get_option('botwriter_seo_translate_image', '1'), // API keys (encrypted, just check if they exist for display purposes) 'botwriter_openai_api_key' => get_option('botwriter_openai_api_key', ''), 'botwriter_google_api_key' => get_option('botwriter_google_api_key', ''), 'botwriter_anthropic_api_key' => get_option('botwriter_anthropic_api_key', ''), 'botwriter_mistral_api_key' => get_option('botwriter_mistral_api_key', ''), 'botwriter_groq_api_key' => get_option('botwriter_groq_api_key', ''), 'botwriter_openrouter_api_key' => get_option('botwriter_openrouter_api_key', ''), 'botwriter_fal_api_key' => get_option('botwriter_fal_api_key', ''), 'botwriter_replicate_api_key' => get_option('botwriter_replicate_api_key', ''), 'botwriter_stability_api_key' => get_option('botwriter_stability_api_key', ''), 'botwriter_cloudflare_api_key' => get_option('botwriter_cloudflare_api_key', ''), // Text models 'botwriter_openai_model' => get_option('botwriter_openai_model', 'gpt-5-mini'), 'botwriter_anthropic_model' => get_option('botwriter_anthropic_model', 'claude-sonnet-4-5-20250929'), 'botwriter_google_model' => get_option('botwriter_google_model', 'gemini-2.5-flash'), 'botwriter_mistral_model' => get_option('botwriter_mistral_model', 'mistral-large-latest'), 'botwriter_groq_model' => get_option('botwriter_groq_model', 'llama-3.3-70b-versatile'), 'botwriter_openrouter_model' => get_option('botwriter_openrouter_model', 'anthropic/claude-sonnet-4'), // Image models 'botwriter_dalle_model' => get_option('botwriter_dalle_model', 'gpt-image-1'), 'botwriter_gemini_image_model' => get_option('botwriter_gemini_image_model', 'gemini-2.5-flash-image'), 'botwriter_fal_model' => get_option('botwriter_fal_model', 'fal-ai/flux-pro/v1.1'), 'botwriter_replicate_model' => get_option('botwriter_replicate_model', 'black-forest-labs/flux-1.1-pro'), 'botwriter_stability_model' => get_option('botwriter_stability_model', 'sd3.5-large-turbo'), 'botwriter_cloudflare_model' => get_option('botwriter_cloudflare_model', 'flux-1-schnell'), 'botwriter_cloudflare_account_id' => get_option('botwriter_cloudflare_account_id', ''), // Stock photo settings 'botwriter_stockphoto_preferred' => get_option('botwriter_stockphoto_preferred', 'pixabay'), 'botwriter_stockphoto_selection' => get_option('botwriter_stockphoto_selection', 'random_top10'), 'botwriter_stockphoto_attribution' => get_option('botwriter_stockphoto_attribution', 'caption'), ); } // Generic function to encrypt any API key function botwriter_encrypt_api_key_generic($api_key) { if (empty($api_key)) { return ''; } if (!function_exists('openssl_encrypt')) { return $api_key; } if (!defined('AUTH_KEY')) { return $api_key; } $key = hash('sha256', AUTH_KEY, true); $encrypted = openssl_encrypt($api_key, 'AES-256-ECB', $key, 0); if ($encrypted === false) { return $api_key; } return base64_encode($encrypted); } // Legacy function for backwards compatibility (OpenAI key) function botwriter_encrypt_api_key($api_key) { global $botwriter_notice; if (!function_exists('openssl_encrypt')) { update_option('botwriter_openai_api_key', $api_key); $botwriter_notice .= __('The OpenSSL extension is not available. The API Key will be stored unencrypted, which is not secure. Contact your hosting provider.', 'botwriter') . '
'; return $api_key; } if (!defined('AUTH_KEY')) { $botwriter_notice .= __('AUTH_KEY not found in wp-config.php. Please configure WordPress security keys.', 'botwriter') . '
'; return get_option('botwriter_openai_api_key'); } $key = hash('sha256', AUTH_KEY, true); $encrypted = openssl_encrypt($api_key, 'AES-256-ECB', $key, 0); if ($encrypted === false) { $botwriter_notice .= __('Failed to encrypt the API Key.', 'botwriter') . '
'; return get_option('botwriter_openai_api_key'); } $encrypted_base64 = base64_encode($encrypted); update_option('botwriter_openai_api_key', $encrypted_base64); return $encrypted_base64; } // Decrypt API key (works for any provider) function botwriter_decrypt_api_key($encrypted_api_key) { if (empty($encrypted_api_key)) { return ''; } if (!function_exists('openssl_decrypt')) { return $encrypted_api_key; } if (!defined('AUTH_KEY')) { return ''; } $key = hash('sha256', AUTH_KEY, true); $encrypted = base64_decode($encrypted_api_key); if (!$encrypted) { return ''; } $decrypted = openssl_decrypt($encrypted, 'AES-256-ECB', $key, 0); if ($decrypted === false) { return ''; } return $decrypted; } // Validate OpenAI API Key format and test it function botwriter_open_api_key_validate($input) { global $botwriter_notice; $input = sanitize_text_field($input); // Validate basic format (e.g., starts with "sk-") if (strpos($input, 'sk-') !== 0) { $botwriter_notice .= __('The OpenAI API Key must start with "sk-".', 'botwriter') . '
'; return false; } // Make a test request to the OpenAI API $response = wp_remote_get('https://api.openai.com/v1/models', array( 'headers' => array( 'Authorization' => 'Bearer ' . $input, 'Content-Type' => 'application/json', ), 'timeout' => 15, )); if (is_wp_error($response)) { $botwriter_notice .= __('Error validating the API Key: ', 'botwriter') . $response->get_error_message() . '
'; return false; } $response_code = wp_remote_retrieve_response_code($response); if ($response_code !== 200) { /* translators: %s: HTTP response code returned by OpenAI when validating the API key. */ $botwriter_notice .= sprintf(__('The OpenAI API Key is invalid or lacks access. Error code: %s', 'botwriter'), $response_code) . '
'; return false; } return true; }