PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.36
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.36
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 / Core.php

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

1,231 lines 52.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Core class do all things at the start of the plugin
5 */
6
7 namespace King_Addons;
8
9 use Elementor\Plugin;
10 use Elementor\Widgets_Manager;
11 use Elementor\Controls_Manager;
12
13 if (!defined('ABSPATH')) {
14 exit; // Exit if accessed directly.
15 }
16
17 final class Core
18 {
19 /**
20 * Instance
21 *
22 * @var Core|null The single instance of the class.
23 */
24 private static ?Core $_instance = null;
25
26 /**
27 * Instance
28 *
29 * Ensures only one instance of the class is loaded or can be loaded.
30 *
31 * @return Core An instance of the class.
32 * @since 1.0.0
33 */
34 public static function instance(): Core
35 {
36 if (is_null(self::$_instance)) {
37 self::$_instance = new self();
38 }
39 return self::$_instance;
40 }
41
42 /**
43 * Constructor
44 *
45 * Perform some compatibility checks to make sure basic requirements are meet.
46 * If all compatibility checks pass, initialize the functionality.
47 *
48 * @since 1.0.0
49 */
50 public function __construct()
51 {
52 require_once(KING_ADDONS_PATH . 'includes/ModulesMap.php');
53 require_once(KING_ADDONS_PATH . 'includes/LibrariesMap.php');
54 require_once(KING_ADDONS_PATH . 'includes/SectionsMap.php');
55
56 if ($this->hasElementorCompatibility()) {
57
58 // Initial requirements check
59 require_once(KING_ADDONS_PATH . 'includes/helpers/Check_Requirements/Check_Requirements.php');
60
61 // Templates Catalog
62 if (KING_ADDONS_EXT_TEMPLATES_CATALOG) {
63 require_once(KING_ADDONS_PATH . 'includes/TemplatesMap.php');
64 require_once(KING_ADDONS_PATH . 'includes/extensions/Templates/CollectionsMap.php');
65 require_once(KING_ADDONS_PATH . 'includes/extensions/Templates/Templates.php');
66
67 // Template Catalog Button for Elementor Editor
68 require_once(KING_ADDONS_PATH . 'includes/extensions/Template_Catalog_Button/Template_Catalog_Button.php');
69 Template_Catalog_Button::instance();
70 }
71
72 // Sections Catalog
73 // if (KING_ADDONS_EXT_SECTIONS_CATALOG) {
74 // require_once(KING_ADDONS_PATH . 'includes/extensions/Sections_Catalog/Sections_Catalog.php');
75 // Sections_Catalog::instance();
76 // }
77
78 // Header & Footer Builder
79 if (KING_ADDONS_EXT_HEADER_FOOTER_BUILDER) {
80 require_once(KING_ADDONS_PATH . 'includes/extensions/Header_Footer_Builder/Header_Footer_Builder.php');
81 Header_Footer_Builder::instance();
82 }
83
84 // Popup Builder
85 if (KING_ADDONS_EXT_POPUP_BUILDER) {
86 require_once(KING_ADDONS_PATH . 'includes/extensions/Popup_Builder/Popup_Builder.php');
87 Popup_Builder::instance();
88 }
89
90 // Admin
91 require_once(KING_ADDONS_PATH . 'includes/Admin.php');
92
93 // Additional - Controls
94 require_once(KING_ADDONS_PATH . 'includes/controls/Ajax_Select2/Ajax_Select2.php');
95 require_once(KING_ADDONS_PATH . 'includes/controls/Ajax_Select2/Ajax_Select2_API.php');
96 require_once(KING_ADDONS_PATH . 'includes/controls/Animations/Animations.php');
97 require_once(KING_ADDONS_PATH . 'includes/controls/Animations/Button_Animations.php');
98
99 // Additional - Widgets
100 require_once(KING_ADDONS_PATH . 'includes/widgets/Search/Search_Ajax.php');
101 require_once(KING_ADDONS_PATH . 'includes/widgets/MailChimp/MailChimp_Ajax.php');
102
103 // Additional - Grids, Magazine Grid
104 require_once(KING_ADDONS_PATH . 'includes/helpers/Grid/Filter_Posts_Ajax.php');
105 require_once(KING_ADDONS_PATH . 'includes/helpers/Grid/Filter_WooCommerce_Products_Ajax.php');
106 require_once(KING_ADDONS_PATH . 'includes/helpers/Grid/Post_Likes_Ajax.php');
107
108 // Additional - Form Builder
109 if (KING_ADDONS_WGT_FORM_BUILDER) {
110 require_once(KING_ADDONS_PATH . 'includes/widgets/Form_Builder/helpers/Create_Submission.php');
111 require_once(KING_ADDONS_PATH . 'includes/widgets/Form_Builder/helpers/Send_Email.php');
112 require_once(KING_ADDONS_PATH . 'includes/widgets/Form_Builder/helpers/Send_Webhook.php');
113 require_once(KING_ADDONS_PATH . 'includes/widgets/Form_Builder/helpers/Subscribe_Mailchimp.php');
114 require_once(KING_ADDONS_PATH . 'includes/widgets/Form_Builder/helpers/Update_Action_Meta.php');
115 require_once(KING_ADDONS_PATH . 'includes/widgets/Form_Builder/helpers/Upload_Email_File.php');
116 require_once(KING_ADDONS_PATH . 'includes/widgets/Form_Builder/helpers/Verify_Google_Recaptcha.php');
117 require_once(KING_ADDONS_PATH . 'includes/widgets/Form_Builder/helpers/View_Submissions_Pro.php');
118 }
119
120 // ADDITIONAL CLASSES
121
122 // Alt Text Generator for Media Library
123 require_once(KING_ADDONS_PATH . 'includes/extensions/alt-text-generator/Alt_Text_Generator.php');
124 new Alt_Text_Generator();
125
126 // Dynamic Posts Grid AJAX Helper - Initialize regardless of Elementor compatibility
127 // This is needed for AJAX functionality to work even when PRO version is disabled
128 require_once(KING_ADDONS_PATH . 'includes/helpers/Dynamic_Posts_Grid_Ajax.php');
129 \King_Addons\Dynamic_Posts_Grid_Ajax::get_instance();
130
131 // Screenshot Generator
132 // require_once(KING_ADDONS_PATH . 'includes/extensions/Templates/screenshot-generator.php');
133 // require_once(KING_ADDONS_PATH . 'includes/extensions/Templates/screenshot-admin-page.php');
134 // new King_Addons\KingAddons\ScreenshotAdmin();
135
136 // END: ADDITIONAL CLASSES
137
138 self::enableWidgetsByDefault();
139
140 add_action('elementor/init', [$this, 'initElementor']);
141
142 add_action('elementor/elements/categories_registered', [$this, 'addWidgetCategory']);
143 add_action('elementor/controls/controls_registered', [$this, 'registerControls']);
144
145 self::enableFeatures();
146
147 // Load and register AJAX handlers for Login Register Form widget
148 require_once(KING_ADDONS_PATH . 'includes/widgets/Login_Register_Form/Login_Register_Form_Ajax.php');
149 require_once(KING_ADDONS_PATH . 'includes/widgets/Login_Register_Form/User_Profile_Fields.php');
150 require_once(KING_ADDONS_PATH . 'includes/widgets/Login_Register_Form/Email_Handler.php');
151 require_once(KING_ADDONS_PATH . 'includes/widgets/Login_Register_Form/Social_Login_Handler.php');
152 add_action('wp_ajax_nopriv_king_addons_user_login', ['King_Addons\Widgets\Login_Register_Form\Login_Register_Form_Ajax', 'handle_login_ajax']);
153 add_action('wp_ajax_king_addons_user_login', ['King_Addons\Widgets\Login_Register_Form\Login_Register_Form_Ajax', 'handle_login_ajax']);
154 add_action('wp_ajax_nopriv_king_addons_user_register', ['King_Addons\Widgets\Login_Register_Form\Login_Register_Form_Ajax', 'handle_register_ajax']);
155 add_action('wp_ajax_king_addons_user_register', ['King_Addons\Widgets\Login_Register_Form\Login_Register_Form_Ajax', 'handle_register_ajax']);
156 add_action('wp_ajax_nopriv_king_addons_user_lostpassword', ['King_Addons\Widgets\Login_Register_Form\Login_Register_Form_Ajax', 'handle_lostpassword_ajax']);
157 add_action('wp_ajax_king_addons_user_lostpassword', ['King_Addons\Widgets\Login_Register_Form\Login_Register_Form_Ajax', 'handle_lostpassword_ajax']);
158
159 // Initialize user profile fields
160 \King_Addons\Widgets\Login_Register_Form\User_Profile_Fields::init();
161
162 // Initialize social login handler
163 \King_Addons\Widgets\Login_Register_Form\Social_Login_Handler::init();
164
165 // Initialize Security Dashboard for admins
166 if (is_admin()) {
167 require_once(KING_ADDONS_PATH . 'includes/widgets/Login_Register_Form/Security_Dashboard.php');
168 \King_Addons\Widgets\Login_Register_Form\Security_Dashboard::init();
169 }
170
171 new Admin();
172
173 add_action('wp_enqueue_scripts', [$this, 'enqueueFrontendStyles']);
174 add_action('wp_enqueue_scripts', [$this, 'enqueueLightboxDynamicStyles']);
175
176 // Notice - Upgrade Suggestion
177 if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
178 add_action('wp_ajax_king_addons_premium_notice_dismiss', [$this, 'king_addons_premium_notice_dismiss_callback']);
179 add_action('admin_notices', [$this, 'showNoticeUpgrade']);
180 }
181
182 // Conditionally enqueue AI text-field enhancement script and styles in Elementor editor
183 $ai_options = get_option('king_addons_ai_options', []);
184 $enable_ai_text_buttons = isset($ai_options['enable_ai_buttons']) ? (bool) $ai_options['enable_ai_buttons'] : true;
185 if ($enable_ai_text_buttons) {
186 // Enqueue AI text-field enhancement script
187 add_action('elementor/editor/after_enqueue_scripts', [$this, 'enqueueAiFieldScript']);
188 // Enqueue styles for AI prompt UI
189 add_action('elementor/editor/after_enqueue_styles', [$this, 'enqueueAiFieldStyles']);
190 // Enqueue AI page translator script
191 add_action('elementor/editor/after_enqueue_scripts', [$this, 'enqueueAiTranslatorScript']);
192 }
193
194 $enable_ai_image_generation_button = isset($ai_options['enable_ai_image_generation_button']) ? (bool) $ai_options['enable_ai_image_generation_button'] : true;
195 if ($enable_ai_image_generation_button) {
196 add_action('elementor/editor/after_enqueue_scripts', [$this, 'enqueueAiImageGenerationScript']);
197 // Enqueue styles for AI Image Generation controls
198 add_action('elementor/editor/after_enqueue_styles', [$this, 'enqueueAiImageFieldStyles']);
199 }
200 }
201 }
202
203 function king_addons_premium_notice_dismiss_callback()
204 {
205 // Check user capabilities
206 if (!current_user_can('manage_options')) {
207 wp_die();
208 }
209 $user_id = get_current_user_id();
210 // Save the current time as the last dismissal time for the premium notice
211 update_user_meta($user_id, 'king_addons_premium_notice_dismissed_time', time());
212 wp_die(); // End AJAX request
213 }
214
215 function showNoticeUpgrade()
216 {
217 // Check user capabilities; show notice only to administrators as an example
218 if (!current_user_can('manage_options')) {
219 return;
220 }
221
222 $user_id = get_current_user_id();
223 $now = time();
224 // Retrieve the last time the premium notice was dismissed by the user
225 $last_dismissed = get_user_meta($user_id, 'king_addons_premium_notice_dismissed_time', true);
226
227 // If the premium notice was dismissed less than a week ago (604800 seconds), do not show it
228 if ($last_dismissed && ($now - $last_dismissed) < 604800) {
229 // if ($last_dismissed && ($now - $last_dismissed) < 60) {
230 return;
231 }
232 ?>
233 <div class="king-addons-upgrade-notice notice notice-info is-dismissible"
234 style="border-left: 4px solid #FF4040;padding: 10px 15px;">
235 <p style="font-size: 15px; margin:0; display: flex; align-items: center;">
236 <span>Unlock <strong style="font-weight: 700;">650+</strong> premium templates and <strong
237 style="font-weight: 700;">200+</strong> advanced features for only $<strong
238 style="font-weight: 700;">4.99</strong>/month. Upgrade now and boost your website's performance!</span>
239 </p>
240 <p style="font-size: 14px; opacity: 0.6;">Trusted by 20,000+ users</p>
241 <p style="display: flex;">
242 <a style="font-size: 14px;padding: 4px 22px;display: flex;align-items: center;background-image: linear-gradient(120deg, #A20BD8 0%, #FF4040 100%);border: none;"
243 href="https://kingaddons.com/pricing?utm_source=kng-notice-offer&utm_medium=plugin&utm_campaign=kng"
244 class="button button-primary"><img style="margin-right: 7px;width: 15px;height: 15px;"
245 src="<?php echo esc_url(KING_ADDONS_URL) . 'includes/admin/img/icon-for-admin.svg'; ?>"
246 alt="<?php echo esc_html__('Upgrade Now', 'king-addons'); ?>">Upgrade Now</a>
247 <a style="margin-left: 20px;display: flex;align-items: center;"
248 href="https://kingaddons.com/pricing?utm_source=kng-notice-offer&utm_medium=plugin&utm_campaign=kng"
249 class="link">Learn More</a>
250 </p>
251 </div>
252 <script>
253 (function($) {
254 // Wait for the document to be ready
255 $(document).ready(function() {
256 // Attach click handler to the dismiss button of the premium notice
257 $('.king-addons-upgrade-notice.notice.is-dismissible').on('click', '.notice-dismiss', function() {
258 $.post(ajaxurl, {
259 action: 'king_addons_premium_notice_dismiss'
260 });
261 });
262 });
263 })(jQuery);
264 </script>
265 <?php
266 }
267
268 function enqueueFrontendStyles()
269 {
270 /**
271 * It fixes the default Elementor SVG icon rendering feature (Settings -> Features -> Inline Font Icons)
272 * because sometimes Elementor still renders Font Awesome icons but doesn't load the corresponding Font Awesome styles.
273 * Therefore, we have to enqueue the styles.
274 */
275 wp_enqueue_style(
276 'font-awesome-5-all',
277 ELEMENTOR_ASSETS_URL . 'lib/font-awesome/css/all' . (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min') . '.css',
278 false,
279 KING_ADDONS_VERSION
280 );
281 }
282
283 function hasElementorCompatibility(): bool
284 {
285 // Check if Elementor installed and activated
286 if (!did_action('elementor/loaded')) {
287 add_action('admin_notices', [$this, 'showAdminNotice_ElementorRequired']);
288 return false;
289 }
290
291 // Check for required Elementor version
292 if (!version_compare(ELEMENTOR_VERSION, '3.19.0', '>=')) {
293 add_action('admin_notices', [$this, 'showAdminNotice_ElementorMinimumVersion']);
294 return false;
295 }
296
297 return true;
298 }
299
300 function showAdminNotice_ElementorRequired(): void
301 {
302 $screen = get_current_screen();
303 if (isset($screen->parent_file) && 'plugins.php' === $screen->parent_file && 'update' === $screen->id) {
304 return;
305 }
306
307 if (isset(get_plugins()['elementor/elementor.php'])) {
308 if (!current_user_can('activate_plugins') || is_plugin_active('elementor/elementor.php')) {
309 return;
310 }
311 $plugin = 'elementor/elementor.php';
312 $activation_url = wp_nonce_url('plugins.php?action=activate&amp;plugin=' . $plugin . '&amp;plugin_status=all&amp;paged=1&amp;s', 'activate-plugin_' . $plugin);
313 $message = '<div class="error"><p>' . esc_html__('King Addons plugin is not working because you need to activate the Elementor plugin.', 'king-addons') . '</p>';
314 /** @noinspection HtmlUnknownTarget */
315 $message .= '<p>' . sprintf('<a href="%s" class="button-primary">%s</a>', $activation_url, esc_html__('Activate Elementor now', 'king-addons')) . '</p></div>';
316 } else {
317 if (!current_user_can('install_plugins')) {
318 return;
319 }
320 $install_url = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=elementor'), 'install-plugin_elementor');
321 $message = '<div class="error"><p>' . esc_html__('King Addons plugin is not working because you need to install the Elementor plugin.', 'king-addons') . '</p>';
322 /** @noinspection HtmlUnknownTarget */
323 $message .= '<p>' . sprintf('<a href="%s" class="button-primary">%s</a>', $install_url, esc_html__('Install Elementor now', 'king-addons')) . '</p></div>';
324 }
325 echo $message;
326 }
327
328 function showAdminNotice_ElementorMinimumVersion(): void
329 {
330 $message = sprintf(
331 /* translators: 1: Plugin name 2: Elementor 3: Required Elementor version */
332 esc_html__('%1$s plugin requires %2$s plugin version %3$s or greater.', 'king-addons'),
333 esc_html__('King Addons', 'king-addons'),
334 esc_html__('Elementor', 'king-addons'),
335 '3.19.0'
336 );
337 echo '<div class="notice notice-error"><p>' . esc_html($message) . '</p></div>';
338 }
339
340 public function initElementor(): void
341 {
342 add_action('elementor/widgets/register', [$this, 'registerWidgets']);
343 add_action('elementor/editor/after_enqueue_styles', [$this, 'enqueueEditorStyles']);
344 add_action('elementor/editor/after_enqueue_scripts', [$this, 'enqueueEditorScripts']);
345 }
346
347 function addWidgetCategory(): void
348 {
349 Plugin::instance()->elements_manager->add_category(
350 'king-addons',
351 [
352 'title' => esc_html__('King Addons', 'king-addons'),
353 'icon' => 'fa fa-plug'
354 ]
355 );
356 }
357
358 /**
359 * Registers Elementor widgets with a mechanism to skip (and remember) broken widgets
360 * that caused a fatal error previously, and try them again if the plugin version is updated.
361 *
362 * @param Widgets_Manager $widgets_manager
363 * @return void
364 */
365 function registerWidgets(Widgets_Manager $widgets_manager): void
366 {
367 // Used to track which widget is currently being loaded when a fatal error occurs
368 static $currentlyLoadingWidgetId = null;
369
370 $currentPluginVersion = KING_ADDONS_VERSION;
371
372 // Get plugin options to check if a widget is enabled
373 $options = get_option('king_addons_options');
374
375 /**
376 * Retrieve the array of broken widgets from the WordPress options.
377 * The structure is expected to be something like:
378 *
379 * 'widget_id' => [
380 * 'version' => '1.2.0',
381 * 'error' => 'Some fatal error message'
382 * ],
383 * ...
384 *
385 */
386 $brokenWidgets = get_option('king_addons_broken_widgets', []);
387
388 /**
389 * STEP 1: Clear out any "broken widgets" where the stored version is
390 * less than the current plugin version. This gives them a second chance
391 * after an update, assuming the issue may have been fixed.
392 */
393 foreach ($brokenWidgets as $brokenId => $brokenData) {
394 if (
395 isset($brokenData['version'])
396 && version_compare($currentPluginVersion, $brokenData['version'], '>')
397 ) {
398 // If the plugin version is now higher, we remove the widget from the blacklist
399 unset($brokenWidgets[$brokenId]);
400 }
401 }
402
403 // Update the option after cleaning up
404 update_option('king_addons_broken_widgets', $brokenWidgets);
405
406 /**
407 * STEP 2: Use register_shutdown_function to detect any fatal errors (E_ERROR, E_PARSE, etc.)
408 * that might occur during the loading of a widget. If an error is detected, store that widget
409 * in the "broken" list with the current plugin version and the error message.
410 */
411 register_shutdown_function(function () use (&$currentlyLoadingWidgetId, $currentPluginVersion) {
412 $error = error_get_last();
413 if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
414 // If a fatal error occurred while loading a specific widget
415 if (!empty($currentlyLoadingWidgetId)) {
416 $brokenWidgetsLocal = get_option('king_addons_broken_widgets', []);
417 $brokenWidgetsLocal[$currentlyLoadingWidgetId] = [
418 'version' => $currentPluginVersion,
419 'error' => $error['message'] ?? ''
420 ];
421 update_option('king_addons_broken_widgets', $brokenWidgetsLocal);
422 }
423 }
424 });
425
426 /**
427 * STEP 3: Now we iterate through all widgets in our modules map and try to load them.
428 * If a widget is in the broken list, we skip it to avoid repeated fatal errors.
429 */
430 foreach (ModulesMap::getModulesMapArray()['widgets'] as $widget_id => $widget) {
431 // Check if the widget is enabled in the options
432 if (!isset($options[$widget_id]) || $options[$widget_id] !== 'enabled') {
433 continue;
434 }
435
436 // If this widget is listed as broken, skip it
437 if (array_key_exists($widget_id, $brokenWidgets)) {
438 // Log something here if needed:
439 // error_log("Skipping widget {$widget_id}, it previously caused a fatal error.");
440 continue;
441 }
442
443 // Track which widget we're loading
444 $currentlyLoadingWidgetId = $widget_id;
445
446 // Include the base widget class
447 $widget_class = $widget['php-class'];
448 $path_widget_class = "King_Addons\\" . $widget_class;
449 require_once(KING_ADDONS_PATH . 'includes/widgets/' . $widget_class . '/' . $widget_class . '.php');
450
451 // Check if we can load the Pro version
452 if (
453 function_exists('king_addons_freemius')
454 && king_addons_freemius()->can_use_premium_code__premium_only()
455 && defined('KING_ADDONS_PRO_PATH')
456 ) {
457 if (!empty($widget['has-pro'])) {
458 $pro_file_path = KING_ADDONS_PRO_PATH . 'includes/widgets/' . $widget_class . '_Pro/' . $widget_class . '_Pro.php';
459
460 if (file_exists($pro_file_path)) {
461 require_once($pro_file_path);
462 $path_widget_class_pro = "King_Addons\\" . $widget_class . '_Pro';
463 $widgets_manager->register(new $path_widget_class_pro);
464 } else {
465 // If Pro file doesn't exist, register the base widget
466 $widgets_manager->register(new $path_widget_class);
467 }
468 } else {
469 // No 'has-pro', register the base widget
470 $widgets_manager->register(new $path_widget_class);
471 }
472 } else {
473 // No Freemius Pro available, register the base widget
474 $widgets_manager->register(new $path_widget_class);
475 }
476
477 // Clear the tracking variable after successful load
478 $currentlyLoadingWidgetId = null;
479 }
480 }
481
482 function enableWidgetsByDefault(): void
483 {
484 $options = get_option('king_addons_options');
485
486 foreach (ModulesMap::getModulesMapArray()['widgets'] as $widget_id => $widget) {
487
488 if (!($options[$widget_id] ?? null)) {
489 $options[$widget_id] = 'enabled';
490 update_option('king_addons_options', $options);
491 }
492 }
493 }
494
495 function enableFeatures(): void
496 {
497 $options = get_option('king_addons_options');
498
499 foreach (ModulesMap::getModulesMapArray()['features'] as $feature_id => $feature) {
500
501 if (!($options[$feature_id] ?? null)) {
502 $options[$feature_id] = 'enabled';
503 update_option('king_addons_options', $options);
504 }
505
506 if ($options[$feature_id] === 'enabled') {
507 $feature_class = $feature['php-class'];
508 $path_feature_class = "King_Addons\\" . $feature_class;
509 require_once(KING_ADDONS_PATH . 'includes/features/' . $feature_class . '/' . $feature_class . '.php');
510 new $path_feature_class;
511 }
512 }
513 }
514
515 public function registerControls(Controls_Manager $controls_manager): void
516 {
517 $controls_manager->register(new AJAX_Select2\Ajax_Select2());
518 $controls_manager->register(new Animations\Animations());
519 $controls_manager->register(new Animations\Animations_Alternative());
520 $controls_manager->register(new Button_Animations\Button_Animations());
521 }
522
523 function enqueueEditorStyles(): void
524 {
525 wp_enqueue_style(KING_ADDONS_ASSETS_UNIQUE_KEY . '-elementor-editor', KING_ADDONS_URL . 'includes/admin/css/elementor-editor.css', '', KING_ADDONS_VERSION);
526 }
527
528 function enqueueEditorScripts(): void
529 {
530 wp_enqueue_script(KING_ADDONS_ASSETS_UNIQUE_KEY . '-elementor-editor', KING_ADDONS_URL . 'includes/admin/js/elementor-editor.js', '', KING_ADDONS_VERSION);
531
532 // Localize script with PRO status
533 wp_localize_script(KING_ADDONS_ASSETS_UNIQUE_KEY . '-elementor-editor', 'kingAddonsEditor', [
534 'isPro' => king_addons_freemius()->can_use_premium_code__premium_only() ? true : false
535 ]);
536
537 wp_enqueue_script(KING_ADDONS_ASSETS_UNIQUE_KEY . '-data-table-export', KING_ADDONS_URL . 'includes/widgets/Data_Table/preview-handler.js', '', KING_ADDONS_VERSION);
538
539 if (KING_ADDONS_WGT_FORM_BUILDER) {
540 wp_enqueue_script(KING_ADDONS_ASSETS_UNIQUE_KEY . '-form-builder-editor-handler', KING_ADDONS_URL . 'includes/widgets/Form_Builder/editor-handler.js', '', KING_ADDONS_VERSION);
541 }
542 }
543
544 public static function renderProFeaturesSection($module, $section, $type, $widget_name, $features): void
545 {
546 if (king_addons_freemius()->can_use_premium_code__premium_only()) {
547 return;
548 }
549
550 $module->start_controls_section(
551 'king_addons_pro_features_section',
552 [
553 'label' => KING_ADDONS_ELEMENTOR_ICON_PRO . '<span class="king-addons-pro-features-heading">' . esc_html__('Pro Features', 'king-addons') . '</span>',
554 'tab' => $section ?: null,
555 ]
556 );
557
558 $list_html = '<ul>' . implode('', array_map(fn($feature) => "<li>$feature</li>", $features)) . '</ul>';
559
560 $module->add_control(
561 'king_addons_pro_features_list',
562 [
563 'type' => $type,
564 'raw' => $list_html . '<a class="king-addons-pro-features-cta-btn" href="https://kingaddons.com/pricing/?utm_source=kng-module-' . $widget_name . '-upgrade-pro&utm_medium=plugin&utm_campaign=kng" target="_blank">' . esc_html__('Upgrade Now', 'king-addons') . '</a>',
565 'content_classes' => 'king-addons-pro-features-list',
566 ]
567 );
568
569 $module->end_controls_section();
570 }
571
572 public static function renderUpgradeProNotice($module, $controls_manager, $widget_name, $option, $condition = []): void
573 {
574 if (king_addons_freemius()->can_use_premium_code__premium_only()) {
575 return;
576 }
577
578 $module->add_control(
579 $option . '_pro_notice_',
580 [
581 'raw' => 'Upgrade to the <strong><a href="https://kingaddons.com/pricing/?utm_source=kng-module-' . $widget_name . '-settings-upgrade-pro&utm_medium=plugin&utm_campaign=kng" target="_blank">Pro version</a></strong> now<br> and unlock this feature!',
582 'type' => $controls_manager,
583 'content_classes' => 'king-addons-pro-notice',
584 'condition' => [
585 $option => $condition,
586 ]
587 ]
588 );
589 }
590
591 public static function getCustomTypes($query, $exclude_defaults = true): array
592 {
593 $custom_types = $query === 'tax'
594 ? get_taxonomies(['show_in_nav_menus' => true], 'objects')
595 : get_post_types(['show_in_nav_menus' => true], 'objects');
596
597 return array_filter(
598 array_map(fn($type) => $type->label, $custom_types),
599 fn($label, $key) => !$exclude_defaults || !in_array($key, ['post', 'page', 'category', 'post_tag']),
600 ARRAY_FILTER_USE_BOTH
601 );
602 }
603
604 public static function getShareIcon($args = []): string
605 {
606 $args = wp_parse_args($args, [
607 'network' => '',
608 'url' => '',
609 'title' => '',
610 'text' => '',
611 'image' => '',
612 'show_whatsapp_title' => 'no',
613 'show_whatsapp_excerpt' => 'no',
614 'tooltip' => 'no',
615 'icons' => 'no',
616 'labels' => 'no',
617 'custom_label' => '',
618 ]);
619
620 $url = esc_url($args['url']);
621 $title = wp_strip_all_tags($args['title']);
622 $text = wp_strip_all_tags($args['text']);
623 $image = esc_url($args['image']);
624 $network = $args['network'];
625
626 $get_whatsapp_url = function ($a) {
627 if ('yes' === $a['show_whatsapp_title'] && 'yes' === $a['show_whatsapp_excerpt']) {
628 return 'https://api.whatsapp.com/send?text=*' . $a['title'] . '*%0a' . $a['text'] . '%0a' . $a['url'];
629 } elseif ('yes' === $a['show_whatsapp_title']) {
630 return 'https://api.whatsapp.com/send?text=*' . $a['title'] . '*%0a' . $a['url'];
631 } elseif ('yes' === $a['show_whatsapp_excerpt']) {
632 return 'https://api.whatsapp.com/send?text=*' . $a['text'] . '%0a' . $a['url'];
633 }
634 return 'https://api.whatsapp.com/send?text=' . $a['url'];
635 };
636
637 $networks_map = [
638 'facebook-f' => [
639 'url' => "https://www.facebook.com/sharer.php?u=$url",
640 'title' => esc_html__('Facebook', 'king-addons'),
641 'icon' => 'fab',
642 ],
643 'x-twitter' => [
644 'url' => "https://twitter.com/intent/tweet?url=$url",
645 'title' => esc_html__('X (Twitter)', 'king-addons'),
646 'icon' => 'fab',
647 ],
648 'linkedin-in' => [
649 'url' => "https://www.linkedin.com/shareArticle?mini=true&url=$url&title=$title&summary=$text&source=$url",
650 'title' => esc_html__('LinkedIn', 'king-addons'),
651 'icon' => 'fab',
652 ],
653 'pinterest-p' => [
654 'url' => "https://www.pinterest.com/pin/create/button/?url=$url&media=$image",
655 'title' => esc_html__('Pinterest', 'king-addons'),
656 'icon' => 'fab',
657 ],
658 'reddit' => [
659 'url' => "https://reddit.com/submit?url=$url&title=$title",
660 'title' => esc_html__('Reddit', 'king-addons'),
661 'icon' => 'fab',
662 ],
663 'tumblr' => [
664 'url' => "https://tumblr.com/share/link?url=$url",
665 'title' => esc_html__('Tumblr', 'king-addons'),
666 'icon' => 'fab',
667 ],
668 'digg' => [
669 'url' => "https://digg.com/submit?url=$url",
670 'title' => esc_html__('Digg', 'king-addons'),
671 'icon' => 'fab',
672 ],
673 'xing' => [
674 'url' => "https://www.xing.com/app/user?op=share&url=$url",
675 'title' => esc_html__('Xing', 'king-addons'),
676 'icon' => 'fab',
677 ],
678 'vk' => [
679 'url' => "https://vk.ru/share.php?url=$url&title=$title&description=" . wp_trim_words($text, 250) . "&image=$image/",
680 'title' => esc_html__('VK', 'king-addons'),
681 'icon' => 'fab',
682 ],
683 'odnoklassniki' => [
684 'url' => "https://connect.ok.ru/offer?url=$url",
685 'title' => esc_html__('OK', 'king-addons'),
686 'icon' => 'fab',
687 ],
688 'get-pocket' => [
689 'url' => "https://getpocket.com/edit?url=$url",
690 'title' => esc_html__('Pocket', 'king-addons'),
691 'icon' => 'fab',
692 ],
693 'skype' => [
694 'url' => "https://web.skype.com/share?url=$url",
695 'title' => esc_html__('Skype', 'king-addons'),
696 'icon' => 'fab',
697 ],
698 'whatsapp' => [
699 'url' => $get_whatsapp_url($args),
700 'title' => esc_html__('WhatsApp', 'king-addons'),
701 'icon' => 'fab',
702 ],
703 'telegram' => [
704 'url' => "https://telegram.me/share/url?url=$url&text=$text",
705 'title' => esc_html__('Telegram', 'king-addons'),
706 'icon' => 'fab',
707 ],
708 'envelope' => [
709 'url' => "mailto:?subject=$title&body=$url",
710 'title' => esc_html__('Email', 'king-addons'),
711 'icon' => 'fas',
712 ],
713 'print' => [
714 'url' => "javascript:window.print()",
715 'title' => esc_html__('Print', 'king-addons'),
716 'icon' => 'fas',
717 ],
718 ];
719
720 if (!isset($networks_map[$network])) {
721 return '';
722 }
723
724 $share_url = $networks_map[$network]['url'];
725 $network_title = $networks_map[$network]['title'];
726 $icon_category = $networks_map[$network]['icon'];
727
728 $output = '<a href="' . esc_url($share_url) . '" class="king-addons-share-icon king-addons-share-' . esc_attr($network) . '" target="_blank">';
729
730 if ('yes' === $args['tooltip']) {
731 $output .= '<span class="king-addons-share-tooltip king-addons-tooltip">' . esc_html($network_title) . '</span>';
732 }
733
734 if ('yes' === $args['icons']) {
735 $output .= '<i class="' . esc_attr($icon_category) . ' fa-' . esc_attr($network) . '"></i>';
736 }
737
738 if ('yes' === $args['labels']) {
739 $label = !empty($args['custom_label']) ? $args['custom_label'] : $network_title;
740 $output .= '<span class="king-addons-share-label">' . esc_html($label) . '</span>';
741 }
742
743 $output .= '</a>';
744
745 return $output;
746 }
747
748 public static function validateHTMLTags($setting, $default, $tags_whitelist)
749 {
750 $value = $setting;
751 if (!in_array($value, $tags_whitelist)) {
752 $value = $default;
753 }
754 return $value;
755 }
756
757 public static function getIcon($icon, $dir)
758 {
759 if (empty($icon) || strpos($icon, 'fa-') === false) {
760 return '';
761 }
762
763 $dir = $dir ? "-$dir" : '';
764 return wp_kses(
765 '<i class="' . esc_attr($icon . $dir) . '"></i>',
766 ['i' => ['class' => []]]
767 );
768 }
769
770 public static function getPluginName()
771 {
772 return 'King Addons';
773 }
774
775 public static function getAnimationTimings(): array
776 {
777 /** @noinspection DuplicatedCode */
778 $timings = [
779 'ease-default' => 'Default',
780 'linear' => 'Linear',
781 'ease-in' => 'Ease In',
782 'ease-out' => 'Ease Out',
783 'pro-eio' => 'EI Out (Pro)',
784 'pro-eiqd' => 'EI Quad (Pro)',
785 'pro-eicb' => 'EI Cubic (Pro)',
786 'pro-eiqrt' => 'EI Quart (Pro)',
787 'pro-eiqnt' => 'EI Quint (Pro)',
788 'pro-eisn' => 'EI Sine (Pro)',
789 'pro-eiex' => 'EI Expo (Pro)',
790 'pro-eicr' => 'EI Circ (Pro)',
791 'pro-eibk' => 'EI Back (Pro)',
792 'pro-eoqd' => 'EO Quad (Pro)',
793 'pro-eocb' => 'EO Cubic (Pro)',
794 'pro-eoqrt' => 'EO Quart (Pro)',
795 'pro-eoqnt' => 'EO Quint (Pro)',
796 'pro-eosn' => 'EO Sine (Pro)',
797 'pro-eoex' => 'EO Expo (Pro)',
798 'pro-eocr' => 'EO Circ (Pro)',
799 'pro-eobk' => 'EO Back (Pro)',
800 'pro-eioqd' => 'EIO Quad (Pro)',
801 'pro-eiocb' => 'EIO Cubic (Pro)',
802 'pro-eioqrt' => 'EIO Quart (Pro)',
803 'pro-eioqnt' => 'EIO Quint (Pro)',
804 'pro-eiosn' => 'EIO Sine (Pro)',
805 'pro-eioex' => 'EIO Expo (Pro)',
806 'pro-eiocr' => 'EIO Circ (Pro)',
807 'pro-eiobk' => 'EIO Back (Pro)',
808 ];
809
810 if (king_addons_freemius()->can_use_premium_code__premium_only()) {
811 /** @noinspection DuplicatedCode */
812 $timings = [
813 'ease-default' => 'Default',
814 'linear' => 'Linear',
815 'ease-in' => 'Ease In',
816 'ease-out' => 'Ease Out',
817 'ease-in-out' => 'Ease In Out',
818 'ease-in-quad' => 'Ease In Quad',
819 'ease-in-cubic' => 'Ease In Cubic',
820 'ease-in-quart' => 'Ease In Quart',
821 'ease-in-quint' => 'Ease In Quint',
822 'ease-in-sine' => 'Ease In Sine',
823 'ease-in-expo' => 'Ease In Expo',
824 'ease-in-circ' => 'Ease In Circ',
825 'ease-in-back' => 'Ease In Back',
826 'ease-out-quad' => 'Ease Out Quad',
827 'ease-out-cubic' => 'Ease Out Cubic',
828 'ease-out-quart' => 'Ease Out Quart',
829 'ease-out-quint' => 'Ease Out Quint',
830 'ease-out-sine' => 'Ease Out Sine',
831 'ease-out-expo' => 'Ease Out Expo',
832 'ease-out-circ' => 'Ease Out Circ',
833 'ease-out-back' => 'Ease Out Back',
834 'ease-in-out-quad' => 'Ease In Out Quad',
835 'ease-in-out-cubic' => 'Ease In Out Cubic',
836 'ease-in-out-quart' => 'Ease In Out Quart',
837 'ease-in-out-quint' => 'Ease In Out Quint',
838 'ease-in-out-sine' => 'Ease In Out Sine',
839 'ease-in-out-expo' => 'Ease In Out Expo',
840 'ease-in-out-circ' => 'Ease In Out Circ',
841 'ease-in-out-back' => 'Ease In Out Back',
842 ];
843 }
844
845 return $timings;
846 }
847
848 public static function getAnimationTimingsConditionsPro()
849 {
850 return [
851 'pro-eibk',
852 'pro-eicb',
853 'pro-eicr',
854 'pro-eiex',
855 'pro-eio',
856 'pro-eiobk',
857 'pro-eiocb',
858 'pro-eiocr',
859 'pro-eioex',
860 'pro-eioqd',
861 'pro-eioqnt',
862 'pro-eioqrt',
863 'pro-eiosn',
864 'pro-eiqd',
865 'pro-eiqnt',
866 'pro-eiqrt',
867 'pro-eisn',
868 'pro-eobk',
869 'pro-eocb',
870 'pro-eocr',
871 'pro-eoex',
872 'pro-eoqd',
873 'pro-eoqnt',
874 'pro-eoqrt',
875 'pro-eosn',
876 ];
877 }
878
879 public static function isBlogArchive()
880 {
881 return (
882 is_home()
883 && '0' === get_option('page_on_front')
884 && '0' === get_option('page_for_posts')
885 ) || (
886 intval(get_option('page_for_posts')) === get_queried_object_id()
887 && !is_404()
888 );
889 }
890
891 public static function filterOembedResults($html)
892 {
893 preg_match('/src="([^"]+)"/', $html, $m);
894 return $m[1] . '&auto_play=true';
895 }
896
897 public static function getWooCommerceTaxonomies()
898 {
899 $filtered = array_filter(get_object_taxonomies('product'), fn($t) => get_taxonomy($t)->show_ui);
900 return array_combine($filtered, array_map(fn($t) => get_taxonomy($t)->label, $filtered));
901 }
902
903 public static function getCustomMetaKeysTaxonomies()
904 {
905 $data = [];
906 $tax_types = Core::getCustomTypes('tax', false);
907
908 foreach ($tax_types as $taxonomy_slug => $post_type_name) {
909 $meta_keys = [];
910 foreach (get_terms($taxonomy_slug) as $tax) {
911 $keys = array_keys(get_term_meta($tax->term_id));
912 $keys = array_filter($keys, fn($key) => '_' !== $key[0]);
913 $meta_keys = array_merge($meta_keys, $keys);
914 }
915 $data[$taxonomy_slug] = array_unique($meta_keys);
916 }
917
918
919 $merged = call_user_func_array('array_merge', array_values($data));
920 $merged_meta_keys = array_values(array_unique($merged));
921
922 $options = array_combine($merged_meta_keys, $merged_meta_keys);
923
924 return [$data, $options];
925 }
926
927 public static function getMailchimpLists()
928 {
929 $api_key = get_option('king_addons_mailchimp_api_key', '');
930 $mailchimp_list = ['def' => esc_html__('Select List', 'king-addons')];
931
932 if (!$api_key) {
933 return $mailchimp_list;
934 }
935
936 $url = 'https://' . explode('-', $api_key)[1] . '.api.mailchimp.com/3.0/lists/';
937 $response = wp_remote_get($url, [
938 'headers' => ['Authorization' => 'Basic ' . base64_encode('user:' . $api_key)]
939 ]);
940
941 $body = json_decode(wp_remote_retrieve_body($response));
942 if (!empty($body->lists)) {
943 foreach ($body->lists as $list) {
944 $mailchimp_list[$list->id] = $list->name . ' (' . $list->stats->member_count . ')';
945 }
946 }
947
948 return $mailchimp_list;
949 }
950
951 public static function getMailchimpGroups()
952 {
953 $apiKey = get_option('king_addons_mailchimp_api_key');
954 $domain = 'https://' . substr($apiKey, strpos($apiKey, '-') + 1) . '.api.mailchimp.com/3.0/';
955 $authArgs = ['headers' => ['Authorization' => 'Basic ' . base64_encode('user:' . $apiKey)]];
956 $groups = ['def' => 'Select Group'];
957 $mailchimpIDs = Core::getMailchimpLists();
958
959 foreach ($mailchimpIDs as $audience => $ignore) {
960 if ($audience === 'def') {
961 continue;
962 }
963
964 $cats = wp_remote_get("{$domain}lists/$audience/interest-categories", $authArgs);
965 $cats = json_decode($cats['body'])->categories ?? [];
966
967 foreach ($cats as $cat) {
968 $interests = wp_remote_get("{$domain}lists/$audience/interest-categories/$cat->id/interests", $authArgs);
969 $interests = json_decode($interests['body'])->interests ?? [];
970
971 foreach ($interests as $int) {
972 $groups[$int->id] = $int->name;
973 }
974 }
975 }
976
977 return $groups;
978 }
979
980 public static function getShopURL($settings)
981 {
982 global $wp;
983 $url = ('' === get_option('permalink_structure'))
984 ? remove_query_arg(['page', 'paged'], add_query_arg($wp->query_string, '', home_url($wp->request)))
985 : preg_replace('%/page/[0-9]+%', '', home_url(trailingslashit($wp->request)));
986 $url = add_query_arg('kingaddonsfilters', '', $url);
987 $single_params = [
988 'min_price' => true,
989 'max_price' => true,
990 'orderby' => false,
991 'psearch' => false,
992 'filter_product_cat' => false,
993 'filter_product_tag' => false,
994 'filter_rating' => false,
995 ];
996 foreach ($single_params as $param => $needs_clean) {
997 if (isset($_GET[$param])) {
998 $value = wp_unslash($_GET[$param]);
999 $value = $needs_clean ? wc_clean($value) : $value;
1000 $url = add_query_arg($param, $value, $url);
1001 }
1002 }
1003 /** @noinspection DuplicatedCode */
1004 if ($chosen_attrs = WC()->query->get_layered_nav_chosen_attributes()) {
1005 foreach ($chosen_attrs as $name => $data) {
1006 $filter_name = wc_attribute_taxonomy_slug($name);
1007 if (!empty($data['terms'])) {
1008 $url = add_query_arg('filter_' . $filter_name, implode(',', $data['terms']), $url);
1009 }
1010 if (!empty($settings)) {
1011 if ('or' === $settings['tax_query_type'] || isset($_GET['query_type_' . $filter_name])) {
1012 $url = add_query_arg('query_type_' . $filter_name, 'or', $url);
1013 }
1014 }
1015 }
1016 }
1017 return $url;
1018 }
1019
1020 public static function getClientIP()
1021 {
1022 $server_ip_keys = [
1023 'HTTP_CLIENT_IP',
1024 'HTTP_X_FORWARDED_FOR',
1025 'HTTP_X_FORWARDED',
1026 'HTTP_X_CLUSTER_CLIENT_IP',
1027 'HTTP_FORWARDED_FOR',
1028 'HTTP_FORWARDED',
1029 'REMOTE_ADDR',
1030 ];
1031
1032 foreach ($server_ip_keys as $key) {
1033 if (isset($_SERVER[$key])) {
1034 $ip = wp_kses_post_deep(wp_unslash($_SERVER[$key]));
1035 if (filter_var($ip, FILTER_VALIDATE_IP)) {
1036 return $ip;
1037 }
1038 }
1039 }
1040
1041 return '127.0.0.1';
1042 }
1043
1044 public static function getCustomMetaKeys()
1045 {
1046 // Get all custom post types (slug => name).
1047 $post_types = Core::getCustomTypes('post', false);
1048
1049 // Build $data with each post type's unique custom meta keys (excluding keys beginning with "_").
1050 $data = array_combine(
1051 array_keys($post_types),
1052 array_map(function ($slug) {
1053 $keys = [];
1054 foreach (get_posts(['post_type' => $slug, 'posts_per_page' => -1]) as $post) {
1055 // get_post_custom_keys can return null, so cast to array:
1056 foreach ((array)get_post_custom_keys($post->ID) as $meta_key) {
1057 // Exclude protected keys (those beginning with "_").
1058 if ($meta_key[0] !== '_') {
1059 $keys[] = $meta_key;
1060 }
1061 }
1062 }
1063 return array_values(array_unique($keys));
1064 }, array_keys($post_types))
1065 );
1066
1067 // Flatten all meta keys across all post types, remove duplicates, and reindex.
1068 $merged_meta_keys = array_values(array_unique(array_merge([], ...$data)));
1069
1070 // Create an associative array where key == value (for convenient dropdowns, etc.).
1071 $options = array_combine($merged_meta_keys, $merged_meta_keys);
1072
1073 // Return both the per-post-type data and the merged, deduplicated options.
1074 return [$data, $options];
1075 }
1076
1077 public function enqueueLightboxDynamicStyles()
1078 {
1079 wp_register_style('king-addons-lightbox-dynamic-style', false);
1080 wp_enqueue_style('king-addons-lightbox-dynamic-style');
1081
1082 $bg = esc_html(get_option('king_addons_lightbox_bg_color', 'rgba(0,0,0,0.6)'));
1083 $toolbar = esc_html(get_option('king_addons_lightbox_toolbar_color', 'rgba(0,0,0,0.8)'));
1084 $caption = esc_html(get_option('king_addons_lightbox_caption_color', 'rgba(0,0,0,0.8)'));
1085 $gallery = esc_html(get_option('king_addons_lightbox_gallery_color', '#444444'));
1086 $progress_bar = esc_html(get_option('king_addons_lightbox_pb_color', '#8a8a8a'));
1087 $ui_color = esc_html(get_option('king_addons_lightbox_ui_color', '#efefef'));
1088 $icon_size = floatval(get_option('king_addons_lightbox_icon_size', 20));
1089 $icon_size_big = $icon_size + 4;
1090 $ui_hover = esc_html(get_option('king_addons_lightbox_ui_hover_color', '#ffffff'));
1091 $text_color = esc_html(get_option('king_addons_lightbox_text_color', '#efefef'));
1092 $text_size = esc_html(get_option('king_addons_lightbox_text_size', 14));
1093 $arrow_size = esc_html(get_option('king_addons_lightbox_arrow_size', 35));
1094
1095 $custom_css = "#lg-counter { color: $text_color !important; font-size: {$text_size}px !important; opacity: 0.9; } .lg-backdrop { background-color: $bg !important; } .lg-dropdown:after { border-bottom-color: $toolbar !important; } .lg-icon { color: $ui_color !important; font-size: {$icon_size}px !important; background-color: transparent !important; } .lg-icon.lg-toogle-thumb { font-size: {$icon_size_big}px !important; } .lg-icon:hover, .lg-dropdown-text:hover { color: $ui_hover !important; } .lg-prev, .lg-next { font-size: {$arrow_size}px !important; } .lg-progress { background-color: $progress_bar !important; } .lg-sub-html { background-color: $caption !important; } .lg-sub-html, .lg-dropdown-text { color: $text_color !important; font-size: {$text_size}px !important; } .lg-thumb-item { border-radius: 0 !important; border: none !important; opacity: 0.5; } .lg-thumb-item.active { opacity: 1; } .lg-thumb-outer, .lg-progress-bar { background-color: $gallery !important; } .lg-thumb-outer { padding: 0 10px; } .lg-toolbar, .lg-dropdown { background-color: $toolbar !important; }";
1096
1097 wp_add_inline_style('king-addons-lightbox-dynamic-style', $custom_css);
1098 }
1099
1100 /**
1101 * Enqueues the AI button injection script in the Elementor editor panel.
1102 *
1103 * @return void
1104 */
1105 public function enqueueAiFieldScript(): void
1106 {
1107 wp_enqueue_script(
1108 'king-addons-ai-field',
1109 KING_ADDONS_URL . 'includes/admin/js/ai-textfield.js',
1110 ['jquery', 'elementor-editor'],
1111 KING_ADDONS_VERSION,
1112 true
1113 );
1114
1115 // Localize for AJAX
1116 wp_localize_script(
1117 'king-addons-ai-field',
1118 'KingAddonsAiField',
1119 [
1120 'ajax_url' => admin_url('admin-ajax.php'),
1121 'generate_nonce' => wp_create_nonce('king_addons_ai_generate_nonce'),
1122 'change_nonce' => wp_create_nonce('king_addons_ai_change_nonce'),
1123 'generate_action' => 'king_addons_ai_generate_text',
1124 'change_action' => 'king_addons_ai_change_text',
1125 'icon_url' => KING_ADDONS_URL . 'includes/admin/img/ai.svg',
1126 'rewrite_icon_url' => KING_ADDONS_URL . 'includes/admin/img/ai-refresh.svg',
1127 'settings_url' => admin_url('admin.php?page=king-addons-ai-settings'),
1128 'plugin_url' => KING_ADDONS_URL,
1129 'is_pro' => king_addons_freemius()->can_use_premium_code__premium_only() ? true : false,
1130 'premium_active' => king_addons_freemius()->can_use_premium_code__premium_only() ? true : false,
1131 'translator_enabled' => isset($ai_options['enable_ai_page_translator']) ? (bool) $ai_options['enable_ai_page_translator'] : true,
1132 ]
1133 );
1134 }
1135
1136 /**
1137 * Enqueues the AI image generation field script in the Elementor editor panel.
1138 *
1139 * @return void
1140 */
1141 public function enqueueAiImageGenerationScript(): void
1142 {
1143 // Retrieve AI options and ensure it's an array to prevent warnings.
1144 $ai_options = get_option('king_addons_ai_options', []);
1145 wp_enqueue_script(
1146 'king-addons-ai-image-field',
1147 KING_ADDONS_URL . 'includes/admin/js/ai-imagefield.js',
1148 ['jquery', 'elementor-editor'],
1149 KING_ADDONS_VERSION,
1150 true
1151 );
1152
1153 // Localize for AJAX
1154 wp_localize_script(
1155 'king-addons-ai-image-field',
1156 'KingAddonsAiImageField',
1157 [
1158 'ajax_url' => admin_url('admin-ajax.php'),
1159 'generate_nonce' => wp_create_nonce('king_addons_ai_generate_image_nonce'),
1160 'generate_action' => 'king_addons_ai_generate_image',
1161 'image_model' => sanitize_text_field($ai_options['openai_image_model'] ?? ''),
1162 'icon_url' => KING_ADDONS_URL . 'includes/admin/img/ai.svg',
1163 'rewrite_icon_url' => KING_ADDONS_URL . 'includes/admin/img/ai-refresh.svg',
1164 'settings_url' => admin_url('admin.php?page=king-addons-ai-settings'),
1165 'plugin_url' => KING_ADDONS_URL,
1166 ]
1167 );
1168 }
1169
1170 /**
1171 * Enqueues the styles for AI prompt UI in the Elementor editor panel.
1172 *
1173 * @return void
1174 */
1175 public function enqueueAiFieldStyles(): void
1176 {
1177 // Enqueue CSS for the AI prompt UI
1178 wp_enqueue_style(
1179 'king-addons-ai-field-css',
1180 KING_ADDONS_URL . 'includes/admin/css/ai-textfield.css',
1181 [],
1182 KING_ADDONS_VERSION
1183 );
1184 }
1185
1186 /**
1187 * Enqueues styles for AI Image Generation UI in the Elementor editor panel.
1188 *
1189 * @return void
1190 */
1191 public function enqueueAiImageFieldStyles(): void
1192 {
1193 wp_enqueue_style(
1194 'king-addons-ai-imagefield',
1195 KING_ADDONS_URL . 'includes/admin/css/ai-imagefield.css',
1196 [],
1197 KING_ADDONS_VERSION
1198 );
1199 }
1200
1201 /**
1202 * Enqueues the AI page translator script in the Elementor editor panel.
1203 *
1204 * @return void
1205 */
1206 public function enqueueAiTranslatorScript(): void
1207 {
1208 // Check if AI Page Translator is enabled in settings
1209 $ai_options = get_option('king_addons_ai_options', []);
1210 $translator_enabled = isset($ai_options['enable_ai_page_translator']) ? (bool) $ai_options['enable_ai_page_translator'] : true;
1211
1212 if (!$translator_enabled) {
1213 return; // Don't load script if translator is disabled
1214 }
1215
1216 wp_enqueue_script(
1217 'king-addons-ai-translator',
1218 KING_ADDONS_URL . 'includes/admin/js/ai-page-translator.js',
1219 ['jquery', 'elementor-editor'],
1220 KING_ADDONS_VERSION,
1221 true
1222 );
1223
1224 // Note: Using existing KingAddonsAiField localization
1225 // The translator script will use the same AJAX endpoints and settings
1226 // No need for separate localization as it reuses existing AI infrastructure
1227 }
1228 }
1229
1230 Core::instance();
1231