prefix . 'igny8_logs'; $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'"); if ($table_exists) { // Get table structure to determine correct column names $columns = $wpdb->get_results("SHOW COLUMNS FROM $table_name"); $column_names = array_column($columns, 'Field'); // Prepare data based on actual table structure $log_data = [ 'timestamp' => $timestamp, 'post_id' => get_queried_object_id(), 'user_id' => get_current_user_id(), 'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown' ]; // Insert based on actual table structure if (in_array('log_type', $column_names) && in_array('message', $column_names) && in_array('data', $column_names)) { // New structure from install.php $wpdb->insert( $table_name, [ 'log_type' => 'field_detection', 'message' => "[{$level}] {$message}", 'data' => json_encode($log_data), 'user_id' => get_current_user_id() ], ['%s', '%s', '%s', '%d'] ); } else { // Fallback: just log to error log if table structure doesn't match error_log("IGNY8: Logs table structure mismatch, skipping database log"); } } else { error_log("IGNY8: Logs table does not exist, skipping database log"); } } /** * Build combined content for personalization */ function igny8_build_combined_content($for_field_detection = false, $post_id = null) { // Check if Content Engine is enabled and use Content Engine-specific settings $content_engine_status = get_option('igny8_content_engine_global_status', 'enabled'); // Use provided post_id or fall back to queried object if ($post_id === null) { $post_id = get_queried_object_id(); } $post_type = get_post_type($post_id); $enabled_post_types = get_option('igny8_content_engine_enabled_post_types', []); if ($content_engine_status === 'enabled' && in_array($post_type, $enabled_post_types)) { // Use Content Engine-specific settings $include_context = get_option('igny8_content_engine_include_page_context', '0') === '1'; $input_scope = get_option('igny8_content_engine_input_scope', '300'); } else { // Use global settings $include_context = get_option('igny8_include_page_context', '0') === '1'; $input_scope = get_option('igny8_input_scope', '300'); } $final_content = ''; // ✅ Use PageContent from form if available if (!empty($_POST['PageContent'])) { $final_content .= "[SOURCE:PageContent from form]\n\n"; $final_content .= trim(sanitize_text_field($_POST['PageContent'])); } else { // ✅ Fallback to raw post content or term description $queried = get_post($post_id); if ($queried instanceof WP_Post) { // 🎯 Post/page/product — use post content with proper scope $raw_content = get_post_field('post_content', $queried->ID); if (!empty($raw_content)) { $final_content .= "[SOURCE:Post Content]\n\n"; // Apply scope logic - only add dynamic messages for field detection if ($for_field_detection) { // Add dynamic messages for field detection if ($input_scope === 'title') { $final_content .= "Use this blog/page title to define the fields:\n\n"; $final_content .= get_the_title($queried->ID); } elseif ($input_scope === '300') { $final_content .= "Use these 300 words to define the fields:\n\n"; $final_content .= wp_trim_words(strip_tags($raw_content), 300, '...'); } elseif ($input_scope === '600') { $final_content .= "Use these 600 words to define the fields:\n\n"; $final_content .= wp_trim_words(strip_tags($raw_content), 600, '...'); } else { $final_content .= "Use this whole content to define the fields:\n\n"; $final_content .= strip_tags($raw_content); } } else { // For content generation, just add content without dynamic messages if ($input_scope === 'title') { $final_content .= get_the_title($queried->ID); } elseif ($input_scope === '300') { $final_content .= wp_trim_words(strip_tags($raw_content), 300, '...'); } elseif ($input_scope === '600') { $final_content .= wp_trim_words(strip_tags($raw_content), 600, '...'); } else { $final_content .= strip_tags($raw_content); } } } } elseif (isset($queried->description) && !empty($queried->description)) { // 🏷️ Archive (term) — use term description $final_content .= "[SOURCE:Term Description]\n\n"; $final_content .= wp_trim_words(strip_tags($queried->description), 300, '...'); } } return trim($final_content) ?: 'No content available.'; } /** * Check content for moderation violations using OpenAI's moderation API */ function igny8_check_moderation($text, $api_key) { $res = wp_remote_post('https://api.openai.com/v1/moderations', [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ], 'body' => json_encode(['input' => $text]), 'timeout' => 20, ]); if (is_wp_error($res)) { return ['flagged' => false, 'error' => $res->get_error_message()]; } $body = json_decode(wp_remote_retrieve_body($res), true); return [ 'flagged' => $body['results'][0]['flagged'] ?? false, 'categories' => $body['results'][0]['categories'] ?? [], ]; } /** * Test OpenAI API connection */ function igny8_test_connection($api_key, $with_response = false) { // Get the current model setting $model = get_option('igny8_model', 'gpt-4.1'); if ($with_response) { // Test with actual API call // Prepare request body with model-specific parameters $request_body = [ 'model' => $model, 'messages' => [ [ 'role' => 'user', 'content' => 'test ping, reply with: OK! Ping Received. Also tell me: what is your maximum token limit that I can use in 1 request?' ] ] ]; // Model-specific parameters $request_body['temperature'] = 0.7; // Log the complete request to file $log_data = [ 'timestamp' => current_time('mysql'), 'model' => $model, 'request_body' => $request_body, 'headers' => [ 'Authorization' => 'Bearer ' . substr($api_key, 0, 10) . '...', 'Content-Type' => 'application/json' ] ]; $log_file = ABSPATH . 'igny8_api_request_log.json'; file_put_contents($log_file, json_encode($log_data, JSON_PRETTY_PRINT)); error_log("Igny8 Debug: Complete API request logged to: " . $log_file); $res = wp_remote_post('https://api.openai.com/v1/chat/completions', [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ], 'body' => json_encode($request_body), 'timeout' => 15, ]); } else { // Simple connection test without API call $res = wp_remote_get('https://api.openai.com/v1/models', [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, ], 'timeout' => 10, ]); } if (is_wp_error($res)) { return $res->get_error_message(); } $code = wp_remote_retrieve_response_code($res); $body = wp_remote_retrieve_body($res); // Log the complete response to file if ($with_response) { $response_log_data = [ 'timestamp' => current_time('mysql'), 'response_code' => $code, 'response_body' => json_decode($body, true), 'raw_response' => $body ]; $response_log_file = ABSPATH . 'igny8_api_response_log.json'; file_put_contents($response_log_file, json_encode($response_log_data, JSON_PRETTY_PRINT)); error_log("Igny8 Debug: Complete API response logged to: " . $response_log_file); } if ($code >= 200 && $code < 300) { if ($with_response) { // Handle API response test $response_data = json_decode($body, true); if (isset($response_data['choices'][0]['message']['content'])) { $response_text = trim($response_data['choices'][0]['message']['content']); // Extract token usage information $input_tokens = $response_data['usage']['prompt_tokens'] ?? 0; $output_tokens = $response_data['usage']['completion_tokens'] ?? 0; $total_tokens = $response_data['usage']['total_tokens'] ?? 0; // Calculate cost using model rates $rates = igny8_get_model_rates($model); $cost = ($input_tokens * $rates['in'] + $output_tokens * $rates['out']) / 1000000; return [ 'success' => true, 'message' => 'API connection and response test successful!', 'model_used' => $model, 'response' => $response_text, 'tokens_used' => $input_tokens . ' / ' . $output_tokens, 'total_tokens' => $total_tokens, 'cost' => '$' . number_format($cost, 4), 'full_response' => $response_data ]; } else { return [ 'success' => false, 'message' => 'API responded but no content received', 'response' => $body ]; } } else { // Handle simple connection test return [ 'success' => true, 'message' => 'API connection successful!', 'model_used' => $model, 'response' => 'Connection verified without API call' ]; } } else { return [ 'success' => false, 'message' => 'HTTP ' . $code . ' – ' . $body ]; } } /** * Log API call with cost calculation and error handling */ function igny8_log_api_call($model, $input_tokens, $output_tokens, $api_id = null, $status = 'success', $error_message = '') { global $wpdb; try { // Calculate cost using model rates $cost_data = igny8_calculate_api_cost($model, $input_tokens, $output_tokens); // Debug logging for cost calculation error_log("Igny8 Cost Debug: Model=$model, Input=$input_tokens, Output=$output_tokens"); error_log("Igny8 Cost Debug: Calculated total_cost=" . $cost_data['total_cost']); // Prepare log data with sanitization $log_data = [ 'event_type' => 'api_call', 'api_id' => $api_id ? esc_sql($api_id) : null, 'status' => esc_sql($status), 'level' => $status === 'success' ? 'info' : 'error', 'message' => sprintf( 'Model: %s | Input: %d tokens | Output: %d tokens | Cost: %s', esc_sql($model), intval($input_tokens), intval($output_tokens), igny8_format_cost($cost_data['total_cost']) ), 'context' => wp_json_encode([ 'model' => $model, 'input_tokens' => intval($input_tokens), 'output_tokens' => intval($output_tokens), 'total_cost' => $cost_data['total_cost'], 'input_cost' => $cost_data['input_cost'], 'output_cost' => $cost_data['output_cost'], 'error_message' => $error_message ]), 'source' => 'openai_api', 'user_id' => get_current_user_id(), 'created_at' => current_time('mysql') ]; // Insert with error handling $result = $wpdb->insert( $wpdb->prefix . 'igny8_logs', $log_data, ['%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s'] ); if ($result === false) { error_log('Igny8 API Logging Error: ' . $wpdb->last_error); } else { error_log("Igny8 Cost Debug: Successfully stored cost=" . $cost_data['total_cost'] . " in database"); } // Maintain 50 row limit for performance igny8_maintain_logs_limit(); } catch (Exception $e) { error_log('Igny8 API Logging Exception: ' . $e->getMessage()); } } /** * Maintain logs table limit for performance */ function igny8_maintain_logs_limit() { global $wpdb; // Keep only the 50 most recent logs $wpdb->query(" DELETE FROM {$wpdb->prefix}igny8_logs WHERE id NOT IN ( SELECT id FROM ( SELECT id FROM {$wpdb->prefix}igny8_logs ORDER BY created_at DESC LIMIT 50 ) AS latest_logs ) "); } /** * Call OpenAI API for content generation */ function igny8_call_openai($prompt, $api_key, $model) { // Debug logging for CRON context if (defined('DOING_CRON') && DOING_CRON) { error_log("Igny8 OpenAI Call: Starting API call - Model: " . $model . ", Prompt length: " . strlen($prompt)); } $body_data = [ 'model' => $model, 'messages' => [['role' => 'user', 'content' => $prompt]], ]; // Model-specific parameters $body_data['temperature'] = 0.7; if (defined('DOING_CRON') && DOING_CRON) { error_log("Igny8 OpenAI Call: Request body prepared - Temperature: " . $body_data['temperature']); } // Log the complete request to file $log_data = [ 'timestamp' => current_time('mysql'), 'model' => $model, 'request_body' => $body_data, 'headers' => [ 'Authorization' => 'Bearer ' . substr($api_key, 0, 10) . '...', 'Content-Type' => 'application/json' ], 'prompt_length' => strlen($prompt), 'prompt_preview' => substr($prompt, 0, 200) . '...' ]; $log_file = ABSPATH . 'igny8_all_api_requests.json'; // Read existing logs and append new one $existing_logs = []; if (file_exists($log_file)) { $existing_content = file_get_contents($log_file); if (!empty($existing_content)) { $existing_logs = json_decode($existing_content, true) ?: []; } } // Add new request to logs $existing_logs[] = $log_data; // Keep only last 50 requests to prevent file from growing too large if (count($existing_logs) > 50) { $existing_logs = array_slice($existing_logs, -50); } file_put_contents($log_file, json_encode($existing_logs, JSON_PRETTY_PRINT)); error_log("Igny8 Debug: API request logged to: " . $log_file); $args = [ 'body' => json_encode($body_data), 'headers' => [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $api_key, ], 'timeout' => 60, ]; if (defined('DOING_CRON') && DOING_CRON) { error_log("Igny8 OpenAI Call: Making HTTP request to OpenAI API..."); } $response = wp_remote_post('https://api.openai.com/v1/chat/completions', $args); if (is_wp_error($response)) { // Log API error with detailed information $error_message = $response->get_error_message(); $error_code = $response->get_error_code(); if (defined('DOING_CRON') && DOING_CRON) { error_log("Igny8 OpenAI Call: HTTP request failed - " . $error_message); } // Enhanced error logging igny8_log_api_call($model, 0, 0, null, 'error', $error_message); // Log detailed error information $error_details = [ 'error_code' => $error_code, 'error_message' => $error_message, 'model' => $model, 'api_key_configured' => !empty($api_key), 'prompt_length' => strlen($prompt), 'timestamp' => current_time('mysql'), 'request_url' => 'https://api.openai.com/v1/chat/completions' ]; // Log to AI events for debug module igny8_log_ai_event('OpenAI HTTP Error', 'ai', 'api_call', 'error', 'HTTP request failed', 'Error: ' . $error_message . ' | Details: ' . json_encode($error_details)); return 'Error: ' . $error_message; } if (defined('DOING_CRON') && DOING_CRON) { error_log("Igny8 OpenAI Call: HTTP request successful, processing response..."); } $response_code = wp_remote_retrieve_response_code($response); $response_body = wp_remote_retrieve_body($response); $response_data = json_decode($response_body, true); // Check for HTTP errors (non-200 status codes) if ($response_code !== 200) { $error_message = "HTTP {$response_code} error"; if (isset($response_data['error']['message'])) { $error_message .= ": " . $response_data['error']['message']; } if (defined('DOING_CRON') && DOING_CRON) { error_log("Igny8 OpenAI Call: HTTP error - " . $error_message); } // Log detailed HTTP error $error_details = [ 'http_code' => $response_code, 'error_message' => $error_message, 'model' => $model, 'api_key_configured' => !empty($api_key), 'response_body' => $response_body, 'timestamp' => current_time('mysql') ]; igny8_log_ai_event('OpenAI HTTP Error', 'ai', 'api_call', 'error', 'HTTP ' . $response_code . ' error', 'Error: ' . $error_message . ' | Details: ' . json_encode($error_details)); return 'Error: ' . $error_message; } if (defined('DOING_CRON') && DOING_CRON) { error_log("Igny8 OpenAI Call: Response decoded - Has data: " . ($response_data ? 'Yes' : 'No')); if ($response_data && isset($response_data['choices'])) { error_log("Igny8 OpenAI Call: Response has " . count($response_data['choices']) . " choices"); } } // Log the complete response to file $response_log_data = [ 'timestamp' => current_time('mysql'), 'model' => $model, 'response_code' => wp_remote_retrieve_response_code($response), 'response_body' => $response_data, 'raw_response' => $response_body ]; $response_log_file = ABSPATH . 'igny8_all_api_responses.json'; // Read existing response logs and append new one $existing_response_logs = []; if (file_exists($response_log_file)) { $existing_content = file_get_contents($response_log_file); if (!empty($existing_content)) { $existing_response_logs = json_decode($existing_content, true) ?: []; } } // Add new response to logs $existing_response_logs[] = $response_log_data; // Keep only last 50 responses to prevent file from growing too large if (count($existing_response_logs) > 50) { $existing_response_logs = array_slice($existing_response_logs, -50); } file_put_contents($response_log_file, json_encode($existing_response_logs, JSON_PRETTY_PRINT)); error_log("Igny8 Debug: API response logged to: " . $response_log_file); // Extract API response data for logging $api_id = $response_data['id'] ?? null; $usage = $response_data['usage'] ?? []; $input_tokens = $usage['prompt_tokens'] ?? 0; $output_tokens = $usage['completion_tokens'] ?? 0; // Log successful API call igny8_log_api_call($model, $input_tokens, $output_tokens, $api_id, 'success'); return $response_data['choices'][0]['message']['content'] ?? 'No response.'; } /** * Get content scope based on settings */ function igny8_get_content_scope($post_id, $scope) { $content = igny8_build_combined_content(true); return $content; } /** * Generate personalized content */ function igny8_generate_content($post_id, $field_inputs, $options = []) { global $wpdb; $api_key = get_option('igny8_api_key'); $model = get_option('igny8_model', 'gpt-4.1'); if (empty($api_key)) { return ['success' => false, 'message' => 'OpenAI API key not configured']; } // Build inputs string $inputs_string = ''; foreach ($field_inputs as $key => $value) { if ($key !== 'PageContent' && !empty($value)) { $inputs_string .= ucfirst($key) . ': ' . $value . "\n"; } } // Get content $content = igny8_build_combined_content(false, $post_id); // Get rewrite prompt $rewrite_prompt = get_option('igny8_content_engine_rewrite_prompt', 'Rewrite the following content to be personalized for a reader with these characteristics: [INPUTS] Original content: [CONTENT] Make the content feel like it was written specifically for this person while maintaining the original message and tone.'); $prompt = str_replace(['[INPUTS]', '[CONTENT]'], [$inputs_string, $content], $rewrite_prompt); // Log the final prompt being sent to OpenAI igny8_log_field_detection_process('INFO', 'Final prompt being sent to OpenAI:'); igny8_log_field_detection_process('INFO', 'INPUTS: ' . $inputs_string); igny8_log_field_detection_process('INFO', 'CONTENT: ' . substr($content, 0, 200) . '...'); igny8_log_field_detection_process('INFO', 'PROMPT: ' . substr($prompt, 0, 500) . '...'); // Call OpenAI $generated_content = igny8_call_openai($prompt, $api_key, $model); if (strpos($generated_content, 'Error:') === 0) { return ['success' => false, 'message' => $generated_content]; } // Save variation if requested $variation_id = null; if ($options['save_variation'] ?? false) { $variation_id = igny8_save_variation($post_id, $field_inputs, $generated_content); } return [ 'success' => true, 'content' => $generated_content, 'variation_id' => $variation_id, 'message' => 'Content generated successfully' ]; } /** * Save content variation */ function igny8_save_variation($post_id, $field_inputs, $content) { global $wpdb; $fields_hash = md5(wp_json_encode($field_inputs)); $fields_json = wp_json_encode($field_inputs); // Check if variation already exists $existing = $wpdb->get_var($wpdb->prepare( "SELECT id FROM {$wpdb->prefix}igny8_variations WHERE post_id = %d AND fields_hash = %s", $post_id, $fields_hash )); if ($existing) { // Update existing variation $wpdb->update( $wpdb->prefix . 'igny8_variations', [ 'content' => $content, 'created_at' => current_time('mysql') ], ['id' => $existing], ['%s', '%s'], ['%d'] ); return $existing; } else { // Insert new variation $wpdb->insert( $wpdb->prefix . 'igny8_variations', [ 'post_id' => $post_id, 'fields_hash' => $fields_hash, 'fields_json' => $fields_json, 'content' => $content, 'created_at' => current_time('mysql') ], ['%d', '%s', '%s', '%s', '%s'] ); return $wpdb->insert_id; } } /** * Get cached variation */ function igny8_get_cached_variation($post_id, $field_inputs) { global $wpdb; $fields_hash = md5(wp_json_encode($field_inputs)); $variation = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}igny8_variations WHERE post_id = %d AND fields_hash = %s", $post_id, $fields_hash )); return $variation ? (array) $variation : null; } /** * Register shortcode [igny8] */ /** * Automatically inject Igny8 shortcode into content */ function igny8_inject_shortcode_into_content($content) { // Only run on frontend if (is_admin()) { return $content; } // Check if Content Engine is enabled globally $global_status = get_option('igny8_content_engine_global_status', 'enabled'); if ($global_status !== 'enabled') { return $content; } // Get current post type $post_type = get_post_type(); if (!$post_type) { return $content; } // Check if this post type is enabled for personalization $enabled_post_types = get_option('igny8_content_engine_enabled_post_types', []); if (!in_array($post_type, $enabled_post_types)) { return $content; } // Get insertion position $insertion_position = get_option('igny8_content_engine_insertion_position', 'before'); // Get display mode $display_mode = get_option('igny8_content_engine_display_mode', 'always'); // Check if we should show personalization based on display mode if ($display_mode === 'logged_in' && !is_user_logged_in()) { return $content; } if ($display_mode === 'logged_out' && is_user_logged_in()) { return $content; } // Inject shortcode based on position $shortcode = '[igny8]'; switch ($insertion_position) { case 'before': return $shortcode . $content; case 'after': return $content . $shortcode; case 'replace': return $shortcode; default: return $shortcode . $content; } } // Hook into the_content filter add_filter('the_content', 'igny8_inject_shortcode_into_content'); // Register AJAX actions add_action('wp_ajax_igny8_get_fields', 'igny8_ajax_get_fields'); add_action('wp_ajax_nopriv_igny8_get_fields', 'igny8_ajax_get_fields'); add_action('wp_ajax_igny8_generate_custom', 'igny8_ajax_generate_custom'); add_action('wp_ajax_nopriv_igny8_generate_custom', 'igny8_ajax_generate_custom'); add_action('wp_ajax_igny8_save_content_manual', 'igny8_ajax_save_content_manual'); add_action('wp_ajax_nopriv_igny8_save_content_manual', 'igny8_ajax_save_content_manual'); add_action('wp_ajax_igny8_test_personalize', 'igny8_ajax_test_personalize'); add_action('wp_ajax_nopriv_igny8_test_personalize', 'igny8_ajax_test_personalize'); /** * AJAX Handler for getting personalization fields */ function igny8_ajax_get_fields() { try { // Log the start of field detection process igny8_log_field_detection_process('START', 'Field detection process initiated'); // Debug logging error_log('IGNY8 AJAX Debug - Request method: ' . $_SERVER['REQUEST_METHOD']); error_log('IGNY8 AJAX Debug - GET params: ' . print_r($_GET, true)); error_log('IGNY8 AJAX Debug - POST params: ' . print_r($_POST, true)); // Check nonce for security - handle both GET and POST $nonce_param = isset($_GET['nonce']) ? $_GET['nonce'] : (isset($_POST['nonce']) ? $_POST['nonce'] : ''); if (!wp_verify_nonce($nonce_param, 'igny8_ajax_nonce')) { igny8_log_field_detection_process('ERROR', 'Security check failed - invalid nonce'); wp_send_json_error('Security check failed - invalid nonce'); } $post_id = isset($_GET['post_id']) ? absint($_GET['post_id']) : 0; $form_fields = isset($_GET['form_fields']) ? sanitize_text_field($_GET['form_fields']) : ''; if (!$post_id) { igny8_log_field_detection_process('ERROR', 'Invalid post ID: ' . $post_id); wp_send_json_error('Invalid post ID'); } igny8_log_field_detection_process('INFO', 'Processing post ID: ' . $post_id); // Get content for field detection $content = igny8_build_combined_content(true, $post_id); if (empty($content)) { igny8_log_field_detection_process('ERROR', 'No content found for field detection'); wp_send_json_error('No content found for field detection'); } igny8_log_field_detection_process('INFO', 'Content retrieved successfully. Length: ' . strlen($content)); // Check if field detection is enabled $field_mode = get_option('igny8_content_engine_field_mode', 'auto'); igny8_log_field_detection_process('INFO', 'Field detection mode: ' . $field_mode); if ($field_mode === 'auto') { // Use AI to detect fields igny8_log_field_detection_process('INFO', 'Starting AI field detection'); $api_key = get_option('igny8_api_key'); $model = get_option('igny8_model', 'gpt-4.1'); $detection_prompt = get_option('igny8_content_engine_detection_prompt', ''); if (empty($api_key)) { igny8_log_field_detection_process('ERROR', 'OpenAI API key not configured'); wp_send_json_error('OpenAI API key not configured. Please set it in Personalize > Settings.'); } if (empty($detection_prompt)) { igny8_log_field_detection_process('ERROR', 'Detection prompt not configured'); wp_send_json_error('Detection prompt not configured. Please set it in Personalize > Settings.'); } // Replace [CONTENT] placeholder in prompt $prompt = str_replace('[CONTENT]', $content, $detection_prompt); igny8_log_field_detection_process('INFO', 'Prompt prepared for OpenAI API'); // Call OpenAI for field detection $response = igny8_call_openai($prompt, $api_key, $model, 1000); if (strpos($response, 'Error:') === 0) { igny8_log_field_detection_process('ERROR', 'OpenAI API error: ' . $response); $fields = []; // Fallback to empty fields on API error } else { igny8_log_field_detection_process('INFO', 'OpenAI API response received successfully'); // Try to parse the JSON response $fields_data = json_decode($response, true); if ($fields_data) { // Handle both formats: array of fields or object with fields property if (is_array($fields_data) && isset($fields_data[0]) && is_array($fields_data[0])) { // Direct array format: [field1, field2, ...] $fields = $fields_data; igny8_log_field_detection_process('SUCCESS', 'Fields detected successfully (array format): ' . count($fields) . ' fields'); } elseif (isset($fields_data['fields']) && is_array($fields_data['fields'])) { // Object format: {fields: [field1, field2, ...]} $fields = $fields_data['fields']; igny8_log_field_detection_process('SUCCESS', 'Fields detected successfully (object format): ' . count($fields) . ' fields'); } else { igny8_log_field_detection_process('ERROR', 'Invalid JSON structure - neither array nor object with fields property'); igny8_log_field_detection_process('ERROR', 'Raw OpenAI response: ' . $response); $fields = []; // Fallback to empty fields } // Log each detected field if (!empty($fields)) { foreach ($fields as $field) { igny8_log_field_detection_process('FIELD', 'Detected field: ' . $field['label'] . ' (type: ' . $field['type'] . ')'); } } } else { igny8_log_field_detection_process('ERROR', 'Failed to parse OpenAI response as valid JSON'); igny8_log_field_detection_process('ERROR', 'Raw OpenAI response: ' . $response); $fields = []; // Fallback to empty fields } } } else { // Use fixed fields from configuration igny8_log_field_detection_process('INFO', 'Using manual field configuration'); $fields = []; $fixed_fields_config = get_option('igny8_content_engine_fixed_fields_config', []); if (!empty($fixed_fields_config)) { // Use the configured fields directly $fields = $fixed_fields_config; igny8_log_field_detection_process('SUCCESS', 'Using configured fields: ' . count($fields) . ' fields'); } elseif (!empty($form_fields)) { // Fallback to form_fields parameter if no config $field_names = explode(',', $form_fields); foreach ($field_names as $field_name) { $fields[] = [ 'label' => trim($field_name), 'type' => 'text', 'options' => 'Example 1, Example 2' ]; } igny8_log_field_detection_process('INFO', 'Using fallback fields from parameter: ' . count($fields) . ' fields'); } } // If no fields were generated, provide a fallback if (empty($fields)) { igny8_log_field_detection_process('ERROR', 'No fields could be generated'); // Provide more detailed error information $error_details = [ 'field_mode' => $field_mode, 'api_key_set' => !empty(get_option('igny8_api_key')), 'detection_prompt_set' => !empty(get_option('igny8_content_engine_detection_prompt')), 'content_length' => strlen($content), 'post_id' => $post_id ]; igny8_log_field_detection_process('ERROR', 'Field generation failed - Details: ' . json_encode($error_details)); wp_send_json_error([ 'message' => 'No fields could be generated. Please check your settings and try again.', 'details' => $error_details ]); } igny8_log_field_detection_process('INFO', 'Generating form HTML for ' . count($fields) . ' fields'); // Generate form HTML with progress messages ob_start(); ?>