PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.83
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.83
51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 51.1.47 51.1.49 All 37 releases
king-addons / includes / extensions / AI_SEO_Tools / AI_SEO_Tools.php

AI_SEO_Tools.php in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.83, at includes/extensions/AI_SEO_Tools/AI_SEO_Tools.php

495 lines 34.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 &amp; 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