Files
igny8/igny8-ai-seo-wp-plugin/core/admin/global-helpers.php
2025-11-11 21:16:37 +05:00

1085 lines
34 KiB
PHP

<?php
/**
* ==========================
* 🔐 IGNY8 FILE RULE HEADER
* ==========================
* @file : global-helpers.php
* @location : /core/admin/global-helpers.php
* @type : Function Library
* @scope : Global
* @allowed : Utility functions, data formatting, WordPress helpers
* @reusability : Globally Reusable
* @notes : Central utility functions used across all modules
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
/**
* Convert cluster ID to cluster name
* Used across multiple submodules and forms
*
* @param int $cluster_id The cluster ID
* @return string The cluster name or empty string if not found
*/
function igny8_get_cluster_term_name($cluster_id) {
if (empty($cluster_id) || !is_numeric($cluster_id)) {
return '';
}
global $wpdb;
// Query the clusters table directly
$cluster_name = $wpdb->get_var($wpdb->prepare(
"SELECT cluster_name FROM {$wpdb->prefix}igny8_clusters WHERE id = %d",
$cluster_id
));
if (!empty($cluster_name)) {
return $cluster_name;
}
// If no cluster found, return empty string
return '';
}
/**
* Convert cluster name to cluster ID
* Used across multiple submodules and forms
*
* @param string $cluster_name The cluster name
* @return int The cluster ID or 0 if not found
*/
function igny8_get_cluster_id_by_name($cluster_name) {
if (empty($cluster_name) || !is_string($cluster_name)) {
return 0;
}
global $wpdb;
// Query the clusters table directly
$cluster_id = $wpdb->get_var($wpdb->prepare(
"SELECT id FROM {$wpdb->prefix}igny8_clusters WHERE cluster_name = %s",
$cluster_name
));
return $cluster_id ? (int)$cluster_id : 0;
}
/**
* Get cluster options for dropdowns
* Used across all modules that need cluster selection
*
* @return array Array of cluster options in format [['value' => id, 'label' => name], ...]
*/
function igny8_get_cluster_options() {
global $wpdb;
// Get all active clusters from database
$clusters = $wpdb->get_results(
"SELECT id, cluster_name FROM {$wpdb->prefix}igny8_clusters WHERE status = 'active' ORDER BY cluster_name ASC"
);
$options = [
['value' => '', 'label' => 'No Cluster']
];
if ($clusters) {
foreach ($clusters as $cluster) {
$options[] = [
'value' => $cluster->id,
'label' => $cluster->cluster_name
];
}
}
return $options;
}
/**
* Get standardized cluster lookup configuration for tables
* This eliminates the need to repeat lookup configuration in every table
*
* @return array Standardized cluster lookup configuration
*/
function igny8_get_cluster_lookup_config() {
return [
'type' => 'lookup',
'source_field' => 'cluster_id',
'display_field' => 'cluster_name',
'sortable' => true,
'join_query' => 'LEFT JOIN {prefix}igny8_clusters c ON {table_name}.cluster_id = c.id',
'select_field' => 'c.cluster_name as cluster_name'
];
}
/**
* Get standardized cluster lookup configuration for ideas table
* Uses keyword_cluster_id instead of cluster_id
*
* @return array Standardized cluster lookup configuration for ideas
*/
function igny8_get_ideas_cluster_lookup_config() {
return [
'type' => 'lookup',
'source_field' => 'keyword_cluster_id',
'display_field' => 'cluster_name',
'sortable' => true,
'join_query' => 'LEFT JOIN {prefix}igny8_clusters c ON {table_name}.keyword_cluster_id = c.id',
'select_field' => 'c.cluster_name as cluster_name'
];
}
/**
* Get dynamic table configuration based on AI mode
*/
function igny8_get_dynamic_table_config($table_id) {
$config = $GLOBALS['igny8_tables_config'][$table_id] ?? [];
// Apply AI-specific modifications
if ($table_id === 'writer_queue') {
$writer_mode = igny8_get_ai_setting('writer_mode', 'manual');
// Hide due_date column for AI mode
if ($writer_mode === 'ai' && isset($config['columns']['due_date'])) {
unset($config['columns']['due_date']);
// Also remove from filters
if (isset($config['filters']['due_date'])) {
unset($config['filters']['due_date']);
}
}
}
// Apply status filter for drafts table
if ($table_id === 'writer_drafts') {
$config['default_filter'] = [
'status' => ['draft']
];
}
// Apply status filter for published table
if ($table_id === 'writer_published') {
$config['default_filter'] = [
'status' => ['published']
];
}
return $config;
}
/**
* Get dynamic form configuration based on table columns
*/
function igny8_get_dynamic_form_config($form_id) {
$form_config = $GLOBALS['igny8_forms_config'][$form_id] ?? [];
// For writer_queue form, conditionally include due_date field
if ($form_id === 'writer_queue') {
$writer_mode = igny8_get_ai_setting('writer_mode', 'manual');
// Remove due_date field for AI mode
if ($writer_mode === 'ai') {
$form_config['fields'] = array_filter($form_config['fields'], function($field) {
return $field['name'] !== 'due_date';
});
// Re-index array
$form_config['fields'] = array_values($form_config['fields']);
}
}
return $form_config;
}
/**
* Convert difficulty number to predefined difficulty range name
*
* @param float $difficulty The difficulty value (0-100)
* @return string The difficulty range name
*/
function igny8_get_difficulty_range_name($difficulty) {
if (empty($difficulty) || !is_numeric($difficulty)) {
return '';
}
$difficulty = floatval($difficulty);
if ($difficulty <= 20) {
return 'Very Easy';
} elseif ($difficulty <= 40) {
return 'Easy';
} elseif ($difficulty <= 60) {
return 'Medium';
} elseif ($difficulty <= 80) {
return 'Hard';
} else {
return 'Very Hard';
}
}
/**
* Convert difficulty text label to numeric range for database queries
*
* @param string $difficulty_label The difficulty text label
* @return array|false Array with 'min' and 'max' keys, or false if invalid
*/
function igny8_get_difficulty_numeric_range($difficulty_label) {
if (empty($difficulty_label)) {
return false;
}
switch ($difficulty_label) {
case 'Very Easy':
return ['min' => 0, 'max' => 20];
case 'Easy':
return ['min' => 21, 'max' => 40];
case 'Medium':
return ['min' => 41, 'max' => 60];
case 'Hard':
return ['min' => 61, 'max' => 80];
case 'Very Hard':
return ['min' => 81, 'max' => 100];
default:
return false;
}
}
/**
* Get page description
*/
function igny8_get_page_description() {
$current_page = $_GET['page'] ?? '';
$sm = $_GET['sm'] ?? '';
switch ($current_page) {
case 'igny8-home':
return 'Welcome to Igny8 AI SEO OS - Your comprehensive SEO management platform.';
case 'igny8-planner':
if ($sm === 'keywords') {
return 'Manage your keywords, track search volumes, and organize by intent and difficulty.';
} elseif ($sm === 'clusters') {
return 'Group related keywords into content clusters for better topical authority.';
} elseif ($sm === 'ideas') {
return 'Generate and organize content ideas based on your keyword research.';
} elseif ($sm === 'mapping') {
return 'Map keywords and clusters to existing pages and content.';
} else {
return 'Plan and organize your content strategy with keyword research and clustering.';
}
case 'igny8-writer':
if ($sm === 'drafts') {
return 'Manage your content drafts and work in progress.';
} elseif ($sm === 'templates') {
return 'Create and manage content templates for consistent writing.';
} else {
return 'Content creation and writing tools for SEO-optimized content.';
}
case 'igny8-optimizer':
if ($sm === 'audits') {
return 'Run comprehensive SEO audits on your content and pages.';
} elseif ($sm === 'suggestions') {
return 'Get AI-powered optimization suggestions for better rankings.';
} else {
return 'SEO optimization and performance tools for better rankings.';
}
case 'igny8-linker':
if ($sm === 'backlinks') {
return 'Track and manage your backlink profile and authority.';
} elseif ($sm === 'campaigns') {
return 'Plan and execute link building campaigns effectively.';
} else {
return 'Link building and backlink management for improved authority.';
}
case 'igny8-personalize':
if ($sm === 'settings') {
return 'Configure global settings, display options, and advanced personalization settings.';
} elseif ($sm === 'content-generation') {
return 'Configure AI prompts, field detection, and content generation parameters.';
} elseif ($sm === 'rewrites') {
return 'View and manage personalized content variations and rewrites.';
} elseif ($sm === 'front-end') {
return 'Manage front-end display settings, shortcode usage, and implementation guides.';
} else {
return 'Content personalization and targeting for better engagement.';
}
case 'igny8-settings':
$sp = $_GET['sp'] ?? 'general';
if ($sp === 'status') {
return 'Monitor system health, database status, and module performance.';
} elseif ($sp === 'integration') {
return 'Configure API keys and integrate with external services.';
} elseif ($sp === 'import-export') {
return 'Import and export data, manage backups, and transfer content.';
} else {
return 'Configure plugin settings, automation, and table preferences.';
}
case 'igny8-analytics':
return 'Performance analytics and reporting for data-driven decisions.';
case 'igny8-schedules':
return 'Content scheduling and automation for consistent publishing.';
case 'igny8-help':
return 'Documentation and support resources for getting started.';
default:
return 'Igny8 AI SEO OS - Advanced SEO Management';
}
}
/**
* Get page title
*/
function igny8_get_page_title() {
$current_page = $_GET['page'] ?? '';
$sm = $_GET['sm'] ?? '';
switch ($current_page) {
case 'igny8-home':
return 'Igny8 Home';
case 'igny8-planner':
if ($sm === 'keywords') {
return 'Keywords';
} elseif ($sm === 'clusters') {
return 'Clusters';
} elseif ($sm === 'ideas') {
return 'Ideas';
} elseif ($sm === 'mapping') {
return 'Mapping';
} else {
return 'Planner';
}
case 'igny8-writer':
if ($sm === 'tasks') {
return 'Content Queue / Tasks';
} elseif ($sm === 'drafts') {
return 'Content Generated';
} elseif ($sm === 'published') {
return 'Live Content';
} else {
return 'Content Writer';
}
case 'igny8-optimizer':
if ($sm === 'audits') {
return 'Audits';
} elseif ($sm === 'suggestions') {
return 'Suggestions';
} else {
return 'Optimizer';
}
case 'igny8-linker':
if ($sm === 'backlinks') {
return 'Backlinks';
} elseif ($sm === 'campaigns') {
return 'Campaigns';
} else {
return 'Linker';
}
case 'igny8-personalize':
if ($sm === 'settings') {
return 'Personalization Settings';
} elseif ($sm === 'content-generation') {
return 'Content Generation';
} elseif ($sm === 'rewrites') {
return 'Rewrites';
} elseif ($sm === 'front-end') {
return 'Front-end';
} else {
return 'Personalize';
}
case 'igny8-thinker':
$sp = $_GET['sp'] ?? 'main';
if ($sp === 'main') {
return 'AI Thinker Dashboard';
} elseif ($sp === 'prompts') {
return 'AI Prompts';
} elseif ($sp === 'profile') {
return 'AI Profile';
} elseif ($sp === 'strategies') {
return 'Content Strategies';
} elseif ($sp === 'image-testing') {
return 'AI Image Testing';
} else {
return 'AI Thinker';
}
case 'igny8-settings':
$sp = $_GET['sp'] ?? 'general';
if ($sp === 'status') {
return 'System Status';
} elseif ($sp === 'integration') {
return 'API Integration';
} elseif ($sp === 'import-export') {
return 'Import/Export';
} else {
return 'General Settings';
}
case 'igny8-analytics':
return 'Analytics';
case 'igny8-schedules':
return 'Schedules';
case 'igny8-test':
$sp = $_GET['sp'] ?? 'system-testing';
if ($sp === 'system-testing') {
return 'System Testing';
} elseif ($sp === 'temp-function-testing') {
return 'Function Testing';
} else {
return 'Test Page';
}
case 'igny8-help':
return 'Help';
default:
return 'Igny8 AI SEO OS';
}
}
// REMOVED: Task variations functionality - tasks don't need variations
/**
* Safe logging helper for Igny8 operations
*
* @param string $type Log type (e.g., 'queue_to_writer', 'task_created')
* @param mixed $data Log data (string, array, or object)
*/
function igny8_write_log($type, $data) {
global $wpdb;
try {
$wpdb->insert($wpdb->prefix . 'igny8_logs', [
'level' => 'info',
'message' => sanitize_text_field($type),
'context' => is_array($data) ? wp_json_encode($data) : (is_string($data) ? $data : null),
'source' => 'igny8_plugin',
'user_id' => get_current_user_id(),
], ['%s', '%s', '%s', '%s', '%d']);
} catch (Exception $e) {
// Log to error log if database logging fails
error_log('Igny8: Failed to write to logs table: ' . $e->getMessage());
}
}
/**
* Get clusters for select dropdown
*
* @return array Array of cluster options for select dropdown
*/
function igny8_get_clusters_for_select() {
global $wpdb;
$clusters = $wpdb->get_results(
"SELECT id, cluster_name FROM {$wpdb->prefix}igny8_clusters ORDER BY cluster_name ASC"
);
$options = ['' => 'Select Cluster'];
foreach ($clusters as $cluster) {
$options[$cluster->id] = $cluster->cluster_name;
}
return $options;
}
/**
* Get sector options for dropdowns
* Used across all modules that need sector selection
* Only returns sectors from saved planner settings
*
* @return array Array of sector options in format [['value' => id, 'label' => name], ...]
*/
function igny8_get_sector_options() {
// Get saved sector selection from user meta
$user_id = get_current_user_id();
$saved_selection = get_user_meta($user_id, 'igny8_planner_sector_selection', true);
$options = [];
// If no saved selection, return empty options
if (empty($saved_selection)) {
return $options;
}
// Add only child sectors (not parent)
if (isset($saved_selection['children']) && is_array($saved_selection['children'])) {
foreach ($saved_selection['children'] as $child) {
if (isset($child['id']) && isset($child['name'])) {
$options[] = [
'value' => $child['id'],
'label' => $child['name']
];
}
}
}
return $options;
}
/**
* Get sectors for select dropdown
* Only returns sectors from saved planner settings
*
* @return array Array of sector options for select dropdown
*/
function igny8_get_sectors_for_select() {
// Get saved sector selection from user meta
$user_id = get_current_user_id();
$saved_selection = get_user_meta($user_id, 'igny8_planner_sector_selection', true);
$options = [];
// If no saved selection, return empty options
if (empty($saved_selection)) {
return $options;
}
// Add only child sectors (not parent)
if (isset($saved_selection['children']) && is_array($saved_selection['children'])) {
foreach ($saved_selection['children'] as $child) {
if (isset($child['id']) && isset($child['name'])) {
$options[$child['id']] = $child['name'];
}
}
}
return $options;
}
/**
* Get ideas for select dropdown
*
* @return array Array of idea options for select dropdown
*/
function igny8_get_ideas_for_select() {
global $wpdb;
$ideas = $wpdb->get_results(
"SELECT id, idea_title FROM {$wpdb->prefix}igny8_content_ideas ORDER BY idea_title ASC"
);
$options = ['' => 'Select Idea'];
foreach ($ideas as $idea) {
$options[$idea->id] = $idea->idea_title;
}
return $options;
}
/**
* Transform database field names to human-readable labels
*
* @param string $field_name The database field name (snake_case)
* @return string The human-readable label (Title Case)
*/
function igny8_humanize_label($field) {
// Handle non-string input safely
if (!is_string($field)) {
return '';
}
// Remove any potentially dangerous characters
$field = sanitize_key($field);
// Specific field mappings for better readability
$field_mappings = [
// Clusters table
'cluster_name' => 'Cluster Name',
'sector_id' => 'Sectors',
'keyword_count' => 'Keywords',
'total_volume' => 'Total Volume',
'avg_difficulty' => 'Avg KD',
'mapped_pages_count' => 'Mapped Pages',
'created_at' => 'Created',
'updated_at' => 'Updated',
// Keywords table
'search_volume' => 'Volume',
'difficulty' => 'Difficulty',
'cpc' => 'CPC',
'intent' => 'Intent',
'status' => 'Status',
'cluster_id' => 'Cluster',
// Ideas table
'idea_title' => 'Title',
'idea_description' => 'Description',
'content_structure' => 'Structure',
'content_angle' => 'Content Angle',
'keyword_cluster_id' => 'Cluster',
'estimated_word_count' => 'Words',
'ai_generated' => 'AI Generated',
'mapped_post_id' => 'Mapped Post',
'tasks_count' => 'Tasks Count',
// Tasks table
'content_type' => 'Content Type',
'cluster_id' => 'Cluster',
'keywords' => 'Keywords',
'schedule_at' => 'Scheduled',
'assigned_post_id' => 'Assigned Post',
'created_at' => 'Created',
'updated_at' => 'Updated',
// Campaigns table
'backlink_count' => 'Backlinks',
'live_links_count' => 'Live Links',
// Mapping table
'page_id' => 'Page ID',
'coverage_percentage' => 'Coverage %',
'coverage_status' => 'Status',
'last_updated' => 'Updated'
];
// Check for specific mapping first
if (isset($field_mappings[$field])) {
return $field_mappings[$field];
}
// Fallback: convert snake_case to Title Case
return ucwords(str_replace('_', ' ', $field));
}
/**
* Transform database field names to human-readable labels (legacy function)
* @deprecated Use igny8_humanize_label() instead
*/
function igny8_transform_field_label($field_name) {
return igny8_humanize_label($field_name);
}
/**
* Map cluster to keywords
*
* @param int $cluster_id Cluster ID to map keywords to
* @param array $keyword_ids Array of keyword IDs to map
* @return array ['success' => bool, 'message' => string, 'mapped_count' => int]
*/
function igny8_map_cluster_to_keywords($cluster_id, $keyword_ids) {
global $wpdb;
if (empty($cluster_id) || !is_numeric($cluster_id)) {
return ['success' => false, 'message' => 'Invalid cluster ID provided', 'mapped_count' => 0];
}
if (empty($keyword_ids) || !is_array($keyword_ids)) {
return ['success' => false, 'message' => 'No keywords provided for mapping', 'mapped_count' => 0];
}
$cluster_id = intval($cluster_id);
// Verify cluster exists
$cluster_exists = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->prefix}igny8_clusters WHERE id = %d",
$cluster_id
));
if (!$cluster_exists) {
return ['success' => false, 'message' => 'Cluster not found', 'mapped_count' => 0];
}
// Sanitize and validate keyword IDs
$keyword_ids = array_map('intval', $keyword_ids);
$keyword_ids = array_filter($keyword_ids, function($id) { return $id > 0; });
if (empty($keyword_ids)) {
return ['success' => false, 'message' => 'No valid keyword IDs provided', 'mapped_count' => 0];
}
// Get old cluster IDs for metrics update
$placeholders = implode(',', array_fill(0, count($keyword_ids), '%d'));
$old_cluster_ids = $wpdb->get_col($wpdb->prepare(
"SELECT DISTINCT cluster_id FROM {$wpdb->prefix}igny8_keywords WHERE id IN ({$placeholders}) AND cluster_id IS NOT NULL",
$keyword_ids
));
// Update keywords to new cluster
$mapped_count = $wpdb->query($wpdb->prepare(
"UPDATE {$wpdb->prefix}igny8_keywords SET cluster_id = %d, status = 'mapped', updated_at = CURRENT_TIMESTAMP WHERE id IN ({$placeholders})",
array_merge([$cluster_id], $keyword_ids)
));
if ($mapped_count === false) {
return ['success' => false, 'message' => 'Failed to map keywords to cluster', 'mapped_count' => 0];
}
// Update metrics for old clusters (they lost keywords)
if (!empty($old_cluster_ids)) {
foreach (array_unique($old_cluster_ids) as $old_cluster_id) {
if ($old_cluster_id && $old_cluster_id != $cluster_id) {
igny8_update_cluster_metrics($old_cluster_id);
}
}
}
// Update metrics for new cluster (gained keywords)
igny8_update_cluster_metrics($cluster_id);
return [
'success' => true,
'message' => "Successfully mapped {$mapped_count} keyword(s) to cluster",
'mapped_count' => $mapped_count
];
}
/**
* =============================================
* UNIFIED DATA VALIDATION LAYER
* =============================================
*/
/**
* Unified record validation function for all Planner module tables
*
* @param string $table_id Table ID (e.g., 'planner_keywords', 'planner_clusters')
* @param array $data Array of field data to validate
* @return array ['valid' => bool, 'error' => string|null]
*/
/**
* Check if automation is enabled for the current user
*
* @return bool True if automation is enabled
*/
function igny8_is_automation_enabled() {
// Default ON for admin users, OFF for others
if (current_user_can('manage_options')) {
return true;
}
// Check if user has specific automation capability
return current_user_can('edit_posts');
}
/**
* Helper function to get sector name
* Used for table display to show sector names instead of IDs
*
* @param mixed $sector_id The sector ID
* @return string The sector name or empty string if not found or 0/null
*/
function igny8_get_sector_name($sector_id) {
// Return empty string for 0, null, or empty values
if (empty($sector_id) || !is_numeric($sector_id) || intval($sector_id) == 0) {
return '';
}
// Check if sectors taxonomy exists
if (!taxonomy_exists('sectors')) {
return '';
}
// Try to get from WordPress taxonomy
$term = get_term(intval($sector_id), 'sectors');
if ($term && !is_wp_error($term)) {
return $term->name;
}
// If term not found, return empty string instead of fallback
return '';
}
/**
* Generate cluster name from keywords
*
* @param array $keywords Array of keyword objects
* @return string Generated cluster name
*/
function igny8_generate_cluster_name_from_keywords($keywords) {
if (empty($keywords)) {
return 'Auto-Generated Cluster';
}
// Get the most common words from keywords
$all_words = [];
foreach ($keywords as $keyword) {
$words = explode(' ', strtolower($keyword->keyword));
$all_words = array_merge($all_words, $words);
}
// Count word frequency
$word_count = array_count_values($all_words);
arsort($word_count);
// Get top 2-3 most common words
$top_words = array_slice(array_keys($word_count), 0, 3);
if (empty($top_words)) {
return 'Auto-Generated Cluster';
}
return ucwords(implode(' ', $top_words)) . ' Cluster';
}
/**
* Calculate relevance score for mapping suggestions
*
* @param string $term The search term
* @param string $title The post title
* @param string $slug The post slug
* @return int Relevance score (0-100)
*/
function igny8_calculate_relevance_score($term, $title, $slug) {
$score = 0;
$term_lower = strtolower($term);
$title_lower = strtolower($title);
$slug_lower = strtolower($slug);
// Exact match in title
if (strpos($title_lower, $term_lower) !== false) {
$score += 50;
}
// Exact match in slug
if (strpos($slug_lower, $term_lower) !== false) {
$score += 30;
}
// Word match in title
$title_words = explode(' ', $title_lower);
$term_words = explode(' ', $term_lower);
foreach ($term_words as $word) {
if (in_array($word, $title_words)) {
$score += 10;
}
}
return min($score, 100);
}
/**
* Remove duplicate suggestions from mapping suggestions
*
* @param array $suggestions Array of suggestion objects
* @return array Deduplicated suggestions
*/
function igny8_remove_duplicate_suggestions($suggestions) {
$seen = [];
$unique = [];
foreach ($suggestions as $suggestion) {
$key = $suggestion['page_id'];
if (!isset($seen[$key])) {
$seen[$key] = true;
$unique[] = $suggestion;
}
}
return $unique;
}
/**
* Get Import/Export Configuration for a table
*
* @param string $table_id The table ID (e.g., 'planner_keywords')
* @return array|false Configuration array or false if not found
*/
function igny8_get_import_export_config($table_id) {
static $config_cache = null;
if ($config_cache === null) {
$config_path = plugin_dir_path(dirname(__FILE__)) . '../modules/config/import-export-config.php';
if (file_exists($config_path)) {
$config_cache = include $config_path;
} else {
$config_cache = [];
}
}
return isset($config_cache[$table_id]) ? $config_cache[$table_id] : false;
}
/**
* AJAX handler for testing API connection
*/
function igny8_test_connection_ajax() {
try {
// Check if user has permission
if (!current_user_can('manage_options')) {
wp_send_json_error('Insufficient permissions');
return;
}
// Verify nonce
if (!check_ajax_referer('igny8_test_connection', 'nonce', false)) {
wp_send_json_error('Invalid nonce');
return;
}
// Test basic HTTP functionality
$test_url = 'https://httpbin.org/get';
$response = wp_remote_get($test_url, ['timeout' => 10]);
if (is_wp_error($response)) {
wp_send_json_error('HTTP request failed: ' . $response->get_error_message());
return;
}
$response_code = wp_remote_retrieve_response_code($response);
if ($response_code !== 200) {
wp_send_json_error('HTTP request returned status code: ' . $response_code);
return;
}
wp_send_json_success('Connection test passed');
} catch (Exception $e) {
wp_send_json_error('Exception: ' . $e->getMessage());
}
}
add_action('wp_ajax_igny8_test_connection', 'igny8_test_connection_ajax');
/**
* AJAX handler for testing API with response
*/
function igny8_test_api_ajax() {
try {
// Check if user has permission
if (!current_user_can('manage_options')) {
wp_send_json_error('Insufficient permissions');
return;
}
// Verify nonce
if (!check_ajax_referer('igny8_ajax_nonce', 'nonce', false)) {
wp_send_json_error('Invalid nonce');
return;
}
// Get API key
$api_key = get_option('igny8_api_key', '');
if (empty($api_key)) {
wp_send_json_error('API key not configured');
return;
}
// Get parameters
$with_response = isset($_POST['with_response']) ? (bool) $_POST['with_response'] : false;
// Test API connection
$result = igny8_test_connection($api_key, $with_response);
if (is_wp_error($result)) {
wp_send_json_error($result->get_error_message());
return;
}
if (is_array($result) && isset($result['success'])) {
if ($result['success']) {
wp_send_json_success($result);
} else {
wp_send_json_error($result['message'] ?? 'API test failed');
}
} else {
wp_send_json_success(['message' => 'API connection successful', 'response' => $result]);
}
} catch (Exception $e) {
wp_send_json_error('Exception: ' . $e->getMessage());
}
}
add_action('wp_ajax_igny8_test_api', 'igny8_test_api_ajax');
/**
* Get saved sector selection from user meta
*
* @return array|false Saved sector selection data or false if not set
*/
function igny8_get_saved_sector_selection() {
$user_id = get_current_user_id();
$saved_selection = get_user_meta($user_id, 'igny8_planner_sector_selection', true);
return !empty($saved_selection) ? $saved_selection : false;
}
/**
* Get system-wide AI workflow data for main dashboard
*
* @return array Array of step data with status and counts for all 9 workflow steps
*/
function igny8_get_system_workflow_data() {
global $wpdb;
// Get counts for each step
$keywords_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_keywords");
$unmapped_keywords = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_keywords WHERE cluster_id IS NULL OR cluster_id = 0");
$clusters_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_clusters");
$ideas_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_content_ideas");
$queued_ideas = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_content_ideas WHERE status = 'new'");
$queued_tasks = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_tasks WHERE status IN ('pending', 'queued', 'new')");
$draft_tasks = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_tasks WHERE status IN ('draft', 'in_progress', 'review')");
$published_tasks = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}igny8_tasks WHERE status = 'completed'");
// Check sector selection
$sector_selected = !empty(igny8_get_saved_sector_selection());
// Check if modules are enabled
$planner_enabled = igny8_is_module_enabled('planner');
$writer_enabled = igny8_is_module_enabled('writer');
return [
'keywords' => [
'count' => $keywords_count,
'unmapped' => $unmapped_keywords,
'status' => $keywords_count > 0 ? 'completed' : 'missing',
'module_enabled' => $planner_enabled,
'url' => $planner_enabled ? '?page=igny8-planner&sm=keywords' : null
],
'sector' => [
'selected' => $sector_selected,
'status' => $sector_selected ? 'completed' : 'missing',
'module_enabled' => $planner_enabled,
'url' => $planner_enabled ? '?page=igny8-planner' : null
],
'clusters' => [
'count' => $clusters_count,
'unmapped_keywords' => $unmapped_keywords,
'status' => $unmapped_keywords == 0 && $clusters_count > 0 ? 'completed' : ($unmapped_keywords > 0 ? 'in_progress' : 'missing'),
'module_enabled' => $planner_enabled,
'url' => $planner_enabled ? '?page=igny8-planner&sm=clusters' : null
],
'ideas' => [
'count' => $ideas_count,
'status' => $ideas_count > 0 ? 'completed' : 'missing',
'module_enabled' => $planner_enabled,
'url' => $planner_enabled ? '?page=igny8-planner&sm=ideas' : null
],
'queue' => [
'queued_ideas' => $queued_ideas,
'status' => $queued_ideas == 0 && $ideas_count > 0 ? 'completed' : ($queued_ideas > 0 ? 'in_progress' : 'missing'),
'module_enabled' => $planner_enabled,
'url' => $planner_enabled ? '?page=igny8-planner&sm=ideas' : null
],
'drafts' => [
'queued_tasks' => $queued_tasks,
'draft_tasks' => $draft_tasks,
'status' => $queued_tasks > 0 ? 'in_progress' : ($draft_tasks > 0 ? 'completed' : 'missing'),
'module_enabled' => $writer_enabled,
'url' => $writer_enabled ? '?page=igny8-writer&sm=tasks' : null
],
'publish' => [
'published_tasks' => $published_tasks,
'draft_tasks' => $draft_tasks,
'status' => $published_tasks > 0 ? 'completed' : ($draft_tasks > 0 ? 'in_progress' : 'missing'),
'module_enabled' => $writer_enabled,
'url' => $writer_enabled ? '?page=igny8-writer&sm=drafts' : null
]
];
}
/**
* Display image prompts in a formatted way for table display
*
* @param string $image_prompts JSON string of image prompts
* @return string Formatted display string
*/