PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.81
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.81
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 51.1.51 All 36 releases
king-addons / king-addons.php

king-addons.php in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.81, at king-addons.php

568 lines 19.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Plugin Name: King Addons for Elementor
5 * Description: Elementor addons, 4,000+ Templates & Sections, 80+ 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.81
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.81';
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 }
568