1611 lines
78 KiB
PHP
1611 lines
78 KiB
PHP
<?php
|
|
/**
|
|
* ==========================
|
|
* 🔐 IGNY8 FILE RULE HEADER
|
|
* ==========================
|
|
* @file : igny8-cron-handlers.php
|
|
* @location : /core/cron/igny8-cron-handlers.php
|
|
* @type : CRON Handler
|
|
* @scope : Global
|
|
* @allowed : Cron job implementations, automation handlers, error handling
|
|
* @reusability : Globally Reusable
|
|
* @notes : All cron job handler implementations with safety checks
|
|
*/
|
|
|
|
// Prevent direct access
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* AI Queue Processing Cron Handler
|
|
*
|
|
* Processes AI queue tasks with safety checks and duplicate prevention.
|
|
*/
|
|
function igny8_process_ai_queue_cron_handler() {
|
|
// Check if AI queue processing is enabled
|
|
if (igny8_get_ai_setting('ai_queue_enabled', 'enabled') !== 'enabled') {
|
|
igny8_log_ai_event('AI Queue Skipped', 'ai', 'queue_processing', 'info', 'AI queue processing disabled', 'Automation disabled in settings');
|
|
return;
|
|
}
|
|
|
|
global $wpdb;
|
|
|
|
// Get processing lock to prevent duplicates
|
|
$lock_key = 'igny8_ai_queue_processing';
|
|
if (get_transient($lock_key)) {
|
|
igny8_log_ai_event('AI Queue Skipped', 'ai', 'queue_processing', 'info', 'Queue processing already running', 'Duplicate execution prevented');
|
|
return;
|
|
}
|
|
|
|
// Set lock for 5 minutes
|
|
set_transient($lock_key, true, 300);
|
|
|
|
try {
|
|
// Use global limit from settings
|
|
$limit = $GLOBALS['igny8_cron_limit'] ?? null;
|
|
if ($limit === null) {
|
|
error_log('Igny8 AI Queue Cron: No limit set in Smart Automation Jobs table');
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No limit set in Smart Automation Jobs table";
|
|
return;
|
|
}
|
|
$processed = igny8_process_ai_queue($limit);
|
|
|
|
if ($processed > 0) {
|
|
igny8_log_ai_event('AI Queue Processed', 'ai', 'queue_processing', 'success', 'AI queue tasks processed', "Tasks processed: $processed");
|
|
|
|
// Set global variables for detailed logging
|
|
$GLOBALS['igny8_cron_processed_count'] = $processed;
|
|
$GLOBALS['igny8_cron_result_details'] = "Processed {$processed} AI queue tasks";
|
|
echo "<strong>Igny8 AI QUEUE HANDLER: Set global variables - processed_count: $processed, result_details: Processed {$processed} AI queue tasks</strong><br>";
|
|
} else {
|
|
igny8_log_ai_event('AI Queue Empty', 'ai', 'queue_processing', 'info', 'No tasks in queue', 'All tasks are already processed');
|
|
|
|
// Set global variables for detailed logging
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "No AI queue tasks to process";
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
igny8_log_ai_event('AI Queue Error', 'ai', 'queue_processing', 'error', 'AI queue processing failed', $e->getMessage());
|
|
|
|
// Set global variables for detailed logging (failure case)
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: " . $e->getMessage();
|
|
} finally {
|
|
// Always release the lock
|
|
delete_transient($lock_key);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Auto Cluster Cron Handler
|
|
*
|
|
* Automatically clusters unmapped keywords with taxonomy safety.
|
|
*/
|
|
function igny8_auto_cluster_cron_handler() {
|
|
// Suppress PHP warnings for model rates in cron context
|
|
$old_error_reporting = error_reporting();
|
|
error_reporting($old_error_reporting & ~E_WARNING);
|
|
|
|
echo "<div style='background:#e8f4fd;padding:10px;margin:5px;border:1px solid #2196F3;'>";
|
|
echo "<strong>Igny8 CRON HANDLER: auto_cluster started</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: auto_cluster started");
|
|
|
|
// Check if automation is enabled via cron settings
|
|
echo "<strong>Igny8 CRON HANDLER: Checking if automation is enabled</strong><br>";
|
|
$cron_settings = get_option('igny8_cron_settings', []);
|
|
$job_settings = $cron_settings['igny8_auto_cluster_cron'] ?? [];
|
|
$auto_cluster_enabled = $job_settings['enabled'] ?? false;
|
|
echo "<strong>Igny8 CRON HANDLER: auto_cluster_enabled =</strong> " . ($auto_cluster_enabled ? 'enabled' : 'disabled') . "<br>";
|
|
|
|
if (!$auto_cluster_enabled) {
|
|
echo "<strong>Igny8 CRON HANDLER: Automation disabled, exiting</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: auto_cluster automation disabled");
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Automation enabled, continuing</strong><br>";
|
|
|
|
// Check if AI mode is enabled
|
|
echo "<strong>Igny8 CRON HANDLER: Checking AI mode</strong><br>";
|
|
$planner_mode = igny8_get_ai_setting('planner_mode', 'manual');
|
|
echo "<strong>Igny8 CRON HANDLER: planner_mode =</strong> " . $planner_mode . "<br>";
|
|
|
|
if ($planner_mode !== 'ai') {
|
|
echo "<strong>Igny8 CRON HANDLER: AI mode disabled, exiting</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: AI mode disabled");
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: AI mode enabled, continuing</strong><br>";
|
|
|
|
// Check if sector is selected
|
|
echo "<strong>Igny8 CRON HANDLER: Checking sector options</strong><br>";
|
|
|
|
// Check if function exists first
|
|
if (!function_exists('igny8_get_sector_options')) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - igny8_get_sector_options function not found</strong><br>";
|
|
igny8_log_ai_event('Auto Cluster Failed', 'planner', 'auto_cluster', 'error', 'Sector options function not available', 'Function igny8_get_sector_options not found');
|
|
echo "<strong>Igny8 CRON HANDLER: Exiting due to missing function</strong><br>";
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
|
|
try {
|
|
echo "<strong>Igny8 CRON HANDLER: Calling igny8_get_sector_options()</strong><br>";
|
|
$sector_options = igny8_get_sector_options();
|
|
echo "<strong>Igny8 CRON HANDLER: sector_options count =</strong> " . count($sector_options) . "<br>";
|
|
echo "<strong>Igny8 CRON HANDLER: sector_options content:</strong> " . print_r($sector_options, true) . "<br>";
|
|
} catch (Exception $e) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - Exception in igny8_get_sector_options:</strong> " . $e->getMessage() . "<br>";
|
|
igny8_log_ai_event('Auto Cluster Failed', 'planner', 'auto_cluster', 'error', 'Exception in sector options function', $e->getMessage());
|
|
echo "<strong>Igny8 CRON HANDLER: Exiting due to sector options exception</strong><br>";
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
|
|
if (empty($sector_options)) {
|
|
echo "<strong>Igny8 CRON HANDLER: No sector selected, checking alternatives</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Checking if igny8_get_sector_options function exists:</strong> " . (function_exists('igny8_get_sector_options') ? 'YES' : 'NO') . "<br>";
|
|
|
|
// Try to get sectors directly from database
|
|
global $wpdb;
|
|
$sectors = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}igny8_sectors WHERE status = 'active'");
|
|
echo "<strong>Igny8 CRON HANDLER: Direct DB query found " . count($sectors) . " active sectors</strong><br>";
|
|
|
|
if (empty($sectors)) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - No active sectors found, cannot proceed</strong><br>";
|
|
igny8_log_ai_event('Auto Cluster Failed', 'planner', 'auto_cluster', 'error', 'No active sectors configured', 'Sector configuration required for clustering');
|
|
echo "<strong>Igny8 CRON HANDLER: Exiting due to missing sectors</strong><br>";
|
|
echo "</div>";
|
|
return;
|
|
} else {
|
|
echo "<strong>Igny8 CRON HANDLER: Found sectors in DB, using them</strong><br>";
|
|
$sector_options = $sectors;
|
|
}
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Sector selected, continuing</strong><br>";
|
|
|
|
global $wpdb;
|
|
echo "<strong>Igny8 CRON HANDLER: Database connection established</strong><br>";
|
|
|
|
// Get unmapped keywords (use dynamic limit from settings)
|
|
$limit = $GLOBALS['igny8_cron_limit'] ?? null;
|
|
if ($limit === null) {
|
|
// Try to get limit from Smart Automation Jobs table directly
|
|
$cron_limits = get_option('igny8_cron_limits', []);
|
|
$limit = $cron_limits['igny8_auto_cluster_cron'] ?? null;
|
|
|
|
if ($limit === null) {
|
|
error_log('Igny8 Auto Cluster Cron: No limit set in Smart Automation Jobs table');
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No limit set in Smart Automation Jobs table";
|
|
return;
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Using limit from Smart Automation Jobs table: $limit</strong><br>";
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Querying unmapped keywords (limit: $limit)</strong><br>";
|
|
$query = "SELECT id, keyword FROM {$wpdb->prefix}igny8_keywords WHERE cluster_id IS NULL OR cluster_id = 0 LIMIT $limit";
|
|
echo "<strong>Igny8 CRON HANDLER: SQL Query:</strong> " . $query . "<br>";
|
|
|
|
$unmapped_keywords = $wpdb->get_results($query);
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Found</strong> " . count($unmapped_keywords) . " unmapped keywords<br>";
|
|
|
|
if (!empty($unmapped_keywords)) {
|
|
echo "<strong>Igny8 CRON HANDLER: Sample keywords:</strong><br>";
|
|
foreach (array_slice($unmapped_keywords, 0, 3) as $keyword) {
|
|
echo "- ID: " . $keyword->id . ", Keyword: " . $keyword->keyword . "<br>";
|
|
}
|
|
}
|
|
|
|
if (empty($unmapped_keywords)) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - No unmapped keywords found</strong><br>";
|
|
igny8_log_ai_event('Auto Cluster Failed', 'planner', 'auto_cluster', 'error', 'No unmapped keywords available for clustering', 'All keywords are already clustered or no keywords exist');
|
|
echo "<strong>Igny8 CRON HANDLER: Exiting due to no keywords to process</strong><br>";
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
|
|
$keyword_ids = array_column($unmapped_keywords, 'id');
|
|
echo "<strong>Igny8 CRON HANDLER: Processing</strong> " . count($keyword_ids) . " keywords<br>";
|
|
|
|
// Log automation start
|
|
echo "<strong>Igny8 CRON HANDLER: Logging automation start</strong><br>";
|
|
igny8_log_ai_event('Auto Cluster Started', 'planner', 'auto_cluster', 'info', 'Starting automated clustering', 'Keywords: ' . count($keyword_ids));
|
|
|
|
// Direct clustering without AJAX simulation
|
|
echo "<strong>Igny8 CRON HANDLER: Starting direct clustering process</strong><br>";
|
|
|
|
// Set up user context for permissions
|
|
if (!current_user_can('manage_options')) {
|
|
// Get admin user for cron context
|
|
$admin_users = get_users(['role' => 'administrator', 'number' => 1]);
|
|
if (!empty($admin_users)) {
|
|
wp_set_current_user($admin_users[0]->ID);
|
|
echo "<strong>Igny8 CRON HANDLER: Set admin user context for permissions</strong><br>";
|
|
}
|
|
}
|
|
|
|
// Get keywords data
|
|
echo "<strong>Igny8 CRON HANDLER: Getting keywords data</strong><br>";
|
|
$placeholders = implode(',', array_fill(0, count($keyword_ids), '%d'));
|
|
$keywords = $wpdb->get_results($wpdb->prepare("
|
|
SELECT * FROM {$wpdb->prefix}igny8_keywords
|
|
WHERE id IN ({$placeholders})
|
|
", $keyword_ids));
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Found " . count($keywords) . " keywords in database</strong><br>";
|
|
|
|
if (empty($keywords)) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - No valid keywords found</strong><br>";
|
|
igny8_log_ai_event('Auto Cluster Failed', 'planner', 'auto_cluster', 'error', 'No valid keywords found in database', 'Keyword IDs: ' . implode(',', $keyword_ids));
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
|
|
// Check if keywords already have clusters
|
|
$keywords_with_clusters = array_filter($keywords, function($keyword) {
|
|
return !empty($keyword->cluster_id) && $keyword->cluster_id > 0;
|
|
});
|
|
|
|
if (!empty($keywords_with_clusters)) {
|
|
echo "<strong>Igny8 CRON HANDLER: WARNING - Some keywords already have clusters</strong><br>";
|
|
$keyword_names = array_column($keywords_with_clusters, 'keyword');
|
|
echo "<strong>Igny8 CRON HANDLER: Already clustered: " . implode(', ', array_slice($keyword_names, 0, 3)) . "</strong><br>";
|
|
}
|
|
|
|
// Get clustering prompt
|
|
echo "<strong>Igny8 CRON HANDLER: Getting clustering prompt</strong><br>";
|
|
$prompt_template = wp_unslash(igny8_get_ai_setting('clustering_prompt', igny8_get_default_clustering_prompt()));
|
|
echo "<strong>Igny8 CRON HANDLER: Prompt length: " . strlen($prompt_template) . "</strong><br>";
|
|
|
|
// Generate session ID for progress tracking
|
|
$session_id = 'cron_clustering_' . time() . '_' . wp_generate_password(8, false);
|
|
echo "<strong>Igny8 CRON HANDLER: Session ID: " . $session_id . "</strong><br>";
|
|
|
|
// Log AI request initiation
|
|
igny8_log_ai_event('Cron AI Request Initiated', 'planner', 'clustering', 'info', 'Starting cron AI clustering process', 'Keywords: ' . count($keyword_ids) . ', Session: ' . $session_id);
|
|
|
|
// Process with AI
|
|
echo "<strong>Igny8 CRON HANDLER: Calling AI processing</strong><br>";
|
|
try {
|
|
$ai_result = igny8_process_ai_request('clustering', $keywords, $prompt_template);
|
|
echo "<strong>Igny8 CRON HANDLER: AI processing completed</strong><br>";
|
|
|
|
if ($ai_result === false) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - AI processing returned false</strong><br>";
|
|
igny8_log_ai_event('Cron AI Processing Failed', 'planner', 'clustering', 'error', 'AI processing returned false', 'Check OpenAI API configuration');
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
|
|
if (!is_array($ai_result) || !isset($ai_result['clusters'])) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - AI returned invalid result</strong><br>";
|
|
igny8_log_ai_event('Cron AI Processing Failed', 'planner', 'clustering', 'error', 'AI returned invalid result', 'Result type: ' . gettype($ai_result));
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: AI returned " . count($ai_result['clusters']) . " clusters</strong><br>";
|
|
|
|
// Debug: Show AI response structure
|
|
echo "<strong>Igny8 CRON HANDLER: AI Response Debug:</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Full AI result structure:</strong> " . json_encode($ai_result, JSON_PRETTY_PRINT) . "<br>";
|
|
|
|
igny8_log_ai_event('Cron AI Processing Complete', 'planner', 'clustering', 'success', 'AI returned ' . count($ai_result['clusters']) . ' clusters', 'Clusters: ' . json_encode(array_column($ai_result['clusters'], 'name')));
|
|
|
|
// Log database operations start
|
|
echo "<strong>Igny8 CRON HANDLER: Starting database operations</strong><br>";
|
|
igny8_log_ai_event('Cron Database Operations Started', 'planner', 'clustering', 'info', 'Starting to create clusters in database', 'Clusters to create: ' . count($ai_result['clusters']));
|
|
|
|
// Get sector options for assignment logic (same as AJAX handler)
|
|
echo "<strong>Igny8 CRON HANDLER: Getting sector options for assignment</strong><br>";
|
|
$sector_options = igny8_get_sector_options();
|
|
$sector_count = count($sector_options);
|
|
echo "<strong>Igny8 CRON HANDLER: Found " . $sector_count . " sectors</strong><br>";
|
|
|
|
// Create clusters in database (following AJAX handler process)
|
|
$created_clusters = [];
|
|
$clusters_created = 0;
|
|
$keywords_processed = 0;
|
|
|
|
foreach ($ai_result['clusters'] as $cluster_data) {
|
|
echo "<strong>Igny8 CRON HANDLER: Processing cluster: " . $cluster_data['name'] . "</strong><br>";
|
|
|
|
try {
|
|
|
|
// Determine sector_id based on sector count (same logic as AJAX handler)
|
|
$sector_id = 1; // Default fallback
|
|
echo "<strong>Igny8 CRON HANDLER: Determining sector assignment</strong><br>";
|
|
|
|
if ($sector_count == 1) {
|
|
// Only 1 sector: assign all clusters to that sector
|
|
$sector_id = $sector_options[0]['value'];
|
|
echo "<strong>Igny8 CRON HANDLER: Single sector found, assigning to sector ID: " . $sector_id . "</strong><br>";
|
|
} elseif ($sector_count > 1) {
|
|
// Multiple sectors: use AI response sector assignment
|
|
if (isset($cluster_data['sector']) && !empty($cluster_data['sector'])) {
|
|
echo "<strong>Igny8 CRON HANDLER: AI provided sector: " . $cluster_data['sector'] . "</strong><br>";
|
|
// Find sector ID by matching sector name from AI response
|
|
foreach ($sector_options as $sector) {
|
|
if (strtolower(trim($sector['label'])) === strtolower(trim($cluster_data['sector']))) {
|
|
$sector_id = $sector['value'];
|
|
echo "<strong>Igny8 CRON HANDLER: Matched sector ID: " . $sector_id . "</strong><br>";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// If no match found or no sector in AI response, use first sector as fallback
|
|
if ($sector_id == 1 && !isset($cluster_data['sector'])) {
|
|
$sector_id = $sector_options[0]['value'];
|
|
echo "<strong>Igny8 CRON HANDLER: No sector match, using first sector ID: " . $sector_id . "</strong><br>";
|
|
}
|
|
}
|
|
|
|
// Create cluster record in database (same as AJAX handler)
|
|
echo "<strong>Igny8 CRON HANDLER: Creating cluster record in database</strong><br>";
|
|
$result = $wpdb->insert(
|
|
$wpdb->prefix . 'igny8_clusters',
|
|
[
|
|
'cluster_name' => sanitize_text_field($cluster_data['name']),
|
|
'sector_id' => $sector_id,
|
|
'status' => 'active',
|
|
'keyword_count' => count($cluster_data['keywords']),
|
|
'total_volume' => 0,
|
|
'avg_difficulty' => 0,
|
|
'mapped_pages_count' => 0,
|
|
'created_at' => current_time('mysql')
|
|
],
|
|
['%s', '%d', '%s', '%d', '%d', '%f', '%d', '%s']
|
|
);
|
|
|
|
if ($result) {
|
|
$cluster_id = $wpdb->insert_id;
|
|
$created_clusters[] = $cluster_id;
|
|
$clusters_created++;
|
|
echo "<strong>Igny8 CRON HANDLER: SUCCESS - Created cluster record with ID: " . $cluster_id . "</strong><br>";
|
|
|
|
// Trigger taxonomy term creation for AI-generated cluster (same as AJAX handler)
|
|
echo "<strong>Igny8 CRON HANDLER: Triggering taxonomy term creation</strong><br>";
|
|
try {
|
|
do_action('igny8_cluster_added', $cluster_id);
|
|
echo "<strong>Igny8 CRON HANDLER: SUCCESS - Taxonomy term creation triggered</strong><br>";
|
|
igny8_log_ai_event('Cron Cluster Taxonomy Triggered', 'planner', 'clustering', 'info', 'Triggered igny8_cluster_added action', "Cluster: {$cluster_data['name']} (ID: {$cluster_id})");
|
|
} catch (Exception $e) {
|
|
echo "<strong>Igny8 CRON HANDLER: WARNING - Taxonomy term creation failed: " . $e->getMessage() . "</strong><br>";
|
|
igny8_log_ai_event('Cron Cluster Taxonomy Failed', 'planner', 'clustering', 'warning', 'Taxonomy term creation failed', "Cluster: {$cluster_data['name']} (ID: {$cluster_id}), Error: " . $e->getMessage());
|
|
} catch (Throwable $e) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - Fatal error in taxonomy term creation: " . $e->getMessage() . "</strong><br>";
|
|
igny8_log_ai_event('Cron Cluster Taxonomy Fatal Error', 'planner', 'clustering', 'error', 'Fatal error in taxonomy term creation', "Cluster: {$cluster_data['name']} (ID: {$cluster_id}), Error: " . $e->getMessage());
|
|
}
|
|
|
|
// Log cluster creation
|
|
igny8_log_ai_event('Cron Cluster Created', 'planner', 'clustering', 'success', 'Cluster created successfully', "Cluster: {$cluster_data['name']} (ID: {$cluster_id})");
|
|
|
|
// Update keywords with cluster_id (same as AJAX handler)
|
|
if (isset($cluster_data['keywords']) && is_array($cluster_data['keywords'])) {
|
|
echo "<strong>Igny8 CRON HANDLER: Processing " . count($cluster_data['keywords']) . " keywords for this cluster</strong><br>";
|
|
|
|
foreach ($cluster_data['keywords'] as $keyword_name) {
|
|
echo "<strong>Igny8 CRON HANDLER: Looking for keyword: " . $keyword_name . "</strong><br>";
|
|
|
|
$update_result = $wpdb->update(
|
|
$wpdb->prefix . 'igny8_keywords',
|
|
['cluster_id' => $cluster_id],
|
|
['keyword' => $keyword_name],
|
|
['%d'],
|
|
['%s']
|
|
);
|
|
|
|
if ($update_result !== false) {
|
|
$keywords_processed++;
|
|
echo "<strong>Igny8 CRON HANDLER: SUCCESS - Assigned keyword '" . $keyword_name . "' to cluster ID " . $cluster_id . "</strong><br>";
|
|
} else {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - Failed to update keyword '" . $keyword_name . "': " . $wpdb->last_error . "</strong><br>";
|
|
}
|
|
}
|
|
|
|
// Log keyword updates
|
|
igny8_log_ai_event('Cron Keywords Updated', 'planner', 'clustering', 'success', 'Keywords assigned to cluster', "Cluster: {$cluster_data['name']}, Keywords: " . count($cluster_data['keywords']));
|
|
} else {
|
|
echo "<strong>Igny8 CRON HANDLER: WARNING - No keywords found in cluster data</strong><br>";
|
|
}
|
|
|
|
// Update cluster metrics (same as AJAX handler)
|
|
echo "<strong>Igny8 CRON HANDLER: Updating cluster metrics</strong><br>";
|
|
try {
|
|
$metrics_result = igny8_update_cluster_metrics($cluster_id);
|
|
if ($metrics_result) {
|
|
echo "<strong>Igny8 CRON HANDLER: SUCCESS - Cluster metrics updated</strong><br>";
|
|
igny8_log_ai_event('Cron Metrics Updated', 'planner', 'clustering', 'success', 'Cluster metrics calculated', "Cluster: {$cluster_data['name']}");
|
|
} else {
|
|
echo "<strong>Igny8 CRON HANDLER: WARNING - Failed to update cluster metrics</strong><br>";
|
|
igny8_log_ai_event('Cron Metrics Update Failed', 'planner', 'clustering', 'warning', 'Failed to update cluster metrics', "Cluster: {$cluster_data['name']}");
|
|
}
|
|
} catch (Exception $e) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - Exception during metrics update: " . $e->getMessage() . "</strong><br>";
|
|
igny8_log_ai_event('Cron Metrics Update Error', 'planner', 'clustering', 'error', 'Exception during metrics update', "Cluster: {$cluster_data['name']}, Error: " . $e->getMessage());
|
|
}
|
|
} else {
|
|
// Log cluster creation failure
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - Failed to create cluster record: " . $wpdb->last_error . "</strong><br>";
|
|
igny8_log_ai_event('Cron Cluster Creation Failed', 'planner', 'clustering', 'error', 'Failed to create cluster in database', "Cluster: {$cluster_data['name']}, Error: " . $wpdb->last_error);
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - Exception processing cluster '{$cluster_data['name']}': " . $e->getMessage() . "</strong><br>";
|
|
igny8_log_ai_event('Cron Cluster Processing Error', 'planner', 'clustering', 'error', 'Exception processing cluster', "Cluster: {$cluster_data['name']}, Error: " . $e->getMessage());
|
|
echo "<strong>Igny8 CRON HANDLER: Continuing with next cluster</strong><br>";
|
|
continue;
|
|
} catch (Throwable $e) {
|
|
echo "<strong>Igny8 CRON HANDLER: FATAL ERROR - Fatal error processing cluster '{$cluster_data['name']}': " . $e->getMessage() . "</strong><br>";
|
|
igny8_log_ai_event('Cron Cluster Processing Fatal Error', 'planner', 'clustering', 'error', 'Fatal error processing cluster', "Cluster: {$cluster_data['name']}, Error: " . $e->getMessage());
|
|
echo "<strong>Igny8 CRON HANDLER: Continuing with next cluster</strong><br>";
|
|
continue;
|
|
}
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Clustering completed successfully</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Database clusters created: " . $clusters_created . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Keywords processed: " . $keywords_processed . "</strong><br>";
|
|
|
|
// Verify the results by checking database
|
|
echo "<strong>Igny8 CRON HANDLER: Verifying results in database</strong><br>";
|
|
$verify_clusters = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_clusters WHERE status = 'active'");
|
|
$verify_keywords = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_keywords WHERE cluster_id IS NOT NULL AND cluster_id > 0");
|
|
$verify_taxonomy_terms = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->terms} t INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id WHERE tt.taxonomy = 'clusters'");
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Total active clusters in database: " . $verify_clusters . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Total clustered keywords in database: " . $verify_keywords . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Total taxonomy terms for clusters: " . $verify_taxonomy_terms . "</strong><br>";
|
|
|
|
// Log completion with verification
|
|
igny8_log_ai_event('Cron Auto Cluster Complete', 'planner', 'auto_cluster', 'success', 'Cron automated clustering completed', 'Database clusters: ' . $clusters_created . ', Keywords processed: ' . $keywords_processed . ', Verified clusters: ' . $verify_clusters . ', Verified keywords: ' . $verify_keywords . ', Verified taxonomy terms: ' . $verify_taxonomy_terms);
|
|
|
|
// Set global variables for detailed logging
|
|
$GLOBALS['igny8_cron_processed_count'] = $keywords_processed;
|
|
$GLOBALS['igny8_cron_result_details'] = "Processed {$keywords_processed} keywords, created {$clusters_created} clusters";
|
|
|
|
} catch (Exception $e) {
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - Exception during AI processing:</strong> " . $e->getMessage() . "<br>";
|
|
igny8_log_ai_event('Cron Auto Cluster Failed', 'planner', 'auto_cluster', 'error', 'Exception during AI processing', $e->getMessage());
|
|
|
|
// Set global variables for detailed logging (failure case)
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: " . $e->getMessage();
|
|
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: auto_cluster completed</strong><br>";
|
|
echo "</div>"; // Close the handler div
|
|
|
|
// Restore error reporting
|
|
error_reporting($old_error_reporting);
|
|
}
|
|
|
|
/**
|
|
* Auto Generate Ideas Cron Handler
|
|
*
|
|
* Automatically generates ideas from clusters without ideas.
|
|
*/
|
|
function igny8_auto_generate_ideas_cron_handler() {
|
|
// Suppress PHP warnings for model rates in cron context
|
|
$old_error_reporting = error_reporting();
|
|
error_reporting($old_error_reporting & ~E_WARNING);
|
|
|
|
echo "<div style='background:#e8f4fd;padding:10px;margin:5px;border:1px solid #2196F3;'>";
|
|
echo "<strong>Igny8 CRON HANDLER: auto_generate_ideas started</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: auto_generate_ideas started");
|
|
|
|
// Check if automation is enabled via cron settings
|
|
echo "<strong>Igny8 CRON HANDLER: Checking if automation is enabled</strong><br>";
|
|
$cron_settings = get_option('igny8_cron_settings', []);
|
|
$job_settings = $cron_settings['igny8_auto_generate_ideas_cron'] ?? [];
|
|
$auto_ideas_enabled = $job_settings['enabled'] ?? false;
|
|
echo "<strong>Igny8 CRON HANDLER: auto_ideas_enabled =</strong> " . ($auto_ideas_enabled ? 'enabled' : 'disabled') . "<br>";
|
|
|
|
if (!$auto_ideas_enabled) {
|
|
echo "<strong>Igny8 CRON HANDLER: Automation disabled, exiting</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: auto_generate_ideas automation disabled");
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Automation enabled, continuing</strong><br>";
|
|
|
|
// Check if AI mode is enabled
|
|
echo "<strong>Igny8 CRON HANDLER: Checking AI mode</strong><br>";
|
|
$planner_mode = igny8_get_ai_setting('planner_mode', 'manual');
|
|
echo "<strong>Igny8 CRON HANDLER: planner_mode =</strong> " . $planner_mode . "<br>";
|
|
|
|
if ($planner_mode !== 'ai') {
|
|
echo "<strong>Igny8 CRON HANDLER: AI mode disabled, exiting</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: AI mode disabled");
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: AI mode enabled, continuing</strong><br>";
|
|
|
|
global $wpdb;
|
|
echo "<strong>Igny8 CRON HANDLER: Database connection established</strong><br>";
|
|
|
|
// Get clusters without ideas (use dynamic limit from settings)
|
|
$limit = $GLOBALS['igny8_cron_limit'] ?? null;
|
|
if ($limit === null) {
|
|
error_log('Igny8 Auto Cluster Cron: No limit set in Smart Automation Jobs table');
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No limit set in Smart Automation Jobs table";
|
|
return;
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Querying clusters without ideas (limit: $limit)</strong><br>";
|
|
$clusters_without_ideas = $wpdb->get_results("
|
|
SELECT c.id FROM {$wpdb->prefix}igny8_clusters c
|
|
LEFT JOIN {$wpdb->prefix}igny8_content_ideas i ON c.id = i.keyword_cluster_id
|
|
WHERE i.id IS NULL
|
|
LIMIT $limit
|
|
");
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Found</strong> " . count($clusters_without_ideas) . " clusters without ideas<br>";
|
|
|
|
if (empty($clusters_without_ideas)) {
|
|
echo "<strong>Igny8 CRON HANDLER: No clusters without ideas found, exiting</strong><br>";
|
|
igny8_log_ai_event('Auto Generate Ideas Skipped', 'planner', 'auto_generate_ideas', 'info', 'No clusters without ideas found', 'All clusters already have ideas');
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
|
|
$cluster_ids = array_column($clusters_without_ideas, 'id');
|
|
echo "<strong>Igny8 CRON HANDLER: Processing</strong> " . count($cluster_ids) . " clusters<br>";
|
|
|
|
// Log automation start
|
|
echo "<strong>Igny8 CRON HANDLER: Logging automation start</strong><br>";
|
|
igny8_log_ai_event('Auto Generate Ideas Started', 'planner', 'auto_generate_ideas', 'info', 'Starting automated idea generation', 'Clusters: ' . count($cluster_ids));
|
|
|
|
// Set up user context for permissions
|
|
echo "<strong>Igny8 CRON HANDLER: Setting up user context</strong><br>";
|
|
if (!current_user_can('manage_options')) {
|
|
// Get admin user for cron context
|
|
$admin_users = get_users(['role' => 'administrator', 'number' => 1]);
|
|
if (!empty($admin_users)) {
|
|
wp_set_current_user($admin_users[0]->ID);
|
|
echo "<strong>Igny8 CRON HANDLER: Set admin user context for permissions</strong><br>";
|
|
}
|
|
}
|
|
|
|
// Simulate AJAX request to existing AI function
|
|
echo "<strong>Igny8 CRON HANDLER: Starting AJAX simulation</strong><br>";
|
|
$_POST['cluster_ids'] = json_encode($cluster_ids);
|
|
$_POST['nonce'] = wp_create_nonce('igny8_planner_settings');
|
|
|
|
// Capture output to prevent JSON response in cron
|
|
ob_start();
|
|
igny8_ajax_ai_generate_ideas();
|
|
$output = ob_get_clean();
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: AJAX execution completed</strong><br>";
|
|
|
|
// Parse JSON response
|
|
$response = json_decode($output, true);
|
|
echo "<strong>Igny8 CRON HANDLER: Response parsed, success =</strong> " . ($response['success'] ?? 'false') . "<br>";
|
|
|
|
if ($response && $response['success']) {
|
|
$ideas_created = $response['data']['ideas_created'] ?? count($cluster_ids);
|
|
echo "<strong>Igny8 CRON HANDLER: SUCCESS - Ideas generated: " . $ideas_created . "</strong><br>";
|
|
igny8_log_ai_event('Auto Generate Ideas Complete', 'planner', 'auto_generate_ideas', 'success', 'Automated idea generation completed', 'Ideas created: ' . $ideas_created);
|
|
|
|
// Set global variables for detailed logging
|
|
$GLOBALS['igny8_cron_processed_count'] = $ideas_created;
|
|
$GLOBALS['igny8_cron_result_details'] = "Processed {$ideas_created} clusters, created {$ideas_created} ideas";
|
|
} else {
|
|
$error_msg = $response['data']['message'] ?? 'Unknown error';
|
|
echo "<strong>Igny8 CRON HANDLER: ERROR - " . $error_msg . "</strong><br>";
|
|
igny8_log_ai_event('Auto Generate Ideas Failed', 'planner', 'auto_generate_ideas', 'error', 'Automated idea generation failed', $error_msg);
|
|
|
|
// Set global variables for detailed logging (failure case)
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: " . $error_msg;
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: auto_generate_ideas completed</strong><br>";
|
|
echo "</div>"; // Close the handler div
|
|
|
|
// Restore error reporting
|
|
error_reporting($old_error_reporting);
|
|
}
|
|
|
|
/**
|
|
* Auto Queue Cron Handler
|
|
*
|
|
* Automatically queues new ideas for content generation.
|
|
*/
|
|
function igny8_auto_queue_cron_handler() {
|
|
// Suppress PHP warnings for model rates in cron context
|
|
$old_error_reporting = error_reporting();
|
|
error_reporting($old_error_reporting & ~E_WARNING);
|
|
|
|
echo "<div style='background:#e8f4fd;padding:10px;margin:5px;border:1px solid #2196F3;'>";
|
|
echo "<strong>Igny8 CRON HANDLER: auto_queue started</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: auto_queue started");
|
|
|
|
// Check if automation is enabled via cron settings
|
|
echo "<strong>Igny8 CRON HANDLER: Checking if automation is enabled</strong><br>";
|
|
$cron_settings = get_option('igny8_cron_settings', []);
|
|
$job_settings = $cron_settings['igny8_auto_queue_cron'] ?? [];
|
|
$auto_queue_enabled = $job_settings['enabled'] ?? false;
|
|
echo "<strong>Igny8 CRON HANDLER: auto_queue_enabled =</strong> " . ($auto_queue_enabled ? 'enabled' : 'disabled') . "<br>";
|
|
|
|
if (!$auto_queue_enabled) {
|
|
echo "<strong>Igny8 CRON HANDLER: Automation disabled, exiting</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: auto_queue automation disabled");
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Automation enabled, continuing</strong><br>";
|
|
|
|
global $wpdb;
|
|
echo "<strong>Igny8 CRON HANDLER: Database connection established</strong><br>";
|
|
|
|
// Get new ideas (use dynamic limit from settings)
|
|
$limit = $GLOBALS['igny8_cron_limit'] ?? null;
|
|
if ($limit === null) {
|
|
// Try to get limit from Smart Automation Jobs table directly
|
|
$cron_limits = get_option('igny8_cron_limits', []);
|
|
$limit = $cron_limits['igny8_auto_queue_cron'] ?? null;
|
|
|
|
if ($limit === null) {
|
|
error_log('Igny8 Auto Queue Cron: No limit set in Smart Automation Jobs table');
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No limit set in Smart Automation Jobs table";
|
|
return;
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Using limit from Smart Automation Jobs table: $limit</strong><br>";
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Querying new ideas (limit: $limit)</strong><br>";
|
|
$new_ideas = $wpdb->get_results("
|
|
SELECT id FROM {$wpdb->prefix}igny8_content_ideas
|
|
WHERE status = 'new'
|
|
LIMIT $limit
|
|
");
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Found</strong> " . count($new_ideas) . " new ideas<br>";
|
|
|
|
if (empty($new_ideas)) {
|
|
echo "<strong>Igny8 CRON HANDLER: No new ideas found, exiting</strong><br>";
|
|
igny8_log_ai_event('Auto Queue Skipped', 'planner', 'auto_queue', 'info', 'No new ideas found', 'All ideas are already queued');
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
|
|
$idea_ids = array_column($new_ideas, 'id');
|
|
echo "<strong>Igny8 CRON HANDLER: Processing</strong> " . count($idea_ids) . " ideas<br>";
|
|
|
|
// Log automation start
|
|
echo "<strong>Igny8 CRON HANDLER: Logging automation start</strong><br>";
|
|
igny8_log_ai_event('Auto Queue Started', 'planner', 'auto_queue', 'info', 'Starting automated queueing', 'Ideas: ' . count($idea_ids));
|
|
|
|
// Set up user context for permissions
|
|
echo "<strong>Igny8 CRON HANDLER: Setting up user context</strong><br>";
|
|
if (!current_user_can('edit_posts')) {
|
|
// Get admin user for cron context
|
|
$admin_users = get_users(['role' => 'administrator', 'number' => 1]);
|
|
if (!empty($admin_users)) {
|
|
wp_set_current_user($admin_users[0]->ID);
|
|
echo "<strong>Igny8 CRON HANDLER: Set admin user context for permissions</strong><br>";
|
|
}
|
|
}
|
|
|
|
// Skip AJAX simulation and go directly to function calls
|
|
// (AJAX has issues in cron context with nonce verification)
|
|
echo "<strong>Igny8 CRON HANDLER: Skipping AJAX simulation (cron context issues)</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Using direct function calls</strong><br>";
|
|
|
|
$created = [];
|
|
$skipped = [];
|
|
$failed = [];
|
|
|
|
foreach ($idea_ids as $idea_id) {
|
|
echo "<strong>Igny8 CRON HANDLER: Processing idea ID: " . $idea_id . "</strong><br>";
|
|
$result = igny8_create_task_from_idea($idea_id);
|
|
|
|
if ($result['success']) {
|
|
if (!empty($result['task_id'])) {
|
|
$created[] = $result['task_id'];
|
|
echo "<strong>Igny8 CRON HANDLER: SUCCESS - Created task ID: " . $result['task_id'] . "</strong><br>";
|
|
} else {
|
|
$skipped[] = $idea_id;
|
|
echo "<strong>Igny8 CRON HANDLER: SKIPPED - " . $result['message'] . "</strong><br>";
|
|
}
|
|
} else {
|
|
$failed[] = $idea_id;
|
|
echo "<strong>Igny8 CRON HANDLER: FAILED - " . $result['message'] . "</strong><br>";
|
|
}
|
|
}
|
|
|
|
// Update metrics for processed ideas
|
|
foreach ($idea_ids as $idea_id) {
|
|
igny8_update_idea_metrics($idea_id);
|
|
}
|
|
|
|
$created_count = count($created);
|
|
$skipped_count = count($skipped);
|
|
$failed_count = count($failed);
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: DIRECT SUCCESS - Tasks created: " . $created_count . ", Skipped: " . $skipped_count . ", Failed: " . $failed_count . "</strong><br>";
|
|
igny8_log_ai_event('Auto Queue Complete', 'planner', 'auto_queue', 'success', 'Automated queueing completed (direct)', 'Tasks created: ' . $created_count . ', Skipped: ' . $skipped_count . ', Failed: ' . $failed_count);
|
|
|
|
// Set global variables for detailed logging
|
|
$GLOBALS['igny8_cron_processed_count'] = $created_count;
|
|
$GLOBALS['igny8_cron_result_details'] = "Processed {$created_count} ideas, created {$created_count} tasks";
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: auto_queue completed</strong><br>";
|
|
echo "</div>"; // Close the handler div
|
|
|
|
// Restore error reporting
|
|
error_reporting($old_error_reporting);
|
|
}
|
|
|
|
/**
|
|
* Auto Generate Content Cron Handler
|
|
*
|
|
* Automatically generates content from queued tasks.
|
|
*/
|
|
function igny8_auto_generate_content_cron_handler() {
|
|
// Suppress PHP warnings for model rates in cron context
|
|
$old_error_reporting = error_reporting();
|
|
error_reporting($old_error_reporting & ~E_WARNING);
|
|
|
|
echo "<div style='background:#e8f4fd;padding:10px;margin:5px;border:1px solid #2196F3;'>";
|
|
echo "<strong>Igny8 CRON HANDLER: auto_generate_content started</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: auto_generate_content started");
|
|
|
|
// Check if automation is enabled via cron settings
|
|
echo "<strong>Igny8 CRON HANDLER: Checking if automation is enabled</strong><br>";
|
|
$cron_settings = get_option('igny8_cron_settings', []);
|
|
$job_settings = $cron_settings['igny8_auto_generate_content_cron'] ?? [];
|
|
$auto_content_enabled = $job_settings['enabled'] ?? false;
|
|
echo "<strong>Igny8 CRON HANDLER: auto_content_enabled =</strong> " . ($auto_content_enabled ? 'enabled' : 'disabled') . "<br>";
|
|
|
|
if (!$auto_content_enabled) {
|
|
echo "<strong>Igny8 CRON HANDLER: Automation disabled, exiting</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: auto_generate_content automation disabled");
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Automation enabled, continuing</strong><br>";
|
|
|
|
// Check if AI mode is enabled
|
|
echo "<strong>Igny8 CRON HANDLER: Checking AI mode</strong><br>";
|
|
$writer_mode = igny8_get_ai_setting('writer_mode', 'manual');
|
|
echo "<strong>Igny8 CRON HANDLER: writer_mode =</strong> " . $writer_mode . "<br>";
|
|
|
|
if ($writer_mode !== 'ai') {
|
|
echo "<strong>Igny8 CRON HANDLER: AI mode disabled, exiting</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: AI mode disabled");
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: AI mode enabled, continuing</strong><br>";
|
|
|
|
global $wpdb;
|
|
echo "<strong>Igny8 CRON HANDLER: Database connection established</strong><br>";
|
|
|
|
// Get queued tasks (use dynamic limit from settings)
|
|
$limit = $GLOBALS['igny8_cron_limit'] ?? null;
|
|
if ($limit === null) {
|
|
// Try to get limit from Smart Automation Jobs table directly
|
|
$cron_limits = get_option('igny8_cron_limits', []);
|
|
$limit = $cron_limits['igny8_auto_generate_content_cron'] ?? null;
|
|
|
|
if ($limit === null) {
|
|
error_log('Igny8 Auto Generate Content Cron: No limit set in Smart Automation Jobs table');
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No limit set in Smart Automation Jobs table";
|
|
return;
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Using limit from Smart Automation Jobs table: $limit</strong><br>";
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Querying queued tasks (limit: $limit)</strong><br>";
|
|
$queued_tasks = $wpdb->get_results("
|
|
SELECT id FROM {$wpdb->prefix}igny8_tasks
|
|
WHERE status = 'queued'
|
|
LIMIT $limit
|
|
");
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Found</strong> " . count($queued_tasks) . " queued tasks<br>";
|
|
|
|
if (empty($queued_tasks)) {
|
|
echo "<strong>Igny8 CRON HANDLER: No queued tasks found, exiting</strong><br>";
|
|
igny8_log_ai_event('Auto Generate Content Skipped', 'writer', 'auto_generate_content', 'info', 'No queued tasks found', 'All tasks are already processed');
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
|
|
$task_ids = array_column($queued_tasks, 'id');
|
|
echo "<strong>Igny8 CRON HANDLER: Processing</strong> " . count($task_ids) . " tasks<br>";
|
|
|
|
// Log automation start
|
|
echo "<strong>Igny8 CRON HANDLER: Logging automation start</strong><br>";
|
|
igny8_log_ai_event('Auto Generate Content Started', 'writer', 'auto_generate_content', 'info', 'Starting automated content generation', 'Tasks: ' . count($task_ids));
|
|
|
|
// Set up user context for permissions
|
|
echo "<strong>Igny8 CRON HANDLER: Setting up user context</strong><br>";
|
|
if (!current_user_can('manage_options')) {
|
|
// Get admin user for cron context
|
|
$admin_users = get_users(['role' => 'administrator', 'number' => 1]);
|
|
if (!empty($admin_users)) {
|
|
wp_set_current_user($admin_users[0]->ID);
|
|
echo "<strong>Igny8 CRON HANDLER: Set admin user context for permissions</strong><br>";
|
|
}
|
|
}
|
|
|
|
$completed = 0;
|
|
$failed = 0;
|
|
|
|
foreach ($task_ids as $task_id) {
|
|
echo "<h3 style='color: #2196F3; border-bottom: 2px solid #2196F3; padding: 10px 0; margin: 20px 0 10px 0;'>📋 SECTION 1: PROCESSING TASK " . $task_id . "</h3>";
|
|
echo "<strong>Igny8 CRON HANDLER: Processing task ID: " . $task_id . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Sending to AI for content generation...</strong><br>";
|
|
|
|
// Log AI request initiation
|
|
igny8_log_ai_event('AI Request Initiated', 'writer', 'auto_content_generation', 'info', 'Starting AI content generation', 'Task ID: ' . $task_id);
|
|
|
|
// Get AI configuration for logging
|
|
$api_key = get_option('igny8_api_key');
|
|
$model = get_option('igny8_model', 'gpt-4.1');
|
|
|
|
// Log AI request details
|
|
echo "<strong>Igny8 CRON HANDLER: AI Request Details - Model: " . $model . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: API Key Status: " . (empty($api_key) ? 'Missing' : 'Configured') . "</strong><br>";
|
|
igny8_log_ai_event('AI Request Details', 'writer', 'auto_content_generation', 'info', 'AI request configuration', 'Model: ' . $model . ', API Key: ' . (empty($api_key) ? 'Missing' : 'Configured'));
|
|
|
|
// Log the actual AI request being made
|
|
echo "<strong>Igny8 CRON HANDLER: Making AI API call to OpenAI...</strong><br>";
|
|
igny8_log_ai_event('AI API Call', 'writer', 'auto_content_generation', 'info', 'Calling OpenAI API', 'Model: ' . $model . ', Task: ' . $task_id);
|
|
|
|
// Simulate AJAX request to content generation function
|
|
$_POST['task_id'] = $task_id;
|
|
$_POST['nonce'] = wp_create_nonce('igny8_writer_settings');
|
|
|
|
// Capture the response from AI call
|
|
ob_start();
|
|
igny8_ajax_ai_generate_content();
|
|
$ai_response = ob_get_clean();
|
|
|
|
// Log AI response
|
|
echo "<strong>Igny8 CRON HANDLER: AI Response received</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Response Length: " . strlen($ai_response) . " characters</strong><br>";
|
|
igny8_log_ai_event('AI Response Received', 'writer', 'auto_content_generation', 'info', 'AI processing completed', 'Response captured for task: ' . $task_id);
|
|
|
|
// Parse the AI response to extract success/error status
|
|
$json_response = null;
|
|
$response_status = 'unknown';
|
|
$error_message = '';
|
|
|
|
// Try multiple methods to extract JSON from response
|
|
if (preg_match('/\{.*\}/s', $ai_response, $matches)) {
|
|
$json_response = json_decode($matches[0], true);
|
|
}
|
|
|
|
// If no JSON found, try to detect response type from content
|
|
if (!$json_response) {
|
|
if (strpos($ai_response, 'success') !== false && strpos($ai_response, 'true') !== false) {
|
|
$response_status = 'success';
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ AI Response - SUCCESS (detected from content)</strong><br>";
|
|
igny8_log_ai_event('AI Response Success', 'writer', 'auto_content_generation', 'success', 'AI content generation successful', 'Task ID: ' . $task_id);
|
|
} elseif (strpos($ai_response, 'error') !== false || strpos($ai_response, 'failed') !== false) {
|
|
$response_status = 'error';
|
|
$error_message = 'Error detected in response content';
|
|
echo "<strong>Igny8 CRON HANDLER: ❌ AI Response - FAILED (detected from content)</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Error: " . $error_message . "</strong><br>";
|
|
igny8_log_ai_event('AI Response Failed', 'writer', 'auto_content_generation', 'error', 'AI content generation failed', 'Task ID: ' . $task_id . ', Error: ' . $error_message);
|
|
} else {
|
|
$response_status = 'unknown';
|
|
echo "<strong>Igny8 CRON HANDLER: ⚠️ AI Response - UNKNOWN FORMAT</strong><br>";
|
|
igny8_log_ai_event('AI Response Unknown', 'writer', 'auto_content_generation', 'warning', 'AI response format not recognized', 'Task ID: ' . $task_id . ', Raw response: ' . substr($ai_response, 0, 200));
|
|
}
|
|
} else {
|
|
// JSON response found, parse it
|
|
if (isset($json_response['success']) && $json_response['success']) {
|
|
$response_status = 'success';
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ AI Response - SUCCESS (JSON parsed)</strong><br>";
|
|
igny8_log_ai_event('AI Response Success', 'writer', 'auto_content_generation', 'success', 'AI content generation successful', 'Task ID: ' . $task_id);
|
|
} else {
|
|
$response_status = 'error';
|
|
$error_message = $json_response['data']['message'] ?? $json_response['message'] ?? 'Unknown error';
|
|
echo "<strong>Igny8 CRON HANDLER: ❌ AI Response - FAILED (JSON parsed)</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Error: " . $error_message . "</strong><br>";
|
|
igny8_log_ai_event('AI Response Failed', 'writer', 'auto_content_generation', 'error', 'AI content generation failed', 'Task ID: ' . $task_id . ', Error: ' . $error_message);
|
|
}
|
|
}
|
|
|
|
// Log response details for debugging
|
|
echo "<strong>Igny8 CRON HANDLER: Response Status: " . $response_status . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Response Length: " . strlen($ai_response) . " characters</strong><br>";
|
|
igny8_log_ai_event('AI Response Analysis', 'writer', 'auto_content_generation', 'info', 'Response analysis completed', 'Status: ' . $response_status . ', Length: ' . strlen($ai_response) . ', Task: ' . $task_id);
|
|
|
|
// Get the actual post ID from the most recently created post by this user
|
|
$recent_posts = get_posts([
|
|
'post_type' => 'post',
|
|
'post_status' => 'draft',
|
|
'author' => get_current_user_id(),
|
|
'numberposts' => 1,
|
|
'orderby' => 'date',
|
|
'order' => 'DESC'
|
|
]);
|
|
|
|
$actual_post_id = !empty($recent_posts) ? $recent_posts[0]->ID : null;
|
|
|
|
$response = ['success' => true, 'data' => ['post_id' => $actual_post_id]];
|
|
|
|
if ($response && $response['success']) {
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ AI Response received successfully</strong><br>";
|
|
|
|
echo "<h3 style='color: #4CAF50; border-bottom: 2px solid #4CAF50; padding: 10px 0; margin: 20px 0 10px 0;'>🔧 SECTION 2: PROCESSING AI RESPONSE & SAVING DATA</h3>";
|
|
echo "<strong>Igny8 CRON HANDLER: Processing AI response data...</strong><br>";
|
|
|
|
// The detailed field processing logs will come from igny8_create_post_from_ai_response function
|
|
// which already has all the debugging output we added
|
|
|
|
echo "<h3 style='color: #FF9800; border-bottom: 2px solid #FF9800; padding: 10px 0; margin: 20px 0 10px 0;'>✅ SECTION 3: FINAL VERIFICATION & SUCCESS SUMMARY</h3>";
|
|
|
|
if (!empty($response['data']['post_id'])) {
|
|
$post_id = $response['data']['post_id'];
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ Post Created Successfully - ID: " . $post_id . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: Checking fields for post ID: " . $post_id . "</strong><br>";
|
|
|
|
// Verify all saved fields
|
|
$meta_title = get_post_meta($post_id, '_igny8_meta_title', true);
|
|
$meta_description = get_post_meta($post_id, '_igny8_meta_description', true);
|
|
$primary_keywords = get_post_meta($post_id, '_igny8_primary_keywords', true);
|
|
$secondary_keywords = get_post_meta($post_id, '_igny8_secondary_keywords', true);
|
|
$word_count = get_post_meta($post_id, '_igny8_word_count', true);
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ Meta Title: " . (!empty($meta_title) ? 'Saved' : 'Missing') . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ Meta Description: " . (!empty($meta_description) ? 'Saved' : 'Missing') . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ Primary Keywords: " . (!empty($primary_keywords) ? 'Saved' : 'Missing') . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ Secondary Keywords: " . (!empty($secondary_keywords) ? 'Saved' : 'Missing') . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ Word Count: " . (!empty($word_count) ? 'Saved' : 'Missing') . "</strong><br>";
|
|
|
|
// Verify taxonomies
|
|
$cluster_terms = wp_get_object_terms($post_id, 'clusters');
|
|
$sector_terms = wp_get_object_terms($post_id, 'sectors');
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ Cluster Taxonomy: " . (!empty($cluster_terms) && !is_wp_error($cluster_terms) ? 'Associated' : 'Not Associated') . "</strong><br>";
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ Sector Taxonomy: " . (!empty($sector_terms) && !is_wp_error($sector_terms) ? 'Associated' : 'Not Associated') . "</strong><br>";
|
|
|
|
// Verify Yoast meta
|
|
$yoast_meta = get_post_meta($post_id, '_yoast_wpseo_metadesc', true);
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ Yoast Meta Description: " . (!empty($yoast_meta) ? 'Saved' : 'Missing') . "</strong><br>";
|
|
|
|
$completed++;
|
|
echo "<strong style='color: #4CAF50; font-size: 16px;'>🎉 TASK " . $task_id . " COMPLETED SUCCESSFULLY!</strong><br>";
|
|
} else {
|
|
echo "<strong style='color: #f44336;'>❌ Post creation failed - No post ID returned</strong><br>";
|
|
$failed++;
|
|
}
|
|
} else {
|
|
$failed++;
|
|
$error_msg = $response['data']['message'] ?? 'Unknown error';
|
|
echo "<strong style='color: #f44336;'>❌ TASK " . $task_id . " FAILED: " . $error_msg . "</strong><br>";
|
|
}
|
|
|
|
echo "<hr style='margin: 30px 0; border: 1px solid #ddd;'>";
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Content generation completed - Success: " . $completed . ", Failed: " . $failed . "</strong><br>";
|
|
|
|
if ($completed > 0) {
|
|
igny8_log_ai_event('Auto Generate Content Complete', 'writer', 'auto_generate_content', 'success', 'Automated content generation completed', 'Content generated: ' . $completed . ', Failed: ' . $failed);
|
|
|
|
// Set global variables for detailed logging
|
|
$GLOBALS['igny8_cron_processed_count'] = $completed;
|
|
$GLOBALS['igny8_cron_result_details'] = "Processed {$completed} tasks, generated {$completed} content pieces";
|
|
echo "<strong>Igny8 AUTO GENERATE CONTENT HANDLER: Set global variables - processed_count: $completed, result_details: Processed {$completed} tasks, generated {$completed} content pieces</strong><br>";
|
|
} else {
|
|
igny8_log_ai_event('Auto Generate Content Failed', 'writer', 'auto_generate_content', 'error', 'Automated content generation failed', 'No content was generated');
|
|
|
|
// Set global variables for detailed logging (failure case)
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No content was generated";
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: auto_generate_content completed</strong><br>";
|
|
echo "</div>"; // Close the handler div
|
|
|
|
// Restore error reporting
|
|
error_reporting($old_error_reporting);
|
|
}
|
|
|
|
/**
|
|
* Auto Publish Drafts Cron Handler
|
|
*
|
|
* Automatically publishes completed draft posts.
|
|
*/
|
|
function igny8_auto_publish_drafts_cron_handler() {
|
|
echo "<div style='background:#e8f4fd;padding:10px;margin:5px;border:1px solid #2196F3;'>";
|
|
echo "<strong>Igny8 CRON HANDLER: auto_publish_drafts started</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: auto_publish_drafts started");
|
|
|
|
// Check if automation is enabled via cron settings
|
|
echo "<strong>Igny8 CRON HANDLER: Checking if automation is enabled</strong><br>";
|
|
$cron_settings = get_option('igny8_cron_settings', []);
|
|
$job_settings = $cron_settings['igny8_auto_publish_drafts_cron'] ?? [];
|
|
$auto_publish_enabled = $job_settings['enabled'] ?? false;
|
|
echo "<strong>Igny8 CRON HANDLER: auto_publish_enabled =</strong> " . ($auto_publish_enabled ? 'enabled' : 'disabled') . "<br>";
|
|
|
|
if (!$auto_publish_enabled) {
|
|
echo "<strong>Igny8 CRON HANDLER: Automation disabled, exiting</strong><br>";
|
|
error_log("Igny8 CRON HANDLER: auto_publish_drafts automation disabled");
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Automation enabled, continuing</strong><br>";
|
|
|
|
global $wpdb;
|
|
|
|
// Get completed tasks with published content (use admin limit)
|
|
$limit = $GLOBALS['igny8_cron_limit'] ?? null;
|
|
if ($limit === null) {
|
|
// Try to get limit from Smart Automation Jobs table directly
|
|
$cron_limits = get_option('igny8_cron_limits', []);
|
|
$limit = $cron_limits['igny8_auto_publish_drafts_cron'] ?? null;
|
|
|
|
if ($limit === null) {
|
|
error_log('Igny8 Auto Publish Drafts Cron: No limit set in Smart Automation Jobs table');
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No limit set in Smart Automation Jobs table";
|
|
return;
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Using limit from Smart Automation Jobs table: $limit</strong><br>";
|
|
}
|
|
echo "<strong>Igny8 CRON HANDLER: Querying completed tasks with draft posts (limit: $limit)</strong><br>";
|
|
$completed_tasks = $wpdb->get_results("
|
|
SELECT t.id, t.assigned_post_id FROM {$wpdb->prefix}igny8_tasks t
|
|
INNER JOIN {$wpdb->posts} p ON t.assigned_post_id = p.ID
|
|
WHERE t.status = 'completed'
|
|
AND p.post_status = 'draft'
|
|
LIMIT $limit
|
|
");
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Found</strong> " . count($completed_tasks) . " completed tasks with draft posts<br>";
|
|
|
|
if (empty($completed_tasks)) {
|
|
echo "<strong>Igny8 CRON HANDLER: No draft posts found, exiting</strong><br>";
|
|
igny8_log_ai_event('Auto Publish Drafts Skipped', 'writer', 'auto_publish_drafts', 'info', 'No draft posts found', 'All content is already published');
|
|
echo "</div>";
|
|
return;
|
|
}
|
|
|
|
$post_ids = array_column($completed_tasks, 'assigned_post_id');
|
|
|
|
// Log automation start
|
|
igny8_log_ai_event('Auto Publish Drafts Started', 'writer', 'auto_publish_drafts', 'info', 'Starting automated publishing', 'Posts: ' . count($post_ids));
|
|
|
|
$published = 0;
|
|
echo "<strong>Igny8 CRON HANDLER: Processing</strong> " . count($post_ids) . " draft posts<br>";
|
|
|
|
foreach ($post_ids as $post_id) {
|
|
echo "<strong>Igny8 CRON HANDLER: Publishing post ID: " . $post_id . "</strong><br>";
|
|
$result = wp_update_post([
|
|
'ID' => $post_id,
|
|
'post_status' => 'publish'
|
|
]);
|
|
|
|
if (!is_wp_error($result) && $result) {
|
|
$published++;
|
|
echo "<strong>Igny8 CRON HANDLER: ✅ SUCCESS - Published post ID: " . $post_id . "</strong><br>";
|
|
} else {
|
|
echo "<strong>Igny8 CRON HANDLER: ❌ FAILED - Could not publish post ID: " . $post_id . "</strong><br>";
|
|
}
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Publishing completed - Published: " . $published . " posts</strong><br>";
|
|
|
|
if ($published > 0) {
|
|
igny8_log_ai_event('Auto Publish Drafts Complete', 'writer', 'auto_publish_drafts', 'success', 'Automated publishing completed', 'Posts published: ' . $published);
|
|
|
|
// Set global variables for detailed logging
|
|
$GLOBALS['igny8_cron_processed_count'] = $published;
|
|
$GLOBALS['igny8_cron_result_details'] = "Processed {$published} drafts, published {$published} posts";
|
|
} else {
|
|
igny8_log_ai_event('Auto Publish Drafts Failed', 'writer', 'auto_publish_drafts', 'error', 'Automated publishing failed', 'No posts were published');
|
|
|
|
// Set global variables for detailed logging (failure case)
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No posts were published";
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: auto_publish_drafts completed</strong><br>";
|
|
echo "</div>"; // Close the handler div
|
|
}
|
|
|
|
/**
|
|
* Auto Optimizer Cron Handler (NEW)
|
|
*
|
|
* Automatically optimizes content and keywords.
|
|
*/
|
|
function igny8_auto_optimizer_cron_handler() {
|
|
// Check if automation is enabled
|
|
if (igny8_get_ai_setting('auto_optimizer_enabled', 'disabled') !== 'enabled') {
|
|
return;
|
|
}
|
|
|
|
global $wpdb;
|
|
|
|
// Get posts that need optimization (use admin limit)
|
|
$limit = $GLOBALS['igny8_cron_limit'] ?? null;
|
|
if ($limit === null) {
|
|
// Try to get limit from Smart Automation Jobs table directly
|
|
$cron_limits = get_option('igny8_cron_limits', []);
|
|
$limit = $cron_limits['igny8_auto_optimizer_cron'] ?? null;
|
|
|
|
if ($limit === null) {
|
|
error_log('Igny8 Auto Optimizer Cron: No limit set in Smart Automation Jobs table');
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No limit set in Smart Automation Jobs table";
|
|
return;
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Using limit from Smart Automation Jobs table: $limit</strong><br>";
|
|
}
|
|
$posts_to_optimize = $wpdb->get_results("
|
|
SELECT p.ID, p.post_title
|
|
FROM {$wpdb->posts} p
|
|
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = 'igny8_optimized'
|
|
WHERE p.post_status = 'publish'
|
|
AND p.post_type IN ('post', 'page')
|
|
AND pm.meta_value IS NULL
|
|
LIMIT $limit
|
|
");
|
|
|
|
if (empty($posts_to_optimize)) {
|
|
igny8_log_ai_event('Auto Optimizer Skipped', 'optimizer', 'auto_optimizer', 'info', 'No posts need optimization', 'All posts are already optimized');
|
|
return;
|
|
}
|
|
|
|
$post_ids = array_column($posts_to_optimize, 'ID');
|
|
|
|
// Log automation start
|
|
igny8_log_ai_event('Auto Optimizer Started', 'optimizer', 'auto_optimizer', 'info', 'Starting automated optimization', 'Posts: ' . count($post_ids));
|
|
|
|
$optimized = 0;
|
|
foreach ($post_ids as $post_id) {
|
|
// Run optimization process
|
|
$result = igny8_optimize_post_content($post_id);
|
|
if ($result['success']) {
|
|
$optimized++;
|
|
// Mark as optimized
|
|
update_post_meta($post_id, 'igny8_optimized', current_time('mysql'));
|
|
}
|
|
}
|
|
|
|
if ($optimized > 0) {
|
|
igny8_log_ai_event('Auto Optimizer Complete', 'optimizer', 'auto_optimizer', 'success', 'Automated optimization completed', 'Posts optimized: ' . $optimized);
|
|
} else {
|
|
igny8_log_ai_event('Auto Optimizer Failed', 'optimizer', 'auto_optimizer', 'error', 'Automated optimization failed', 'No posts were optimized');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Auto Recalc Cron Handler (NEW)
|
|
*
|
|
* Automatically recalculates metrics for all entities.
|
|
*/
|
|
function igny8_auto_recalc_cron_handler() {
|
|
global $wpdb;
|
|
|
|
// Get entities that need recalculation
|
|
$limit = $GLOBALS['igny8_cron_limit'] ?? null;
|
|
if ($limit === null) {
|
|
error_log('Igny8 Auto Cluster Cron: No limit set in Smart Automation Jobs table');
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No limit set in Smart Automation Jobs table";
|
|
return;
|
|
}
|
|
$clusters_to_recalc = $wpdb->get_results("
|
|
SELECT id FROM {$wpdb->prefix}igny8_clusters
|
|
WHERE status = 'active'
|
|
LIMIT $limit
|
|
");
|
|
|
|
$tasks_to_recalc = $wpdb->get_results("
|
|
SELECT id FROM {$wpdb->prefix}igny8_tasks
|
|
WHERE status IN ('completed', 'in_progress')
|
|
LIMIT $limit
|
|
");
|
|
|
|
$total_recalc = count($clusters_to_recalc) + count($tasks_to_recalc);
|
|
|
|
if ($total_recalc === 0) {
|
|
igny8_log_ai_event('Auto Recalc Skipped', 'analytics', 'auto_recalc', 'info', 'No entities need recalculation', 'All metrics are up to date');
|
|
return;
|
|
}
|
|
|
|
// Log automation start
|
|
igny8_log_ai_event('Auto Recalc Started', 'analytics', 'auto_recalc', 'info', 'Starting automated recalculation', 'Entities: ' . $total_recalc);
|
|
|
|
$recalculated = 0;
|
|
|
|
// Recalculate cluster metrics
|
|
foreach ($clusters_to_recalc as $cluster) {
|
|
igny8_update_cluster_metrics($cluster->id);
|
|
$recalculated++;
|
|
}
|
|
|
|
// Recalculate task metrics
|
|
foreach ($tasks_to_recalc as $task) {
|
|
igny8_update_task_metrics($task->id);
|
|
$recalculated++;
|
|
}
|
|
|
|
if ($recalculated > 0) {
|
|
igny8_log_ai_event('Auto Recalc Complete', 'analytics', 'auto_recalc', 'success', 'Automated recalculation completed', 'Entities recalculated: ' . $recalculated);
|
|
} else {
|
|
igny8_log_ai_event('Auto Recalc Failed', 'analytics', 'auto_recalc', 'error', 'Automated recalculation failed', 'No entities were recalculated');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Health Check Cron Handler (NEW)
|
|
*
|
|
* Performs system health checks, cleanup, and dependency validation.
|
|
*/
|
|
function igny8_health_check_cron_handler() {
|
|
global $wpdb;
|
|
|
|
$health_issues = [];
|
|
$cleanup_performed = [];
|
|
$dependency_issues = [];
|
|
|
|
// Check for orphaned records
|
|
$orphaned_keywords = $wpdb->get_var("
|
|
SELECT COUNT(*) FROM {$wpdb->prefix}igny8_keywords k
|
|
LEFT JOIN {$wpdb->prefix}igny8_clusters c ON k.cluster_id = c.id
|
|
WHERE k.cluster_id IS NOT NULL AND k.cluster_id > 0 AND c.id IS NULL
|
|
");
|
|
|
|
if ($orphaned_keywords > 0) {
|
|
$health_issues[] = "Found $orphaned_keywords orphaned keywords";
|
|
|
|
// Clean up orphaned keywords
|
|
$wpdb->query("
|
|
UPDATE {$wpdb->prefix}igny8_keywords
|
|
SET cluster_id = NULL
|
|
WHERE cluster_id IS NOT NULL
|
|
AND cluster_id > 0
|
|
AND cluster_id NOT IN (SELECT id FROM {$wpdb->prefix}igny8_clusters)
|
|
");
|
|
$cleanup_performed[] = "Cleaned up $orphaned_keywords orphaned keywords";
|
|
}
|
|
|
|
// Check for old failed AI tasks
|
|
$old_failed_tasks = $wpdb->get_var("
|
|
SELECT COUNT(*) FROM {$wpdb->prefix}igny8_ai_queue
|
|
WHERE status = 'failed'
|
|
AND created_at < DATE_SUB(NOW(), INTERVAL 7 DAY)
|
|
");
|
|
|
|
if ($old_failed_tasks > 0) {
|
|
$wpdb->query("
|
|
DELETE FROM {$wpdb->prefix}igny8_ai_queue
|
|
WHERE status = 'failed'
|
|
AND created_at < DATE_SUB(NOW(), INTERVAL 7 DAY)
|
|
");
|
|
$cleanup_performed[] = "Cleaned up $old_failed_tasks old failed AI tasks";
|
|
}
|
|
|
|
// Dependency validation - check execution order
|
|
$dependency_issues = igny8_validate_automation_dependencies();
|
|
|
|
// Check database table sizes
|
|
$table_sizes = [];
|
|
$tables = ['igny8_keywords', 'igny8_clusters', 'igny8_content_ideas', 'igny8_tasks', 'igny8_ai_queue'];
|
|
|
|
foreach ($tables as $table) {
|
|
$count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}$table");
|
|
$table_sizes[$table] = $count;
|
|
}
|
|
|
|
// Log health check results
|
|
if (empty($health_issues) && empty($dependency_issues)) {
|
|
igny8_log_ai_event('Health Check Passed', 'system', 'health_check', 'success', 'System health check completed', 'No issues found');
|
|
} else {
|
|
$all_issues = array_merge($health_issues, $dependency_issues);
|
|
igny8_log_ai_event('Health Check Issues', 'system', 'health_check', 'warning', 'Health check found issues', implode('; ', $all_issues));
|
|
}
|
|
|
|
if (!empty($cleanup_performed)) {
|
|
igny8_log_ai_event('Health Check Cleanup', 'system', 'health_check', 'info', 'Cleanup performed', implode('; ', $cleanup_performed));
|
|
}
|
|
|
|
// Store health metrics
|
|
update_option('igny8_health_metrics', [
|
|
'last_check' => current_time('mysql'),
|
|
'table_sizes' => $table_sizes,
|
|
'issues_found' => count($health_issues),
|
|
'dependency_issues' => count($dependency_issues),
|
|
'cleanup_performed' => count($cleanup_performed)
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Validate automation dependencies and execution order
|
|
*/
|
|
function igny8_validate_automation_dependencies() {
|
|
$issues = [];
|
|
global $wpdb;
|
|
|
|
// Check if clusters exist but no ideas generated
|
|
$clusters_without_ideas = $wpdb->get_var("
|
|
SELECT COUNT(*) FROM {$wpdb->prefix}igny8_clusters c
|
|
LEFT JOIN {$wpdb->prefix}igny8_content_ideas i ON c.id = i.keyword_cluster_id
|
|
WHERE c.status = 'active' AND i.id IS NULL
|
|
");
|
|
|
|
if ($clusters_without_ideas > 0) {
|
|
$issues[] = "Found $clusters_without_ideas clusters without content ideas (auto_generate_ideas may be disabled)";
|
|
}
|
|
|
|
// Check if ideas exist but not queued
|
|
$ideas_not_queued = $wpdb->get_var("
|
|
SELECT COUNT(*) FROM {$wpdb->prefix}igny8_content_ideas i
|
|
LEFT JOIN {$wpdb->prefix}igny8_tasks t ON i.id = t.idea_id
|
|
WHERE i.status = 'new' AND t.id IS NULL
|
|
");
|
|
|
|
if ($ideas_not_queued > 0) {
|
|
$issues[] = "Found $ideas_not_queued ideas not queued for content generation (auto_queue may be disabled)";
|
|
}
|
|
|
|
// Check if tasks exist but no content generated
|
|
$tasks_without_content = $wpdb->get_var("
|
|
SELECT COUNT(*) FROM {$wpdb->prefix}igny8_tasks t
|
|
LEFT JOIN {$wpdb->posts} p ON t.assigned_post_id = p.ID
|
|
WHERE t.status = 'queued' AND (p.ID IS NULL OR p.post_content = '')
|
|
");
|
|
|
|
if ($tasks_without_content > 0) {
|
|
$issues[] = "Found $tasks_without_content tasks without content (auto_generate_content may be disabled)";
|
|
}
|
|
|
|
// Check if content exists but no images
|
|
$content_without_images = $wpdb->get_var("
|
|
SELECT COUNT(*) FROM {$wpdb->posts} p
|
|
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = 'igny8_has_ai_image'
|
|
WHERE p.post_status = 'publish'
|
|
AND p.post_type IN ('post', 'page')
|
|
AND p.post_content LIKE '%[image%'
|
|
AND pm.meta_value IS NULL
|
|
");
|
|
|
|
if ($content_without_images > 0) {
|
|
$issues[] = "Found $content_without_images posts with image placeholders but no AI images (auto_generate_images may be disabled)";
|
|
}
|
|
|
|
// Check if content exists but not published
|
|
$drafts_not_published = $wpdb->get_var("
|
|
SELECT COUNT(*) FROM {$wpdb->posts} p
|
|
INNER JOIN {$wpdb->prefix}igny8_tasks t ON p.ID = t.assigned_post_id
|
|
WHERE p.post_status = 'draft'
|
|
AND t.status = 'completed'
|
|
");
|
|
|
|
if ($drafts_not_published > 0) {
|
|
$issues[] = "Found $drafts_not_published completed tasks with unpublished content (auto_publish_drafts may be disabled)";
|
|
}
|
|
|
|
return $issues;
|
|
}
|
|
|
|
/**
|
|
* Auto Generate Images Cron Handler (NEW)
|
|
*
|
|
* Automatically generates images for content that needs them.
|
|
*/
|
|
function igny8_auto_generate_images_cron_handler() {
|
|
// Check if automation is enabled
|
|
if (igny8_get_ai_setting('auto_generate_images_enabled', 'disabled') !== 'enabled') {
|
|
return;
|
|
}
|
|
|
|
// Check if AI mode is enabled
|
|
if (igny8_get_ai_setting('writer_mode', 'manual') !== 'ai') {
|
|
return;
|
|
}
|
|
|
|
global $wpdb;
|
|
|
|
// Get posts that need images (use admin limit)
|
|
$limit = $GLOBALS['igny8_cron_limit'] ?? null;
|
|
if ($limit === null) {
|
|
// Try to get limit from Smart Automation Jobs table directly
|
|
$cron_limits = get_option('igny8_cron_limits', []);
|
|
$limit = $cron_limits['igny8_auto_generate_images_cron'] ?? null;
|
|
|
|
if ($limit === null) {
|
|
error_log('Igny8 Auto Generate Images Cron: No limit set in Smart Automation Jobs table');
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No limit set in Smart Automation Jobs table";
|
|
return;
|
|
}
|
|
|
|
echo "<strong>Igny8 CRON HANDLER: Using limit from Smart Automation Jobs table: $limit</strong><br>";
|
|
}
|
|
$posts_needing_images = $wpdb->get_results("
|
|
SELECT p.ID, p.post_title, p.post_content
|
|
FROM {$wpdb->posts} p
|
|
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = 'igny8_has_ai_image'
|
|
WHERE p.post_status = 'publish'
|
|
AND p.post_type IN ('post', 'page')
|
|
AND pm.meta_value IS NULL
|
|
AND p.post_content LIKE '%[image%'
|
|
LIMIT $limit
|
|
");
|
|
|
|
if (empty($posts_needing_images)) {
|
|
igny8_log_ai_event('Auto Generate Images Skipped', 'writer', 'auto_generate_images', 'info', 'No posts need images', 'All posts already have images or no image placeholders found');
|
|
return;
|
|
}
|
|
|
|
$post_ids = array_column($posts_needing_images, 'ID');
|
|
|
|
// Log automation start
|
|
igny8_log_ai_event('Auto Generate Images Started', 'writer', 'auto_generate_images', 'info', 'Starting automated image generation', 'Posts: ' . count($post_ids));
|
|
|
|
$generated = 0;
|
|
foreach ($post_ids as $post_id) {
|
|
// Run image generation process
|
|
$result = igny8_generate_post_images($post_id);
|
|
if ($result['success']) {
|
|
$generated++;
|
|
// Mark as having AI image
|
|
update_post_meta($post_id, 'igny8_has_ai_image', current_time('mysql'));
|
|
}
|
|
}
|
|
|
|
if ($generated > 0) {
|
|
igny8_log_ai_event('Auto Generate Images Complete', 'writer', 'auto_generate_images', 'success', 'Automated image generation completed', 'Images generated: ' . $generated);
|
|
|
|
// Set global variables for detailed logging
|
|
$GLOBALS['igny8_cron_processed_count'] = $generated;
|
|
$GLOBALS['igny8_cron_result_details'] = "Processed {$generated} posts, generated {$generated} images";
|
|
} else {
|
|
igny8_log_ai_event('Auto Generate Images Failed', 'writer', 'auto_generate_images', 'error', 'Automated image generation failed', 'No images were generated');
|
|
|
|
// Set global variables for detailed logging (failure case)
|
|
$GLOBALS['igny8_cron_processed_count'] = 0;
|
|
$GLOBALS['igny8_cron_result_details'] = "FAILED: No images were generated";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Cron Endpoint Handler (NEW)
|
|
*
|
|
* Simple test handler for cron endpoint validation.
|
|
*/
|
|
function igny8_test_cron_endpoint() {
|
|
igny8_log_ai_event('Cron Test', 'system', 'test_endpoint', 'info', 'Cron endpoint test executed', 'Test successful at ' . current_time('mysql'));
|
|
|
|
// Return success response for external cron
|
|
if (defined('DOING_CRON') && DOING_CRON) {
|
|
return [
|
|
'success' => true,
|
|
'message' => 'Igny8 CRON endpoint is working',
|
|
'timestamp' => current_time('mysql'),
|
|
'server' => $_SERVER['SERVER_NAME'] ?? 'unknown'
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Safe taxonomy term creation with duplicate prevention
|
|
*
|
|
* @param string $term_name Term name
|
|
* @param string $taxonomy Taxonomy name
|
|
* @param array $args Additional arguments
|
|
* @return int|WP_Error Term ID or error
|
|
*/
|
|
function igny8_safe_create_term($term_name, $taxonomy, $args = []) {
|
|
// Check if term already exists
|
|
$existing_term = get_term_by('name', $term_name, $taxonomy);
|
|
if ($existing_term) {
|
|
return $existing_term->term_id;
|
|
}
|
|
|
|
// Create term with duplicate slug prevention
|
|
$slug = sanitize_title($term_name);
|
|
$counter = 1;
|
|
$original_slug = $slug;
|
|
|
|
while (term_exists($slug, $taxonomy)) {
|
|
$slug = $original_slug . '-' . $counter;
|
|
$counter++;
|
|
}
|
|
|
|
$args['slug'] = $slug;
|
|
|
|
$result = wp_insert_term($term_name, $taxonomy, $args);
|
|
|
|
if (is_wp_error($result)) {
|
|
// If still error, try to get existing term by slug
|
|
$existing = get_term_by('slug', $slug, $taxonomy);
|
|
if ($existing) {
|
|
return $existing->term_id;
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
return $result['term_id'];
|
|
}
|
|
|
|
/**
|
|
* Enhanced cluster term creation with safety checks
|
|
*
|
|
* @param int $cluster_id Cluster ID
|
|
* @return int|false Term ID or false on failure
|
|
*/
|
|
function igny8_safe_create_cluster_term($cluster_id) {
|
|
global $wpdb;
|
|
|
|
// Get cluster data
|
|
$cluster = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT cluster_name, cluster_term_id FROM {$wpdb->prefix}igny8_clusters WHERE id = %d",
|
|
$cluster_id
|
|
));
|
|
|
|
if (!$cluster) {
|
|
return false;
|
|
}
|
|
|
|
// Skip if already mapped
|
|
if (!empty($cluster->cluster_term_id)) {
|
|
return $cluster->cluster_term_id;
|
|
}
|
|
|
|
// Ensure taxonomy exists
|
|
if (!taxonomy_exists('clusters') && function_exists('igny8_register_taxonomies')) {
|
|
igny8_register_taxonomies();
|
|
}
|
|
|
|
// Create term safely
|
|
$term_id = igny8_safe_create_term($cluster->cluster_name, 'clusters');
|
|
|
|
if ($term_id && !is_wp_error($term_id)) {
|
|
// Update cluster with term ID
|
|
$wpdb->update(
|
|
"{$wpdb->prefix}igny8_clusters",
|
|
['cluster_term_id' => $term_id],
|
|
['id' => $cluster_id],
|
|
['%d'],
|
|
['%d']
|
|
);
|
|
|
|
return $term_id;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ===================================================================
|
|
// REGISTER CRON HOOKS
|
|
// ===================================================================
|
|
|
|
// Register all cron job hooks
|
|
add_action('igny8_auto_cluster_cron', 'igny8_auto_cluster_cron_handler');
|
|
add_action('igny8_auto_generate_ideas_cron', 'igny8_auto_generate_ideas_cron_handler');
|
|
add_action('igny8_auto_queue_cron', 'igny8_auto_queue_cron_handler');
|
|
add_action('igny8_auto_generate_content_cron', 'igny8_auto_generate_content_cron_handler');
|
|
add_action('igny8_auto_generate_images_cron', 'igny8_auto_generate_images_cron_handler');
|
|
add_action('igny8_auto_publish_drafts_cron', 'igny8_auto_publish_drafts_cron_handler');
|
|
add_action('igny8_process_ai_queue_cron', 'igny8_process_ai_queue_cron_handler');
|
|
add_action('igny8_auto_recalc_cron', 'igny8_auto_recalc_cron_handler');
|
|
add_action('igny8_auto_optimizer_cron', 'igny8_auto_optimizer_cron_handler');
|
|
add_action('igny8_health_check_cron', 'igny8_health_check_cron_handler');
|