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(); ?>
Field Detection Complete! Found personalization fields.
Fields were automatically detected using AI analysis of your content. Fields were loaded from your manual configuration.
$field): ?>
getMessage()); error_log('Igny8 AJAX Error: ' . $e->getMessage()); error_log('Igny8 AJAX Trace: ' . $e->getTraceAsString()); wp_send_json_error('Error: ' . $e->getMessage()); } } /** * AJAX Handler for generating personalized content */ function igny8_ajax_generate_custom() { try { // Log the start of content generation process igny8_log_field_detection_process('START', 'Content generation process initiated'); // Check nonce for security if (!check_ajax_referer('igny8_ajax_nonce', 'nonce')) { igny8_log_field_detection_process('ERROR', 'Security check failed for content generation'); wp_send_json_error('Security check failed'); } $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0; if (!$post_id) { igny8_log_field_detection_process('ERROR', 'Invalid post ID for content generation: ' . $post_id); wp_send_json_error('Invalid post ID'); } igny8_log_field_detection_process('INFO', 'Generating content for post ID: ' . $post_id); // Get field inputs from form $field_inputs = []; foreach ($_POST as $key => $value) { if ($key !== 'action' && $key !== 'nonce' && $key !== 'post_id') { $field_inputs[sanitize_text_field($key)] = sanitize_text_field($value); } } igny8_log_field_detection_process('INFO', 'Field inputs collected: ' . count($field_inputs) . ' fields'); // Log each field input foreach ($field_inputs as $key => $value) { igny8_log_field_detection_process('FIELD', 'Field input: ' . $key . ' = ' . $value); } // Generate personalized content igny8_log_field_detection_process('INFO', 'Starting OpenAI content generation'); $result = igny8_generate_content($post_id, $field_inputs, []); if ($result['success']) { igny8_log_field_detection_process('SUCCESS', 'Content generated successfully. Length: ' . strlen($result['content'])); // Return enhanced content with generation details $enhanced_content = '
Personalized Content Generated!
Content was personalized using AI based on your inputs. Generated on ' . current_time('F j, Y \a\t g:i A') . '
' . wp_kses_post($result['content']) . '
' . (current_user_can('manage_options') ? '
' : '') . '
'; wp_send_json_success($enhanced_content); } else { igny8_log_field_detection_process('ERROR', 'Content generation failed: ' . $result['message']); wp_send_json_error($result['message']); } } catch (Exception $e) { igny8_log_field_detection_process('ERROR', 'Exception in content generation: ' . $e->getMessage()); error_log('Igny8 Content Generation Error: ' . $e->getMessage()); error_log('Igny8 Content Generation Trace: ' . $e->getTraceAsString()); wp_send_json_error('Error: ' . $e->getMessage()); } } /** * AJAX Handler for saving content manually */ function igny8_ajax_save_content_manual() { try { // Check nonce for security if (!check_ajax_referer('igny8_ajax_nonce', 'nonce')) { wp_send_json_error('Security check failed'); } $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0; $content = isset($_POST['content']) ? wp_kses_post($_POST['content']) : ''; $field_inputs = isset($_POST['field_inputs']) ? json_decode(stripslashes($_POST['field_inputs']), true) : []; if (!$post_id || empty($content)) { wp_send_json_error('Invalid post ID or content'); } // Save content variation $result = igny8_save_variation($post_id, $field_inputs, $content); if ($result) { wp_send_json_success('Content saved successfully'); } else { wp_send_json_error('Failed to save content'); } } catch (Exception $e) { wp_send_json_error('Error: ' . $e->getMessage()); } } /** * Simple test AJAX handler */ function igny8_ajax_test_personalize() { try { // Check nonce for security $nonce_param = isset($_GET['nonce']) ? $_GET['nonce'] : (isset($_POST['nonce']) ? $_POST['nonce'] : ''); if (!wp_verify_nonce($nonce_param, 'igny8_ajax_nonce')) { wp_send_json_error('Security check failed - invalid nonce'); } wp_send_json_success([ 'message' => 'Personalization AJAX is working!', 'post_id' => get_queried_object_id(), 'timestamp' => current_time('mysql') ]); } catch (Exception $e) { wp_send_json_error('Error: ' . $e->getMessage()); } } /** * AJAX Handler for testing API connection */ function igny8_ajax_test_api() { // Check nonce for security if (!wp_verify_nonce($_POST['nonce'] ?? '', 'igny8_ajax_nonce')) { wp_send_json_error('Security check failed'); } // Check permissions if (!current_user_can('edit_posts')) { wp_send_json_error('Insufficient permissions'); } // Get API key $api_key = get_option('igny8_api_key', ''); if (empty($api_key)) { wp_send_json_error(['message' => 'API key not configured']); } // Check if response test is requested $with_response = isset($_POST['with_response']) && $_POST['with_response'] === '1'; // Test the connection $result = igny8_test_connection($api_key, $with_response); // Handle the new response format if (is_array($result)) { if ($result['success']) { $response_data = [ 'message' => $result['message'], 'model_used' => $result['model_used'], 'response' => $result['response'] ]; // Add cost and token information if available if (isset($result['full_response']['usage'])) { $usage = $result['full_response']['usage']; $model = $result['model_used']; $cost_data = igny8_calculate_api_cost($model, $usage['prompt_tokens'], $usage['completion_tokens']); $response_data['tokens'] = $usage['prompt_tokens'] . ' / ' . $usage['completion_tokens']; $response_data['cost'] = igny8_format_cost($cost_data['total_cost']); } wp_send_json_success($response_data); } else { wp_send_json_error([ 'message' => $result['message'], 'details' => $result['response'] ?? '' ]); } } else { // Handle legacy string responses if ($result === true) { wp_send_json_success(['message' => 'Connection successful']); } else { $error_message = is_string($result) ? $result : 'Connection failed'; wp_send_json_error(['message' => $error_message]); } } } // Register the test AJAX handler add_action('wp_ajax_igny8_test_personalize', 'igny8_ajax_test_personalize'); add_action('wp_ajax_nopriv_igny8_test_personalize', 'igny8_ajax_test_personalize'); // Register the API test AJAX handler add_action('wp_ajax_igny8_test_api', 'igny8_ajax_test_api'); // Register the test field detection AJAX handler add_action('wp_ajax_igny8_test_field_detection', 'igny8_ajax_test_field_detection'); // Register debug AJAX handler add_action('wp_ajax_igny8_debug_personalization', 'igny8_ajax_debug_personalization'); add_action('wp_ajax_nopriv_igny8_debug_personalization', 'igny8_ajax_debug_personalization'); // Register test field detection with sample content add_action('wp_ajax_igny8_test_sample_field_detection', 'igny8_ajax_test_sample_field_detection'); // Register save variation AJAX handler add_action('wp_ajax_igny8_save_variation', 'igny8_ajax_save_variation'); /** * AJAX Handler for testing field detection */ function igny8_ajax_test_field_detection() { try { // Check nonce for security if (!check_ajax_referer('igny8_ajax_nonce', 'nonce')) { wp_send_json_error('Security check failed'); } // Check permissions if (!current_user_can('edit_posts')) { wp_send_json_error('Insufficient permissions'); } $content = isset($_POST['content']) ? sanitize_textarea_field($_POST['content']) : ''; if (empty($content)) { wp_send_json_error('No content provided for testing'); } // Log the test igny8_log_field_detection_process('INFO', 'Field detection test initiated by admin'); // Check if field detection is enabled $field_mode = get_option('igny8_content_engine_field_mode', 'auto'); if ($field_mode === 'auto') { // Use AI to detect fields $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)) { wp_send_json_error('OpenAI API key not configured'); } if (empty($detection_prompt)) { wp_send_json_error('Detection prompt not configured'); } // Replace [CONTENT] placeholder in prompt $prompt = str_replace('[CONTENT]', $content, $detection_prompt); // Call OpenAI for field detection $response = igny8_call_openai($prompt, $api_key, $model, 1000); if (strpos($response, 'Error:') === 0) { wp_send_json_error('OpenAI API error: ' . $response); } else { // 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, ...] - convert to expected format $fields_data = ['fields' => $fields_data]; igny8_log_field_detection_process('SUCCESS', 'Test field detection successful (array format): ' . count($fields_data['fields']) . ' fields detected'); } elseif (isset($fields_data['fields']) && is_array($fields_data['fields'])) { // Object format: {fields: [field1, field2, ...]} igny8_log_field_detection_process('SUCCESS', 'Test field detection successful (object format): ' . count($fields_data['fields']) . ' fields detected'); } else { igny8_log_field_detection_process('ERROR', 'Test field detection failed: Invalid JSON structure'); wp_send_json_error('Invalid JSON structure - neither array nor object with fields property'); } wp_send_json_success($fields_data); } else { igny8_log_field_detection_process('ERROR', 'Test field detection failed: Invalid JSON response'); wp_send_json_error('Failed to parse OpenAI response as valid JSON'); } } } else { // Use fixed fields from configuration $fixed_fields_config = get_option('igny8_content_engine_fixed_fields_config', []); if (!empty($fixed_fields_config)) { $fields_data = ['fields' => $fixed_fields_config]; igny8_log_field_detection_process('SUCCESS', 'Test field detection successful: ' . count($fixed_fields_config) . ' configured fields'); wp_send_json_success($fields_data); } else { igny8_log_field_detection_process('ERROR', 'Test field detection failed: No configured fields'); wp_send_json_error('No fields configured for manual mode'); } } } catch (Exception $e) { igny8_log_field_detection_process('ERROR', 'Exception in test field detection: ' . $e->getMessage()); wp_send_json_error('Error: ' . $e->getMessage()); } } /** * Debug AJAX handler to check personalization setup */ function igny8_ajax_debug_personalization() { try { // Check nonce for security if (!check_ajax_referer('igny8_ajax_nonce', 'nonce')) { wp_send_json_error('Security check failed'); } $debug_info = [ 'timestamp' => current_time('mysql'), 'wordpress_version' => get_bloginfo('version'), 'plugin_version' => get_option('igny8_version', 'unknown'), 'current_user' => wp_get_current_user()->user_login, 'is_admin' => current_user_can('manage_options'), 'ajax_url' => admin_url('admin-ajax.php'), 'post_id' => get_queried_object_id(), 'post_type' => get_post_type(), ]; // Check Content Engine settings $debug_info['content_engine'] = [ 'global_status' => get_option('igny8_content_engine_global_status', 'not_set'), 'enabled_post_types' => get_option('igny8_content_engine_enabled_post_types', []), 'display_mode' => get_option('igny8_content_engine_display_mode', 'not_set'), 'insertion_position' => get_option('igny8_content_engine_insertion_position', 'not_set'), 'teaser_text' => get_option('igny8_content_engine_teaser_text', 'not_set'), 'field_mode' => get_option('igny8_content_engine_field_mode', 'not_set'), 'detection_prompt' => get_option('igny8_content_engine_detection_prompt', 'not_set'), 'api_key_set' => !empty(get_option('igny8_api_key', '')), 'model' => get_option('igny8_model', 'not_set'), ]; // Check if shortcode would be injected $debug_info['shortcode_injection'] = [ 'content_filter_active' => has_filter('the_content', 'igny8_inject_shortcode_into_content'), 'would_show_personalization' => igny8_should_show_personalization(), 'post_type_enabled' => igny8_is_post_type_enabled_for_personalization(), ]; // Check database tables global $wpdb; $debug_info['database'] = [ 'logs_table_exists' => $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}igny8_logs'") ? true : false, 'variations_table_exists' => $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}igny8_variations'") ? true : false, 'logs_count' => $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_logs") ?: 0, ]; wp_send_json_success($debug_info); } catch (Exception $e) { wp_send_json_error('Debug error: ' . $e->getMessage()); } } /** * Check if personalization should be shown for current context */ function igny8_should_show_personalization() { // Only run on frontend if (is_admin()) { return false; } // Check if Content Engine is enabled globally $global_status = get_option('igny8_content_engine_global_status', 'enabled'); if ($global_status !== 'enabled') { return false; } // Get current post type $post_type = get_post_type(); if (!$post_type) { return false; } // 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 false; } // 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 false; } if ($display_mode === 'logged_out' && is_user_logged_in()) { return false; } return true; } /** * Check if current post type is enabled for personalization */ function igny8_is_post_type_enabled_for_personalization() { $post_type = get_post_type(); if (!$post_type) { return false; } $enabled_post_types = get_option('igny8_content_engine_enabled_post_types', []); return in_array($post_type, $enabled_post_types); } /** * Test field detection with sample cabinet content */ function igny8_ajax_test_sample_field_detection() { try { // Check nonce for security if (!check_ajax_referer('igny8_ajax_nonce', 'nonce')) { wp_send_json_error('Security check failed'); } // Check permissions if (!current_user_can('edit_posts')) { wp_send_json_error('Insufficient permissions'); } // Sample cabinet content $sample_content = "Revamp Your Space with Style and Utility Introducing our exquisite Chic Wood Countertop Cabinet, a seamless fusion of sophistication and functionality tailored for your kitchen or bathroom. Crafted with precision, this cabinet is meticulously designed to elevate your home's aesthetic while offering a streamlined solution for organizing your essentials. Highlight Features Dual Window Doors: Transparent panels provide a clear view of neatly arranged items, safeguarding them from dust and moisture. Multi-Purpose Storage: Perfect for stowing spice jars, vanity beauty essentials, and other petite necessities. Premium Wood Construction: Crafted with high-quality wood for enduring durability and a touch of natural warmth that enhances any decor. Compact Design: Tailored to fit seamlessly on countertops, delivering exceptional space-saving prowess. Where and When to Utilize? Versatile in its application, this cabinet thrives in diverse environments. Whether adorning your kitchen to keep spices and condiments accessible or gracing the bathroom to house beauty and skincare essentials, its compact stature renders it a perfect fit for small apartments, dormitories, or any space craving efficient organization."; // Get detection prompt $detection_prompt = get_option('igny8_content_engine_detection_prompt', ''); if (empty($detection_prompt)) { wp_send_json_error('Detection prompt not configured'); } // Replace [CONTENT] placeholder in prompt $prompt = str_replace('[CONTENT]', $sample_content, $detection_prompt); // Get API settings $api_key = get_option('igny8_api_key'); $model = get_option('igny8_model', 'gpt-4.1'); if (empty($api_key)) { wp_send_json_error('OpenAI API key not configured'); } // Call OpenAI for field detection $response = igny8_call_openai($prompt, $api_key, $model, 1000); if (strpos($response, 'Error:') === 0) { wp_send_json_error('OpenAI API error: ' . $response); } else { // Try to parse the JSON response $fields_data = json_decode($response, true); if ($fields_data && isset($fields_data['fields'])) { wp_send_json_success([ 'message' => 'Field detection test successful', 'sample_content' => $sample_content, 'detected_fields' => $fields_data, 'raw_response' => $response ]); } else { wp_send_json_error([ 'message' => 'Failed to parse OpenAI response as valid JSON', 'raw_response' => $response ]); } } } catch (Exception $e) { wp_send_json_error('Error: ' . $e->getMessage()); } } /** * AJAX Handler for saving content variations */ function igny8_ajax_save_variation() { try { // Check nonce for security if (!check_ajax_referer('igny8_ajax_nonce', 'nonce')) { wp_send_json_error('Security check failed'); } // Check if user has permission to save content if (!current_user_can('manage_options')) { wp_send_json_error('Insufficient permissions'); } $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0; $content = isset($_POST['content']) ? wp_kses_post($_POST['content']) : ''; $field_inputs = isset($_POST['field_inputs']) ? json_decode(stripslashes($_POST['field_inputs']), true) : []; if (!$post_id || empty($content)) { wp_send_json_error('Missing required data'); } // Save to variations table global $wpdb; $table_name = $wpdb->prefix . 'igny8_variations'; $result = $wpdb->insert( $table_name, [ 'post_id' => $post_id, 'field_inputs' => json_encode($field_inputs), 'personalized_content' => $content, 'created_at' => current_time('mysql'), 'created_by' => get_current_user_id() ], ['%d', '%s', '%s', '%s', '%d'] ); if ($result === false) { wp_send_json_error('Failed to save variation to database'); } wp_send_json_success([ 'variation_id' => $wpdb->insert_id, 'message' => 'Content variation saved successfully' ]); } catch (Exception $e) { wp_send_json_error('Error: ' . $e->getMessage()); } }