// =========================== // PERSONAL STYLES AJAX HANDLERS // =========================== add_action('wp_ajax_save_personal_style', 'ai_summary_save_personal_style'); function ai_summary_save_personal_style() { // Verify nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'personal_style_nonce')) { ai_summary_log('[ERROR] Personal style save failed: Security check failed'); wp_send_json_error('Security check failed'); } // Create automatic backup before any modifications if (ai_summary_backup_table_exists()) { ai_summary_create_backup('auto_backup_before_save_' . date('Y-m-d_H-i-s'), null, null, 'auto'); } // Get current styles $styles = get_option('ai_summary_personal_styles', []); // Ensure we have a proper array if (!is_array($styles)) { ai_summary_log('[ERROR] Personal styles corrupted during edit, recreating'); $styles = []; } // Get style data $style_id = sanitize_text_field($_POST['style_id'] ?? ''); $style_name = sanitize_text_field($_POST['name'] ?? ''); $style_type = sanitize_text_field($_POST['type'] ?? ''); $style_expertise = sanitize_text_field($_POST['expertise'] ?? ''); $style_insights = sanitize_textarea_field($_POST['insights'] ?? ''); $style_description = sanitize_textarea_field($_POST['description'] ?? ''); // Validate required fields if (empty($style_name)) { ai_summary_log('[ERROR] Personal style save failed: No name provided'); wp_send_json_error('Style name is required'); } // Generate new ID if creating new style if (empty($style_id)) { $style_id = 'style_' . uniqid() . '_' . time(); ai_summary_log('[DEBUG] Creating new personal style with ID: ' . $style_id); } else { ai_summary_log('[DEBUG] Updating existing personal style ID: ' . $style_id); } // Create the style array with humanization note $new_style = [ 'name' => $style_name, 'type' => $style_type, 'expertise' => $style_expertise, 'insights' => $style_insights, 'description' => $style_description, 'humanized' => true, // Mark as supporting humanization 'created_date' => current_time('mysql') ]; // Add to styles array $styles[$style_id] = $new_style; // Save to database $result = update_option('ai_summary_personal_styles', $styles); if ($result !== false) { ai_summary_log('[SUCCESS] Personal style saved with humanization support: ' . $style_name . ' (ID: ' . $style_id . ')'); wp_send_json_success('Style saved successfully with humanization features'); } else { ai_summary_log('[ERROR] Failed to save personal style to database'); wp_send_json_error('Failed to save style to database'); } } // Get personal style AJAX handler add_action('wp_ajax_get_personal_style', 'ai_summary_get_personal_style'); function ai_summary_get_personal_style() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'personal_style_nonce')) { wp_send_json_error('Security check failed'); } $styles = get_option('ai_summary_personal_styles', []); $style_id = sanitize_text_field($_POST['style_id'] ?? ''); ai_summary_log('[DEBUG] Attempting to get personal style ID: ' . $style_id); ai_summary_log('[DEBUG] Available style IDs: ' . implode(', ', array_keys($styles))); if (isset($styles[$style_id]) && is_array($styles[$style_id])) { ai_summary_log('[SUCCESS] Retrieved personal style: ' . $style_id); wp_send_json_success($styles[$style_id]); } else { ai_summary_log('[ERROR] Personal style not found: ' . $style_id); wp_send_json_error('Style not found: ' . $style_id); } } // Delete personal style AJAX handler add_action('wp_ajax_delete_personal_style', 'ai_summary_delete_personal_style'); function ai_summary_delete_personal_style() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'personal_style_nonce')) { wp_send_json_error('Security check failed'); } // Create backup before deletion if (ai_summary_backup_table_exists()) { ai_summary_create_backup('auto_backup_before_delete_' . date('Y-m-d_H-i-s'), null, null, 'auto'); } $styles = get_option('ai_summary_personal_styles', []); $style_id = sanitize_text_field($_POST['style_id'] ?? ''); if (isset($styles[$style_id])) { unset($styles[$style_id]); update_option('ai_summary_personal_styles', $styles); ai_summary_log('[SUCCESS] Deleted personal style: ' . $style_id); wp_send_json_success('Style deleted successfully'); } else { wp_send_json_error('Style not found'); } } // =========================== // DEBUG API TEST HANDLER // =========================== add_action('wp_ajax_test_ai_api_call', 'ai_summary_test_api_call'); function ai_summary_test_api_call() { if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'ai_summary_meta_box')) { wp_send_json_error('Security check failed'); } $post_id = intval($_POST['post_id'] ?? 0); $post = get_post($post_id); if (!$post) { wp_send_json_error('Invalid post ID'); } ai_summary_log("[DEBUG_TEST] Starting API test for post ID {$post_id}"); // Test the API call with detailed logging $api_key = get_option('ai_summary_api_key'); if (!$api_key) { wp_send_json_error('No API key configured'); } // Simple test prompt $test_prompt = "Please provide a brief summary and analysis for this test article. Format exactly as: TITLE: Test Article About Technology SUMMARY: • First summary point about the topic • Second summary point with details • Third summary point explaining key aspects ANALYSIS: • First analytical insight about implications • Second analysis point about significance • Third analysis examining deeper meaning Test article content: " . wp_trim_words(strip_tags($post->post_content), 100); $response = wp_remote_post('https://api.openai.com/v1/chat/completions', [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ], 'body' => json_encode([ 'model' => get_option('ai_summary_model', 'gpt-4o-mini'), 'messages' => [ [ 'role' => 'system', 'content' => 'You are a helpful assistant that provides structured summaries and analysis.' ], [ 'role' => 'user', 'content' => $test_prompt ] ], 'temperature' => 0.7, // Lower temperature for more consistent test 'max_tokens' => 500 ]), 'timeout' => 30 ]); if (is_wp_error($response)) { ai_summary_log("[DEBUG_TEST] API request failed: " . $response->get_error_message()); wp_send_json_error('API request failed: ' . $response->get_error_message()); } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (!isset($data['choices'][0]['message']['content'])) { ai_summary_log("[DEBUG_TEST] Invalid API response: " . $body); wp_send_json_error('Invalid API response - check debug log'); } $ai_response = $data['choices'][0]['message']['content']; ai_summary_log("[DEBUG_TEST] Raw API response: " . $ai_response); // Test parsing $title = ''; $summary = ''; $analysis = ''; $lines = explode("\n", $ai_response); $current_section = ''; foreach ($lines as $line) { $line = trim($line); if (empty($line)) continue; if (stripos($line, 'TITLE:') === 0) { $current_section = 'title'; $title = trim(substr($line, 6)); } elseif (stripos($line, 'SUMMARY:') === 0) { $current_section = 'summary'; $summary = trim(substr($line, 8)); } elseif (stripos($line, 'ANALYSIS:') === 0) { $current_section = 'analysis'; $analysis = trim(substr($line, 9)); } elseif (!empty($line)) { if ($current_section === 'title' && empty($title)) { $title = $line; } elseif ($current_section === 'summary') { $summary .= ($summary ? "\n" : "") . $line; } elseif ($current_section === 'analysis') { $analysis .= ($analysis ? "\n" : "") . $line; } } } ai_summary_log("[DEBUG_TEST] Parsed - Title: {$title}, Summary length: " . strlen($summary) . ", Analysis length: " . strlen($analysis)); wp_send_json_success([ 'response_length' => strlen($ai_response), 'title' => $title, 'summary' => $summary, 'analysis' => $analysis, 'raw_response' => substr($ai_response, 0, 500) . '...' // First 500 chars for debugging ]); } // =========================== // AJAX HANDLERS FOR GENERATION WITH STYLE AND HUMANIZATION // =========================== add_action('wp_ajax_generate_single_summary_with_style', 'ai_summary_generate_single_with_style'); function ai_summary_generate_single_with_style() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'generate_summary')) { wp_die('Security check failed'); } $post_id = intval($_POST['post_id'] ?? 0); $style_id = sanitize_text_field($_POST['style_id'] ?? ''); $post = get_post($post_id); if (!$post) { wp_send_json_error('Invalid post ID'); } // Store the selected style for this post if ($style_id !== 'default') { update_post_meta($post_id, '_ai_summary_style', $style_id); } else { delete_post_meta($post_id, '_ai_summary_style'); } // Mark this as humanized generation update_post_meta($post_id, '_ai_summary_humanized', current_time('mysql')); $summary_data = get_ai_summary_with_style($post, $style_id); if ($summary_data) { update_post_meta($post_id, '_ai_summary', $summary_data['summary']); update_post_meta($post_id, '_ai_analysis', $summary_data['analysis']); // Handle title generation and application if (get_option('ai_summary_generate_titles', 1) && !empty($summary_data['title'])) { update_post_meta($post_id, '_ai_suggested_title', $summary_data['title']); // Auto-apply title if setting is enabled if (get_option('ai_summary_auto_apply_titles', 0)) { $updated_post = [ 'ID' => $post_id, 'post_title' => $summary_data['title'] ]; $update_result = wp_update_post($updated_post); if (is_wp_error($update_result)) { ai_summary_log('[ERROR] Failed to update post title for post ID ' . $post_id . ': ' . $update_result->get_error_message()); } else { ai_summary_log('[SUCCESS] Updated humanized post title with keyword preservation for post ID ' . $post_id . ' to: ' . $summary_data['title']); } } } update_post_meta($post_id, '_ai_summary_generated', current_time('mysql')); wp_send_json_success('Humanized summary with keyword preservation generated successfully'); } else { wp_send_json_error('Failed to generate humanized summary'); } } // Regenerate AI summary with style AJAX handler add_action('wp_ajax_regenerate_ai_summary_with_style', 'ai_summary_regenerate_with_style'); function ai_summary_regenerate_with_style() { if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'ai_summary_meta_box')) { wp_die('Security check failed'); } $post_id = intval($_POST['post_id'] ?? 0); $style_id = sanitize_text_field($_POST['style_id'] ?? ''); $post = get_post($post_id); if (!$post) { wp_send_json_error('Invalid post ID'); } // Store the selected style for this post if ($style_id !== 'default') { update_post_meta($post_id, '_ai_summary_style', $style_id); } else { delete_post_meta($post_id, '_ai_summary_style'); } // Mark this as humanized regeneration update_post_meta($post_id, '_ai_summary_humanized', current_time('mysql')); $summary_data = get_ai_summary_with_style($post, $style_id); if ($summary_data) { update_post_meta($post_id, '_ai_summary', $summary_data['summary']); update_post_meta($post_id, '_ai_analysis', $summary_data['analysis']); // Handle title generation (but don't auto-apply from post editor) if (get_option('ai_summary_generate_titles', 1) && !empty($summary_data['title'])) { update_post_meta($post_id, '_ai_suggested_title', $summary_data['title']); } update_post_meta($post_id, '_ai_summary_generated', current_time('mysql')); wp_send_json_success('Humanized summary with keyword preservation regenerated successfully'); } else { wp_send_json_error('Failed to regenerate humanized summary'); } } // =========================== // ENHANCED AI SUMMARY FUNCTION WITH SPECIFIC STYLE // =========================== function get_ai_summary_with_style($post, $style_id = 'default') { $api_key = get_option('ai_summary_api_key'); if (!$api_key) { ai_summary_log('[ERROR] No API key configured'); return false; } // Extract keywords from original title for preservation $original_keywords = []; if (get_option('ai_summary_keyword_preservation', 1) && get_option('ai_summary_generate_titles', 1)) { $original_keywords = ai_summary_extract_keywords($post->post_title); } // Check if multi-pass generation is enabled if (get_option('ai_summary_multi_pass', 0)) { return get_multi_pass_ai_summary_with_style($post, $style_id, $original_keywords); } // Prepare the content $content = strip_tags($post->post_content ?? ''); $content = wp_trim_words($content, 1000); // Use humanized template with keyword awareness $base_template = get_option('ai_summary_humanize_output', 1) ? build_humanized_prompt_template($original_keywords) : get_option('ai_summary_template', build_humanized_prompt_template($original_keywords)); // Build personalized analysis instructions based on style $personal_touch = ''; if ($style_id !== 'default') { $personal_touch = build_personal_analysis_prompt_for_style($style_id); } else { $personal_touch = build_personal_analysis_prompt(); } // Combine base template with personal touch $prompt = $base_template; if (!empty($personal_touch)) { $prompt .= "\n\n" . $personal_touch; } $prompt .= "\n\nCurrent article title: {$post->post_title}\n\nArticle content:\n{$content}"; ai_summary_log("[DEBUG] Sending humanized request with keyword preservation and style {$style_id} for post ID {$post->ID}"); // Build system message with personality and humanization $system_message = build_humanized_system_message_for_style($style_id); // Get humanization parameters $temperature = (float) get_option('ai_summary_api_temperature', 1.2); $presence_penalty = (float) get_option('ai_summary_presence_penalty', 0.6); $frequency_penalty = (float) get_option('ai_summary_frequency_penalty', 0.3); // Call OpenAI API with humanization parameters $response = wp_remote_post('https://api.openai.com/v1/chat/completions', [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ], 'body' => json_encode([ 'model' => get_option('ai_summary_model', 'gpt-4o-mini'), 'messages' => [ [ 'role' => 'system', 'content' => $system_message ], [ 'role' => 'user', 'content' => $prompt ] ], 'temperature' => $temperature, 'presence_penalty' => $presence_penalty, 'frequency_penalty' => $frequency_penalty, 'max_tokens' => 1000 ]), 'timeout' => 30 ]); if (is_wp_error($response)) { ai_summary_log('[ERROR] API request failed: ' . $response->get_error_message()); return false; } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (!isset($data['choices'][0]['message']['content'])) { ai_summary_log('[ERROR] Invalid API response: ' . $body); return false; } $ai_response = $data['choices'][0]['message']['content']; ai_summary_log("[DEBUG] Raw humanized AI response for post ID {$post->ID}: " . $ai_response); // Parse the response to extract title, summary and analysis $title = ''; $summary = ''; $analysis = ''; // Split response by lines and process $lines = explode("\n", $ai_response); $current_section = ''; foreach ($lines as $line) { $line = trim($line); // Skip empty lines if (empty($line)) { continue; } // Handle both markdown (**TITLE:**) and plain text (TITLE:) headers $line_clean = str_replace(['**', '*'], '', $line); // Remove markdown formatting if (stripos($line_clean, 'TITLE:') === 0) { $current_section = 'title'; // Extract title content after the colon $inline_content = trim(substr($line_clean, 6)); if (!empty($inline_content)) { $title = $inline_content; } } elseif (stripos($line_clean, 'SUMMARY:') === 0) { $current_section = 'summary'; // Extract any inline content after the colon $inline_content = trim(substr($line_clean, 8)); if (!empty($inline_content)) { $summary = $inline_content; } } elseif (stripos($line_clean, 'ANALYSIS:') === 0) { $current_section = 'analysis'; // Extract any inline content after the colon $inline_content = trim(substr($line_clean, 9)); if (!empty($inline_content)) { $analysis = $inline_content; } } elseif (!empty($line)) { // Process content lines based on current section if ($current_section === 'title' && empty($title)) { $title = str_replace(['**', '*'], '', $line); } elseif ($current_section === 'summary') { $clean_line = str_replace(['**', '*'], '', $line); if (!empty($summary)) { $summary .= "\n" . $clean_line; } else { $summary = $clean_line; } } elseif ($current_section === 'analysis') { $clean_line = str_replace(['**', '*'], '', $line); if (!empty($analysis)) { $analysis .= "\n" . $clean_line; } else { $analysis = $clean_line; } } } } $title = trim($title); $summary = trim($summary); $analysis = trim($analysis); // Apply humanization post-processing if (get_option('ai_summary_humanize_output', 1)) { $title = humanize_ai_text($title); $summary = humanize_ai_text($summary); $analysis = humanize_ai_text($analysis); } // KEYWORD PRESERVATION: Validate and fix title if needed if (!empty($title) && get_option('ai_summary_generate_titles', 1) && get_option('ai_summary_keyword_preservation', 1) && !empty($original_keywords)) { $retention_percentage = ai_summary_validate_keywords($original_keywords, $title); $threshold = (int) get_option('ai_summary_keyword_retention_threshold', 60); if ($retention_percentage < $threshold) { ai_summary_log("[KEYWORD_FAIL] Generated title '{$title}' only retained {$retention_percentage}% of keywords (threshold: {$threshold}%)"); // Auto-fix if enabled if (get_option('ai_summary_keyword_auto_fix', 1)) { $missing_keywords = array_filter($original_keywords, function($keyword) use ($title) { return strpos(strtolower($title), strtolower($keyword)) === false; }); $title = ai_summary_auto_fix_title($post->post_title, $title, $missing_keywords); // Validate the fix $new_retention = ai_summary_validate_keywords($original_keywords, $title); ai_summary_log("[KEYWORD_FIX] After auto-fix: {$new_retention}% keyword retention"); } else { // Fall back to original title ai_summary_log("[KEYWORD_FALLBACK] Using original title due to insufficient keyword retention"); $title = $post->post_title; } } else { ai_summary_log("[KEYWORD_SUCCESS] Title validated: {$retention_percentage}% keyword retention (threshold: {$threshold}%)"); } } // Validate title doesn't contain overused words if (!empty($title) && get_option('ai_summary_generate_titles', 1)) { $title = validate_and_clean_title($title); } ai_summary_log("[DEBUG] Parsed humanized title with keyword preservation: " . $title); ai_summary_log("[DEBUG] Parsed humanized summary: " . $summary); ai_summary_log("[DEBUG] Parsed humanized analysis: " . $analysis); if (empty($summary) || empty($analysis)) { ai_summary_log('[ERROR] Failed to parse summary or analysis from humanized response'); return false; } $result = [ 'summary' => $summary, 'analysis' => $analysis, 'humanized' => true ]; if (get_option('ai_summary_generate_titles', 1) && !empty($title)) { $result['title'] = $title; } return $result; } // =========================== // MULTI-PASS GENERATION WITH STYLE SUPPORT // =========================== function get_multi_pass_ai_summary_with_style($post, $style_id = 'default', $original_keywords = []) { ai_summary_log("[MULTI_PASS] Starting multi-pass humanized generation for post ID {$post->ID} with style {$style_id}"); // First pass - get initial content $first_pass = get_single_pass_ai_summary_with_style($post, $style_id, 'first', null, $original_keywords); if (!$first_pass) { return false; } // Brief delay sleep(2); // Second pass - refine and humanize further $second_pass = get_single_pass_ai_summary_with_style($post, $style_id, 'second', $first_pass, $original_keywords); if (!$second_pass) { return $first_pass; // Fallback to first pass } // Blend the results return blend_multi_pass_results($first_pass, $second_pass); } // Single pass for multi-pass generation with style function get_single_pass_ai_summary_with_style($post, $style_id = 'default', $pass_type = 'first', $previous_result = null, $original_keywords = []) { $api_key = get_option('ai_summary_api_key'); if (!$api_key) { return false; } $content = strip_tags($post->post_content ?? ''); $content = wp_trim_words($content, 1000); if ($pass_type === 'second' && $previous_result) { $prompt = "Please review and improve the following AI-generated summary and analysis to make it sound more human, natural, and conversational. Apply the specified style while maintaining authenticity:\n\n"; $prompt .= "Previous Summary:\n" . $previous_result['summary'] . "\n\n"; $prompt .= "Previous Analysis:\n" . $previous_result['analysis'] . "\n\n"; if (isset($previous_result['title'])) { $prompt .= "Previous Title: " . $previous_result['title'] . "\n\n"; } // Add style-specific refinement instructions if ($style_id !== 'default') { $personal_touch = build_personal_analysis_prompt_for_style($style_id); if (!empty($personal_touch)) { $prompt .= "\nStyle Instructions:\n" . $personal_touch . "\n\n"; } } // Add keyword preservation reminder for second pass if (!empty($original_keywords) && get_option('ai_summary_keyword_preservation', 1)) { $keyword_list = implode(', ', array_slice($original_keywords, 0, 5)); $prompt .= "IMPORTANT: Ensure the title includes these keywords: {$keyword_list}\n\n"; } $prompt .= "Original Article: " . $content; } else { $prompt = build_humanized_prompt_template($original_keywords); // Add style-specific instructions for first pass if ($style_id !== 'default') { $personal_touch = build_personal_analysis_prompt_for_style($style_id); if (!empty($personal_touch)) { $prompt .= "\n\n" . $personal_touch; } } $prompt .= "\n\nCurrent article title: {$post->post_title}\n\nArticle content:\n{$content}"; } $temperature = $pass_type === 'first' ? 1.1 : 1.4; // Higher temperature for second pass $response = wp_remote_post('https://api.openai.com/v1/chat/completions', [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ], 'body' => json_encode([ 'model' => get_option('ai_summary_model', 'gpt-4o-mini'), 'messages' => [ [ 'role' => 'system', 'content' => build_humanized_system_message_for_style($style_id) ], [ 'role' => 'user', 'content' => $prompt ] ], 'temperature' => $temperature, 'presence_penalty' => 0.6, 'frequency_penalty' => 0.3, 'max_tokens' => 1000 ]), 'timeout' => 30 ]); if (is_wp_error($response)) { return false; } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (!isset($data['choices'][0]['message']['content'])) { return false; } // Parse response (use same parsing logic as main function) $ai_response = $data['choices'][0]['message']['content']; // Basic parsing $title = ''; $summary = ''; $analysis = ''; // [Parse using same logic as get_ai_summary_with_style] $lines = explode("\n", $ai_response); $current_section = ''; foreach ($lines as $line) { $line = trim($line); if (empty($line)) continue; $line_clean = str_replace(['**', '*'], '', $line); if (stripos($line_clean, 'TITLE:') === 0) { $current_section = 'title'; $inline_content = trim(substr($line_clean, 6)); if (!empty($inline_content)) { $title = $inline_content; } } elseif (stripos($line_clean, 'SUMMARY:') === 0) { $current_section = 'summary'; $inline_content = trim(substr($line_clean, 8)); if (!empty($inline_content)) { $summary = $inline_content; } } elseif (stripos($line_clean, 'ANALYSIS:') === 0) { $current_section = 'analysis'; $inline_content = trim(substr($line_clean, 9)); if (!empty($inline_content)) { $analysis = $inline_content; } } elseif (!empty($line)) { if ($current_section === 'title' && empty($title)) { $title = str_replace(['**', '*'], '', $line); } elseif ($current_section === 'summary') { $clean_line = str_replace(['**', '*'], '', $line); $summary .= ($summary ? "\n" : "") . $clean_line; } elseif ($current_section === 'analysis') { $clean_line = str_replace(['**', '*'], '', $line); $analysis .= ($analysis ? "\n" : "") . $clean_line; } } } // Apply humanization if (get_option('ai_summary_humanize_output', 1)) { $title = humanize_ai_text($title); $summary = humanize_ai_text($summary); $analysis = humanize_ai_text($analysis); } return [ 'summary' => $summary, 'analysis' => $analysis, 'title' => $title, 'humanized' => true, 'pass_type' => $pass_type ]; } // =========================== // SYSTEM MESSAGE BUILDERS FOR SPECIFIC STYLES // =========================== function build_humanized_system_message_for_style($style_id) { $base_message = 'You are a knowledgeable person sharing insights about articles in a natural, conversational way. Write as if you\'re a real human explaining things to a colleague - use natural language, contractions, and authentic expressions. Avoid sounding robotic or overly formal.'; // Add title generation capability if (get_option('ai_summary_generate_titles', 1)) { $base_message .= ' Create titles that sound like a real person wrote them, not an AI. Be authentic and natural.'; } // Get the user's writing profile $writing_profile = get_option('ai_summary_writing_profile', ''); if (!empty($writing_profile)) { $base_message .= ' Your writing should match this personal style: ' . $writing_profile; } if ($style_id === 'default') { $base_message .= ' Maintain a professional but natural tone with humanized language.'; return $base_message; } $personal_styles = get_option('ai_summary_personal_styles', []); if (!isset($personal_styles[$style_id])) { return $base_message; } $style = $personal_styles[$style_id]; // Add conversational base for all non-default styles if (($style['type'] ?? '') !== 'default') { $base_message .= ' Use a conversational, friendly tone that makes complex topics accessible and engaging.'; } // Add specific style enhancements with humanization switch ($style['type'] ?? '') { case 'conversational': $base_message .= ' Focus on natural, human-like conversation and authentic expressions.'; break; case 'conversational_expert': $base_message .= ' Combine your conversational approach with deep industry expertise while maintaining natural, human language patterns.'; break; case 'conversational_critical': $base_message .= ' Apply a friendly but critical analytical mindset with authentic questioning and natural skepticism.'; break; case 'conversational_optimistic': $base_message .= ' Maintain an optimistic, forward-thinking perspective with genuine enthusiasm and natural positivity.'; break; case 'conversational_educational': $base_message .= ' Take on the role of a knowledgeable, friendly teacher with natural explanatory skills and authentic teaching style.'; break; } if (!empty($style['expertise'])) { $base_message .= ' Your area of expertise is ' . $style['expertise'] . '.'; } // Add humanization reminder $base_message .= ' Remember to use contractions naturally, vary your sentence structure, and include casual phrases that make your writing sound genuinely human.'; return $base_message; } // =========================== // PERSONAL ANALYSIS PROMPT BUILDERS // =========================== function build_personal_analysis_prompt_for_style($style_id) { $personal_styles = get_option('ai_summary_personal_styles', []); if (!isset($personal_styles[$style_id])) { return ''; } $style = $personal_styles[$style_id]; $personal_instructions = ''; // Get the user's writing profile $writing_profile = get_option('ai_summary_writing_profile', ''); // Start with personal writing style if available if (!empty($writing_profile)) { $personal_instructions .= "PERSONAL WRITING STYLE: Write in the following personal voice and style: " . $writing_profile . "\n\n"; } // Add humanization instructions if (get_option('ai_summary_humanize_output', 1)) { $personal_instructions .= "HUMANIZATION: Write as if you're a real person sharing insights naturally. Use contractions, casual phrases, and authentic expressions. Avoid robotic or overly formal language. Make it sound like genuine human analysis.\n\n"; } // Add conversational base for all styles except 'default' if (($style['type'] ?? '') !== 'default') { $personal_instructions .= "CONVERSATIONAL BASE: Maintain a friendly, conversational tone throughout your analysis. Use approachable language as if explaining to a colleague. Make it engaging and relatable. Use phrases like 'What's interesting here is...' or 'This makes me think...' to create connection with readers.\n\n"; } // Add style-specific instructions (these enhance the conversational base) switch ($style['type'] ?? '') { case 'conversational': $personal_instructions .= "ANALYSIS APPROACH: Focus on making complex topics accessible and engaging with natural, human-like observations. Use relatable examples and practical takeaways that sound authentic."; break; case 'conversational_expert': $personal_instructions .= "EXPERT ENHANCEMENT: While maintaining your conversational tone, showcase deep industry knowledge with authentic expertise. Reference industry trends and best practices in a natural, non-robotic way."; break; case 'conversational_critical': $personal_instructions .= "CRITICAL ENHANCEMENT: While staying friendly and approachable, ask probing questions with genuine human curiosity. Look for potential flaws with authentic skepticism, not artificial criticism."; break; case 'conversational_optimistic': $personal_instructions .= "OPTIMISTIC ENHANCEMENT: Emphasize opportunities with genuine enthusiasm and natural positivity. Look for silver linings with authentic human optimism, not forced cheerfulness."; break; case 'conversational_educational': $personal_instructions .= "EDUCATIONAL ENHANCEMENT: Take on the role of a friendly teacher with natural explanatory skills. Make complex ideas accessible with authentic teaching enthusiasm."; break; case 'custom': if (!empty($style['description'])) { $personal_instructions .= "CUSTOM APPROACH: Apply your conversational base with this additional approach: " . $style['description'] . " - Remember to maintain natural, human-like language throughout."; } break; case 'default': $personal_instructions .= "PROFESSIONAL APPROACH: Maintain a balanced, professional tone but with humanized language and natural expressions."; break; } // Add expertise focus with humanization if (!empty($style['expertise'])) { $personal_instructions .= "\n\nEXPERTISE LENS: Analyze this through the lens of " . $style['expertise'] . " while maintaining your natural writing style. Share insights the way a real expert would explain things to someone they're mentoring."; } // Add signature insights with humanization if (!empty($style['insights'])) { $personal_instructions .= "\n\nSIGNATURE FOCUS: Always consider these aspects in your analysis with authentic curiosity: " . $style['insights'] . " - Approach these topics the way you would naturally think about them."; } return $personal_instructions; } // =========================== // BACKUP AND RECOVERY FUNCTIONS // =========================== function ai_summary_create_all_base_styles($force_recreate = false) { $existing_styles = get_option('ai_summary_personal_styles', []); // Ensure we have a proper array if (!is_array($existing_styles)) { ai_summary_log("[CREATE_BASE_STYLES] Corrupted styles data detected, resetting"); $existing_styles = []; delete_option('ai_summary_personal_styles'); add_option('ai_summary_personal_styles', []); } ai_summary_log("[CREATE_BASE_STYLES] Starting with " . count($existing_styles) . " existing styles (force_recreate: " . ($force_recreate ? 'true' : 'false') . ")"); // Create enhanced base styles with humanization support $base_styles = [ 'conversational_expert' => [ 'name' => 'Conversational & Expert (Humanized)', 'type' => 'conversational_expert', 'expertise' => 'business strategy and market analysis', 'insights' => 'competitive landscape, market positioning, strategic implications', 'description' => 'Friendly, conversational tone combined with deep industry expertise and professional insights - enhanced with natural, human-like language patterns', 'humanized' => true ], 'conversational_critical' => [ 'name' => 'Conversational & Critical (Humanized)', 'type' => 'conversational_critical', 'expertise' => '', 'insights' => 'potential risks, missing information, alternative perspectives, critical questions', 'description' => 'Approachable, friendly questioning that looks for flaws and biases in a conversational way - with authentic human skepticism', 'humanized' => true ], 'conversational_optimistic' => [ 'name' => 'Conversational & Optimistic (Humanized)', 'type' => 'conversational_optimistic', 'expertise' => 'innovation and future trends', 'insights' => 'growth opportunities, positive outcomes, innovation potential, silver linings', 'description' => 'Friendly, upbeat tone focused on opportunities and positive implications - with genuine human enthusiasm', 'humanized' => true ], 'conversational_educational' => [ 'name' => 'Conversational & Educational (Humanized)', 'type' => 'conversational_educational', 'expertise' => '', 'insights' => 'learning objectives, key concepts, practical applications, broader context', 'description' => 'Friendly teaching approach that explains and educates readers in an accessible, conversational way - with natural teaching patterns', 'humanized' => true ], 'pure_conversational' => [ 'name' => 'Pure Conversational (Humanized)', 'type' => 'conversational', 'expertise' => '', 'insights' => 'reader engagement, practical takeaways, relatable examples', 'description' => 'Friendly, approachable tone that makes complex topics accessible and engaging - enhanced with authentic human expressions', 'humanized' => true ], 'professional_humanized' => [ 'name' => 'Professional (Humanized)', 'type' => 'default', 'expertise' => '', 'insights' => 'key implications, important factors, relevant considerations', 'description' => 'Balanced, professional analysis enhanced with natural language patterns and human-like expressions', 'humanized' => true ] ]; $styles_created = 0; foreach ($base_styles as $type => $style_data) { // Check if we already have a style of this type (unless force recreating) $has_type = false; if (!$force_recreate) { foreach ($existing_styles as $existing_style_id => $existing_style) { if (is_array($existing_style) && isset($existing_style['type']) && $existing_style['type'] === $style_data['type']) { $has_type = true; ai_summary_log("[CREATE_BASE_STYLES] Type '{$style_data['type']}' already exists as style ID: {$existing_style_id}"); break; } } } // Create the style if it doesn't exist or if we're force recreating if (!$has_type || $force_recreate) { $style_id = 'style_' . $type . '_humanized_' . time() . '_' . rand(1000, 9999); $style_data['created_date'] = current_time('mysql'); $existing_styles[$style_id] = $style_data; $styles_created++; ai_summary_log("[CREATE_BASE_STYLES] Created new humanized base style: {$style_data['name']} (ID: {$style_id})"); } } if ($styles_created > 0) { ai_summary_log("[CREATE_BASE_STYLES] Saving " . count($existing_styles) . " total styles to database"); $result = update_option('ai_summary_personal_styles', $existing_styles); ai_summary_log("[CREATE_BASE_STYLES] Save result: " . ($result ? 'SUCCESS' : 'FAILED')); // Verify the save worked $verification = get_option('ai_summary_personal_styles', []); if (is_array($verification) && count($verification) >= $styles_created) { ai_summary_log("[CREATE_BASE_STYLES] Verification successful: " . count($verification) . " humanized styles in database"); } else { ai_summary_log("[CREATE_BASE_STYLES] Verification failed: " . print_r($verification, true)); } } else { ai_summary_log("[CREATE_BASE_STYLES] No new humanized base styles needed"); } return $styles_created; } // Backup table functions function ai_summary_backup_table_exists() { global $wpdb; $table_name = $wpdb->prefix . 'ai_summary_backups'; $result = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)); return $result === $table_name; } function ai_summary_create_backup_table() { global $wpdb; $table_name = $wpdb->prefix . 'ai_summary_backups'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE IF NOT EXISTS {$table_name} ( id mediumint(9) NOT NULL AUTO_INCREMENT, backup_name varchar(255) NOT NULL, personal_styles longtext NOT NULL, writing_profile longtext DEFAULT '', backup_date datetime DEFAULT CURRENT_TIMESTAMP, backup_type varchar(50) DEFAULT 'manual', humanization_settings longtext DEFAULT '', PRIMARY KEY (id) ) {$charset_collate};"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); $result = dbDelta($sql); // Log the result if (ai_summary_backup_table_exists()) { ai_summary_log("[BACKUP] Backup table created/verified successfully with humanization support"); } else { ai_summary_log("[BACKUP] Failed to create backup table. SQL: {$sql}"); ai_summary_log("[BACKUP] dbDelta result: " . print_r($result, true)); ai_summary_log("[BACKUP] Last error: " . $wpdb->last_error); } } function ai_summary_create_backup($name, $personal_styles = null, $writing_profile = null, $type = 'manual') { global $wpdb; // Ensure backup table exists if (!ai_summary_backup_table_exists()) { ai_summary_log("[BACKUP] Backup table doesn't exist, creating it"); ai_summary_create_backup_table(); if (!ai_summary_backup_table_exists()) { ai_summary_log("[BACKUP] Failed to create backup table"); return false; } } if ($personal_styles === null) { $personal_styles = get_option('ai_summary_personal_styles', []); } if ($writing_profile === null) { $writing_profile = get_option('ai_summary_writing_profile', ''); } // Backup humanization settings $humanization_settings = [ 'humanize_output' => get_option('ai_summary_humanize_output', 1), 'api_temperature' => get_option('ai_summary_api_temperature', 1.2), 'presence_penalty' => get_option('ai_summary_presence_penalty', 0.6), 'frequency_penalty' => get_option('ai_summary_frequency_penalty', 0.3), 'casual_phrases' => get_option('ai_summary_casual_phrases', 1), 'sentence_variety' => get_option('ai_summary_sentence_variety', 1), 'multi_pass' => get_option('ai_summary_multi_pass', 0), 'human_expressions' => get_option('ai_summary_human_expressions', 1), 'keyword_preservation' => get_option('ai_summary_keyword_preservation', 1), 'keyword_auto_fix' => get_option('ai_summary_keyword_auto_fix', 1), 'keyword_retention_threshold' => get_option('ai_summary_keyword_retention_threshold', 60) ]; $table_name = $wpdb->prefix . 'ai_summary_backups'; // Ensure personal_styles is an array before encoding if (!is_array($personal_styles)) { $personal_styles = []; } $styles_json = wp_json_encode($personal_styles); $humanization_json = wp_json_encode($humanization_settings); if ($styles_json === false || $humanization_json === false) { ai_summary_log("[BACKUP] Failed to encode data as JSON"); return false; } $result = $wpdb->insert( $table_name, [ 'backup_name' => sanitize_text_field($name), 'personal_styles' => $styles_json, 'writing_profile' => $writing_profile, 'backup_type' => $type, 'humanization_settings' => $humanization_json ], ['%s', '%s', '%s', '%s', '%s'] ); if ($result !== false) { $backup_id = $wpdb->insert_id; ai_summary_log("[BACKUP] Created humanized backup '{$name}' (ID: {$backup_id}) with " . count($personal_styles) . " styles"); return $backup_id; } else { ai_summary_log("[BACKUP] Failed to create backup '{$name}': " . $wpdb->last_error); return false; } } function ai_summary_get_backups() { global $wpdb; if (!ai_summary_backup_table_exists()) { ai_summary_log("[BACKUP] Backup table doesn't exist when trying to get backups"); return []; } $table_name = $wpdb->prefix . 'ai_summary_backups'; $backups = $wpdb->get_results( "SELECT * FROM {$table_name} ORDER BY backup_date DESC", ARRAY_A ); if ($backups === null) { ai_summary_log("[BACKUP] Error getting backups: " . $wpdb->last_error); return []; } return $backups ? $backups : []; } function ai_summary_restore_from_backup($backup_id) { global $wpdb; if (!ai_summary_backup_table_exists()) { ai_summary_log("[BACKUP] Backup table doesn't exist when trying to restore"); return false; } $table_name = $wpdb->prefix . 'ai_summary_backups'; $backup = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$table_name} WHERE id = %d", $backup_id), ARRAY_A ); if (!$backup) { ai_summary_log("[BACKUP] Backup ID {$backup_id} not found"); return false; } // Decode the data $personal_styles = json_decode($backup['personal_styles'], true); $writing_profile = $backup['writing_profile']; $humanization_settings = json_decode($backup['humanization_settings'] ?? '{}', true); if (!is_array($personal_styles)) { ai_summary_log("[BACKUP] Invalid styles data in backup ID {$backup_id}"); return false; } // Create current backup before restoring $pre_restore_backup = ai_summary_create_backup('pre_restore_backup_' . date('Y-m-d_H-i-s'), null, null, 'auto'); if (!$pre_restore_backup) { ai_summary_log("[BACKUP] Failed to create pre-restore backup"); } // Restore the data $styles_result = update_option('ai_summary_personal_styles', $personal_styles); $profile_result = true; if (!empty($writing_profile)) { $profile_result = update_option('ai_summary_writing_profile', $writing_profile); } // Restore humanization settings if available if (is_array($humanization_settings) && !empty($humanization_settings)) { foreach ($humanization_settings as $setting_key => $setting_value) { update_option('ai_summary_' . $setting_key, $setting_value); } ai_summary_log("[BACKUP] Restored humanization settings"); } if ($styles_result !== false) { ai_summary_log("[BACKUP] Successfully restored " . count($personal_styles) . " styles with humanization from backup '{$backup['backup_name']}'"); return [ 'styles_count' => count($personal_styles), 'writing_profile' => !empty($writing_profile), 'backup_name' => $backup['backup_name'], 'humanization_restored' => !empty($humanization_settings) ]; } else { ai_summary_log("[BACKUP] Failed to restore from backup ID {$backup_id}"); return false; } } // =========================== // AJAX HANDLERS FOR BACKUP MANAGEMENT // =========================== add_action('wp_ajax_create_manual_backup', 'ai_summary_create_manual_backup'); function ai_summary_create_manual_backup() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'personal_style_nonce')) { wp_send_json_error('Security check failed'); } $backup_name = sanitize_text_field($_POST['backup_name'] ?? ''); if (empty($backup_name)) { wp_send_json_error('Backup name is required'); } // Ensure backup table exists if (!ai_summary_backup_table_exists()) { ai_summary_create_backup_table(); if (!ai_summary_backup_table_exists()) { wp_send_json_error('Could not create backup table'); } } $backup_id = ai_summary_create_backup($backup_name, null, null, 'manual'); if ($backup_id) { wp_send_json_success('Humanized backup created successfully'); } else { wp_send_json_error('Failed to create backup'); } } add_action('wp_ajax_restore_from_backup', 'ai_summary_restore_from_backup_ajax'); function ai_summary_restore_from_backup_ajax() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'personal_style_nonce')) { wp_send_json_error('Security check failed'); } $backup_id = intval($_POST['backup_id'] ?? 0); $result = ai_summary_restore_from_backup($backup_id); if ($result) { $message = "Restored {$result['styles_count']} styles"; if ($result['writing_profile']) { $message .= " + writing profile"; } if ($result['humanization_restored']) { $message .= " + humanization settings"; } $result['message'] = $message; wp_send_json_success($result); } else { wp_send_json_error('Failed to restore from backup'); } } add_action('wp_ajax_delete_backup', 'ai_summary_delete_backup_ajax'); function ai_summary_delete_backup_ajax() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'personal_style_nonce')) { wp_send_json_error('Security check failed'); } global $wpdb; $backup_id = intval($_POST['backup_id'] ?? 0); $table_name = $wpdb->prefix . 'ai_summary_backups'; $result = $wpdb->delete($table_name, ['id' => $backup_id], ['%d']); if ($result !== false) { wp_send_json_success('Backup deleted successfully'); } else { wp_send_json_error('Failed to delete backup'); } } // =========================== // RECOVERY AJAX HANDLERS // =========================== add_action('wp_ajax_restore_default_styles', 'ai_summary_restore_default_styles'); function ai_summary_restore_default_styles() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'personal_style_nonce')) { wp_send_json_error('Security check failed'); } ai_summary_log("[RECOVERY] Starting humanized default styles restoration"); // Force recreate all base styles with humanization $styles_created = ai_summary_create_all_base_styles(true); if ($styles_created > 0) { ai_summary_log("[RECOVERY] Successfully restored {$styles_created} humanized default styles"); wp_send_json_success("Restored {$styles_created} humanized default styles successfully"); } else { $existing_styles = get_option('ai_summary_personal_styles', []); if (is_array($existing_styles) && !empty($existing_styles)) { ai_summary_log("[RECOVERY] Humanized default styles already exist (" . count($existing_styles) . " styles found)"); wp_send_json_success('Humanized default styles are already present (' . count($existing_styles) . ' styles found)'); } else { ai_summary_log("[RECOVERY] Failed to restore or locate default styles"); wp_send_json_error('Failed to restore default styles'); } } } add_action('wp_ajax_reset_styles_option', 'ai_summary_reset_styles_option'); function ai_summary_reset_styles_option() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'personal_style_nonce')) { wp_send_json_error('Security check failed'); } ai_summary_log("[RECOVERY] Resetting styles database option"); // Delete the option completely delete_option('ai_summary_personal_styles'); // Add it back as a fresh empty array add_option('ai_summary_personal_styles', []); // Verify it was created properly $test_option = get_option('ai_summary_personal_styles', 'NOT_FOUND'); if (is_array($test_option)) { ai_summary_log("[RECOVERY] Successfully reset styles option"); wp_send_json_success('Styles database option reset successfully'); } else { ai_summary_log("[RECOVERY] Failed to reset styles option - got: " . print_r($test_option, true)); wp_send_json_error('Failed to reset styles option'); } } add_action('wp_ajax_create_backup_table', 'ai_summary_create_backup_table_ajax'); function ai_summary_create_backup_table_ajax() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'personal_style_nonce')) { wp_send_json_error('Security check failed'); } ai_summary_create_backup_table(); if (ai_summary_backup_table_exists()) { wp_send_json_success('Backup table created successfully with humanization support'); } else { wp_send_json_error('Failed to create backup table'); } } add_action('wp_ajax_create_default_personal_styles', 'ai_summary_create_default_personal_styles_ajax'); function ai_summary_create_default_personal_styles_ajax() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'personal_style_nonce')) { wp_send_json_error('Security check failed'); } ai_summary_log("[AJAX] Creating humanized default personal styles"); // First ensure we have a proper array in the database $existing_styles = get_option('ai_summary_personal_styles', []); if (!is_array($existing_styles)) { ai_summary_log("[AJAX] Existing styles option was corrupted, resetting"); delete_option('ai_summary_personal_styles'); add_option('ai_summary_personal_styles', []); $existing_styles = []; } $styles_created = ai_summary_create_all_base_styles(); if ($styles_created > 0) { ai_summary_log("[AJAX] Successfully created {$styles_created} humanized default styles"); wp_send_json_success("Created {$styles_created} humanized default styles successfully"); } else { $current_styles = get_option('ai_summary_personal_styles', []); if (is_array($current_styles) && !empty($current_styles)) { ai_summary_log("[AJAX] Humanized default styles already exist (" . count($current_styles) . " styles)"); wp_send_json_success('Humanized default styles already exist (' . count($current_styles) . ' styles)'); } else { ai_summary_log("[AJAX] Failed to create default styles"); wp_send_json_error('Failed to create default styles'); } } } // =========================== // AJAX HANDLER TO CLEAR WRITING PROFILE // =========================== add_action('wp_ajax_clear_writing_profile', 'ai_summary_clear_writing_profile'); function ai_summary_clear_writing_profile() { if (!wp_verify_nonce($_POST['nonce'] ?? '', 'clear_writing_profile')) { wp_send_json_error('Security check failed'); } // Create backup before clearing if (ai_summary_backup_table_exists()) { ai_summary_create_backup('auto_backup_before_clear_profile_' . date('Y-m-d_H-i-s'), null, null, 'auto'); } delete_option('ai_summary_writing_profile'); delete_option('ai_summary_writing_profile_generated'); ai_summary_log("[DEBUG] Writing profile cleared by user (backup created)"); wp_send_json_success('Writing profile cleared successfully'); } // =========================== // AJAX HANDLER FOR SAVING AI SUMMARY EDITS // =========================== add_action('wp_ajax_save_ai_summary_edits', 'ai_summary_save_edits'); function ai_summary_save_edits() { if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'ai_summary_meta_box')) { wp_send_json_error('Security check failed'); } $post_id = intval($_POST['post_id'] ?? 0); $title = sanitize_textarea_field($_POST['title'] ?? ''); $summary = sanitize_textarea_field($_POST['summary'] ?? ''); $analysis = sanitize_textarea_field($_POST['analysis'] ?? ''); // Check if user has permission to edit this post if (!current_user_can('edit_post', $post_id)) { wp_send_json_error('You do not have permission to edit this post'); } // Apply humanization to edited content if enabled if (get_option('ai_summary_humanize_output', 1)) { $title = humanize_ai_text($title); $summary = humanize_ai_text($summary); $analysis = humanize_ai_text($analysis); } // Update the meta fields $summary_updated = update_post_meta($post_id, '_ai_summary', $summary); $analysis_updated = update_post_meta($post_id, '_ai_analysis', $analysis); // Update suggested title if provided if (!empty($title)) { update_post_meta($post_id, '_ai_suggested_title', $title); } // Update the last modified timestamp and mark as humanized update_post_meta($post_id, '_ai_summary_last_edited', current_time('mysql')); update_post_meta($post_id, '_ai_summary_humanized', current_time('mysql')); // Log the edit ai_summary_log("[EDIT] User manually edited humanized AI summary for post ID {$post_id}"); if ($summary_updated !== false || $analysis_updated !== false) { wp_send_json_success('Humanized AI Summary updated successfully'); } else { wp_send_json_error('Failed to update AI Summary'); } } // =========================== // CLEANUP OLD BACKUPS // =========================== function ai_summary_cleanup_old_backups() { global $wpdb; if (!ai_summary_backup_table_exists()) { return; } $table_name = $wpdb->prefix . 'ai_summary_backups'; // Get auto backups count $auto_count = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name} WHERE backup_type = 'auto'"); if ($auto_count > 10) { // Delete oldest auto backups, keeping 10 most recent $old_auto_backups = $wpdb->get_results( "SELECT id FROM {$table_name} WHERE backup_type = 'auto' ORDER BY backup_date ASC LIMIT " . ($auto_count - 10), ARRAY_A ); foreach ($old_auto_backups as $backup) { $wpdb->delete($table_name, ['id' => $backup['id']], ['%d']); } ai_summary_log("[BACKUP] Cleaned up " . count($old_auto_backups) . " old auto backups"); } } // Run cleanup daily add_action('wp_loaded', function() { if (!wp_next_scheduled('ai_summary_cleanup_backups')) { wp_schedule_event(time(), 'daily', 'ai_summary_cleanup_backups'); } }); add_action('ai_summary_cleanup_backups', 'ai_summary_cleanup_old_backups'); ?>