| 1 |
<?php |
| 2 |
/** |
| 3 |
* AI SEO Tools extension bootstrap. |
| 4 |
* |
| 5 |
* @package King_Addons |
| 6 |
*/ |
| 7 |
|
| 8 |
namespace King_Addons\AI_SEO_Tools; |
| 9 |
|
| 10 |
use King_Addons\Alt_Text_Generator; |
| 11 |
|
| 12 |
if (!defined('ABSPATH')) { |
| 13 |
exit; |
| 14 |
} |
| 15 |
|
| 16 |
class AI_SEO_Tools |
| 17 |
{ |
| 18 |
private static ?AI_SEO_Tools $instance = null; |
| 19 |
|
| 20 |
private Alt_Text_Generator $alt_text_generator; |
| 21 |
|
| 22 |
private Bulk_Alt_Text_Module $bulk_alt_module; |
| 23 |
|
| 24 |
private Auto_Tagging_Module $auto_tagging_module; |
| 25 |
|
| 26 |
private Post_Generator_Module $post_gen_module; |
| 27 |
|
| 28 |
public static function instance(): AI_SEO_Tools |
| 29 |
{ |
| 30 |
if (self::$instance === null) { |
| 31 |
self::$instance = new self(); |
| 32 |
} |
| 33 |
|
| 34 |
return self::$instance; |
| 35 |
} |
| 36 |
|
| 37 |
private function __construct() |
| 38 |
{ |
| 39 |
require_once KING_ADDONS_PATH . 'includes/extensions/alt-text-generator/Alt_Text_Generator.php'; |
| 40 |
require_once __DIR__ . '/Bulk_Alt_Text_Module.php'; |
| 41 |
require_once __DIR__ . '/Auto_Tagging_Module.php'; |
| 42 |
require_once __DIR__ . '/Post_Generator_Module.php'; |
| 43 |
|
| 44 |
$this->alt_text_generator = new Alt_Text_Generator(); |
| 45 |
$this->bulk_alt_module = new Bulk_Alt_Text_Module($this->alt_text_generator); |
| 46 |
$this->auto_tagging_module = new Auto_Tagging_Module(); |
| 47 |
$this->post_gen_module = new Post_Generator_Module(); |
| 48 |
|
| 49 |
add_action('admin_menu', [$this, 'registerAdminMenu']); |
| 50 |
add_action('admin_enqueue_scripts', [$this, 'enqueueAdminAssets']); |
| 51 |
add_action('wp_ajax_king_addons_ai_seo_save_settings', [$this, 'handle_ajax_save_settings']); |
| 52 |
} |
| 53 |
|
| 54 |
public function handle_ajax_save_settings(): void |
| 55 |
{ |
| 56 |
check_ajax_referer('king_addons_ai_seo_save_settings_nonce', 'nonce'); |
| 57 |
|
| 58 |
if (!current_user_can('manage_options')) { |
| 59 |
wp_send_json_error(['message' => esc_html__('Permission denied.', 'king-addons')], 403); |
| 60 |
} |
| 61 |
|
| 62 |
$existing = get_option('king_addons_ai_options', []); |
| 63 |
|
| 64 |
$existing['auto_tagging_max_tags'] = max(1, min(20, absint($_POST['auto_tagging_max_tags'] ?? 5))); |
| 65 |
$existing['auto_tagging_confidence_threshold'] = max(0.0, min(1.0, (float) ($_POST['auto_tagging_confidence_threshold'] ?? 0.75))); |
| 66 |
$existing['auto_tagging_stop_words'] = sanitize_text_field(wp_unslash($_POST['auto_tagging_stop_words'] ?? '')); |
| 67 |
|
| 68 |
update_option('king_addons_ai_options', $existing); |
| 69 |
|
| 70 |
wp_send_json_success(['message' => esc_html__('Settings saved.', 'king-addons')]); |
| 71 |
} |
| 72 |
|
| 73 |
public function registerAdminMenu(): void |
| 74 |
{ |
| 75 |
add_submenu_page( |
| 76 |
'king-addons', |
| 77 |
esc_html__('AI SEO Tools', 'king-addons'), |
| 78 |
esc_html__('AI SEO Tools', 'king-addons'), |
| 79 |
'manage_options', |
| 80 |
'king-addons-ai-seo-tools', |
| 81 |
[$this, 'renderAdminPage'] |
| 82 |
); |
| 83 |
} |
| 84 |
|
| 85 |
public function enqueueAdminAssets(string $hook): void |
| 86 |
{ |
| 87 |
if ($hook !== 'king-addons_page_king-addons-ai-seo-tools') { |
| 88 |
return; |
| 89 |
} |
| 90 |
|
| 91 |
wp_enqueue_style( |
| 92 |
'king-addons-admin-v3-shared', |
| 93 |
KING_ADDONS_URL . 'includes/admin/layouts/shared/admin-v3-styles.css', |
| 94 |
[], |
| 95 |
KING_ADDONS_VERSION |
| 96 |
); |
| 97 |
|
| 98 |
wp_enqueue_style( |
| 99 |
'king-addons-ai-seo-tools', |
| 100 |
KING_ADDONS_URL . 'includes/extensions/AI_SEO_Tools/assets/ai-seo-tools.css', |
| 101 |
['king-addons-admin-v3-shared'], |
| 102 |
KING_ADDONS_VERSION |
| 103 |
); |
| 104 |
|
| 105 |
wp_enqueue_script( |
| 106 |
'king-addons-ai-seo-tools', |
| 107 |
KING_ADDONS_URL . 'includes/extensions/AI_SEO_Tools/assets/ai-seo-tools.js', |
| 108 |
['jquery'], |
| 109 |
KING_ADDONS_VERSION, |
| 110 |
true |
| 111 |
); |
| 112 |
|
| 113 |
$ka_ai_options_for_js = get_option('king_addons_ai_options', []); |
| 114 |
wp_localize_script('king-addons-ai-seo-tools', 'kingAddonsAiSeoTools', [ |
| 115 |
'ajaxUrl' => admin_url('admin-ajax.php'), |
| 116 |
'settingsUrl' => admin_url('admin.php?page=king-addons-ai-settings'), |
| 117 |
'hasApiKey' => ('' !== \King_Addons\AI_Provider::getApiKey()) ? '1' : '', |
| 118 |
'dashboardUiNonce' => wp_create_nonce('king_addons_dashboard_ui'), |
| 119 |
'nonces' => [ |
| 120 |
'altStart' => wp_create_nonce('king_addons_ai_seo_bulk_alt_start_nonce'), |
| 121 |
'altStatus' => wp_create_nonce('king_addons_ai_seo_bulk_alt_status_nonce'), |
| 122 |
'altStop' => wp_create_nonce('king_addons_ai_seo_bulk_alt_stop_nonce'), |
| 123 |
'altStats' => wp_create_nonce('king_addons_ai_seo_get_alt_stats_nonce'), |
| 124 |
|
| 125 |
'tagsStart' => wp_create_nonce('king_addons_ai_seo_bulk_tags_start_nonce'), |
| 126 |
'tagsStatus' => wp_create_nonce('king_addons_ai_seo_bulk_tags_status_nonce'), |
| 127 |
'tagsStop' => wp_create_nonce('king_addons_ai_seo_bulk_tags_stop_nonce'), |
| 128 |
|
| 129 |
'appendStart' => wp_create_nonce('king_addons_ai_seo_bulk_append_tags_start_nonce'), |
| 130 |
'appendStatus' => wp_create_nonce('king_addons_ai_seo_bulk_append_tags_status_nonce'), |
| 131 |
'appendStop' => wp_create_nonce('king_addons_ai_seo_bulk_append_tags_stop_nonce'), |
| 132 |
|
| 133 |
'regenStart' => wp_create_nonce('king_addons_ai_seo_bulk_regenerate_tags_start_nonce'), |
| 134 |
'regenStatus' => wp_create_nonce('king_addons_ai_seo_bulk_regenerate_tags_status_nonce'), |
| 135 |
'regenStop' => wp_create_nonce('king_addons_ai_seo_bulk_regenerate_tags_stop_nonce'), |
| 136 |
|
| 137 |
'postgenStart' => wp_create_nonce('king_addons_ai_seo_post_gen_start_nonce'), |
| 138 |
'postgenStatus' => wp_create_nonce('king_addons_ai_seo_post_gen_status_nonce'), |
| 139 |
'postgenStop' => wp_create_nonce('king_addons_ai_seo_post_gen_stop_nonce'), |
| 140 |
|
| 141 |
'settingsSave' => wp_create_nonce('king_addons_ai_seo_save_settings_nonce'), |
| 142 |
], |
| 143 |
'i18n' => [ |
| 144 |
'processed' => esc_html__('Processed %1$d of %2$d', 'king-addons'), |
| 145 |
'completed' => esc_html__('Completed', 'king-addons'), |
| 146 |
'stopped' => esc_html__('Stopped', 'king-addons'), |
| 147 |
'error' => esc_html__('Error', 'king-addons'), |
| 148 |
'backgroundNotice' => esc_html__('AI SEO Tools is processing in the background. You can close this tab and continue working.', 'king-addons'), |
| 149 |
], |
| 150 |
]); |
| 151 |
} |
| 152 |
|
| 153 |
public function renderAdminPage(): void |
| 154 |
{ |
| 155 |
if (!current_user_can('manage_options')) { |
| 156 |
return; |
| 157 |
} |
| 158 |
|
| 159 |
$theme_mode = get_user_meta(get_current_user_id(), 'king_addons_theme_mode', true); |
| 160 |
if (!in_array($theme_mode, ['dark', 'light', 'auto'], true)) { |
| 161 |
$theme_mode = 'auto'; |
| 162 |
} |
| 163 |
|
| 164 |
$alt_stats = Alt_Text_Generator::get_alt_text_stats(); |
| 165 |
$tag_stats = Auto_Tagging_Module::get_tagging_stats(); |
| 166 |
$ka_ai_options = get_option('king_addons_ai_options', []); |
| 167 |
?> |
| 168 |
<script> |
| 169 |
(function() { |
| 170 |
document.body.classList.add('ka-admin-v3'); |
| 171 |
const mode = '<?php echo esc_js($theme_mode); ?>'; |
| 172 |
const mql = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null; |
| 173 |
const isDark = mode === 'auto' ? !!(mql && mql.matches) : mode === 'dark'; |
| 174 |
document.documentElement.classList.toggle('ka-v3-dark', isDark); |
| 175 |
document.body.classList.toggle('ka-v3-dark', isDark); |
| 176 |
})(); |
| 177 |
</script> |
| 178 |
|
| 179 |
<div class="ka-admin-wrap ka-ai-seo-tools-wrap"> |
| 180 |
<div class="ka-admin-header"> |
| 181 |
<div class="ka-admin-header-left"> |
| 182 |
<div class="ka-admin-header-icon purple"><span class="dashicons dashicons-chart-area"></span></div> |
| 183 |
<div> |
| 184 |
<h1 class="ka-admin-title"><?php esc_html_e('AI SEO Tools', 'king-addons'); ?></h1> |
| 185 |
<p class="ka-admin-subtitle"><?php esc_html_e('Alt Text Generator and Auto Tagging for SEO workflows.', 'king-addons'); ?></p> |
| 186 |
</div> |
| 187 |
</div> |
| 188 |
<div class="ka-admin-header-actions"> |
| 189 |
<div class="ka-v3-segmented" id="ka-v3-theme-segment" role="radiogroup" aria-label="<?php echo esc_attr(esc_html__('Theme', 'king-addons')); ?>" data-active="<?php echo esc_attr($theme_mode); ?>"> |
| 190 |
<span class="ka-v3-segmented-indicator" aria-hidden="true"></span> |
| 191 |
<button type="button" class="ka-v3-segmented-btn" data-theme="light" aria-pressed="<?php echo $theme_mode === 'light' ? 'true' : 'false'; ?>"> |
| 192 |
<span class="ka-v3-segmented-icon" aria-hidden="true">☀︎</span> |
| 193 |
<?php esc_html_e('Light', 'king-addons'); ?> |
| 194 |
</button> |
| 195 |
<button type="button" class="ka-v3-segmented-btn" data-theme="dark" aria-pressed="<?php echo $theme_mode === 'dark' ? 'true' : 'false'; ?>"> |
| 196 |
<span class="ka-v3-segmented-icon" aria-hidden="true">☾</span> |
| 197 |
<?php esc_html_e('Dark', 'king-addons'); ?> |
| 198 |
</button> |
| 199 |
<button type="button" class="ka-v3-segmented-btn" data-theme="auto" aria-pressed="<?php echo $theme_mode === 'auto' ? 'true' : 'false'; ?>"> |
| 200 |
<span class="ka-v3-segmented-icon" aria-hidden="true">◐</span> |
| 201 |
<?php esc_html_e('Auto', 'king-addons'); ?> |
| 202 |
</button> |
| 203 |
</div> |
| 204 |
<?php if (!king_addons_freemius()->can_use_premium_code()): ?> |
| 205 |
<a href="https://kingaddons.com/pricing/?utm_source=kng-ai-seo-tools&utm_medium=wp-admin&utm_campaign=kng" target="_blank" rel="noopener" class="ka-btn ka-btn-primary"><?php esc_html_e('Upgrade to PRO', 'king-addons'); ?></a> |
| 206 |
<?php endif; ?> |
| 207 |
</div> |
| 208 |
</div> |
| 209 |
|
| 210 |
<div id="ka-ai-seo-background-notice" class="notice notice-info ka-ai-seo-notice" hidden> |
| 211 |
<p> |
| 212 |
<strong><?php esc_html_e('Background process is running.', 'king-addons'); ?></strong> |
| 213 |
<?php esc_html_e('AI SEO Tools is processing in the background. You can close this tab and continue working.', 'king-addons'); ?> |
| 214 |
</p> |
| 215 |
</div> |
| 216 |
|
| 217 |
<?php if ('' === \King_Addons\AI_Provider::getApiKey()) : ?> |
| 218 |
<div class="ka-ai-seo-nokey-banner"> |
| 219 |
⚠️ <strong><?php esc_html_e('OpenAI API key is missing.', 'king-addons'); ?></strong> |
| 220 |
<?php esc_html_e('AI features are disabled until you', 'king-addons'); ?> |
| 221 |
<a href="<?php echo esc_url(admin_url('admin.php?page=king-addons-ai-settings')); ?>"><?php esc_html_e('add your API key in AI Settings', 'king-addons'); ?></a>. |
| 222 |
</div> |
| 223 |
<?php endif; ?> |
| 224 |
|
| 225 |
<div class="ka-tabs"> |
| 226 |
<button type="button" class="ka-tab active" data-tab="alt"><?php esc_html_e('Alt Text Generator', 'king-addons'); ?> <span class="ka-tab-badge ka-tab-badge--blue"><?php esc_html_e('Media', 'king-addons'); ?></span></button> |
| 227 |
<button type="button" class="ka-tab" data-tab="tagging"><?php esc_html_e('Auto Tagging', 'king-addons'); ?> <span class="ka-tab-badge ka-tab-badge--green"><?php esc_html_e('Blog Post', 'king-addons'); ?></span></button> |
| 228 |
<button type="button" class="ka-tab" data-tab="postgen"><?php esc_html_e('Post Generator', 'king-addons'); ?> <span class="ka-tab-badge ka-tab-badge--purple"><?php esc_html_e('Blog Post', 'king-addons'); ?></span></button> |
| 229 |
<button type="button" class="ka-tab" data-tab="settings"><?php esc_html_e('Settings', 'king-addons'); ?></button> |
| 230 |
</div> |
| 231 |
|
| 232 |
<div class="ka-tab-content active" data-tab="alt"> |
| 233 |
<div class="ka-seo-intro-callout"> |
| 234 |
<div class="ka-seo-intro-icon"> |
| 235 |
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 2a7 7 0 0 1 4.5 12.37V16a1 1 0 0 1-1 1h-7a1 1 0 0 1-1-1v-1.63A7 7 0 0 1 12 2Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/><path d="M9.5 21h5M10.5 17v4M13.5 17v4" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg> |
| 236 |
</div> |
| 237 |
<div> |
| 238 |
<div class="ka-seo-intro-label"><?php esc_html_e('What SEO problem does this solve?', 'king-addons'); ?></div> |
| 239 |
<p class="ka-seo-intro-text"><?php esc_html_e('Many site owners upload images without providing descriptive alt text or optimizing filenames, which hurts both accessibility and SEO. Over half of website homepages have images with missing alternative text, leaving visually impaired users in the dark and missing an SEO opportunity (search engines use alt text to understand images). Writing alt text for every image is tedious, and many people simply forget or don\'t know how to write a good description. This is a pain point for bloggers, e-commerce (lots of product images), and anyone mindful of SEO and accessibility compliance.', 'king-addons'); ?></p> |
| 240 |
</div> |
| 241 |
</div> |
| 242 |
|
| 243 |
<div class="ka-card"><div class="ka-card-body"> |
| 244 |
<h3><?php esc_html_e('Post Alt Text Statistics & Generation', 'king-addons'); ?></h3> |
| 245 |
<div id="ka-ai-seo-alt-stats" |
| 246 |
data-total="<?php echo esc_attr((string) $alt_stats['total']); ?>" |
| 247 |
data-with-alt="<?php echo esc_attr((string) $alt_stats['with_alt']); ?>" |
| 248 |
data-without-alt="<?php echo esc_attr((string) $alt_stats['without_alt']); ?>"></div> |
| 249 |
</div></div> |
| 250 |
|
| 251 |
<div class="ka-card"><div class="ka-card-body"> |
| 252 |
<h3><?php esc_html_e('Bulk Generation', 'king-addons'); ?></h3> |
| 253 |
<label for="ka-ai-seo-alt-limit"><?php esc_html_e('Process maximum:', 'king-addons'); ?></label> |
| 254 |
<input id="ka-ai-seo-alt-limit" type="number" min="1" max="<?php echo esc_attr((string) max(1, (int) $alt_stats['without_alt'])); ?>" value="<?php echo esc_attr((string) max(1, (int) $alt_stats['without_alt'])); ?>"> |
| 255 |
<button type="button" id="ka-ai-seo-alt-start" class="ka-btn ka-btn-primary"><?php esc_html_e('Start Bulk Generation', 'king-addons'); ?></button> |
| 256 |
<button type="button" id="ka-ai-seo-alt-stop" class="ka-btn ka-btn-secondary" hidden><?php esc_html_e('Stop Generation', 'king-addons'); ?></button> |
| 257 |
<span id="ka-ai-seo-alt-spinner" class="spinner ka-bulk-spinner" hidden></span> |
| 258 |
<div id="ka-ai-seo-alt-progress" class="ka-progress" hidden><div id="ka-ai-seo-alt-progress-bar" class="ka-progress-bar">0%</div></div> |
| 259 |
<p id="ka-ai-seo-alt-progress-text"></p> |
| 260 |
<div id="ka-ai-seo-alt-details" class="ka-bulk-details" hidden></div> |
| 261 |
</div></div> |
| 262 |
</div> |
| 263 |
|
| 264 |
<div class="ka-tab-content" data-tab="tagging"> |
| 265 |
<div class="ka-seo-intro-callout ka-seo-intro-callout--tags"> |
| 266 |
<div class="ka-seo-intro-icon"> |
| 267 |
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.5 3H4a1 1 0 0 0-1 1v5.5a1 1 0 0 0 .29.71l9.5 9.5a1 1 0 0 0 1.42 0l5.5-5.5a1 1 0 0 0 0-1.42l-9.5-9.5A1 1 0 0 0 9.5 3Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/><circle cx="6.5" cy="6.5" r="1" fill="currentColor"/></svg> |
| 268 |
</div> |
| 269 |
<div> |
| 270 |
<div class="ka-seo-intro-label"><?php esc_html_e('What SEO problem does this solve?', 'king-addons'); ?></div> |
| 271 |
<p class="ka-seo-intro-text"><?php esc_html_e('Automated tagging enriches metadata, improves internal linking, and reduces manual effort for editors. Generate semantically relevant tags based on post content.', 'king-addons'); ?></p> |
| 272 |
</div> |
| 273 |
</div> |
| 274 |
|
| 275 |
<div class="ka-card"><div class="ka-card-body"> |
| 276 |
<h3><?php esc_html_e('Post Tagging Statistics & Generation', 'king-addons'); ?></h3> |
| 277 |
<div id="ka-ai-seo-tags-stats" |
| 278 |
data-total="<?php echo esc_attr((string) $tag_stats['total']); ?>" |
| 279 |
data-with-tags="<?php echo esc_attr((string) $tag_stats['with_tags']); ?>" |
| 280 |
data-without-tags="<?php echo esc_attr((string) $tag_stats['without_tags']); ?>"></div> |
| 281 |
</div></div> |
| 282 |
|
| 283 |
<div class="ka-card"><div class="ka-card-body"> |
| 284 |
<h3><?php esc_html_e('Bulk Tagging', 'king-addons'); ?></h3> |
| 285 |
<input id="ka-ai-seo-tags-limit" type="number" min="1" max="<?php echo esc_attr((string) max(1, (int) $tag_stats['without_tags'])); ?>" value="<?php echo esc_attr((string) max(1, (int) $tag_stats['without_tags'])); ?>"> |
| 286 |
<button type="button" id="ka-ai-seo-tags-start" class="ka-btn ka-btn-primary"><?php esc_html_e('Start Bulk Tagging', 'king-addons'); ?></button> |
| 287 |
<button type="button" id="ka-ai-seo-tags-stop" class="ka-btn ka-btn-secondary" hidden><?php esc_html_e('Stop Tagging', 'king-addons'); ?></button> |
| 288 |
<span id="ka-ai-seo-tags-spinner" class="spinner ka-bulk-spinner" hidden></span> |
| 289 |
<div id="ka-ai-seo-tags-progress" class="ka-progress" hidden><div id="ka-ai-seo-tags-progress-bar" class="ka-progress-bar">0%</div></div> |
| 290 |
<p id="ka-ai-seo-tags-progress-text"></p> |
| 291 |
<div id="ka-ai-seo-tags-details" class="ka-bulk-details" hidden></div> |
| 292 |
</div></div> |
| 293 |
|
| 294 |
<div class="ka-card"><div class="ka-card-body"> |
| 295 |
<h3><?php esc_html_e('Bulk Append Tags', 'king-addons'); ?></h3> |
| 296 |
<input id="ka-ai-seo-append-limit" type="number" min="1" max="<?php echo esc_attr((string) max(1, (int) $tag_stats['with_tags'])); ?>" value="<?php echo esc_attr((string) max(1, (int) $tag_stats['with_tags'])); ?>"> |
| 297 |
<button type="button" id="ka-ai-seo-append-start" class="ka-btn ka-btn-primary"><?php esc_html_e('Start Bulk Append', 'king-addons'); ?></button> |
| 298 |
<button type="button" id="ka-ai-seo-append-stop" class="ka-btn ka-btn-secondary" hidden><?php esc_html_e('Stop Append', 'king-addons'); ?></button> |
| 299 |
<span id="ka-ai-seo-append-spinner" class="spinner ka-bulk-spinner" hidden></span> |
| 300 |
<div id="ka-ai-seo-append-progress" class="ka-progress" hidden><div id="ka-ai-seo-append-progress-bar" class="ka-progress-bar">0%</div></div> |
| 301 |
<p id="ka-ai-seo-append-progress-text"></p> |
| 302 |
<div id="ka-ai-seo-append-details" class="ka-bulk-details" hidden></div> |
| 303 |
</div></div> |
| 304 |
|
| 305 |
<div class="ka-card"><div class="ka-card-body"> |
| 306 |
<h3><?php esc_html_e('Bulk Regenerate Tags', 'king-addons'); ?></h3> |
| 307 |
<input id="ka-ai-seo-regen-limit" type="number" min="1" max="<?php echo esc_attr((string) max(1, (int) $tag_stats['with_tags'])); ?>" value="<?php echo esc_attr((string) max(1, (int) $tag_stats['with_tags'])); ?>"> |
| 308 |
<button type="button" id="ka-ai-seo-regen-start" class="ka-btn ka-btn-primary"><?php esc_html_e('Start Bulk Regenerate', 'king-addons'); ?></button> |
| 309 |
<button type="button" id="ka-ai-seo-regen-stop" class="ka-btn ka-btn-secondary" hidden><?php esc_html_e('Stop Regenerate', 'king-addons'); ?></button> |
| 310 |
<span id="ka-ai-seo-regen-spinner" class="spinner ka-bulk-spinner" hidden></span> |
| 311 |
<div id="ka-ai-seo-regen-progress" class="ka-progress" hidden><div id="ka-ai-seo-regen-progress-bar" class="ka-progress-bar">0%</div></div> |
| 312 |
<p id="ka-ai-seo-regen-progress-text"></p> |
| 313 |
<div id="ka-ai-seo-regen-details" class="ka-bulk-details" hidden></div> |
| 314 |
</div></div> |
| 315 |
</div> |
| 316 |
|
| 317 |
<div class="ka-tab-content" data-tab="postgen"> |
| 318 |
<div class="ka-seo-intro-callout ka-seo-intro-callout--postgen"> |
| 319 |
<div class="ka-seo-intro-icon"> |
| 320 |
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg> |
| 321 |
</div> |
| 322 |
<div> |
| 323 |
<div class="ka-seo-intro-label"><?php esc_html_e('AI Blog Post Generator', 'king-addons'); ?></div> |
| 324 |
<p class="ka-seo-intro-text"><?php esc_html_e('Automatically generate complete, unique blog posts using AI — title, full HTML content, excerpt, and tags. Optionally generate a matching featured image for each post using DALL·E 3 or GPT Image 1. Posts are saved as drafts by default so you can review them before publishing.', 'king-addons'); ?></p> |
| 325 |
</div> |
| 326 |
</div> |
| 327 |
|
| 328 |
<div class="ka-card"><div class="ka-card-body"> |
| 329 |
<h3><?php esc_html_e('Generation Settings', 'king-addons'); ?></h3> |
| 330 |
<div class="ka-postgen-form"> |
| 331 |
<div> |
| 332 |
<label for="ka-postgen-description"><?php esc_html_e('Describe what the posts should be about:', 'king-addons'); ?></label> |
| 333 |
<textarea id="ka-postgen-description" rows="3" placeholder="<?php esc_attr_e('e.g. healthy breakfast recipes for busy professionals', 'king-addons'); ?>"></textarea> |
| 334 |
</div> |
| 335 |
<div class="ka-postgen-row"> |
| 336 |
<label for="ka-postgen-count"><?php esc_html_e('Number of posts to generate:', 'king-addons'); ?></label> |
| 337 |
<input id="ka-postgen-count" type="number" min="1" max="50" value="3"> |
| 338 |
</div> |
| 339 |
<div class="ka-postgen-row"> |
| 340 |
<label for="ka-postgen-length"><?php esc_html_e('Post length:', 'king-addons'); ?></label> |
| 341 |
<div class="ka-postgen-length-toggle"> |
| 342 |
<button type="button" class="ka-postgen-length-btn" data-value="short"><?php esc_html_e('Short', 'king-addons'); ?><span class="ka-postgen-length-hint">~300 <?php esc_html_e('words', 'king-addons'); ?></span></button> |
| 343 |
<button type="button" class="ka-postgen-length-btn active" data-value="medium"><?php esc_html_e('Medium', 'king-addons'); ?><span class="ka-postgen-length-hint">~600 <?php esc_html_e('words', 'king-addons'); ?></span></button> |
| 344 |
<button type="button" class="ka-postgen-length-btn" data-value="long"><?php esc_html_e('Long', 'king-addons'); ?><span class="ka-postgen-length-hint">~1200 <?php esc_html_e('words', 'king-addons'); ?></span></button> |
| 345 |
</div> |
| 346 |
<input type="hidden" id="ka-postgen-length" value="medium"> |
| 347 |
</div> |
| 348 |
<div class="ka-postgen-row"> |
| 349 |
<label for="ka-postgen-category"><?php esc_html_e('Category:', 'king-addons'); ?></label> |
| 350 |
<select id="ka-postgen-category"> |
| 351 |
<option value="auto"><?php esc_html_e('✨ Auto-generate category', 'king-addons'); ?></option> |
| 352 |
<option value="0"><?php esc_html_e('— None / Uncategorized —', 'king-addons'); ?></option> |
| 353 |
<?php |
| 354 |
$cats = get_categories(['hide_empty' => false, 'orderby' => 'name', 'order' => 'ASC']); |
| 355 |
foreach ($cats as $cat) { |
| 356 |
echo '<option value="' . esc_attr((string) $cat->term_id) . '">' . esc_html($cat->name) . ' (' . esc_html((string) $cat->count) . ')</option>'; |
| 357 |
} |
| 358 |
?> |
| 359 |
</select> |
| 360 |
</div> |
| 361 |
<div class="ka-postgen-row"> |
| 362 |
<label for="ka-postgen-status"><?php esc_html_e('Save posts as:', 'king-addons'); ?></label> |
| 363 |
<select id="ka-postgen-status"> |
| 364 |
<option value="draft" selected><?php esc_html_e('Draft (recommended)', 'king-addons'); ?></option> |
| 365 |
<option value="publish"><?php esc_html_e('Published', 'king-addons'); ?></option> |
| 366 |
</select> |
| 367 |
</div> |
| 368 |
<?php $is_image_pro = !king_addons_freemius()->can_use_premium_code(); ?> |
| 369 |
<div class="ka-postgen-row"> |
| 370 |
<label class="ka-postgen-checkbox-label<?php echo $is_image_pro ? ' ka-postgen-checkbox-label--disabled ka-postgen-gen-label-pro' : ''; ?>"> |
| 371 |
<input type="checkbox" id="ka-postgen-gen-image"<?php echo $is_image_pro ? ' disabled' : ''; ?>> |
| 372 |
<?php esc_html_e('Generate featured image for each post', 'king-addons'); ?> |
| 373 |
<?php if ($is_image_pro): ?> |
| 374 |
<span class="ka-tab-badge ka-tab-badge--purple" style="margin-left:6px;"><?php esc_html_e('PRO', 'king-addons'); ?></span> |
| 375 |
<a href="https://kingaddons.com/pricing/?utm_source=kng-ai-seo-tools&utm_medium=wp-admin&utm_campaign=kng" target="_blank" rel="noopener" class="ka-postgen-pro-link"><?php esc_html_e('Upgrade →', 'king-addons'); ?></a> |
| 376 |
<?php endif; ?> |
| 377 |
</label> |
| 378 |
</div> |
| 379 |
<div id="ka-postgen-image-settings" class="ka-postgen-image-settings" hidden> |
| 380 |
<div class="ka-postgen-row"> |
| 381 |
<label for="ka-postgen-image-model"><?php esc_html_e('Image model:', 'king-addons'); ?></label> |
| 382 |
<select id="ka-postgen-image-model"> |
| 383 |
<?php |
| 384 |
// Options follow whichever AI provider is configured. |
| 385 |
$ka_image_models = \King_Addons\AI_Provider::getModelsFor('image'); |
| 386 |
$ka_selected_image = \King_Addons\AI_Provider::getImageModel(); |
| 387 |
foreach ($ka_image_models as $ka_image_model) : |
| 388 |
?> |
| 389 |
<option value="<?php echo esc_attr($ka_image_model['id']); ?>" <?php selected($ka_selected_image, $ka_image_model['id']); ?>><?php echo esc_html($ka_image_model['label']); ?></option> |
| 390 |
<?php endforeach; ?> |
| 391 |
</select> |
| 392 |
</div> |
| 393 |
<div id="ka-postgen-dalle3-opts"> |
| 394 |
<div class="ka-postgen-row" style="margin-bottom: 8px;"> |
| 395 |
<label for="ka-postgen-dalle3-quality"><?php esc_html_e('Quality:', 'king-addons'); ?></label> |
| 396 |
<select id="ka-postgen-dalle3-quality"> |
| 397 |
<option value="standard" selected><?php esc_html_e('Standard', 'king-addons'); ?></option> |
| 398 |
<option value="hd">HD</option> |
| 399 |
</select> |
| 400 |
</div> |
| 401 |
<div class="ka-postgen-row"> |
| 402 |
<label for="ka-postgen-dalle3-size"><?php esc_html_e('Size:', 'king-addons'); ?></label> |
| 403 |
<select id="ka-postgen-dalle3-size"> |
| 404 |
<option value="1024x1024" selected>1024 × 1024</option> |
| 405 |
<option value="1792x1024">1792 × 1024 <?php esc_html_e('(landscape)', 'king-addons'); ?></option> |
| 406 |
<option value="1024x1792">1024 × 1792 <?php esc_html_e('(portrait)', 'king-addons'); ?></option> |
| 407 |
</select> |
| 408 |
</div> |
| 409 |
</div> |
| 410 |
<div id="ka-postgen-gptimg-opts" hidden> |
| 411 |
<div class="ka-postgen-row" style="margin-bottom: 8px;"> |
| 412 |
<label for="ka-postgen-gptimg-quality"><?php esc_html_e('Quality:', 'king-addons'); ?></label> |
| 413 |
<select id="ka-postgen-gptimg-quality"> |
| 414 |
<option value="auto" selected>Auto</option> |
| 415 |
<option value="low"><?php esc_html_e('Low', 'king-addons'); ?></option> |
| 416 |
<option value="medium"><?php esc_html_e('Medium', 'king-addons'); ?></option> |
| 417 |
<option value="high"><?php esc_html_e('High', 'king-addons'); ?></option> |
| 418 |
</select> |
| 419 |
</div> |
| 420 |
<div class="ka-postgen-row"> |
| 421 |
<label for="ka-postgen-gptimg-size"><?php esc_html_e('Size:', 'king-addons'); ?></label> |
| 422 |
<select id="ka-postgen-gptimg-size"> |
| 423 |
<option value="1024x1024" selected>1024 × 1024</option> |
| 424 |
<option value="1536x1024">1536 × 1024 <?php esc_html_e('(landscape)', 'king-addons'); ?></option> |
| 425 |
<option value="1024x1536">1024 × 1536 <?php esc_html_e('(portrait)', 'king-addons'); ?></option> |
| 426 |
</select> |
| 427 |
</div> |
| 428 |
</div> |
| 429 |
</div> |
| 430 |
<div class="ka-postgen-actions"> |
| 431 |
<button type="button" id="ka-postgen-start" class="ka-btn ka-btn-primary"><?php esc_html_e('Generate Posts', 'king-addons'); ?></button> |
| 432 |
<button type="button" id="ka-postgen-stop" class="ka-btn ka-btn-secondary" hidden><?php esc_html_e('Stop Generation', 'king-addons'); ?></button> |
| 433 |
<span id="ka-postgen-spinner" class="spinner ka-bulk-spinner" hidden></span> |
| 434 |
</div> |
| 435 |
<div id="ka-postgen-progress" class="ka-progress" hidden><div id="ka-postgen-progress-bar" class="ka-progress-bar">0%</div></div> |
| 436 |
<p id="ka-postgen-progress-text"></p> |
| 437 |
<div id="ka-postgen-details" class="ka-bulk-details" hidden></div> |
| 438 |
<div id="ka-postgen-run-info" class="ka-postgen-run-info" hidden></div> |
| 439 |
</div> |
| 440 |
</div></div> |
| 441 |
</div> |
| 442 |
|
| 443 |
<div class="ka-tab-content" data-tab="settings"> |
| 444 |
<?php |
| 445 |
$ka_seo_opts = get_option('king_addons_ai_options', []); |
| 446 |
$ka_s_max_tags = isset($ka_seo_opts['auto_tagging_max_tags']) ? (int) $ka_seo_opts['auto_tagging_max_tags'] : 5; |
| 447 |
$ka_s_confidence = isset($ka_seo_opts['auto_tagging_confidence_threshold']) ? (float) $ka_seo_opts['auto_tagging_confidence_threshold'] : 0.75; |
| 448 |
$ka_s_stop_words = $ka_seo_opts['auto_tagging_stop_words'] ?? ''; |
| 449 |
?> |
| 450 |
<div class="ka-card"> |
| 451 |
<div class="ka-card-body"> |
| 452 |
<h2 class="ka-seo-settings-section-title"><?php esc_html_e('Auto Tagging Settings', 'king-addons'); ?></h2> |
| 453 |
<p class="ka-seo-settings-section-desc"><?php esc_html_e('Configure default settings for the Auto Tagging module.', 'king-addons'); ?></p> |
| 454 |
<table class="ka-seo-settings-table form-table"> |
| 455 |
<tr> |
| 456 |
<th scope="row"><label for="ka-seo-max-tags"><?php esc_html_e('Max Tags per Post', 'king-addons'); ?></label></th> |
| 457 |
<td> |
| 458 |
<input type="number" id="ka-seo-max-tags" name="auto_tagging_max_tags" value="<?php echo esc_attr($ka_s_max_tags); ?>" min="1" max="20" class="ka-seo-settings-input-sm" /> |
| 459 |
<p class="description"><?php esc_html_e('Maximum number of tags to generate per post (1-20).', 'king-addons'); ?></p> |
| 460 |
</td> |
| 461 |
</tr> |
| 462 |
<tr> |
| 463 |
<th scope="row"><label for="ka-seo-confidence"><?php esc_html_e('Confidence Threshold', 'king-addons'); ?></label></th> |
| 464 |
<td> |
| 465 |
<input type="number" id="ka-seo-confidence" name="auto_tagging_confidence_threshold" value="<?php echo esc_attr(number_format($ka_s_confidence, 2)); ?>" min="0.00" max="1.00" step="0.01" class="ka-seo-settings-input-sm" /> |
| 466 |
<p class="description"><?php esc_html_e('Confidence threshold for tag relevance (0.00-1.00).', 'king-addons'); ?></p> |
| 467 |
</td> |
| 468 |
</tr> |
| 469 |
<tr> |
| 470 |
<th scope="row"><label for="ka-seo-stop-words"><?php esc_html_e('Stop-Words List', 'king-addons'); ?></label></th> |
| 471 |
<td> |
| 472 |
<input type="text" id="ka-seo-stop-words" name="auto_tagging_stop_words" value="<?php echo esc_attr($ka_s_stop_words); ?>" class="ka-seo-settings-input-lg" /> |
| 473 |
<p class="description"><?php esc_html_e('Comma-separated list of words to exclude from generated tags.', 'king-addons'); ?></p> |
| 474 |
</td> |
| 475 |
</tr> |
| 476 |
</table> |
| 477 |
<div class="ka-seo-settings-actions"> |
| 478 |
<button type="button" id="ka-seo-settings-save" class="ka-btn ka-btn-primary"><?php esc_html_e('Save Settings', 'king-addons'); ?></button> |
| 479 |
<span id="ka-seo-settings-feedback" class="ka-seo-settings-feedback" hidden></span> |
| 480 |
</div> |
| 481 |
</div> |
| 482 |
</div> |
| 483 |
<div class="ka-card"> |
| 484 |
<div class="ka-card-body"> |
| 485 |
<h2 class="ka-seo-settings-section-title"><?php esc_html_e('AI Keys & Models', 'king-addons'); ?></h2> |
| 486 |
<p><?php esc_html_e('OpenAI API key, model selection and other general AI settings are managed in AI Settings.', 'king-addons'); ?></p> |
| 487 |
<a class="ka-btn ka-btn-primary" href="<?php echo esc_url(admin_url('admin.php?page=king-addons-ai-settings')); ?>"><?php esc_html_e('Go to AI Settings', 'king-addons'); ?></a> |
| 488 |
</div> |
| 489 |
</div> |
| 490 |
</div> |
| 491 |
</div> |
| 492 |
<?php |
| 493 |
} |
| 494 |
} |
| 495 |
|