Initial commit: igny8 project

This commit is contained in:
igny8
2025-11-09 10:27:02 +00:00
commit 60b8188111
27265 changed files with 4360521 additions and 0 deletions

View File

@@ -0,0 +1,676 @@
<?php
/**
* ==========================
* 🔐 IGNY8 FILE RULE HEADER
* ==========================
* @file : general-settings.php
* @location : /modules/settings/general-settings.php
* @type : Admin Page
* @scope : Module Only
* @allowed : Settings configuration, subpage routing, plugin preferences
* @reusability : Single Use
* @notes : Main settings page with subpage routing for settings module
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
// Initialize module manager and render the complete page
$module_manager = igny8_module_manager();
// Handle URL parameters for subpages
$subpage = $_GET['sp'] ?? 'general';
// Start output buffering
ob_start();
switch ($subpage) {
case 'status':
include plugin_dir_path(__FILE__) . 'status.php';
break;
case 'integration':
include plugin_dir_path(__FILE__) . 'integration.php';
break;
case 'schedules':
include plugin_dir_path(__FILE__) . 'schedules.php';
break;
case 'import-export':
include plugin_dir_path(__FILE__) . 'import-export.php';
break;
case 'general':
default:
// General settings content
// Handle image generation settings form submission
if (isset($_POST['igny8_image_settings_nonce']) && wp_verify_nonce($_POST['igny8_image_settings_nonce'], 'igny8_image_settings')) {
$image_type = sanitize_text_field($_POST['igny8_image_type'] ?? 'realistic');
$desktop_enabled = isset($_POST['igny8_desktop_enabled']) ? '1' : '0';
$mobile_enabled = isset($_POST['igny8_mobile_enabled']) ? '1' : '0';
$max_in_article_images = intval($_POST['igny8_max_in_article_images'] ?? 1);
$image_format = sanitize_text_field($_POST['igny8_image_format'] ?? 'jpg');
update_option('igny8_image_type', $image_type);
update_option('igny8_desktop_enabled', $desktop_enabled);
update_option('igny8_mobile_enabled', $mobile_enabled);
update_option('igny8_max_in_article_images', $max_in_article_images);
update_option('igny8_image_format', $image_format);
echo '<div class="notice notice-success"><p>Image generation settings saved successfully!</p></div>';
} elseif (isset($_POST['igny8_image_settings_nonce'])) {
echo '<div class="notice notice-error"><p>Security check failed. Please try again.</p></div>';
}
// Handle editor type settings form submission
if (isset($_POST['igny8_editor_type_nonce']) && wp_verify_nonce($_POST['igny8_editor_type_nonce'], 'igny8_editor_type_settings')) {
$editor_type = isset($_POST['igny8_editor_type']) ? sanitize_text_field($_POST['igny8_editor_type']) : 'block';
update_option('igny8_editor_type', $editor_type);
echo '<div class="notice notice-success"><p>Editor type settings saved successfully! Selected: ' . esc_html($editor_type) . '</p></div>';
} elseif (isset($_POST['igny8_editor_type_nonce'])) {
echo '<div class="notice notice-error"><p>Security check failed. Please try again.</p></div>';
}
// Handle image metabox settings form submission
if (isset($_POST['igny8_image_metabox_nonce']) && wp_verify_nonce($_POST['igny8_image_metabox_nonce'], 'igny8_image_metabox_settings')) {
$enabled_types = isset($_POST['igny8_enable_image_metabox']) ? $_POST['igny8_enable_image_metabox'] : [];
$enabled_types = array_map('sanitize_text_field', $enabled_types);
update_option('igny8_enable_image_metabox', $enabled_types);
echo '<div class="notice notice-success"><p>Image metabox settings saved successfully!</p></div>';
}
// Handle module settings form submission (only if not editor type or image metabox form)
if (isset($_POST['submit']) && !isset($_POST['igny8_editor_type_nonce']) && !isset($_POST['igny8_image_metabox_nonce'])) {
$module_manager->save_module_settings();
}
// Debug: Log form submission data (remove in production)
if (isset($_POST['submit']) && current_user_can('manage_options')) {
error_log('Igny8 Settings Debug - POST data: ' . print_r($_POST, true));
}
$settings = get_option('igny8_module_settings', []);
?>
<div class="igny8-settings-section">
<!-- Module Manager Section -->
<div class="igny8-settings-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Module Manager</h3>
<p class="igny8-card-subtitle">Enable or disable plugin modules and features</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-tools igny8-dashboard-icon-lg igny8-dashboard-icon-blue"></span>
</div>
</div>
</div>
<!-- Module Settings -->
<div class="igny8-settings-section">
<div class="igny8-settings">
<form method="post" action="">
<?php wp_nonce_field('igny8_module_settings', 'igny8_module_nonce'); ?>
<!-- Main Modules Section -->
<div class="igny8-settings-section">
<div class="igny8-module-cards-grid">
<?php foreach ($module_manager->get_modules() as $module_key => $module): ?>
<?php if ($module['category'] === 'main'): ?>
<div class="igny8-card igny8-module-card">
<div class="igny8-module-header">
<div class="igny8-card-title">
<span class="dashicons <?php echo esc_attr($module['icon']); ?>" style="color: var(--blue); font-size: 20px; margin-right: 10px;"></span>
<h6><?php echo esc_html($module['name']); ?></h6>
</div>
<div class="igny8-module-toggle">
<label class="igny8-toggle-switch">
<input type="checkbox"
id="module_<?php echo esc_attr($module_key); ?>"
name="igny8_module_settings[<?php echo esc_attr($module_key); ?>]"
value="1"
<?php checked($module_manager->is_module_enabled($module_key)); ?>>
<span class="igny8-toggle-slider"></span>
</label>
</div>
</div>
<div class="igny8-module-description">
<p><?php echo esc_html($module['description']); ?></p>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
<!-- Admin & Analytics Section -->
<div class="igny8-settings-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Admin & Analytics</h3>
<p class="igny8-card-subtitle">Administrative tools and analytics modules</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-chart-bar igny8-dashboard-icon-lg igny8-dashboard-icon-green"></span>
</div>
</div>
</div>
<div class="igny8-module-cards-grid">
<?php foreach ($module_manager->get_modules() as $module_key => $module): ?>
<?php if ($module['category'] === 'admin'): ?>
<div class="igny8-card igny8-module-card">
<div class="igny8-module-header">
<div class="igny8-card-title">
<span class="dashicons <?php echo esc_attr($module['icon']); ?>" style="color: var(--green); font-size: 20px; margin-right: 10px;"></span>
<h6><?php echo esc_html($module['name']); ?></h6>
</div>
<div class="igny8-module-toggle">
<label class="igny8-toggle-switch">
<input type="checkbox"
id="module_<?php echo esc_attr($module_key); ?>"
name="igny8_module_settings[<?php echo esc_attr($module_key); ?>]"
value="1"
<?php checked($module_manager->is_module_enabled($module_key)); ?>>
<span class="igny8-toggle-slider"></span>
</label>
</div>
</div>
<div class="igny8-module-description">
<p><?php echo esc_html($module['description']); ?></p>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
<?php submit_button('Save Module Settings', 'primary', 'submit', true, ['style' => 'margin-top: 20px;']); ?>
</form>
</div>
</div>
</div>
<!-- Editor Type Selection Section -->
<div class="igny8-settings-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Content Editor Type</h3>
<p class="igny8-card-subtitle">Choose between Classic editor or Block (Gutenberg) editor for AI-generated content</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-edit-page igny8-dashboard-icon-lg igny8-dashboard-icon-green"></span>
</div>
</div>
</div>
<div class="igny8-settings">
<form method="post" action="">
<?php wp_nonce_field('igny8_editor_type_settings', 'igny8_editor_type_nonce'); ?>
<div class="igny8-form-group">
<label for="igny8_editor_type"><strong>Select Editor Type:</strong></label>
<div style="margin-top: 15px;">
<?php
$current_editor_type = get_option('igny8_editor_type', 'block');
?>
<!-- Current Setting Display -->
<div style="background: #e8f4fd; border: 1px solid #0073aa; padding: 10px; border-radius: 4px; margin-bottom: 15px;">
<strong>Current Setting:</strong>
<span style="color: #0073aa; font-weight: 600;">
<?php echo $current_editor_type === 'block' ? 'Block Editor (Gutenberg)' : 'Classic Editor'; ?>
</span>
</div>
<label class="igny8-editor-option <?php echo $current_editor_type === 'block' ? 'selected' : ''; ?>">
<input type="radio" name="igny8_editor_type" value="block" <?php checked($current_editor_type, 'block'); ?>>
<div class="igny8-editor-option-content">
<div class="igny8-editor-option-title">Block Editor (Gutenberg)</div>
<div class="igny8-editor-option-description">
Modern block-based editor with advanced formatting options. Recommended for better content structure and WordPress compatibility.
</div>
</div>
</label>
<label class="igny8-editor-option <?php echo $current_editor_type === 'classic' ? 'selected' : ''; ?>">
<input type="radio" name="igny8_editor_type" value="classic" <?php checked($current_editor_type, 'classic'); ?>>
<div class="igny8-editor-option-content">
<div class="igny8-editor-option-title">Classic Editor</div>
<div class="igny8-editor-option-description">
Traditional WYSIWYG editor. Choose this if you prefer the classic WordPress editing experience.
</div>
</div>
</label>
</div>
<div style="background: #f8f9fa; border: 1px solid #e9ecef; padding: 15px; border-radius: 6px; margin-top: 20px;">
<p style="margin: 0 0 10px 0; font-weight: bold; color: #495057;">📝 <strong>How this affects your content:</strong></p>
<ul style="margin: 0; padding-left: 20px; color: #6c757d; font-size: 14px;">
<li><strong>Block Editor:</strong> AI content will be converted to WordPress blocks for better formatting and structure</li>
<li><strong>Classic Editor:</strong> AI content will be saved as HTML and displayed in the classic editor</li>
<li>You can change this setting anytime and it will apply to all new AI-generated content</li>
</ul>
</div>
</div>
<?php submit_button('Save Editor Settings', 'primary', 'submit', true, ['style' => 'margin-top: 20px;']); ?>
</form>
</div>
</div>
<script>
// Enhanced editor selection interaction
document.addEventListener('DOMContentLoaded', function() {
const editorOptions = document.querySelectorAll('.igny8-editor-option');
editorOptions.forEach(option => {
const radio = option.querySelector('input[type="radio"]');
// Add click handler to the entire label
option.addEventListener('click', function(e) {
if (e.target !== radio) {
radio.checked = true;
updateSelection();
}
});
// Add change handler to radio buttons
radio.addEventListener('change', function() {
updateSelection();
});
});
function updateSelection() {
editorOptions.forEach(option => {
const radio = option.querySelector('input[type="radio"]');
if (radio.checked) {
option.classList.add('selected');
} else {
option.classList.remove('selected');
}
});
}
// Initialize selection on page load
updateSelection();
});
</script>
<!-- Image Generation Settings Section -->
<div class="igny8-settings-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Image Generation</h3>
<p class="igny8-card-subtitle">Configure AI image generation settings and preferences</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-format-image igny8-dashboard-icon-lg igny8-dashboard-icon-blue"></span>
</div>
</div>
</div>
<div class="igny8-settings">
<form method="post" action="" id="igny8-image-generation-form">
<?php wp_nonce_field('igny8_image_settings', 'igny8_image_settings_nonce'); ?>
<div class="igny8-form-group">
<label><strong>Image Settings</strong></label>
<div style="display: flex; gap: 20px; align-items: end; margin-top: 10px;">
<div style="flex: 1;">
<label for="igny8_image_type" style="display: block; margin-bottom: 5px; font-weight: 500;">Image Type</label>
<select id="igny8_image_type" name="igny8_image_type" class="igny8-form-control">
<option value="realistic" <?php selected(get_option('igny8_image_type', 'realistic'), 'realistic'); ?>>Realistic</option>
<option value="illustration" <?php selected(get_option('igny8_image_type', 'realistic'), 'illustration'); ?>>Illustration</option>
<option value="3D render" <?php selected(get_option('igny8_image_type', 'realistic'), '3D render'); ?>>3D Render</option>
<option value="minimalist" <?php selected(get_option('igny8_image_type', 'realistic'), 'minimalist'); ?>>Minimalist</option>
<option value="cartoon" <?php selected(get_option('igny8_image_type', 'realistic'), 'cartoon'); ?>>Cartoon</option>
</select>
</div>
<div style="flex: 1;">
<label for="igny8_max_in_article_images" style="display: block; margin-bottom: 5px; font-weight: 500;">Max In-Article Images</label>
<select id="igny8_max_in_article_images" name="igny8_max_in_article_images" class="igny8-form-control">
<option value="1" <?php selected(get_option('igny8_max_in_article_images', '1'), '1'); ?>>1 Image</option>
<option value="2" <?php selected(get_option('igny8_max_in_article_images', '1'), '2'); ?>>2 Images</option>
<option value="3" <?php selected(get_option('igny8_max_in_article_images', '1'), '3'); ?>>3 Images</option>
<option value="4" <?php selected(get_option('igny8_max_in_article_images', '1'), '4'); ?>>4 Images</option>
<option value="5" <?php selected(get_option('igny8_max_in_article_images', '1'), '5'); ?>>5 Images</option>
</select>
</div>
<div style="flex: 1;">
<label for="igny8_image_format" style="display: block; margin-bottom: 5px; font-weight: 500;">Image Format</label>
<select id="igny8_image_format" name="igny8_image_format" class="igny8-form-control">
<option value="jpg" <?php selected(get_option('igny8_image_format', 'jpg'), 'jpg'); ?>>JPG</option>
<option value="png" <?php selected(get_option('igny8_image_format', 'jpg'), 'png'); ?>>PNG</option>
<option value="webp" <?php selected(get_option('igny8_image_format', 'jpg'), 'webp'); ?>>WEBP</option>
</select>
<div id="igny8-selected-format" style="margin-top: 5px; font-weight: bold; color: #0073aa;"></div>
</div>
</div>
</div>
<div class="igny8-form-group">
<label><strong>Current Image Provider & Model</strong></label>
<div style="background: #f8f9fa; border: 1px solid #e9ecef; padding: 15px; border-radius: 6px; margin-top: 10px;">
<?php
$current_service = get_option('igny8_image_service', 'openai');
$current_model = get_option('igny8_image_model', 'dall-e-3');
$current_runware_model = get_option('igny8_runware_model', 'runware:97@1');
if ($current_service === 'openai') {
$model_names = [
'dall-e-3' => 'DALL·E 3',
'dall-e-2' => 'DALL·E 2',
'gpt-image-1' => 'GPT Image 1 (Full)',
'gpt-image-1-mini' => 'GPT Image 1 Mini'
];
$model_name = $model_names[$current_model] ?? $current_model;
echo '<div style="display: flex; align-items: center; margin-bottom: 8px;">';
echo '<span style="font-weight: bold; color: #0073aa; margin-right: 10px;">Provider:</span>';
echo '<span style="color: #495057;">OpenAI</span>';
echo '</div>';
echo '<div style="display: flex; align-items: center;">';
echo '<span style="font-weight: bold; color: #0073aa; margin-right: 10px;">Model:</span>';
echo '<span style="color: #495057;">' . esc_html($model_name) . '</span>';
echo '</div>';
} else {
echo '<div style="display: flex; align-items: center; margin-bottom: 8px;">';
echo '<span style="font-weight: bold; color: #0073aa; margin-right: 10px;">Provider:</span>';
echo '<span style="color: #495057;">Runware</span>';
echo '</div>';
echo '<div style="display: flex; align-items: center;">';
echo '<span style="font-weight: bold; color: #0073aa; margin-right: 10px;">Model:</span>';
echo '<span style="color: #495057;">HiDream-I1 Full</span>';
echo '</div>';
}
?>
<div style="margin-top: 10px; padding-top: 10px; border-top: 1px solid #dee2e6;">
<small style="color: #6c757d;">
<strong>Note:</strong> To change the image provider or model, go to
<a href="<?php echo admin_url('admin.php?page=igny8-settings&sp=integration'); ?>" style="color: #0073aa;">Integration Settings</a>
</small>
</div>
</div>
</div>
<div class="igny8-form-group">
<label><strong>Image Size Options</strong></label>
<div class="igny8-size-checkbox-container">
<!-- Featured Image - Simple row without checkbox/count -->
<div class="igny8-size-option igny8-featured-image-row">
<div class="igny8-size-info igny8-size-featured">Featured Image</div>
<div class="igny8-size-info" id="featured-size-info">1280×832 pixels</div>
</div>
<div class="igny8-size-option">
<label class="igny8-checkbox-label">
<input type="checkbox" id="igny8_desktop_enabled" name="igny8_desktop_enabled" value="1" <?php checked(get_option('igny8_desktop_enabled', '1'), '1'); ?>>
<span class="igny8-checkbox-text">Desktop Images</span>
</label>
<div class="igny8-size-info" id="desktop-size-info">1024×1024 pixels</div>
</div>
<div class="igny8-size-option">
<label class="igny8-checkbox-label">
<input type="checkbox" id="igny8_mobile_enabled" name="igny8_mobile_enabled" value="1" <?php checked(get_option('igny8_mobile_enabled', '0'), '1'); ?>>
<span class="igny8-checkbox-text">Mobile Images</span>
</label>
<div class="igny8-size-info" id="mobile-size-info">960×1280 pixels</div>
</div>
</div>
<small class="form-help">Choose which image sizes to generate and how many of each type.</small>
</div>
<?php submit_button('Save Image Settings', 'primary', 'submit', true, ['style' => 'margin-top: 20px;']); ?>
</form>
</div>
</div>
<script>
// Image generation settings JavaScript
document.addEventListener('DOMContentLoaded', function() {
// Get current provider from integration settings
const currentProvider = '<?php echo esc_js(get_option('igny8_image_service', 'openai')); ?>';
function updateSizeInfo(provider) {
const sizeInfo = {
'runware': {
featured: '1280×832 pixels',
desktop: '1024×1024 pixels',
mobile: '960×1280 pixels'
},
'openai': {
featured: '1024×1024 pixels',
desktop: '1024×1024 pixels',
mobile: '1024×1024 pixels'
},
'dalle': {
featured: '1024×1024 pixels',
desktop: '1024×1024 pixels',
mobile: '1024×1024 pixels'
}
};
if (sizeInfo[provider]) {
$('#featured-size-info').text(sizeInfo[provider].featured);
$('#desktop-size-info').text(sizeInfo[provider].desktop);
$('#mobile-size-info').text(sizeInfo[provider].mobile);
}
}
// Initialize with current provider
updateSizeInfo(currentProvider);
// Image format selector functionality
const $formatSelector = $('#igny8_image_format');
const $formatDisplay = $('#igny8-selected-format');
$formatSelector.on('change', function() {
const selectedFormat = $(this).val().toUpperCase();
$formatDisplay.text(selectedFormat + ' format');
});
// Initialize format display with saved value
const savedFormat = '<?php echo esc_js(get_option('igny8_image_format', 'jpg')); ?>';
$formatSelector.val(savedFormat);
$formatSelector.trigger('change');
});
</script>
<style>
/* Image Generation Settings Styles */
.igny8-size-checkbox-container {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 20px;
margin-top: 10px;
}
.igny8-size-option {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #e9ecef;
}
.igny8-size-option:last-child {
border-bottom: none;
}
.igny8-featured-image-row {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 6px;
padding: 15px 20px;
margin-bottom: 15px;
border-bottom: none;
}
.igny8-size-featured {
font-weight: bold;
font-size: 16px;
}
.igny8-checkbox-label {
display: flex;
align-items: center;
cursor: pointer;
font-weight: 500;
}
.igny8-checkbox-label input[type="checkbox"] {
margin-right: 10px;
transform: scale(1.2);
}
.igny8-size-info {
font-size: 14px;
color: #6c757d;
font-weight: 500;
}
.igny8-featured-image-row .igny8-size-info {
color: rgba(255, 255, 255, 0.9);
}
.form-help {
display: block;
margin-top: 5px;
font-size: 13px;
color: #6c757d;
font-style: italic;
}
</style>
<!-- Image Metabox Settings Section -->
<div class="igny8-settings-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>In-Article Image Meta Box</h3>
<p class="igny8-card-subtitle">Enable image metabox for specific post types</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-format-image igny8-dashboard-icon-lg igny8-dashboard-icon-blue"></span>
</div>
</div>
</div>
<div class="igny8-settings">
<form method="post" action="">
<?php wp_nonce_field('igny8_image_metabox_settings', 'igny8_image_metabox_nonce'); ?>
<div class="igny8-form-group">
<label for="igny8_enable_image_metabox"><strong>Enable In-Article Image Meta Box For:</strong></label>
<div style="max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 15px; background: #f9f9f9; border-radius: 4px; margin-top: 10px;">
<?php
$all_post_types = get_post_types(['public' => true], 'objects');
$enabled_types = (array) get_option('igny8_enable_image_metabox', []);
foreach ($all_post_types as $pt => $obj) {
$checked = in_array($pt, $enabled_types) ? 'checked' : '';
echo '<label style="display: block; margin-bottom: 8px; padding: 5px;">';
echo '<input type="checkbox" name="igny8_enable_image_metabox[]" value="' . esc_attr($pt) . '" ' . $checked . ' style="margin-right: 8px;"> ';
echo '<strong>' . esc_html($obj->label) . '</strong> <em>(' . esc_html($pt) . ')</em>';
echo '</label>';
}
?>
</div>
<p class="description" style="margin-top: 10px;">Select which post types should display the In-Article Image metabox in the WordPress editor.</p>
</div>
<!-- Shortcode Usage Examples -->
<div class="igny8-form-group" style="margin-top: 25px;">
<label><strong>Shortcode Usage Examples:</strong></label>
<div style="background: #f8f9fa; border: 1px solid #e9ecef; padding: 15px; border-radius: 4px; margin-top: 10px;">
<p style="margin: 0 0 10px 0; font-weight: bold; color: #495057;">Use these shortcodes in your posts/pages to display the selected images:</p>
<div style="margin-bottom: 12px;">
<code style="background: #fff; padding: 4px 8px; border: 1px solid #ddd; border-radius: 3px; font-size: 13px;">[igny8-images]</code>
<span style="margin-left: 8px; color: #6c757d; font-size: 13px;">Display all images</span>
</div>
<div style="margin-bottom: 12px;">
<code style="background: #fff; padding: 4px 8px; border: 1px solid #ddd; border-radius: 3px; font-size: 13px;">[igny8-image id="desktop-1"]</code>
<span style="margin-left: 8px; color: #6c757d; font-size: 13px;">Display specific image by ID</span>
</div>
<div style="margin-bottom: 12px;">
<code style="background: #fff; padding: 4px 8px; border: 1px solid #ddd; border-radius: 3px; font-size: 13px;">[igny8-desktop-images]</code>
<span style="margin-left: 8px; color: #6c757d; font-size: 13px;">Display only desktop images</span>
</div>
<div style="margin-bottom: 12px;">
<code style="background: #fff; padding: 4px 8px; border: 1px solid #ddd; border-radius: 3px; font-size: 13px;">[igny8-mobile-images]</code>
<span style="margin-left: 8px; color: #6c757d; font-size: 13px;">Display only mobile images</span>
</div>
<div style="margin-bottom: 12px;">
<code style="background: #fff; padding: 4px 8px; border: 1px solid #ddd; border-radius: 3px; font-size: 13px;">[igny8-responsive-gallery]</code>
<span style="margin-left: 8px; color: #6c757d; font-size: 13px;">Responsive gallery (desktop on large screens, mobile on small screens)</span>
</div>
<div style="margin-bottom: 0;">
<code style="background: #fff; padding: 4px 8px; border: 1px solid #ddd; border-radius: 3px; font-size: 13px;">[igny8-image-count]</code>
<span style="margin-left: 8px; color: #6c757d; font-size: 13px;">Display count of images</span>
</div>
<p style="margin: 15px 0 0 0; font-size: 12px; color: #6c757d; font-style: italic;">
💡 <strong>Tip:</strong> After selecting images in the metabox, use these shortcodes in your post content to display them on the frontend.
</p>
</div>
</div>
<?php submit_button('Save Image Metabox Settings', 'primary', 'submit', true, ['style' => 'margin-top: 20px;']); ?>
</form>
</div>
</div>
<!-- Table Settings Section -->
<div class="igny8-settings-section">
<form method="post" action="options.php">
<?php settings_fields('igny8_table_settings'); ?>
<table class="form-table">
<tr>
<th scope="row">
<label for="igny8_records_per_page">Records Per Page</label>
</th>
<td>
<select name="igny8_records_per_page" id="igny8_records_per_page">
<option value="10" <?php selected(get_option('igny8_records_per_page', 20), 10); ?>>10</option>
<option value="20" <?php selected(get_option('igny8_records_per_page', 20), 20); ?>>20</option>
<option value="50" <?php selected(get_option('igny8_records_per_page', 20), 50); ?>>50</option>
<option value="100" <?php selected(get_option('igny8_records_per_page', 20), 100); ?>>100</option>
</select>
<p class="description">Default number of records to display per page across all tables in the plugin.</p>
</td>
</tr>
</table>
<?php submit_button('Save Settings'); ?>
</form>
</div>
</div>
<?php
break;
}
// Capture page content
$igny8_page_content = ob_get_clean();
// Include global layout
include plugin_dir_path(__FILE__) . '../../core/global-layout.php';
?>

View File

@@ -0,0 +1,267 @@
<?php
/**
* ==========================
* 🔐 IGNY8 FILE RULE HEADER
* ==========================
* @file : import-export.php
* @location : /modules/settings/import-export.php
* @type : Admin Page
* @scope : Module Only
* @allowed : Data import/export, backup operations, data transfer
* @reusability : Single Use
* @notes : Import/export settings page for settings module
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
// Start output buffering
ob_start();
// Get current import/export settings
$import_export_settings = get_option('igny8_import_export_settings', [
'default_format' => 'csv',
'overwrite_existing' => false,
'include_metrics' => true,
'file_naming_pattern' => 'igny8_export_[date].csv'
]);
// Get recent import/export logs
$recent_logs = get_option('igny8_import_export_logs', []);
$recent_logs = array_slice($recent_logs, 0, 10); // Last 10 entries
// Script localization will be done in the JavaScript section below
?>
<div class="igny8-import-export-page">
<div class="igny8-container">
<!-- Import Data Section -->
<div class="igny8-card igny8-mb-20">
<div class="igny8-card-header igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Import Data</h3>
<div class="igny8-card-subtitle">Download CSV templates and import your data into the Planner module</div>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-upload igny8-dashboard-icon-sm"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<!-- Template Downloads -->
<div class="igny8-mb-20">
<h4>Download Templates</h4>
<div class="igny8-grid-2 igny8-gap-10">
<a href="<?php echo admin_url('admin-ajax.php?action=igny8_download_template&template_type=keywords&nonce=' . wp_create_nonce('igny8_import_export_nonce')); ?>" class="igny8-btn igny8-btn-outline">
<span class="dashicons dashicons-download"></span> Keywords Template
</a>
<a href="<?php echo admin_url('admin-ajax.php?action=igny8_download_template&template_type=clusters&nonce=' . wp_create_nonce('igny8_import_export_nonce')); ?>" class="igny8-btn igny8-btn-outline">
<span class="dashicons dashicons-download"></span> Clusters Template
</a>
<a href="<?php echo admin_url('admin-ajax.php?action=igny8_download_template&template_type=ideas&nonce=' . wp_create_nonce('igny8_import_export_nonce')); ?>" class="igny8-btn igny8-btn-outline">
<span class="dashicons dashicons-download"></span> Ideas Template
</a>
</div>
</div>
<!-- Import Form -->
<form id="igny8-import-form" enctype="multipart/form-data" action="<?php echo admin_url('admin-ajax.php'); ?>" method="post">
<input type="hidden" name="action" value="igny8_run_import">
<input type="hidden" name="nonce" value="<?php echo wp_create_nonce('igny8_import_export_nonce'); ?>">
<div class="igny8-form-group">
<label for="import-file">Select CSV File</label>
<input type="file" id="import-file" name="import_file" accept=".csv" required>
<p class="description">Upload a CSV file with your data. Use the templates above for proper format.</p>
</div>
<div class="igny8-form-group">
<label for="import-type">Import Type</label>
<select id="import-type" name="import_type" required>
<option value="">Select import type...</option>
<option value="keywords">Keywords</option>
<option value="clusters">Clusters</option>
<option value="ideas">Content Ideas</option>
</select>
</div>
<div class="igny8-form-actions">
<button type="submit" class="igny8-btn igny8-btn-success">
<span class="dashicons dashicons-upload"></span> Run Import
</button>
</div>
</form>
<!-- Import Results -->
<div id="import-results" class="igny8-mt-20" style="display: none;"></div>
</div>
</div>
<!-- Export Data Section -->
<div class="igny8-card igny8-mb-20">
<div class="igny8-card-header igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Export Data</h3>
<div class="igny8-card-subtitle">Export your data in various formats for backup and migration</div>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-download igny8-dashboard-icon-sm"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<form id="igny8-export-form" action="<?php echo admin_url('admin-ajax.php'); ?>" method="post">
<input type="hidden" name="action" value="igny8_run_export">
<input type="hidden" name="nonce" value="<?php echo wp_create_nonce('igny8_import_export_nonce'); ?>">
<div class="igny8-form-group">
<label for="export-type">Export Type</label>
<select id="export-type" name="export_type" required>
<option value="">Select export type...</option>
<option value="keywords">Keywords</option>
<option value="clusters">Clusters</option>
<option value="ideas">Content Ideas</option>
</select>
</div>
<div class="igny8-form-group">
<h4>Export Options</h4>
<div class="igny8-checkbox-group">
<label class="igny8-checkbox-label">
<input type="checkbox" id="include-metrics" name="include_metrics" <?php checked($import_export_settings['include_metrics'], true); ?>>
<span class="igny8-checkbox-text">Include Metrics</span>
</label>
<label class="igny8-checkbox-label">
<input type="checkbox" id="include-relationships" name="include_relationships">
<span class="igny8-checkbox-text">Include Relationships</span>
</label>
<label class="igny8-checkbox-label">
<input type="checkbox" id="include-timestamps" name="include_timestamps">
<span class="igny8-checkbox-text">Include Timestamps</span>
</label>
</div>
</div>
<div class="igny8-form-actions">
<button type="submit" class="igny8-btn igny8-btn-primary">
<span class="dashicons dashicons-download"></span> Export CSV
</button>
</div>
</form>
<!-- Export Results -->
<div id="export-results" class="igny8-mt-20" style="display: none;"></div>
</div>
</div>
<!-- Settings & Logging Section -->
<div class="igny8-card">
<div class="igny8-card-header igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Import / Export Preferences</h3>
<div class="igny8-card-subtitle">Configure import/export settings and view operation logs</div>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-generic igny8-dashboard-icon-sm"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<form id="igny8-settings-form" action="<?php echo admin_url('admin-ajax.php'); ?>" method="post">
<input type="hidden" name="action" value="igny8_save_import_export_settings">
<input type="hidden" name="nonce" value="<?php echo wp_create_nonce('igny8_import_export_nonce'); ?>">
<div class="igny8-grid-2 igny8-gap-20">
<div class="igny8-form-group">
<label for="default-format">Default Format</label>
<select id="default-format" name="default_format">
<option value="csv" <?php selected($import_export_settings['default_format'], 'csv'); ?>>CSV</option>
<option value="json" <?php selected($import_export_settings['default_format'], 'json'); ?>>JSON</option>
</select>
</div>
<div class="igny8-form-group">
<label for="file-naming">File Naming Pattern</label>
<input type="text" id="file-naming" name="file_naming_pattern" value="<?php echo esc_attr($import_export_settings['file_naming_pattern']); ?>" placeholder="igny8_export_[date].csv">
<p class="description">Use [date], [type], [time] placeholders</p>
</div>
</div>
<div class="igny8-form-group">
<h4>Default Options</h4>
<div class="igny8-checkbox-group">
<label class="igny8-checkbox-label">
<input type="checkbox" id="overwrite-existing" name="overwrite_existing" <?php checked($import_export_settings['overwrite_existing'], true); ?>>
<span class="igny8-checkbox-text">Overwrite Existing Records</span>
</label>
<label class="igny8-checkbox-label">
<input type="checkbox" id="include-metrics-default" name="include_metrics" <?php checked($import_export_settings['include_metrics'], true); ?>>
<span class="igny8-checkbox-text">Include Metrics in Export by Default</span>
</label>
</div>
</div>
<div class="igny8-form-actions">
<button type="submit" class="igny8-btn igny8-btn-success">Save Preferences</button>
</div>
</form>
<!-- Recent Logs -->
<?php if (!empty($recent_logs)): ?>
<div class="igny8-mt-30">
<h4>Recent Import/Export Activity</h4>
<div class="igny8-logs-container" style="max-height: 300px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 10px; background: #f9f9f9;">
<?php foreach ($recent_logs as $log): ?>
<div class="igny8-log-entry" style="border-bottom: 1px solid #eee; padding: 8px 0; font-size: 12px;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span style="font-weight: bold; color: <?php echo $log['status'] === 'success' ? 'green' : 'red'; ?>;">
<?php echo $log['status'] === 'success' ? '✓' : '✗'; ?>
<?php echo esc_html($log['operation']); ?>
</span>
<span style="color: #666;"><?php echo esc_html($log['timestamp']); ?></span>
</div>
<div style="color: #666; margin-top: 2px;">
<?php echo esc_html($log['message']); ?>
<?php if (isset($log['details'])): ?>
<br><small><?php echo esc_html($log['details']); ?></small>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<script>
// Localize script variables
window.IGNY8_IMPORT_EXPORT = {
ajaxUrl: '<?php echo admin_url('admin-ajax.php'); ?>',
nonce: '<?php echo wp_create_nonce('igny8_import_export_nonce'); ?>',
settings: <?php echo json_encode($import_export_settings); ?>
};
document.addEventListener('DOMContentLoaded', function() {
console.log('Import/Export page loaded');
console.log('IGNY8_IMPORT_EXPORT:', window.IGNY8_IMPORT_EXPORT);
// Initialize Import/Export functionality
if (typeof window.initializeImportExport === 'function') {
console.log('Initializing Import/Export functionality');
window.initializeImportExport();
} else {
console.error('initializeImportExport function not found');
}
});
</script>

View File

@@ -0,0 +1,744 @@
<?php
/**
* ==========================
* 🔐 IGNY8 FILE RULE HEADER
* ==========================
* @file : integration.php
* @location : /modules/settings/integration.php
* @type : Admin Page
* @scope : Module Only
* @allowed : API integration, connection management, external service settings
* @reusability : Single Use
* @notes : API integration settings page for settings module
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
// Start output buffering
ob_start();
?>
<!-- API Integration Section -->
<div class="igny8-dashboard-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>API Integration</h3>
<p class="igny8-card-subtitle">Configure external API connections and integrations</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-site igny8-dashboard-icon-lg igny8-dashboard-icon-blue"></span>
</div>
</div>
</div>
<!-- API Services Grid -->
<div class="igny8-grid-2 igny8-dashboard-section" style="display: flex; flex-direction: row;">
<!-- OpenAI API Card -->
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>OpenAI API</h3>
<p class="igny8-card-subtitle">AI-powered content generation and analysis</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-site igny8-dashboard-icon-lg igny8-dashboard-icon-green"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<form method="post" action="options.php">
<?php settings_fields('igny8_api_settings'); ?>
<table class="form-table">
<tr>
<th scope="row">
<label for="igny8_api_key">OpenAI API Key</label>
</th>
<td>
<input type="password" name="igny8_api_key" id="igny8_api_key" value="<?php echo esc_attr(get_option('igny8_api_key', '')); ?>" class="regular-text" />
<p class="description">Your OpenAI API key for DALL-E 3 image generation and text AI features.</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="igny8_runware_api_key">Runware API Key</label>
</th>
<td>
<input type="password" name="igny8_runware_api_key" id="igny8_runware_api_key" value="<?php echo esc_attr(get_option('igny8_runware_api_key', '')); ?>" class="regular-text" />
<p class="description">Your Runware API key for high-quality image generation. <a href="https://runware.com" target="_blank">Get your API key here</a>.</p>
</td>
</tr>
<tr>
<th scope="row">
<label>AI Model</label>
</th>
<td>
<fieldset>
<label style="display: block; margin-bottom: 10px;">
<input type="radio" name="igny8_model" value="gpt-4.1" <?php checked(get_option('igny8_model', 'gpt-4.1'), 'gpt-4.1'); ?> />
<strong>GPT-4.1</strong> — $2.00 / $8.00 per 1M tokens<br>
<span style="color: #666; font-size: 12px;">Content creation, coding, analysis, high-quality content generation</span>
</label>
<label style="display: block; margin-bottom: 10px;">
<input type="radio" name="igny8_model" value="gpt-4o-mini" <?php checked(get_option('igny8_model', 'gpt-4.1'), 'gpt-4o-mini'); ?> />
<strong>GPT-4o mini</strong> — $0.15 / $0.60 per 1M tokens<br>
<span style="color: #666; font-size: 12px;">Bulk tasks, lightweight AI, cost-effective for high-volume operations</span>
</label>
<label style="display: block;">
<input type="radio" name="igny8_model" value="gpt-4o" <?php checked(get_option('igny8_model', 'gpt-4.1'), 'gpt-4o'); ?> />
<strong>GPT-4o</strong> — $2.50 / $10.00 per 1M tokens<br>
<span style="color: #666; font-size: 12px;">Advanced AI for general and multimodal tasks, faster than GPT-4.1</span>
</label>
</fieldset>
<p class="description">Select the AI model to use for content generation. Pricing shown per 1M tokens.</p>
</td>
</tr>
<tr>
<th scope="row">Image Generation Service</th>
<td>
<fieldset>
<label style="display: block; margin-bottom: 10px;">
<input type="radio" name="igny8_image_service" value="openai" <?php checked(get_option('igny8_image_service', 'openai'), 'openai'); ?> />
<strong>OpenAI</strong> — Multiple models available<br>
<span style="color: #666; font-size: 12px;">High-quality image generation with OpenAI's models</span>
</label>
<label style="display: block;">
<input type="radio" name="igny8_image_service" value="runware" <?php checked(get_option('igny8_image_service', 'openai'), 'runware'); ?> />
<strong>Runware</strong> — $0.036 per image<br>
<span style="color: #666; font-size: 12px;">High-quality AI image generation with Runware's models</span>
</label>
</fieldset>
<p class="description">Select the image generation service to use. Each service requires its own API key.</p>
</td>
</tr>
<tr id="igny8-openai-models-row" style="display: none;">
<th scope="row">OpenAI Image Model</th>
<td>
<fieldset>
<label style="display: block; margin-bottom: 10px;">
<input type="radio" name="igny8_image_model" value="dall-e-3" <?php checked(get_option('igny8_image_model', 'dall-e-3'), 'dall-e-3'); ?> />
<strong>DALL·E 3</strong> — $0.040 per image<br>
<span style="color: #666; font-size: 12px;">High-quality image generation with advanced AI capabilities</span>
</label>
<label style="display: block; margin-bottom: 10px;">
<input type="radio" name="igny8_image_model" value="dall-e-2" <?php checked(get_option('igny8_image_model', 'dall-e-3'), 'dall-e-2'); ?> />
<strong>DALL·E 2</strong> — $0.020 per image<br>
<span style="color: #666; font-size: 12px;">Cost-effective image generation with good quality</span>
</label>
<label style="display: block; margin-bottom: 10px;">
<input type="radio" name="igny8_image_model" value="gpt-image-1" <?php checked(get_option('igny8_image_model', 'dall-e-3'), 'gpt-image-1'); ?> />
<strong>GPT Image 1 (Full)</strong> — $0.042 per image<br>
<span style="color: #666; font-size: 12px;">Full-featured image generation with comprehensive capabilities</span>
</label>
<label style="display: block;">
<input type="radio" name="igny8_image_model" value="gpt-image-1-mini" <?php checked(get_option('igny8_image_model', 'dall-e-3'), 'gpt-image-1-mini'); ?> />
<strong>GPT Image 1 Mini</strong> — $0.011 per image<br>
<span style="color: #666; font-size: 12px;">Lightweight, cost-effective image generation for bulk operations</span>
</label>
</fieldset>
<p class="description">Select the OpenAI image model to use. Pricing shown per image.</p>
</td>
</tr>
<tr id="igny8-runware-models-row" style="display: none;">
<th scope="row">Runware Image Model</th>
<td>
<fieldset>
<label style="display: block;">
<input type="radio" name="igny8_runware_model" value="runware:97@1" <?php checked(get_option('igny8_runware_model', 'runware:97@1'), 'runware:97@1'); ?> />
<strong>HiDream-I1 Full</strong> — $0.036 per image<br>
<span style="color: #666; font-size: 12px;">High-quality AI image generation with Runware's HiDream model</span>
</label>
</fieldset>
<p class="description">Select the Runware image model to use. Pricing shown per image.</p>
</td>
</tr>
<tr>
<th scope="row">API Validation</th>
<td>
<div id="igny8-openai-validation" style="display: none;">
<button type="button" id="igny8-test-api" class="button">Test OpenAI Connection</button>
<button type="button" id="igny8-test-response" class="button">Test OpenAI Response (Ping)</button>
</div>
<div id="igny8-runware-validation" style="display: none;">
<button type="button" id="igny8-test-runware-btn" class="button">Test Runware Connection</button>
<div id="igny8-runware-test-result" style="margin-top: 10px;"></div>
</div>
<div id="igny8-api-test-result" style="margin-top: 10px;"></div>
</td>
</tr>
</table>
<?php submit_button('Save API Settings'); ?>
</form>
</div>
</div>
<!-- Google Search Console API Card -->
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Google Search Console API</h3>
<p class="igny8-card-subtitle">Search performance and ranking data integration</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-chart-bar igny8-dashboard-icon-lg igny8-dashboard-icon-orange"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<div style="background: rgba(255, 193, 7, 0.1); border: 1px solid var(--amber); border-radius: var(--radius); padding: 16px; margin-bottom: 20px;">
<div style="display: flex; align-items: center; gap: 12px;">
<span style="font-size: 24px;">⚠️</span>
<div>
<strong style="color: var(--amber-dark);">Coming Soon</strong><br>
<span style="color: var(--text-dim); font-size: 14px;">
Google Search Console API integration is currently in development.
This will provide search performance data and ranking insights.
</span>
</div>
</div>
</div>
<div style="color: var(--text-dim); margin-bottom: 16px;">
<strong>Planned Features:</strong>
<ul style="margin: 8px 0; padding-left: 20px;">
<li>Search performance metrics</li>
<li>Keyword ranking data</li>
<li>Click-through rate analysis</li>
<li>Search appearance insights</li>
</ul>
</div>
<div style="text-align: center; padding: 20px; background: var(--bg-light); border-radius: var(--radius);">
<span style="color: var(--text-dim); font-size: 14px;">
Integration will be available in a future update
</span>
</div>
</div>
</div>
</div>
</div>
<!-- API Request Logs Section -->
<div class="igny8-dashboard-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>API Request Logs</h3>
<p class="igny8-card-subtitle">Monitor API usage and performance metrics</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-chart-line igny8-dashboard-icon-lg igny8-dashboard-icon-purple"></span>
</div>
</div>
</div>
<div class="igny8-card">
<div class="igny8-card-body">
<div id="igny8-api-logs-container">
<div class="tablenav top">
<div class="alignleft actions">
<button type="button" id="igny8-refresh-logs" class="button">Refresh Logs</button>
<button type="button" id="igny8-clear-logs" class="button">Clear Logs</button>
</div>
<div class="alignright actions">
<span class="displaying-num">
<span id="igny8-logs-count">0</span> API calls
</span>
</div>
</div>
<table class="widefat fixed striped" id="igny8-api-logs">
<thead>
<tr>
<th>Timestamp</th>
<th>Status</th>
<th>Model</th>
<th>Tokens (In/Out)</th>
<th>Cost</th>
<th>API ID</th>
</tr>
</thead>
<tbody>
<?php
global $wpdb;
$logs = $wpdb->get_results("
SELECT * FROM {$wpdb->prefix}igny8_logs
WHERE source = 'openai_api'
ORDER BY created_at DESC
LIMIT 20
");
if ($logs) {
foreach ($logs as $log) {
$context = json_decode($log->context, true);
$status_class = $log->status === 'success' ? 'success' : 'error';
$status_icon = $log->status === 'success' ? '✅' : '❌';
// Debug logging for cost display
error_log("Igny8 Display Debug: Log ID=" . $log->id . ", total_cost=" . ($context['total_cost'] ?? 'null') . ", formatted=" . igny8_format_cost($context['total_cost'] ?? 0));
echo "<tr>
<td>" . esc_html($log->created_at) . "</td>
<td><span class='igny8-status {$status_class}'>{$status_icon} " . esc_html($log->status) . "</span></td>
<td>" . esc_html($context['model'] ?? 'Unknown') . "</td>
<td>" . intval($context['input_tokens'] ?? 0) . " / " . intval($context['output_tokens'] ?? 0) . "</td>
<td>" . igny8_format_cost($context['total_cost'] ?? 0) . "</td>
<td>" . esc_html($log->api_id ? substr($log->api_id, 0, 12) . '...' : 'N/A') . "</td>
</tr>";
}
} else {
echo '<tr><td colspan="6">No API logs found.</td></tr>';
}
?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Image Request Logs Section -->
<div class="igny8-dashboard-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Image Request Logs</h3>
<p class="igny8-card-subtitle">Monitor AI image generation requests and performance</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-format-image igny8-dashboard-icon-lg igny8-dashboard-icon-teal"></span>
</div>
</div>
</div>
<div class="igny8-card">
<div class="igny8-card-body">
<div id="igny8-image-logs-container">
<div class="tablenav top">
<div class="alignleft actions">
<button type="button" id="igny8-refresh-image-logs" class="button">Refresh Logs</button>
<button type="button" id="igny8-clear-image-logs" class="button">Clear Logs</button>
</div>
<div class="alignright actions">
<span class="displaying-num">
<span id="igny8-image-logs-count">0</span> image requests
</span>
</div>
</div>
<table class="widefat fixed striped" id="igny8-image-logs">
<thead>
<tr>
<th>Timestamp</th>
<th>Status</th>
<th>Model</th>
<th>Prompt Length</th>
<th>Cost</th>
<th>Image Size</th>
<th>API ID</th>
</tr>
</thead>
<tbody>
<?php
$image_logs = $wpdb->get_results("
SELECT * FROM {$wpdb->prefix}igny8_logs
WHERE source = 'openai_image'
ORDER BY created_at DESC
LIMIT 20
");
if ($image_logs) {
foreach ($image_logs as $log) {
$context = json_decode($log->context, true);
$status_class = $log->status === 'success' ? 'success' : 'error';
$status_icon = $log->status === 'success' ? '✅' : '❌';
echo "<tr>
<td>" . esc_html($log->created_at) . "</td>
<td><span class='igny8-status {$status_class}'>{$status_icon} " . esc_html($log->status) . "</span></td>
<td>" . esc_html($context['model'] ?? 'dall-e-3') . "</td>
<td>" . intval($context['prompt_length'] ?? 0) . " chars</td>
<td>" . igny8_format_cost($context['total_cost'] ?? 0) . "</td>
<td>" . esc_html($context['image_size'] ?? '1024x1024') . "</td>
<td>" . esc_html($log->api_id ? substr($log->api_id, 0, 12) . '...' : 'N/A') . "</td>
</tr>";
}
} else {
echo '<tr><td colspan="7">No image request logs found.</td></tr>';
}
?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Content Engine Settings Section -->
<div class="igny8-dashboard-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Content Engine Settings</h3>
<p class="igny8-card-subtitle">Personalization and content generation configuration</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-generic igny8-dashboard-icon-lg igny8-dashboard-icon-amber"></span>
</div>
</div>
</div>
<div class="igny8-card">
<div class="igny8-card-body">
<div style="background: rgba(59, 130, 246, 0.1); border: 1px solid var(--blue); border-radius: var(--radius); padding: 16px; margin-bottom: 20px;">
<div style="display: flex; align-items: center; gap: 12px;">
<span style="font-size: 24px;"></span>
<div>
<strong style="color: var(--blue-dark);">Settings Moved</strong><br>
<span style="color: var(--text-dim); font-size: 14px;">
Content Engine settings have been moved to the Personalize module for better organization.
</span>
</div>
</div>
</div>
<p><strong>Note:</strong> Content Engine settings have been moved to the <a href="<?php echo admin_url('admin.php?page=igny8-personalize&sm=settings'); ?>">Personalize module</a> for better organization.</p>
<p>Please configure personalization settings in the Personalize → Settings section.</p>
</div>
</div>
</div>
<!-- Third-party Integrations Section -->
<div class="igny8-dashboard-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Third-party Integrations</h3>
<p class="igny8-card-subtitle">Additional SEO tools and data sources</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-tools igny8-dashboard-icon-lg igny8-dashboard-icon-red"></span>
</div>
</div>
</div>
<div class="igny8-card">
<div class="igny8-card-body">
<div style="background: rgba(255, 193, 7, 0.1); border: 1px solid var(--amber); border-radius: var(--radius); padding: 16px; margin-bottom: 20px;">
<div style="display: flex; align-items: center; gap: 12px;">
<span style="font-size: 24px;">⚠️</span>
<div>
<strong style="color: var(--amber-dark);">Coming Soon</strong><br>
<span style="color: var(--text-dim); font-size: 14px;">
Additional third-party integrations are currently in development.
</span>
</div>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
<div style="padding: 16px; background: var(--bg-light); border-radius: var(--radius);">
<h4 style="margin: 0 0 8px 0; color: var(--text-primary);">Ahrefs API</h4>
<p style="margin: 0; color: var(--text-dim); font-size: 14px;">Integration with Ahrefs for keyword and backlink data.</p>
</div>
<div style="padding: 16px; background: var(--bg-light); border-radius: var(--radius);">
<h4 style="margin: 0 0 8px 0; color: var(--text-primary);">SEMrush API</h4>
<p style="margin: 0; color: var(--text-dim); font-size: 14px;">Integration with SEMrush for competitive analysis.</p>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Handle conditional display of image model options and API validation
const imageServiceRadios = document.querySelectorAll('input[name="igny8_image_service"]');
const openaiModelsRow = document.getElementById('igny8-openai-models-row');
const runwareModelsRow = document.getElementById('igny8-runware-models-row');
const openaiValidation = document.getElementById('igny8-openai-validation');
const runwareValidation = document.getElementById('igny8-runware-validation');
function toggleServiceOptions() {
const selectedService = document.querySelector('input[name="igny8_image_service"]:checked');
if (selectedService) {
if (selectedService.value === 'openai') {
openaiModelsRow.style.display = 'table-row';
runwareModelsRow.style.display = 'none';
openaiValidation.style.display = 'block';
runwareValidation.style.display = 'none';
} else if (selectedService.value === 'runware') {
openaiModelsRow.style.display = 'none';
runwareModelsRow.style.display = 'table-row';
openaiValidation.style.display = 'none';
runwareValidation.style.display = 'block';
}
}
}
// Add event listeners to image service radio buttons
imageServiceRadios.forEach(radio => {
radio.addEventListener('change', toggleServiceOptions);
});
// Initialize display on page load
toggleServiceOptions();
const testApiButton = document.getElementById('igny8-test-api');
const testResponseButton = document.getElementById('igny8-test-response');
const refreshLogsButton = document.getElementById('igny8-refresh-logs');
const clearLogsButton = document.getElementById('igny8-clear-logs');
const refreshImageLogsButton = document.getElementById('igny8-refresh-image-logs');
const clearImageLogsButton = document.getElementById('igny8-clear-image-logs');
const resultDiv = document.getElementById('igny8-api-test-result');
// Test API Connection (without I/O messages)
if (testApiButton) {
testApiButton.addEventListener('click', function() {
testApiConnection(false);
});
}
// Test API Response (with "test ping")
if (testResponseButton) {
testResponseButton.addEventListener('click', function() {
testApiConnection(true);
});
}
// Refresh Logs
if (refreshLogsButton) {
refreshLogsButton.addEventListener('click', function() {
loadApiLogs();
});
}
// Clear Logs
if (clearLogsButton) {
clearLogsButton.addEventListener('click', function() {
clearApiLogs();
});
}
// Refresh Image Logs
if (refreshImageLogsButton) {
refreshImageLogsButton.addEventListener('click', function() {
loadImageLogs();
});
}
// Clear Image Logs
if (clearImageLogsButton) {
clearImageLogsButton.addEventListener('click', function() {
clearImageLogs();
});
}
function testApiConnection(withResponse = false) {
resultDiv.innerHTML = '<span style="color: blue;">Testing API connection...</span>';
const formData = new FormData();
formData.append('action', 'igny8_test_api');
formData.append('nonce', '<?php echo wp_create_nonce('igny8_ajax_nonce'); ?>');
formData.append('with_response', withResponse ? '1' : '0');
fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
const modelUsed = data.data?.model_used || 'Unknown';
const response = data.data?.response || 'No response';
const cost = data.data?.cost || 'N/A';
const tokens = data.data?.tokens || 'N/A';
const tokensSent = data.data?.tokens_sent || 'N/A';
const tokensUsed = data.data?.tokens_used || 'N/A';
const totalTokens = data.data?.total_tokens || 'N/A';
resultDiv.innerHTML = `
<div style="color: green; margin-bottom: 10px;">
✓ API connection successful!
</div>
<div style="background: #f0f8ff; padding: 10px; border-radius: 4px; border-left: 4px solid #0073aa;">
<strong>Model Used:</strong> ${modelUsed}<br>
${withResponse ? `<strong>Expected:</strong> "OK! Ping Received"<br><strong>Actual Response:</strong> "${response}"<br>` : ''}
<strong>Token Limit Sent:</strong> ${tokensSent} (from your settings)<br>
<strong>Tokens Used:</strong> ${tokensUsed} (input/output)<br>
<strong>Total Tokens:</strong> ${totalTokens}<br>
<strong>Cost:</strong> ${cost}
</div>
`;
// Refresh logs to show new entry
setTimeout(() => loadApiLogs(), 1000);
} else {
const errorMessage = data.data?.message || 'Unknown error';
const errorDetails = data.data?.details || '';
resultDiv.innerHTML = `
<div style="color: red; margin-bottom: 10px;">
✗ API connection failed: ${errorMessage}
</div>
${errorDetails ? `<div style="background: #fff2f2; padding: 10px; border-radius: 4px; border-left: 4px solid #dc3232; font-size: 12px; color: #666;">
<strong>Details:</strong> ${errorDetails}
</div>` : ''}
`;
}
})
.catch(error => {
resultDiv.innerHTML = '<span style="color: red;">✗ API connection failed: ' + error.message + '</span>';
});
}
function loadApiLogs() {
fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
action: 'igny8_get_api_logs',
nonce: '<?php echo wp_create_nonce('igny8_ajax_nonce'); ?>'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
const logsTable = document.querySelector('#igny8-api-logs tbody');
const logsCount = document.getElementById('igny8-logs-count');
if (logsTable) {
logsTable.innerHTML = data.data.html;
}
if (logsCount) {
logsCount.textContent = data.data.total;
}
}
})
.catch(error => {
console.error('Error loading logs:', error);
});
}
function clearApiLogs() {
if (!confirm('Are you sure you want to clear all API logs? This action cannot be undone.')) {
return;
}
fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
action: 'igny8_clear_api_logs',
nonce: '<?php echo wp_create_nonce('igny8_ajax_nonce'); ?>'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
loadApiLogs();
alert('API logs cleared successfully!');
} else {
alert('Error clearing logs: ' + (data.data?.message || 'Unknown error'));
}
})
.catch(error => {
console.error('Error clearing logs:', error);
alert('Error clearing logs: ' + error.message);
});
}
function loadImageLogs() {
fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
action: 'igny8_get_image_logs',
nonce: '<?php echo wp_create_nonce('igny8_ajax_nonce'); ?>'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
const logsTable = document.querySelector('#igny8-image-logs tbody');
const logsCount = document.getElementById('igny8-image-logs-count');
if (logsTable) {
logsTable.innerHTML = data.data.html;
}
if (logsCount) {
logsCount.textContent = data.data.total;
}
}
})
.catch(error => {
console.error('Error loading image logs:', error);
});
}
function clearImageLogs() {
if (!confirm('Are you sure you want to clear all image request logs? This action cannot be undone.')) {
return;
}
fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
action: 'igny8_clear_image_logs',
nonce: '<?php echo wp_create_nonce('igny8_ajax_nonce'); ?>'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
loadImageLogs();
alert('Image request logs cleared successfully!');
} else {
alert('Error clearing image logs: ' + (data.data?.message || 'Unknown error'));
}
})
.catch(error => {
console.error('Error clearing image logs:', error);
alert('Error clearing image logs: ' + error.message);
});
}
// Load logs on page load
loadApiLogs();
loadImageLogs();
});
</script>
<style>
.igny8-status.success {
color: #46b450;
font-weight: bold;
}
.igny8-status.error {
color: #dc3232;
font-weight: bold;
}
#igny8-api-logs {
margin-top: 15px;
}
#igny8-api-logs th {
background: #f1f1f1;
font-weight: bold;
}
#igny8-api-logs td {
padding: 8px 10px;
}
</style>

View File

@@ -0,0 +1,297 @@
<?php
/**
* ==========================
* 🔐 IGNY8 FILE RULE HEADER
* ==========================
* @file : schedules.php
* @location : /modules/settings/schedules.php
* @type : Admin Page
* @scope : Module Only
* @allowed : Automation scheduling, cron configuration, timing settings
* @reusability : Single Use
* @notes : Automation schedules configuration page for settings module
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
// Start output buffering
ob_start();
// Load master dispatcher functions
if (!function_exists('igny8_get_defined_cron_jobs')) {
include_once plugin_dir_path(__FILE__) . '../../core/cron/igny8-cron-master-dispatcher.php';
}
// Handle form submission
if (isset($_POST['igny8_save_cron_settings']) && wp_verify_nonce($_POST['igny8_cron_nonce'], 'igny8_cron_settings')) {
$cron_jobs = $_POST['cron_jobs'] ?? [];
$cron_settings = get_option('igny8_cron_settings', []);
$cron_limits = get_option('igny8_cron_limits', []);
// Update settings for each job
foreach ($cron_jobs as $job_name => $job_data) {
$cron_settings[$job_name] = [
'enabled' => isset($job_data['enabled']),
'last_run' => $cron_settings[$job_name]['last_run'] ?? 0
];
// Update limits
if (isset($job_data['limit'])) {
$cron_limits[$job_name] = intval($job_data['limit']);
}
}
update_option('igny8_cron_settings', $cron_settings);
update_option('igny8_cron_limits', $cron_limits);
echo '<div class="notice notice-success"><p>Settings saved successfully!</p></div>';
}
// Get current data
$defined_jobs = igny8_get_defined_cron_jobs();
$cron_settings = get_option('igny8_cron_settings', []);
$cron_limits = get_option('igny8_cron_limits', []);
$last_execution = get_option('igny8_cron_last_execution', []);
// Initialize defaults if needed
if (empty($cron_settings)) {
$cron_settings = igny8_get_default_cron_settings();
update_option('igny8_cron_settings', $cron_settings);
}
if (empty($cron_limits)) {
$cron_limits = igny8_get_default_cron_limits();
update_option('igny8_cron_limits', $cron_limits);
}
// Get health status for all jobs
$health_status = [];
foreach ($defined_jobs as $job_name => $job_config) {
$health_status[$job_name] = igny8_get_job_health_status($job_name);
}
?>
<div class="wrap igny8-admin-page">
<!-- Smart Automation Jobs Table -->
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Smart Automation Jobs</h3>
<p class="igny8-card-subtitle">Configure and manage all automation jobs</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-tools igny8-dashboard-icon-lg igny8-dashboard-icon-purple"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<form method="post" action="">
<?php wp_nonce_field('igny8_cron_settings', 'igny8_cron_nonce'); ?>
<table class="igny8-table" data-cron-key="<?php echo esc_attr(get_option('igny8_secure_cron_key')); ?>">
<thead>
<tr>
<th>Job Name</th>
<th>Module</th>
<th>Enable</th>
<th>Max Items</th>
<th>Last Run</th>
<th>Execution Time</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($defined_jobs as $job_name => $job_config):
// Skip crons if their respective modules are disabled
$analytics_crons = ['igny8_process_ai_queue_cron', 'igny8_auto_recalc_cron', 'igny8_health_check_cron'];
$writer_crons = ['igny8_auto_generate_content_cron', 'igny8_auto_generate_images_cron', 'igny8_auto_publish_drafts_cron'];
$optimizer_crons = ['igny8_auto_optimizer_cron'];
if (in_array($job_name, $analytics_crons) && !igny8_is_module_enabled('analytics')) {
continue;
}
if (in_array($job_name, $writer_crons) && !igny8_is_module_enabled('writer')) {
continue;
}
if (in_array($job_name, $optimizer_crons) && !igny8_is_module_enabled('optimizer')) {
continue;
}
$job_settings = $cron_settings[$job_name] ?? [];
$job_status = igny8_get_cron_job_status($job_name);
$job_health = $health_status[$job_name];
?>
<tr>
<td>
<strong><?php echo esc_html($job_config['description']); ?></strong>
</td>
<td>
<span class="igny8-module-badge igny8-module-<?php echo esc_attr($job_config['module']); ?>">
<?php echo esc_html(ucfirst($job_config['module'])); ?>
</span>
</td>
<td>
<label class="igny8-toggle">
<input type="checkbox" name="cron_jobs[<?php echo esc_attr($job_name); ?>][enabled]"
<?php checked($job_settings['enabled'] ?? false); ?>>
<span class="igny8-toggle-slider"></span>
</label>
</td>
<td>
<input type="number" name="cron_jobs[<?php echo esc_attr($job_name); ?>][limit]"
value="<?php echo esc_attr($cron_limits[$job_name] ?? 10); ?>"
min="1" max="100" style="width: 60px;">
<?php
// Add descriptive text based on job type
$item_text = '';
switch($job_name) {
case 'igny8_auto_cluster_cron':
$item_text = 'keywords';
break;
case 'igny8_auto_generate_ideas_cron':
$item_text = 'clusters';
break;
case 'igny8_auto_queue_cron':
$item_text = 'ideas';
break;
case 'igny8_auto_generate_content_cron':
$item_text = 'tasks';
break;
case 'igny8_auto_generate_images_cron':
$item_text = 'posts';
break;
case 'igny8_auto_publish_drafts_cron':
$item_text = 'drafts';
break;
case 'igny8_process_ai_queue_cron':
$item_text = 'tasks';
break;
case 'igny8_auto_recalc_cron':
$item_text = 'items';
break;
default:
$item_text = 'items';
}
echo ' <small style="color: #666; font-size: 12px;">' . $item_text . '</small>';
?>
</td>
<td>
<?php echo esc_html($job_health['last_run']); ?>
<?php if (!empty($job_health['result_details'])): ?>
<br><small style="color: <?php echo ($job_health['last_success'] === true) ? '#28a745' : '#dc3545'; ?>;">
<?php echo esc_html($job_health['result_details']); ?>
<?php if ($job_health['last_success'] === true): ?>
<?php else: ?>
<?php endif; ?>
</small>
<?php endif; ?>
</td>
<td>
<?php
$execution_time = $job_health['execution_time'] ?? 0;
echo $execution_time > 0 ? number_format($execution_time, 2) . 's' : 'N/A';
?>
<?php if (!empty($job_health['execution_method'])): ?>
<br><small style="color: #666;">
via <?php echo esc_html($job_health['execution_method']); ?>
</small>
<?php endif; ?>
</td>
<td class="igny8-align-center igny8-actions">
<button class="igny8-icon-only igny8-icon-external" data-action="openInNewWindow" data-hook="<?php echo esc_attr($job_name); ?>" title="Open in New Window">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
<polyline points="15,3 21,3 21,9"></polyline>
<line x1="10" y1="14" x2="21" y2="3"></line>
</svg>
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<p class="submit">
<input type="submit" name="igny8_save_cron_settings" class="button-primary" value="Save All Settings">
</p>
</form>
</div>
</div>
<!-- Master Scheduler Status -->
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Master Scheduler Configuration</h3>
<p class="igny8-card-subtitle">Single cron job manages all automation</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-clock igny8-dashboard-icon-lg igny8-dashboard-icon-blue"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<p><strong>Single cPanel Configuration Required:</strong></p>
<code>*/5 * * * * curl -s "https://<?php echo $_SERVER['HTTP_HOST']; ?>/wp-load.php?import_key=<?php echo get_option('igny8_secure_cron_key'); ?>&import_id=igny8_cron&action=master_scheduler" > /dev/null 2>&1</code>
<p><em>This single cron job will intelligently manage all automation based on your settings below.</em></p>
</div>
</div>
<!-- System Overview -->
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>System Overview</h3>
<p class="igny8-card-subtitle">Current automation system status</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-dashboard igny8-dashboard-icon-lg igny8-dashboard-icon-green"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<?php
$total_jobs = count($defined_jobs);
$enabled_jobs = count(array_filter($cron_settings, function($settings) { return $settings['enabled'] ?? false; }));
$scheduled_jobs = count(array_filter($health_status, function($status) { return $status['enabled']; }));
$failed_jobs = count(array_filter($health_status, function($status) { return $status['last_success'] === false; }));
?>
<div class="igny8-stats-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 20px; margin: 20px 0;">
<div class="igny8-metric-item" style="background: var(--panel); border: 1px solid var(--stroke); border-radius: var(--radius); padding: 15px; text-align: center;">
<h4 style="margin: 0 0 10px 0; color: var(--blue-dark);">Total Jobs</h4>
<p style="margin: 0; font-size: 24px; font-weight: 700; color: var(--text);"><?php echo esc_html($total_jobs); ?></p>
</div>
<div class="igny8-metric-item" style="background: var(--panel); border: 1px solid var(--stroke); border-radius: var(--radius); padding: 15px; text-align: center;">
<h4 style="margin: 0 0 10px 0; color: var(--green-dark);">Enabled Jobs</h4>
<p style="margin: 0; font-size: 24px; font-weight: 700; color: var(--text);"><?php echo esc_html($enabled_jobs); ?></p>
</div>
<div class="igny8-metric-item" style="background: var(--panel); border: 1px solid var(--stroke); border-radius: var(--radius); padding: 15px; text-align: center;">
<h4 style="margin: 0 0 10px 0; color: var(--amber-dark);">Scheduled Jobs</h4>
<p style="margin: 0; font-size: 24px; font-weight: 700; color: var(--text);"><?php echo esc_html($scheduled_jobs); ?></p>
</div>
<div class="igny8-metric-item" style="background: var(--panel); border: 1px solid var(--stroke); border-radius: var(--radius); padding: 15px; text-align: center;">
<h4 style="margin: 0 0 10px 0; color: var(--red-dark);">Failed Jobs</h4>
<p style="margin: 0; font-size: 24px; font-weight: 700; color: var(--text);"><?php echo esc_html($failed_jobs); ?></p>
</div>
</div>
</div>
</div>
</div>
<?php
// Capture page content
$igny8_page_content = ob_get_clean();
// Include global layout
include plugin_dir_path(__FILE__) . '../../core/global-layout.php';
?>

View File

@@ -0,0 +1,353 @@
<?php
/**
* ==========================
* 🔐 IGNY8 FILE RULE HEADER
* ==========================
* @file : status.php
* @location : /modules/settings/status.php
* @type : Admin Page
* @scope : Module Only
* @allowed : System status monitoring, health checks, diagnostics
* @reusability : Single Use
* @notes : System status monitoring page for settings module
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
?>
<!-- System Status Section -->
<div class="igny8-dashboard-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>System Status</h3>
<p class="igny8-card-subtitle">Monitor system health and component status</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-site igny8-dashboard-icon-lg igny8-dashboard-icon-blue"></span>
</div>
</div>
</div>
<!-- Debug Monitoring & System Layers Section -->
<div class="igny8-grid-2 igny8-dashboard-section" style="
display: flex;
flex-direction: row;
">
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Debug Monitoring</h3>
<p class="igny8-card-subtitle">Real-time debug monitoring controls and status</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-tools igny8-dashboard-icon-lg igny8-dashboard-icon-orange"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<p style="color: var(--text-dim); margin-bottom: 16px;">Enable or disable submodule debug monitoring for Planner, Writer, Linker, Optimizer and Personalize</p>
<!-- Real-time Monitoring Controls -->
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 20px;">
<div style="font-size: 13px; color: var(--text-dim); text-align: right;">
Real-time Monitoring
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<div style="display: flex; align-items: center; gap: 4px;">
<input type="radio" id="debug-enabled" name="debug_monitoring" value="1" <?php echo get_option('igny8_debug_enabled', false) ? 'checked' : ''; ?>>
<label for="debug-enabled" style="font-size: 12px; color: var(--text-dim);">On</label>
</div>
<div style="display: flex; align-items: center; gap: 4px;">
<input type="radio" id="debug-disabled" name="debug_monitoring" value="0" <?php echo !get_option('igny8_debug_enabled', false) ? 'checked' : ''; ?>>
<label for="debug-disabled" style="font-size: 12px; color: var(--text-dim);">Off</label>
</div>
<button type="button" id="save-debug-setting" class="igny8-btn igny8-btn-primary">
<span class="dashicons dashicons-yes-alt" style="font-size: 14px;"></span>
Save
</button>
</div>
</div>
<!-- Current Status Display -->
<?php
$debug_enabled = get_option('igny8_debug_enabled', false);
$status_text = $debug_enabled ? 'Enabled' : 'Disabled';
$status_color = $debug_enabled ? 'var(--green-dark)' : 'var(--red-dark)';
$status_icon = $debug_enabled ? '✅' : '❌';
// Set background and border colors based on status
if ($debug_enabled) {
$status_bg = 'rgba(16,185,129,0.1)';
$status_border = 'var(--green)';
} else {
$status_bg = 'rgba(239,68,68,0.1)';
$status_border = 'var(--red)';
}
?>
<div style="background: <?php echo $status_bg; ?>; border: 1px solid <?php echo $status_border; ?>; border-radius: var(--radius); padding: 16px; margin-top: 16px;">
<div style="display: flex; align-items: center; gap: 12px;">
<span style="font-size: 24px;"><?php echo $status_icon; ?></span>
<div>
<strong style="color: <?php echo $status_color; ?>;">Debug Monitoring: <?php echo $status_text; ?></strong><br>
<span style="color: var(--text-dim); font-size: 14px;">
<?php if ($debug_enabled): ?>
Real-time debug monitoring is active for all submodules. Debug cards and status indicators are visible on submodule pages.
<?php else: ?>
Debug monitoring is disabled. Debug cards and status indicators are hidden on submodule pages.
<?php endif; ?>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>System Layers</h3>
<p class="igny8-card-subtitle">System layer health and operational metrics</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-chart-bar igny8-dashboard-icon-lg igny8-dashboard-icon-teal"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<!-- Metrics Row -->
<div class="igny8-metrics-row">
<div class="igny8-metric">
<div class="igny8-metric-value">100%</div>
<div class="igny8-metric-label">Layer Health</div>
</div>
<div class="igny8-metric">
<div class="igny8-metric-value" style="color: var(--green);">6</div>
<div class="igny8-metric-label">Operational</div>
</div>
<div class="igny8-metric">
<div class="igny8-metric-value" style="color: var(--red-dark);">0</div>
<div class="igny8-metric-label">Failed</div>
</div>
<div class="igny8-metric">
<div class="igny8-metric-value">6</div>
<div class="igny8-metric-label">Total Layers</div>
</div>
</div>
<!-- Layer Status Circles -->
<div class="igny8-flex" style="justify-content: center; gap: 16px; margin: 20px 0;">
<?php
$layer_labels = [
'database_system' => 'DB',
'configuration_system' => 'CFG',
'rendering_system' => 'RND',
'javascript_ajax' => 'JS',
'component_functionality' => 'CMP',
'data_flow' => 'FLW'
];
foreach ($layer_labels as $layer_key => $label):
$layer_status = true; // Simplified - always true for basic layer summary
$status_class = $layer_status ? 'bg-success' : 'bg-error';
?>
<div class="bg-circle <?php echo $status_class; ?>" title="<?php echo ucfirst(str_replace('_', ' ', $layer_key)); ?>: <?php echo $layer_status ? 'Operational' : 'Failed'; ?>">
<?php echo $label; ?>
</div>
<?php endforeach; ?>
</div>
<div style="background: rgba(16,185,129,0.1); border: 1px solid var(--green); border-radius: var(--radius); padding: 16px; margin-top: 16px;">
<div style="display: flex; align-items: center; gap: 12px;">
<span style="font-size: 24px;">✅</span>
<div>
<strong style="color: var(--green-dark);">All Layers Operational</strong><br>
<span style="color: var(--text-dim); font-size: 14px;">
All 6 layers are functioning correctly.
The Igny8 plugin is operating at full capacity.
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- System Information & Database Status Section -->
<div class="igny8-dashboard-section">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>System Information & Database Status</h3>
<p class="igny8-card-subtitle">System details, database tables, and module status</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-site igny8-dashboard-icon-lg igny8-dashboard-icon-blue"></span>
</div>
</div>
</div>
<!-- 4 Cards Grid -->
<div class="igny8-grid igny8-grid-4">
<!-- Card 1: System Information & API Status -->
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>System & API Info</h3>
<p class="igny8-card-subtitle">System information and API configuration status</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-site igny8-dashboard-icon-lg igny8-dashboard-icon-blue"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<div style="margin-bottom: 15px;">
<div style="font-weight: bold; margin-bottom: 8px; color: #333;">System Information</div>
<div style="font-size: 12px; margin-bottom: 4px;"><strong>Plugin:</strong> <?php echo get_option('igny8_version', 'Unknown'); ?></div>
<div style="font-size: 12px; margin-bottom: 4px;"><strong>WordPress:</strong> <?php echo get_bloginfo('version'); ?></div>
<div style="font-size: 12px; margin-bottom: 4px;"><strong>PHP:</strong> <?php echo PHP_VERSION; ?></div>
<div style="font-size: 12px; margin-bottom: 4px;"><strong>MySQL:</strong> <?php global $wpdb; echo $wpdb->db_version(); ?></div>
</div>
<div>
<div style="font-weight: bold; margin-bottom: 8px; color: #333;">API Status</div>
<?php
$api_key = get_option('igny8_api_key');
$api_configured = !empty($api_key);
$api_status_color = $api_configured ? 'green' : 'red';
$api_status_icon = $api_configured ? '✓' : '✗';
?>
<div style="font-size: 12px; margin-bottom: 4px; color: <?php echo $api_status_color; ?>;">
<strong>OpenAI API:</strong> <?php echo $api_status_icon; ?> <?php echo $api_configured ? 'Configured' : 'Not Configured'; ?>
</div>
<div style="font-size: 12px; margin-bottom: 4px;"><strong>Model:</strong> <?php echo get_option('igny8_model', 'gpt-4.1'); ?></div>
</div>
</div>
</div>
<!-- Card 2: Database Tables Part 1 -->
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Database Tables 1</h3>
<p class="igny8-card-subtitle">Core database tables status and health</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-database igny8-dashboard-icon-lg igny8-dashboard-icon-green"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<?php
global $wpdb;
$tables_part1 = [
'igny8_keywords' => 'Keywords',
'igny8_tasks' => 'Tasks',
'igny8_data' => 'Data',
'igny8_variations' => 'Variations',
'igny8_rankings' => 'Rankings',
'igny8_suggestions' => 'Suggestions',
'igny8_campaigns' => 'Campaigns'
];
foreach ($tables_part1 as $table => $name) {
$table_name = $wpdb->prefix . $table;
$exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name;
$status_color = $exists ? 'green' : 'red';
$status_icon = $exists ? '✓' : '✗';
echo "<div style='font-size: 12px; margin-bottom: 3px; color: $status_color;'>$status_icon $name</div>";
}
?>
</div>
</div>
<!-- Card 3: Database Tables Part 2 -->
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Database Tables 2</h3>
<p class="igny8-card-subtitle">Extended database tables status and health</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-database igny8-dashboard-icon-lg igny8-dashboard-icon-purple"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<?php
$tables_part2 = [
'igny8_content_ideas' => 'Content Ideas',
'igny8_clusters' => 'Clusters',
'igny8_sites' => 'Sites',
'igny8_backlinks' => 'Backlinks',
'igny8_mapping' => 'Mapping',
'igny8_prompts' => 'Prompts',
'igny8_logs' => 'Logs'
];
foreach ($tables_part2 as $table => $name) {
$table_name = $wpdb->prefix . $table;
$exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name;
$status_color = $exists ? 'green' : 'red';
$status_icon = $exists ? '✓' : '✗';
echo "<div style='font-size: 12px; margin-bottom: 3px; color: $status_color;'>$status_icon $name</div>";
}
?>
</div>
</div>
<!-- Card 4: Module Status -->
<div class="igny8-card">
<div class="igny8-standard-header">
<div class="igny8-card-header-content">
<div class="igny8-card-title-text">
<h3>Module Status</h3>
<p class="igny8-card-subtitle">Plugin modules activation and status</p>
</div>
<div class="igny8-card-icon">
<span class="dashicons dashicons-admin-tools igny8-dashboard-icon-lg igny8-dashboard-icon-amber"></span>
</div>
</div>
</div>
<div class="igny8-card-body">
<?php
$modules = [
'planner' => 'Planner',
'writer' => 'Writer',
'personalize' => 'Personalize',
'optimizer' => 'Optimizer',
'linker' => 'Linker'
];
foreach ($modules as $module => $name) {
$enabled = get_option("igny8_{$module}_enabled", true);
$status_color = $enabled ? 'green' : 'red';
$status_icon = $enabled ? '✓' : '✗';
echo "<div style='font-size: 12px; margin-bottom: 3px; color: $status_color;'>$status_icon $name</div>";
}
?>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
if (typeof window.initializeDebugToggle === 'function') {
window.initializeDebugToggle();
}
});
</script>