PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.87
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.87
51.1.87 51.1.86 51.1.84 51.1.85 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 All 41 releases
← All changes | king-addons.php +567 -0 51.1.2 → 51.1.87 View file →
@@ -1,0 +1,567 @@
1 +<?php
2 +
3 +/**
4 + * Plugin Name: King Addons for Elementor
5 + * Description: Elementor addons, 4,000+ Templates & Sections, 100+ Widgets, AI Tools, Mega Menu, Popup Builder, WooCommerce, Templates & Sections. Lightweight & fast Elementor toolkit.
6 + * Author URI: https://kingaddons.com/
7 + * Author: KingAddons.com
8 + * Version: 51.1.87
9 + * Text Domain: king-addons
10 + * Requires at least: 6.0
11 + * Requires PHP: 7.4
12 + * License: GPLv3
13 + * License URI: https://www.gnu.org/licenses/gpl-3.0.html
14 + */
15 +
16 +/** @noinspection SpellCheckingInspection */
17 +if (!defined('ABSPATH')) {
18 + exit; // Exit if accessed directly.
19 +}
20 +
21 +// Load plugin textdomain immediately to prevent early translation loading notices.
22 +load_plugin_textdomain('king-addons');
23 +
24 +/** PLUGIN VERSION */
25 +const KING_ADDONS_VERSION = '51.1.87';
26 +
27 +/** DEFINES */
28 +define('KING_ADDONS_PATH', plugin_dir_path(__FILE__));
29 +define('KING_ADDONS_URL', plugins_url('/', __FILE__));
30 +
31 +/** ASSETS KEY - It's using to have the unique wp_register (style, script) handle */
32 +const KING_ADDONS_ASSETS_UNIQUE_KEY = 'king-addons';
33 +
34 +require_once(KING_ADDONS_PATH . 'includes/helpers/Global/global-constants.php');
35 +
36 +// Shared AI provider abstraction (OpenAI / OpenRouter), used by admin and extensions.
37 +require_once(KING_ADDONS_PATH . 'includes/AI_Provider.php');
38 +
39 +if (!function_exists('king_addons_freemius')) {
40 + // Create a helper function for easy SDK access.
41 + function king_addons_freemius()
42 + {
43 + global $king_addons_freemius;
44 +
45 + if (!isset($king_addons_freemius)) {
46 + // Include Freemius SDK.
47 + require_once dirname(__FILE__) . '/freemius/start.php';
48 +
49 + /** @noinspection PhpUnhandledExceptionInspection */
50 + $king_addons_freemius = fs_dynamic_init(array(
51 + 'id' => '16154',
52 + 'slug' => 'king-addons',
53 + 'premium_slug' => 'king-addons-pro',
54 + 'type' => 'plugin',
55 + 'public_key' => 'pk_eac3624cbc14c1846cf1ab9abbd68',
56 + 'is_premium' => false,
57 + 'premium_suffix' => 'pro',
58 + // If your plugin is a serviceware, set this option to false.
59 + 'has_premium_version' => true,
60 + 'has_addons' => false,
61 + 'has_paid_plans' => true,
62 + 'has_affiliation' => 'selected',
63 + 'menu' => array(
64 + 'slug' => 'king-addons',
65 + 'first-path' => 'plugins.php',
66 + 'pricing' => false,
67 + 'contact' => false,
68 + 'support' => false,
69 + 'affiliation' => false,
70 + ),
71 + ));
72 + }
73 +
74 + return $king_addons_freemius;
75 + }
76 +
77 + // Init Freemius.
78 + king_addons_freemius();
79 + // Signal that SDK was initiated.
80 + do_action('king_addons_freemius_loaded');
81 + king_addons_freemius()->add_filter('show_deactivation_subscription_cancellation', '__return_false');
82 + king_addons_freemius()->add_filter('deactivate_on_activation', '__return_false');
83 +}
84 +
85 +/**
86 + * Safe check for Pro/Premium availability.
87 + *
88 + * This helper function safely checks if the premium code can be used,
89 + * preventing fatal errors if Freemius is not properly initialized.
90 + *
91 + * @since 51.1.40
92 + * @return bool True if premium code can be used, false otherwise.
93 + */
94 +if (!function_exists('king_addons_can_use_pro')) {
95 + function king_addons_can_use_pro(): bool
96 + {
97 + if (!function_exists('king_addons_freemius')) {
98 + return false;
99 + }
100 +
101 + $fs = king_addons_freemius();
102 + if (!is_object($fs) || !method_exists($fs, 'can_use_premium_code')) {
103 + return false;
104 + }
105 +
106 + return (bool) $fs->can_use_premium_code();
107 + }
108 +}
109 +
110 +/**
111 + * Whether the WooCommerce Builder top-level menu is registered.
112 + *
113 + * Wishlist and other store screens hang off that menu when it exists,
114 + * and fall back to King Addons when it does not.
115 + *
116 + * @return bool
117 + */
118 +if (!function_exists('king_addons_woo_builder_menu_is_active')) {
119 + function king_addons_woo_builder_menu_is_active(): bool
120 + {
121 + $options = get_option('king_addons_options', []);
122 + $enabled = !isset($options['ext_woo-builder']) || $options['ext_woo-builder'] === 'enabled';
123 +
124 + return $enabled
125 + && (defined('KING_ADDONS_EXT_WOO_BUILDER') ? (bool) KING_ADDONS_EXT_WOO_BUILDER : true)
126 + && class_exists('WooCommerce')
127 + && function_exists('WC');
128 + }
129 +}
130 +
131 +/**
132 + * Parent slug for WooCommerce-related admin screens.
133 + *
134 + * Page slugs stay the same; only the WP menu parent changes.
135 + *
136 + * @return string
137 + */
138 +if (!function_exists('king_addons_woo_admin_parent_slug')) {
139 + function king_addons_woo_admin_parent_slug(): string
140 + {
141 + return king_addons_woo_builder_menu_is_active() ? 'king-addons-woo-builder' : 'king-addons';
142 + }
143 +}
144 +
145 +/**
146 + * Whether the current admin screen belongs to King Addons.
147 + *
148 + * Screen IDs follow the WP parent menu title, so Woo screens under
149 + * WooCommerce Builder become `woocommerce-builder_page_*`. Page slugs
150 + * still start with `king-addons`.
151 + *
152 + * @param string|null $current_screen Optional screen id; current screen if omitted.
153 + * @return bool
154 + */
155 +if (!function_exists('king_addons_is_plugin_admin_screen')) {
156 + function king_addons_is_plugin_admin_screen(?string $current_screen = null): bool
157 + {
158 + $page = isset($_GET['page']) ? sanitize_key(wp_unslash($_GET['page'])) : '';
159 + if ($page !== '' && strpos($page, 'king-addons') === 0) {
160 + return true;
161 + }
162 +
163 + if ($current_screen === null) {
164 + $screen = function_exists('get_current_screen') ? get_current_screen() : null;
165 + if (!$screen || empty($screen->id)) {
166 + return false;
167 + }
168 + $current_screen = (string) $screen->id;
169 + }
170 +
171 + $legacy_screens = [
172 + 'edit-king-addons-el-hf',
173 + 'edit-king-addons-fb-sub',
174 + 'header-footer_page_king-addons-el-hf-settings',
175 + ];
176 +
177 + return (strpos($current_screen, 'king-addons_') === 0)
178 + || (strpos($current_screen, 'toplevel_page_king-addons') === 0)
179 + || (strpos($current_screen, 'woocommerce-builder_page_') === 0)
180 + || in_array($current_screen, $legacy_screens, true);
181 + }
182 +}
183 +
184 +if (!function_exists('king_addons_doActivation')) {
185 + function king_addons_doActivation()
186 + {
187 + add_option('king_addons_plugin_activated', true);
188 + if (false === get_option('king_addons_optionActivationTime')) {
189 + add_option('king_addons_optionActivationTime', absint(intval(strtotime('now'))));
190 + }
191 +
192 + // Ensure wishlist tables are created on activation.
193 + require_once plugin_dir_path(__FILE__) . 'includes/wishlist/Wishlist_DB.php';
194 + \King_Addons\Wishlist\Wishlist_DB::maybe_create_tables();
195 +
196 + // Ensure Smart Links tables are created on activation.
197 + require_once plugin_dir_path(__FILE__) . 'includes/extensions/Smart_Links/Smart_Links_DB.php';
198 + \King_Addons\Smart_Links\Smart_Links_DB::maybe_create_tables();
199 + update_option('king_addons_smart_links_flush_rewrite', 1);
200 + }
201 +
202 + register_activation_hook(__FILE__, 'king_addons_doActivation');
203 +}
204 +
205 +if (!function_exists('king_addons_doDectivation')) {
206 + function king_addons_doDectivation()
207 + {
208 + delete_option('king_addons_HFB_flushed_rewrite_rules');
209 + delete_option('king_addons_optionActivationTime');
210 + }
211 +
212 + register_deactivation_hook(__FILE__, 'king_addons_doDectivation');
213 +}
214 +
215 +if (!function_exists('king_addons_doRedirect_after_activation')) {
216 + function king_addons_doRedirect_after_activation()
217 + {
218 + if (did_action('elementor/loaded')) {
219 + if (get_option('king_addons_plugin_activated', false)) {
220 + delete_option('king_addons_plugin_activated');
221 + wp_redirect(admin_url('admin.php?page=king-addons'));
222 + exit;
223 + }
224 + }
225 + }
226 +
227 + add_action('admin_init', 'king_addons_doRedirect_after_activation');
228 +}
229 +
230 +/**
231 + * Main function
232 + *
233 + * @return void
234 + * @since 1.0.0
235 + * @access public
236 + */
237 +if (!function_exists('king_addons_doPlugin')) {
238 + /** @noinspection PhpMissingReturnTypeInspection */
239 + function king_addons_doPlugin()
240 + {
241 + require_once(KING_ADDONS_PATH . 'includes/Core.php');
242 + }
243 + // Using after_setup_theme to fix: PHP Notice: Function _load_textdomain_just_in_time was called incorrectly.
244 + add_action('after_setup_theme', 'king_addons_doPlugin');
245 +}
246 +
247 +/**
248 + * Register Assets
249 + *
250 + * @return void
251 + * @since 1.0.0
252 + * @access public
253 + */
254 +if (!function_exists('king_addons_registerAssets')) {
255 + /** @noinspection PhpMissingReturnTypeInspection */
256 + function king_addons_registerAssets()
257 + {
258 + require_once(KING_ADDONS_PATH . 'includes/RegisterAssets.php');
259 + }
260 +
261 + add_action('wp_loaded', 'king_addons_registerAssets');
262 +}
263 +
264 +/**
265 + * Enqueue small frontend-only CSS fixes.
266 + *
267 + * @return void
268 + * @since 51.1.42
269 + */
270 +if (!function_exists('king_addons_enqueue_frontend_fixes_css')) {
271 + function king_addons_enqueue_frontend_fixes_css(): void
272 + {
273 + if (is_admin()) {
274 + return;
275 + }
276 +
277 + wp_enqueue_style(
278 + KING_ADDONS_ASSETS_UNIQUE_KEY . '-fixes-for-elementor',
279 + KING_ADDONS_URL . 'includes/assets/css/fixes-for-elementor.css',
280 + [],
281 + KING_ADDONS_VERSION
282 + );
283 + }
284 +
285 + add_action('wp_enqueue_scripts', 'king_addons_enqueue_frontend_fixes_css', 99);
286 + // Ensure the stylesheet is also loaded in Elementor's preview iframe inside the editor.
287 + add_action('elementor/frontend/after_enqueue_styles', 'king_addons_enqueue_frontend_fixes_css', 99);
288 + add_action('elementor/preview/enqueue_styles', 'king_addons_enqueue_frontend_fixes_css', 99);
289 +}
290 +
291 +/**
292 + * Hides spaming notices from another plugins on the plugin settings page
293 + *
294 + * @return void
295 + * @since 1.0.0
296 + * @access public
297 + */
298 +if (!function_exists('king_addons_hideAnotherNotices')) {
299 + /** @noinspection PhpMissingReturnTypeInspection */
300 + function king_addons_hideAnotherNotices()
301 + {
302 + // Exclude the account page from notice hiding.
303 + // URL: /wp-admin/admin.php?page=king-addons-account
304 + if (isset($_GET['page']) && $_GET['page'] === 'king-addons-account') {
305 + return;
306 + }
307 +
308 + if (king_addons_is_plugin_admin_screen()) {
309 + // Remove all notices
310 + remove_all_actions('user_admin_notices');
311 + remove_all_actions('admin_notices');
312 + }
313 + }
314 +
315 + add_action('in_admin_header', 'king_addons_hideAnotherNotices', 99);
316 +}
317 +
318 +/**
319 + * Custom admin footer text on King Addons pages
320 + * Shows rating request similar to WooCommerce
321 + *
322 + * @param string $footer_text Default footer text.
323 + * @return string Modified footer text.
324 + * @since 51.2.0
325 + */
326 +if (!function_exists('king_addons_admin_footer_text')) {
327 + function king_addons_admin_footer_text($footer_text)
328 + {
329 + if (!current_user_can('manage_options')) {
330 + return $footer_text;
331 + }
332 +
333 + if (!king_addons_is_plugin_admin_screen()) {
334 + return $footer_text;
335 + }
336 +
337 + // Check if user has already rated
338 + if (!get_option('king_addons_admin_footer_text_rated')) {
339 + $footer_text = sprintf(
340 + /* translators: 1: King Addons 2: five stars */
341 + __('If you like %1$s please leave us a %2$s rating. A huge thanks in advance!', 'king-addons'),
342 + sprintf('<strong>%s</strong>', esc_html__('King Addons', 'king-addons')),
343 + '<a href="https://wordpress.org/support/plugin/king-addons/reviews?rate=5#new-post" target="_blank" class="king-addons-rating-link" aria-label="' . esc_attr__('five star', 'king-addons') . '" data-rated="' . esc_attr__('Thanks :)', 'king-addons') . '">&#9733;&#9733;&#9733;&#9733;&#9733;</a>'
344 + );
345 + } else {
346 + $footer_text = __('Thank you for using King Addons!', 'king-addons');
347 + }
348 +
349 + return '<span id="footer-thankyou">' . $footer_text . '</span>';
350 + }
351 +
352 + add_filter('admin_footer_text', 'king_addons_admin_footer_text', 1);
353 +}
354 +
355 +/**
356 + * Enqueue script for rating link click handler
357 + *
358 + * @return void
359 + * @since 51.2.0
360 + */
361 +if (!function_exists('king_addons_rating_script')) {
362 + function king_addons_rating_script()
363 + {
364 + if (!current_user_can('manage_options')) {
365 + return;
366 + }
367 +
368 + // Only on King Addons pages and only if not already rated
369 + if (!king_addons_is_plugin_admin_screen() || get_option('king_addons_admin_footer_text_rated')) {
370 + return;
371 + }
372 +
373 + $script = "
374 + (function() {
375 + 'use strict';
376 + var ratingLink = document.querySelector('a.king-addons-rating-link');
377 + if (ratingLink) {
378 + ratingLink.addEventListener('click', function(e) {
379 + var link = e.currentTarget;
380 + var formData = new FormData();
381 + formData.append('action', 'king_addons_rated');
382 + formData.append('nonce', '" . esc_js(wp_create_nonce('king_addons_rated')) . "');
383 +
384 + fetch('" . esc_js(admin_url('admin-ajax.php')) . "', {
385 + method: 'POST',
386 + body: formData,
387 + credentials: 'same-origin'
388 + });
389 +
390 + var parent = link.parentElement;
391 + if (parent) {
392 + parent.textContent = link.getAttribute('data-rated');
393 + }
394 + });
395 + }
396 + })();
397 + ";
398 +
399 + $handle = 'king-addons-admin-footer-rating';
400 + wp_register_script($handle, '', [], KING_ADDONS_VERSION, true);
401 + wp_enqueue_script($handle);
402 + wp_add_inline_script($handle, $script);
403 + }
404 +
405 + add_action('admin_enqueue_scripts', 'king_addons_rating_script');
406 +}
407 +
408 +/**
409 + * AJAX handler for saving rated status
410 + *
411 + * @return void
412 + * @since 51.2.0
413 + */
414 +if (!function_exists('king_addons_rated_callback')) {
415 + function king_addons_rated_callback()
416 + {
417 + if (!current_user_can('manage_options')) {
418 + wp_die(-1, 403);
419 + }
420 +
421 + check_ajax_referer('king_addons_rated', 'nonce');
422 +
423 + update_option('king_addons_admin_footer_text_rated', 1);
424 + wp_die();
425 + }
426 +
427 + add_action('wp_ajax_king_addons_rated', 'king_addons_rated_callback');
428 +}
429 +
430 +/**
431 + * Apply theme detection script to Account page
432 + * Reads user's theme preference and applies ka-v3-dark class if needed
433 + *
434 + * @return void
435 + * @since 51.2.0
436 + */
437 +if (!function_exists('king_addons_account_page_theme_script')) {
438 + function king_addons_account_page_theme_script()
439 + {
440 + $screen = function_exists('get_current_screen') ? get_current_screen() : null;
441 + if (!$screen || $screen->id !== 'king-addons_page_king-addons-account') {
442 + return;
443 + }
444 +
445 + // Get user's theme preference
446 + $theme_mode = get_user_meta(get_current_user_id(), 'king_addons_theme_mode', true);
447 + $allowed_theme_modes = ['dark', 'light', 'auto'];
448 + if (!in_array($theme_mode, $allowed_theme_modes, true)) {
449 + $theme_mode = 'auto';
450 + }
451 + ?>
452 + <script>
453 + (function() {
454 + var themeMode = '<?php echo esc_js($theme_mode); ?>';
455 + var root = document.documentElement;
456 + var mql = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
457 +
458 + // Prevent flash by disabling transitions early (body isn't available in admin_head).
459 + root.classList.add('ka-no-transition');
460 +
461 + function isDarkForMode(mode) {
462 + if (mode === 'auto') {
463 + return !!(mql && mql.matches);
464 + }
465 +
466 + return mode === 'dark';
467 + }
468 +
469 + function applyTheme(mode) {
470 + var isDark = isDarkForMode(mode);
471 +
472 + root.classList.toggle('ka-v3-dark', isDark);
473 +
474 + // body may not exist yet (this script runs in <head>).
475 + if (document.body) {
476 + document.body.classList.toggle('ka-v3-dark', isDark);
477 + }
478 + }
479 +
480 + applyTheme(themeMode);
481 +
482 + // Once body exists, ensure it mirrors the html class.
483 + document.addEventListener('DOMContentLoaded', function() {
484 + applyTheme(themeMode);
485 + if (document.body) {
486 + document.body.classList.remove('ka-no-transition');
487 + }
488 + });
489 +
490 + // Listen for system theme changes if in auto mode.
491 + if (themeMode === 'auto' && mql) {
492 + var onMqlChange = function() {
493 + applyTheme('auto');
494 + };
495 +
496 + if (typeof mql.addEventListener === 'function') {
497 + mql.addEventListener('change', onMqlChange);
498 + } else if (typeof mql.addListener === 'function') {
499 + mql.addListener(onMqlChange);
500 + }
501 + }
502 +
503 + // Re-enable transitions.
504 + setTimeout(function() {
505 + root.classList.remove('ka-no-transition');
506 + }, 50);
507 + })();
508 + </script>
509 + <?php
510 + }
511 +
512 + add_action('admin_head', 'king_addons_account_page_theme_script', 1);
513 +}
514 +
515 +/**
516 + * Apply styles to the plugin menu icon because some plugins broke the menu icon styles
517 + *
518 + * @return void
519 + * @since 24.8.25
520 + * @access public
521 + */
522 +if (!function_exists('king_addons_styleMenuIcon')) {
523 + /** @noinspection PhpMissingReturnTypeInspection */
524 + function king_addons_styleMenuIcon()
525 + {
526 + wp_enqueue_style('king-addons-plugin-style-menu-icon', plugin_dir_url(__FILE__) . 'includes/admin/css/menu-icon.css', '', KING_ADDONS_VERSION);
527 + if (get_current_screen()->id == 'king-addons_page_king-addons-pricing') {
528 + wp_enqueue_style('king-addons-plugin-style-pricing', plugin_dir_url(__FILE__) . 'includes/admin/css/pricing.css', '', KING_ADDONS_VERSION);
529 + }
530 + // Load Account page styles
531 + if (get_current_screen()->id == 'king-addons_page_king-addons-account') {
532 + wp_enqueue_style('king-addons-plugin-style-account', plugin_dir_url(__FILE__) . 'includes/admin/css/account.css', '', KING_ADDONS_VERSION);
533 + }
534 + }
535 +
536 + add_action('admin_enqueue_scripts', 'king_addons_styleMenuIcon');
537 +}
538 +
539 +/**
540 + * Add "Upgrade to Pro" link to the Plugins list table.
541 + *
542 + * @param array $links Existing plugin action links.
543 + *
544 + * @return array Modified action links with Upgrade link.
545 + * @since 24.12.78
546 + */
547 +if (! function_exists('king_addons_add_action_links')) {
548 + function king_addons_add_action_links(array $links): array
549 + {
550 + // Pricing page with UTM parameters for tracking.
551 + $pro_url = 'https://kingaddons.com/pricing/?utm_source=kng-plugin-list&utm_medium=wp-plugins-page&utm_campaign=kng';
552 +
553 + // Prepend the Upgrade link.
554 + $links['go_pro'] = sprintf(
555 + '<a href="%1$s" target="_blank" class="king-addons-plugins-gopro">%2$s</a>',
556 + esc_url($pro_url),
557 + esc_html__('Upgrade to Pro', 'king-addons')
558 + );
559 +
560 + return $links;
561 + }
562 +
563 + if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
564 + add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'king_addons_add_action_links');
565 + add_filter('network_admin_plugin_action_links_' . plugin_basename(__FILE__), 'king_addons_add_action_links');
566 + }
567 +}