PluginProbe
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets / 4.0.9
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets v4.0.9
4.5.4 4.2.1 4.2.2 4.2.3 4.5.0 4.5.2 4.5.3 4.2.0 4.1.18 4.1.17 4.1.16 4.1.15 4.1.14 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 All 146 releases
ultimate-post-kit / admin / admin-settings.php

admin-settings.php in Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets 4.0.9, at admin/admin-settings.php

4,425 lines 166.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use UltimatePostKit\Notices;
4 use UltimatePostKit\Utils;
5 use UltimatePostKit\Admin\ModuleService;
6 use Elementor\Modules\Usage\Module;
7 use Elementor\Tracker;
8
9
10 /**
11 * Ultimate Post Kit Admin Settings Class
12 */
13
14 // Include rollback version functionality
15 require_once BDTUPK_ADMIN_PATH . 'class-rollback-version.php';
16
17 class UltimatePostKit_Admin_Settings {
18
19 public static $modules_list = null;
20 public static $modules_names = null;
21
22 public static $modules_list_only_widgets = null;
23 public static $modules_names_only_widgets = null;
24
25 public static $modules_list_only_3rdparty = null;
26 public static $modules_names_only_3rdparty = null;
27
28 const PAGE_ID = 'ultimate_post_kit_options';
29
30 private $settings_api;
31
32 public $responseObj;
33 public $licenseMessage;
34 public $showMessage = false;
35 private $is_activated = false;
36
37 /**
38 * Rollback version instance
39 *
40 * @var UltimatePostKit_Rollback_Version
41 */
42 public $rollback_version;
43
44 function __construct() {
45 $this->settings_api = new UltimatePostKit_Settings_API;
46
47 if (!defined('BDTUPK_HIDE')) {
48 add_action('admin_init', [$this, 'admin_init']);
49 add_action('admin_menu', [$this, 'admin_menu'], 201);
50 }
51
52 // Handle white label access link
53 $this->handle_white_label_access();
54
55 // Add custom CSS/JS functionality
56 $this->init_custom_code_functionality();
57
58 // White label settings (admin only)
59 add_action( 'wp_ajax_upk_save_white_label', [ $this, 'save_white_label_ajax' ] );
60 add_action( 'wp_ajax_upk_revoke_white_label_token', [ $this, 'revoke_white_label_token_ajax' ] );
61 add_action( 'admin_head', [ $this, 'inject_white_label_icon_css' ] );
62
63 // Plugin installation (admin only)
64 add_action('wp_ajax_upk_install_plugin', [$this, 'install_plugin_ajax']);
65
66 // Initialize rollback version functionality
67 $this->rollback_version = new UltimatePostKit\Admin\UltimatePostKit_Rollback_Version();
68
69 }
70
71
72 /**
73 * Initialize Custom Code Functionality
74 *
75 * @access public
76 * @return void
77 */
78 public function init_custom_code_functionality() {
79 // AJAX handler for saving custom code (admin only)
80 add_action( 'wp_ajax_upk_save_custom_code', [ $this, 'save_custom_code_ajax' ] );
81
82
83 // Admin scripts (admin only)
84 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_custom_code_scripts' ] );
85
86 // Frontend injection is now handled by global functions in the main plugin file
87 self::init_frontend_injection();
88 }
89
90 /**
91 * Initialize frontend injection hooks (works on both admin and frontend)
92 *
93 * @access public static
94 * @return void
95 */
96 public static function init_frontend_injection() {
97 // Frontend hooks are now registered in the main plugin file
98 // This method is kept for backwards compatibility but does nothing
99 }
100
101 /**
102 * Enqueue scripts for custom code editor
103 *
104 * @access public
105 * @return void
106 */
107 public function enqueue_custom_code_scripts( $hook ) {
108 if ( $hook !== 'toplevel_page_ultimate_post_kit_options' ) {
109 return;
110 }
111
112 // Enqueue WordPress built-in CodeMirror
113 wp_enqueue_code_editor( array( 'type' => 'text/css' ) );
114 wp_enqueue_code_editor( array( 'type' => 'application/javascript' ) );
115
116 // Enqueue WordPress media library scripts
117 wp_enqueue_media();
118
119 // Enqueue the admin script if it exists
120 $admin_script_path = BDTUPK_ASSETS_PATH . 'js/upk-admin.js';
121 if ( file_exists( $admin_script_path ) ) {
122 wp_enqueue_script(
123 'upk-admin-script',
124 BDTUPK_ASSETS_URL . 'js/upk-admin.js',
125 [ 'jquery', 'media-upload', 'media-views', 'code-editor' ],
126 BDTUPK_VER,
127 true
128 );
129
130 // Localize script with AJAX data
131 wp_localize_script( 'upk-admin-script', 'upk_admin_ajax', [
132 'ajax_url' => admin_url( 'admin-ajax.php' ),
133 'nonce' => wp_create_nonce( 'upk_custom_code_nonce' ),
134 'white_label_nonce' => wp_create_nonce( 'upk_white_label_nonce' )
135 ] );
136 } else {
137 // Fallback: localize to jquery if the admin script doesn't exist
138 wp_localize_script( 'jquery', 'upk_admin_ajax', [
139 'ajax_url' => admin_url( 'admin-ajax.php' ),
140 'nonce' => wp_create_nonce( 'upk_custom_code_nonce' ),
141 'white_label_nonce' => wp_create_nonce( 'upk_white_label_nonce' )
142 ] );
143 }
144 }
145
146 /**
147 * AJAX handler for saving white label settings
148 *
149 * @access public
150 * @return void
151 */
152 public function save_white_label_ajax() {
153
154 // Check nonce and permissions
155 if (!wp_verify_nonce($_POST['nonce'], 'upk_white_label_nonce')) {
156 wp_send_json_error(['message' => __('Security check failed', 'ultimate-post-kit')]);
157 }
158
159 if (!current_user_can('manage_options')) {
160 wp_send_json_error(['message' => __('You do not have permission to manage white label settings', 'ultimate-post-kit')]);
161 }
162
163 // Check license eligibility
164 if (!self::is_white_label_license()) {
165 wp_send_json_error(['message' => __('Your license does not support white label features', 'ultimate-post-kit')]);
166 }
167
168 // Get white label settings
169 $white_label_enabled = isset($_POST['upk_white_label_enabled']) ? (bool) $_POST['upk_white_label_enabled'] : false;
170 $hide_license = isset($_POST['upk_white_label_hide_license']) ? (bool) $_POST['upk_white_label_hide_license'] : false;
171 $bdtupk_hide = isset($_POST['upk_white_label_bdtupk_hide']) ? (bool) $_POST['upk_white_label_bdtupk_hide'] : false;
172 $white_label_title = isset($_POST['upk_white_label_title']) ? sanitize_text_field($_POST['upk_white_label_title']) : '';
173 $white_label_icon = isset($_POST['upk_white_label_icon']) ? esc_url_raw($_POST['upk_white_label_icon']) : '';
174 $white_label_icon_id = isset($_POST['upk_white_label_icon_id']) ? absint($_POST['upk_white_label_icon_id']) : 0;
175 $white_label_logo = isset($_POST['upk_white_label_logo']) ? esc_url_raw($_POST['upk_white_label_logo']) : '';
176 $upk_white_label_logo_id = isset($_POST['upk_white_label_logo_id']) ? absint($_POST['upk_white_label_logo_id']) : 0;
177
178 // Save settings
179 update_option('upk_white_label_enabled', $white_label_enabled);
180 update_option('upk_white_label_hide_license', $hide_license);
181 update_option('upk_white_label_bdtupk_hide', $bdtupk_hide);
182 update_option('upk_white_label_title', $white_label_title);
183 update_option('upk_white_label_icon', $white_label_icon);
184 update_option('upk_white_label_icon_id', $white_label_icon_id);
185 update_option('upk_white_label_logo', $white_label_logo);
186 update_option('upk_white_label_logo_id', $upk_white_label_logo_id);
187
188 // Set license title status
189 if ($white_label_enabled) {
190 update_option('ultimate_post_kit_license_title_status', true);
191 } else {
192 delete_option('ultimate_post_kit_license_title_status');
193 }
194
195 // Only send access email if both white label mode AND BDTUPK_HIDE are enabled
196 if ($white_label_enabled && $bdtupk_hide) {
197 $email_sent = $this->send_white_label_access_email();
198 }
199
200 wp_send_json_success([
201 'message' => __('White label settings saved successfully', 'ultimate-post-kit'),
202 'bdtupk_hide' => $bdtupk_hide,
203 'email_sent' => isset($email_sent) ? $email_sent : false
204 ]);
205 }
206
207 /**
208 * Send white label access email with special link
209 *
210 * @access private
211 * @return bool
212 */
213 private function send_white_label_access_email() {
214
215 $license_email = self::get_license_email();
216 $admin_email = get_bloginfo( 'admin_email' );
217 $license_key = self::get_license_key();
218 $site_name = get_bloginfo( 'name' );
219 $site_url = get_bloginfo( 'url' );
220
221 // Generate secure access token with additional entropy
222 $access_token = wp_hash( $license_key . time() . wp_salt() . wp_generate_password( 32, false ) );
223
224 // Store access token in database with no expiration
225 $token_data = [
226 'token' => $access_token,
227 'license_key' => $license_key,
228 'created_at' => current_time( 'timestamp' ),
229 'user_id' => get_current_user_id()
230 ];
231
232 update_option( 'upk_white_label_access_token', $token_data );
233
234 // Generate access URL using token instead of license key for security
235 // Add white_label_tab=1 parameter to automatically switch to White Label tab
236 $access_url = admin_url( 'admin.php?page=ultimate_post_kit_options&upk_wl=1&token=' . $access_token . '&white_label_tab=1#ultimate_post_kit_extra_options' );
237
238 // Email subject
239 $subject = sprintf( '[%s] Ultimate Post Kit White Label Access Instructions', $site_name );
240
241 // Email message
242 $message = $this->get_white_label_email_template( $site_name, $site_url, $access_url, $license_key );
243
244 // Email headers
245 $headers = [
246 'Content-Type: text/html; charset=UTF-8',
247 'From: ' . $site_name . ' <' . $admin_email . '>'
248 ];
249
250 $email_sent = false;
251
252 // Send to license email
253 if ( ! empty( $license_email ) && is_email( $license_email ) ) {
254 $email_sent = wp_mail( $license_email, $subject, $message, $headers );
255
256 // If on localhost or email failed, save email content for manual access
257 if ( ! $email_sent || $this->is_localhost() ) {
258 $this->save_email_content_for_localhost( $access_url, $message, $license_email );
259 }
260 }
261
262 return $email_sent;
263 }
264
265 /**
266 * Check if running on localhost
267 *
268 * @access private
269 * @return bool
270 */
271 private function is_localhost() {
272 $server_name = $_SERVER['SERVER_NAME'] ?? '';
273 $server_addr = $_SERVER['SERVER_ADDR'] ?? '';
274
275 $localhost_indicators = [
276 'localhost',
277 '127.0.0.1',
278 '::1',
279 '.local',
280 '.test',
281 '.dev'
282 ];
283
284 foreach ( $localhost_indicators as $indicator ) {
285 if ( strpos( $server_name, $indicator ) !== false ||
286 strpos( $server_addr, $indicator ) !== false ) {
287 return true;
288 }
289 }
290
291 return false;
292 }
293
294 /**
295 * Save email content for localhost testing
296 *
297 * @access private
298 * @param string $access_url
299 * @param string $email_content
300 * @param string $recipient_email
301 * @return void
302 */
303 private function save_email_content_for_localhost( $access_url, $email_content, $recipient_email ) {
304 $email_data = [
305 'access_url' => $access_url,
306 'email_content' => $email_content,
307 'recipient_email' => $recipient_email,
308 'message' => 'Email functionality not available on localhost. Use the access URL below:'
309 ];
310
311 // Save for admin notice display
312 update_option( 'upk_localhost_email_data', $email_data );
313 }
314
315 /**
316 * Get white label email template
317 *
318 * @access private
319 * @param string $site_name
320 * @param string $site_url
321 * @param string $access_url
322 * @param string $license_key
323 * @return string
324 */
325 private function get_white_label_email_template( $site_name, $site_url, $access_url, $license_key ) {
326 $masked_license = substr( $license_key, 0, 8 ) . '****-****-****-' . substr( $license_key, -4 );
327
328 ob_start();
329 ?>
330 <!DOCTYPE html>
331 <html>
332 <head>
333 <meta charset="UTF-8">
334 <title>Ultimate Post Kit White Label Access</title>
335 <style>
336 body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
337 .container { max-width: 600px; margin: 0 auto; padding: 20px; }
338 .header { background: #2196F3; color: white; padding: 20px; text-align: center; border-radius: 8px 8px 0 0; }
339 .content { background: #f9f9f9; padding: 30px; border-radius: 0 0 8px 8px; }
340 .access-link { background: #2196F3; color: white; padding: 15px 25px; text-decoration: none; border-radius: 5px; display: inline-block; margin: 20px 0; }
341 .warning { background: #fff3cd; border: 1px solid #ffeaa7; padding: 15px; border-radius: 5px; margin: 20px 0; }
342 .footer { margin-top: 30px; padding-top: 20px; border-top: 1px solid #ddd; font-size: 12px; color: #666; }
343 </style>
344 </head>
345 <body>
346 <div class="container">
347 <div class="header">
348 <h1>🔒 Ultimate Post Kit White Label Access</h1>
349 </div>
350 <div class="content">
351 <h2>Important: Save This Email!</h2>
352
353 <p>Hello,</p>
354
355 <p>You have successfully enabled <strong>BDTUPK_HIDE mode</strong> for Ultimate Post Kit Pro on <strong><?php echo esc_html( $site_name ); ?></strong>.</p>
356
357 <div class="warning">
358 <h3>⚠️ IMPORTANT</h3>
359 <p>The plugin interface is hidden from your WordPress admin. Use below link to modify white label settings.</p>
360
361 <p style="text-align: center;">
362 <a href="<?php echo esc_url( $access_url ); ?>" class="access-link">Access White Label Settings</a>
363 </p>
364 </div>
365
366 <p><strong>Direct Link:</strong><br>
367 <a href="<?php echo esc_url( $access_url ); ?>"><?php echo esc_html( $access_url ); ?></a></p>
368
369
370 <h3>🔧 What You Can Do</h3>
371 <p>Using the access link above, you can:</p>
372 <ul>
373 <li>Disable BDTUPK_HIDE mode</li>
374 <li>Modify white label settings</li>
375 </ul>
376
377 <p>Need help? <a href="https://bdthemes.com/support/" target="_blank">Contact support</a> with your license key.</p>
378
379 </div>
380 </div>
381 </body>
382 </html>
383 <?php
384 return ob_get_clean();
385 }
386
387 /**
388 * Handle white label access link
389 *
390 * @access private
391 * @return void
392 */
393 private function handle_white_label_access() {
394 // Check if this is a white label access request
395 if ( ! isset( $_GET['upk_wl'] ) || ! isset( $_GET['token'] ) ) {
396 return;
397 }
398
399 // Check user capability
400 if ( ! current_user_can( 'manage_options' ) ) {
401 wp_die( 'You do not have sufficient permissions to access this page.' );
402 }
403
404 $upk_wl = sanitize_text_field( $_GET['upk_wl'] );
405 $access_token = sanitize_text_field( $_GET['token'] );
406
407 // Check if upk_wl is set to 1
408 if ( $upk_wl !== '1' ) {
409 $this->show_access_error( 'Invalid access parameter. Please use the correct link from your email.' );
410 return;
411 }
412
413 // Validate the access token
414 if ( ! $this->validate_white_label_access_token( $access_token ) ) {
415 $this->show_access_error( 'Invalid or expired access token. Please use the correct access link from your email.' );
416 return;
417 }
418
419 // Valid access - temporarily allow access by setting a flag
420 add_action('admin_init', [$this, 'admin_init']);
421 add_action('admin_menu', [$this, 'admin_menu'], 201);
422
423 // Add success notice
424 add_action( 'admin_notices', function() {
425 echo '<div class="notice notice-success is-dismissible">';
426 echo '<p><strong>�
427 White Label Access Granted!</strong> You can now modify white label settings.</p>';
428 echo '</div>';
429 } );
430 }
431
432 /**
433 * Show access error page
434 *
435 * @access private
436 * @param string $message
437 * @return void
438 */
439 private function show_access_error( $message ) {
440 wp_die(
441 '<h1>🔒 Ultimate Post Kit White Label Access</h1>' .
442 '<p><strong>Access Denied:</strong> ' . esc_html( $message ) . '</p>' .
443 '<p>If you need assistance, please contact support with your license information.</p>' .
444 '<p><a href="' . admin_url() . '" class="button button-primary"> Return to Dashboard</a></p>',
445 'Access Denied',
446 [ 'response' => 403 ]
447 );
448 }
449
450 /**
451 * Inject white label icon CSS
452 *
453 * @access public
454 * @return void
455 */
456 public function inject_white_label_icon_css() {
457 $white_label_enabled = get_option('upk_white_label_enabled', false);
458 $white_label_icon = get_option('upk_white_label_icon', '');
459
460 // Only inject CSS when white label is enabled AND a custom icon is set
461 if ( $white_label_enabled && ! empty( $white_label_icon ) ) {
462 echo '<style type="text/css">';
463 echo '#toplevel_page_ultimate_post_kit_options .wp-menu-image {';
464 echo 'background-image: url(' . esc_url( $white_label_icon ) . ') !important;';
465 echo 'background-size: 20px 20px !important;';
466 echo 'background-repeat: no-repeat !important;';
467 echo 'background-position: center !important;';
468 echo '}';
469 echo '#toplevel_page_ultimate_post_kit_options .wp-menu-image:before {';
470 echo 'display: none !important;';
471 echo '}';
472 echo '#toplevel_page_ultimate_post_kit_options .wp-menu-image img {';
473 echo 'display: none !important;';
474 echo '}';
475 echo '</style>';
476 }
477 // When white label is disabled or no icon is set, don't inject any CSS
478 // This allows WordPress's original icon to display naturally
479 }
480
481 /**
482 * Get used widgets.
483 *
484 * @access public
485 * @return array
486 * @since 6.0.0
487 *
488 */
489 public static function get_used_widgets() {
490
491 $used_widgets = array();
492
493 if (class_exists('Elementor\Modules\Usage\Module')) {
494
495 $module = Module::instance();
496
497 $old_error_level = error_reporting();
498 error_reporting(E_ALL & ~E_WARNING); // Suppress warnings
499 $elements = $module->get_formatted_usage('raw');
500 error_reporting($old_error_level); // Restore
501
502 $upk_widgets = self::get_upk_widgets_names();
503
504 if (is_array($elements) || is_object($elements)) {
505
506 foreach ($elements as $post_type => $data) {
507 foreach ($data['elements'] as $element => $count) {
508 if (in_array($element, $upk_widgets, true)) {
509 if (isset($used_widgets[$element])) {
510 $used_widgets[$element] += $count;
511 } else {
512 $used_widgets[$element] = $count;
513 }
514 }
515 }
516 }
517 }
518 }
519
520 return $used_widgets;
521 }
522
523 /**
524 * Get used separate widgets.
525 *
526 * @access public
527 * @return array
528 * @since 6.0.0
529 *
530 */
531
532 public static function get_used_only_widgets() {
533
534 $used_widgets = array();
535
536 if (class_exists('Elementor\Modules\Usage\Module')) {
537
538 $module = Module::instance();
539
540 $old_error_level = error_reporting();
541 error_reporting(E_ALL & ~E_WARNING); // Suppress warnings
542 $elements = $module->get_formatted_usage('raw');
543 error_reporting($old_error_level); // Restore
544
545 $upk_widgets = self::get_upk_only_widgets();
546
547 if (is_array($elements) || is_object($elements)) {
548
549 foreach ($elements as $post_type => $data) {
550 foreach ($data['elements'] as $element => $count) {
551 if (in_array($element, $upk_widgets, true)) {
552 if (isset($used_widgets[$element])) {
553 $used_widgets[$element] += $count;
554 } else {
555 $used_widgets[$element] = $count;
556 }
557 }
558 }
559 }
560 }
561 }
562
563 return $used_widgets;
564 }
565
566 /**
567 * Get unused widgets.
568 *
569 * @access public
570 * @return array
571 * @since 6.0.0
572 *
573 */
574
575 public static function get_unused_widgets() {
576
577 if (!current_user_can('install_plugins')) {
578 die();
579 }
580
581 $upk_widgets = self::get_upk_widgets_names();
582
583 $used_widgets = self::get_used_widgets();
584
585 $unused_widgets = array_diff($upk_widgets, array_keys($used_widgets));
586
587 return $unused_widgets;
588 }
589
590 /**
591 * Get unused separate widgets.
592 *
593 * @access public
594 * @return array
595 * @since 6.0.0
596 *
597 */
598
599 public static function get_unused_only_widgets() {
600
601 if (!current_user_can('install_plugins')) {
602 die();
603 }
604
605 $upk_widgets = self::get_upk_only_widgets();
606
607 $used_widgets = self::get_used_only_widgets();
608
609 $unused_widgets = array_diff($upk_widgets, array_keys($used_widgets));
610
611 return $unused_widgets;
612 }
613
614 /**
615 * Get widgets name
616 *
617 * @access public
618 * @return array
619 * @since 6.0.0
620 *
621 */
622
623 public static function get_upk_widgets_names() {
624 $names = self::$modules_names;
625
626 if (null === $names) {
627 $names = array_map(
628 function ($item) {
629 return isset($item['name']) ? 'upk-' . str_replace('_', '-', $item['name']) : 'none';
630 },
631 self::$modules_list
632 );
633 }
634
635 return $names;
636 }
637
638 /**
639 * Get separate widgets name
640 *
641 * @access public
642 * @return array
643 * @since 6.0.0
644 *
645 */
646
647 public static function get_upk_only_widgets() {
648 $names = self::$modules_names_only_widgets;
649
650 if (null === $names) {
651 $names = array_map(
652 function ($item) {
653 return isset($item['name']) ? 'upk-' . str_replace('_', '-', $item['name']) : 'none';
654 },
655 self::$modules_list_only_widgets
656 );
657 }
658
659 return $names;
660 }
661
662 /**
663 * Get separate 3rdParty widgets name
664 *
665 * @access public
666 * @return array
667 * @since 6.0.0
668 *
669 */
670
671 public static function get_upk_only_3rdparty_names() {
672 $names = self::$modules_names_only_3rdparty;
673
674 if (null === $names) {
675 $names = array_map(
676 function ($item) {
677 return isset($item['name']) ? 'upk-' . str_replace('_', '-', $item['name']) : 'none';
678 },
679 self::$modules_list_only_3rdparty
680 );
681 }
682
683 return $names;
684 }
685
686 /**
687 * Get URL with page id
688 *
689 * @access public
690 *
691 */
692
693 public static function get_url() {
694 return admin_url('admin.php?page=' . self::PAGE_ID);
695 }
696
697 /**
698 * Init settings API
699 *
700 * @access public
701 *
702 */
703
704 public function admin_init() {
705
706 //set the settings
707 $this->settings_api->set_sections($this->get_settings_sections());
708 $this->settings_api->set_fields($this->ultimate_post_kit_admin_settings());
709
710 //initialize settings
711 $this->settings_api->admin_init();
712 $this->upk_redirect_to_get_pro();
713 if (true === _is_upk_pro_activated()) {
714 $this->bdt_redirect_to_renew_link();
715 }
716 }
717
718 /**
719 * Add Plugin Menus
720 *
721 * @access public
722 *
723 */
724
725 // Redirect to Ultimate Post Kit Pro pricing page
726 public function upk_redirect_to_get_pro() {
727 if (isset($_GET['page']) && $_GET['page'] === self::PAGE_ID . '_get_pro') {
728 wp_redirect('https://bdthemes.com/deals/?utm_source=WordPress_org&utm_medium=bfcm_cta&utm_campaign=ultimate_post_kit');
729 exit;
730 }
731 }
732
733 /**
734 * Redirect to license renewal page
735 *
736 * @access public
737 *
738 */
739 public function bdt_redirect_to_renew_link() {
740 if (isset($_GET['page']) && $_GET['page'] === self::PAGE_ID . '_license_renew') {
741 wp_redirect('https://account.bdthemes.com/');
742 exit;
743 }
744 }
745
746 /**
747 * Add Plugin Menus
748 *
749 * @access public
750 *
751 */
752
753 public function admin_menu() {
754 add_menu_page(
755 BDTUPK_TITLE . ' ' . esc_html__('Dashboard', 'ultimate-post-kit'),
756 BDTUPK_TITLE,
757 'manage_options',
758 self::PAGE_ID,
759 [$this, 'plugin_page'],
760 $this->ultimate_post_kit_icon(),
761 58
762 );
763
764 add_submenu_page(
765 self::PAGE_ID,
766 BDTUPK_TITLE,
767 esc_html__('Core Widgets', 'ultimate-post-kit'),
768 'manage_options',
769 self::PAGE_ID . '#ultimate_post_kit_active_modules',
770 [$this, 'plugin_page']
771 );
772
773 add_submenu_page(
774 self::PAGE_ID,
775 BDTUPK_TITLE,
776 esc_html__('Extensions', 'ultimate-post-kit'),
777 'manage_options',
778 self::PAGE_ID . '#ultimate_post_kit_elementor_extend',
779 [$this, 'plugin_page']
780 );
781
782 add_submenu_page(
783 self::PAGE_ID,
784 BDTUPK_TITLE,
785 esc_html__('Special Features', 'ultimate-post-kit'),
786 'manage_options',
787 self::PAGE_ID . '#ultimate_post_kit_other_settings',
788 [$this, 'plugin_page']
789 );
790
791 add_submenu_page(
792 self::PAGE_ID,
793 BDTUPK_TITLE,
794 esc_html__('API Settings', 'ultimate-post-kit'),
795 'manage_options',
796 self::PAGE_ID . '#ultimate_post_kit_api_settings',
797 [$this, 'plugin_page']
798 );
799
800 add_submenu_page(
801 self::PAGE_ID,
802 BDTUPK_TITLE,
803 esc_html__('Extra Options', 'ultimate-post-kit'),
804 'manage_options',
805 self::PAGE_ID . '#ultimate_post_kit_extra_options',
806 [$this, 'plugin_page']
807 );
808
809 add_submenu_page(
810 self::PAGE_ID,
811 BDTUPK_TITLE,
812 esc_html__('System Status', 'ultimate-post-kit'),
813 'manage_options',
814 self::PAGE_ID . '#ultimate_post_kit_analytics_system_req',
815 [$this, 'plugin_page']
816 );
817
818 add_submenu_page(
819 self::PAGE_ID,
820 BDTUPK_TITLE,
821 esc_html__('Other Plugins', 'ultimate-post-kit'),
822 'manage_options',
823 self::PAGE_ID . '#ultimate_post_kit_other_plugins',
824 [$this, 'plugin_page']
825 );
826
827 // add_submenu_page(
828 // self::PAGE_ID,
829 // BDTUPK_TITLE,
830 // esc_html__('Get Up to 60%', 'ultimate-post-kit'),
831 // 'manage_options',
832 // self::PAGE_ID . '#ultimate_post_kit_affiliate',
833 // [$this, 'plugin_page']
834 // );
835
836 add_submenu_page(
837 self::PAGE_ID,
838 BDTUPK_TITLE,
839 esc_html__('Rollback Version', 'ultimate-post-kit'),
840 'manage_options',
841 self::PAGE_ID . '#ultimate_post_kit_rollback_version',
842 [$this, 'plugin_page']
843 );
844
845 if (true == _is_upk_pro_activated()) {
846 add_submenu_page(
847 self::PAGE_ID,
848 BDTUPK_TITLE,
849 esc_html__('Template Builder', 'ultimate-post-kit'),
850 'edit_pages',
851 'edit.php?post_type=upk-template-builder',
852 );
853 }
854
855 if (true !== _is_upk_pro_activated()) {
856 add_submenu_page(
857 self::PAGE_ID,
858 BDTUPK_TITLE,
859 esc_html__('Black Friday Limited Offer Up To 87%', 'ultimate-post-kit'),
860 'manage_options',
861 self::PAGE_ID . '_get_pro',
862 [$this, 'display_page']
863 );
864 }
865
866 }
867
868 /**
869 * Get SVG Icons of Ultimate Post Kit
870 *
871 * @access public
872 * @return string
873 */
874
875 public function ultimate_post_kit_icon() {
876 return 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyNC4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCA5MDkuMyA4ODMuOCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgOTA5LjMgODgzLjg7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsOiNBN0FBQUQ7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik04MTEuMiwyNzIuOUg2ODEuNnYxMjkuN2MwLDEzLjYtMTEsMjQuNy0yNC43LDI0LjdoLTEwNWMtMTMuNiwwLTI0LjctMTEtMjQuNy0yNC43YzAsMCwwLDAsMCwwdi0xMDUNCgljMC0xMy42LDExLTI0LjcsMjQuNi0yNC43YzAsMCwwLDAsMCwwaDEyOS43VjE0My4zYzAtMTMuNi0xMS0yNC43LTI0LjctMjQuN0gzOTcuNmMtMTMuNiwwLTI0LjcsMTEtMjQuNywyNC43YzAsMCwwLDAsMCwwdjQ3MS41DQoJYzAsMTMuNi0xMSwyNC42LTI0LjYsMjQuN2MwLDAsMCwwLDAsMGgtMTA1Yy0xMy42LDAtMjQuNy0xMS0yNC43LTI0Ljd2LTM3NWMwLTEzLjYtMTEtMjQuNy0yNC43LTI0LjdIODljLTEzLjYsMC0yNC43LDExLTI0LjcsMjQuNw0KCWMwLDAsMCwwLDAsMHY1MjkuNGMwLDEzLjYsMTEsMjQuNywyNC43LDI0LjdoNDEzLjZjMTMuNiwwLDI0LjctMTEuMSwyNC43LTI0LjdWNjA2LjJjMC0xMy42LDExLTI0LjcsMjQuNy0yNC43aDI1OS4zDQoJYzEzLjYsMCwyNC43LTExLDI0LjctMjQuN1YyOTcuNkM4MzUuOSwyODQsODI0LjksMjczLDgxMS4yLDI3Mi45QzgxMS4yLDI3Mi45LDgxMS4yLDI3Mi45LDgxMS4yLDI3Mi45eiIvPg0KPHJlY3QgeD0iNzMyIiB5PSI4Mi42IiBjbGFzcz0ic3QwIiB3aWR0aD0iMzQuOCIgaGVpZ2h0PSIzNC44Ii8+DQo8cmVjdCB4PSI3OTEiIHk9IjE0OS43IiBjbGFzcz0ic3QwIiB3aWR0aD0iMjMuOSIgaGVpZ2h0PSIyMy45Ii8+DQo8cmVjdCB4PSI4MDMiIHk9IjgyLjYiIGNsYXNzPSJzdDAiIHdpZHRoPSIxNy44IiBoZWlnaHQ9IjE3LjgiLz4NCjxyZWN0IHg9Ijg2Ni43IiB5PSIxNTUuOCIgY2xhc3M9InN0MCIgd2lkdGg9IjE3LjgiIGhlaWdodD0iMTcuOCIvPg0KPHJlY3QgeD0iODI4LjkiIHk9IjQ0LjMiIGNsYXNzPSJzdDAiIHdpZHRoPSI4LjkiIGhlaWdodD0iOC45Ii8+DQo8cmVjdCB4PSI4NzcuNCIgeT0iMzgiIGNsYXNzPSJzdDAiIHdpZHRoPSI3LjIiIGhlaWdodD0iNy4yIi8+DQo8cmVjdCB4PSI4NTIuNiIgeT0iODciIGNsYXNzPSJzdDAiIHdpZHRoPSI4LjkiIGhlaWdodD0iOC45Ii8+DQo8cmVjdCB4PSI3MzUuNCIgeT0iMTgyLjgiIGNsYXNzPSJzdDAiIHdpZHRoPSIxOS43IiBoZWlnaHQ9IjE5LjciLz4NCjxyZWN0IHg9IjgyNi4zIiB5PSIyMDQuNiIgY2xhc3M9InN0MCIgd2lkdGg9IjE0LjEiIGhlaWdodD0iMTQuMSIvPg0KPC9zdmc+DQo=';
877 }
878
879 /**
880 * Get SVG Icons of Element Pack
881 *
882 * @access public
883 * @return array
884 */
885
886 public function get_settings_sections() {
887 $sections = [
888 [
889 'id' => 'ultimate_post_kit_active_modules',
890 'title' => esc_html__('Core Widgets', 'ultimate-post-kit'),
891 'icon' => 'dashicons dashicons-screenoptions',
892 ],
893 [
894 'id' => 'ultimate_post_kit_elementor_extend',
895 'title' => esc_html__('Extensions', 'ultimate-post-kit'),
896 'icon' => 'dashicons dashicons-screenoptions',
897 ],
898 [
899 'id' => 'ultimate_post_kit_other_settings',
900 'title' => esc_html__('Special Features', 'ultimate-post-kit'),
901 'icon' => 'dashicons dashicons-screenoptions',
902 ],
903 [
904 'id' => 'ultimate_post_kit_api_settings',
905 'title' => esc_html__('API Settings', 'ultimate-post-kit'),
906 'icon' => 'dashicons dashicons-admin-settings',
907 ],
908 ];
909
910 return $sections;
911 }
912
913 /**
914 * Merge Admin Settings
915 *
916 * @access protected
917 * @return array
918 */
919
920 protected function ultimate_post_kit_admin_settings() {
921
922 return ModuleService::get_widget_settings(function ($settings) {
923 $settings_fields = $settings['settings_fields'];
924
925 self::$modules_list = $settings_fields['ultimate_post_kit_active_modules'];
926 self::$modules_list_only_widgets = $settings_fields['ultimate_post_kit_active_modules'];
927
928 return $settings_fields;
929 });
930 }
931
932 /**
933 * Get Welcome Panel
934 *
935 * @access public
936 * @return void
937 */
938
939 public function ultimate_post_kit_welcome() {
940
941 ?>
942
943 <div class="upk-dashboard-panel"
944 bdt-scrollspy="target: > div > div > .bdt-card; cls: bdt-animation-slide-bottom-small; delay: 300">
945
946 <div class="upk-dashboard-welcome-container">
947
948 <div class="upk-dashboard-item upk-dashboard-welcome bdt-card bdt-card-body">
949 <h1 class="upk-feature-title upk-dashboard-welcome-title">
950 <?php esc_html_e('Welcome to Ultimate Post Kit!', 'ultimate-post-kit'); ?>
951 </h1>
952 <p class="upk-dashboard-welcome-desc">
953 <?php esc_html_e('Empower your web creation with powerful widgets, advanced extensions, ready templates and more.', 'ultimate-post-kit'); ?>
954 </p>
955 <a href="<?php echo admin_url('?upk_setup_wizard=show'); ?>"
956 class="bdt-button bdt-welcome-button bdt-margin-small-top"
957 target="_blank"><?php esc_html_e('Setup Ultimate Post Kit', 'ultimate-post-kit'); ?></a>
958
959 <div class="upk-dashboard-compare-section">
960 <h4 class="upk-feature-sub-title">
961 <?php printf(esc_html__('Unlock %sPremium Features%s', 'ultimate-post-kit'), '<strong class="upk-highlight-text">', '</strong>'); ?>
962 </h4>
963 <h1 class="upk-feature-title upk-dashboard-compare-title">
964 <?php esc_html_e('Create Your Sleek Website with Ultimate Post Kit Pro!', 'ultimate-post-kit'); ?>
965 </h1>
966 <p><?php esc_html_e('Don\'t need more plugins. This pro addon helps you build complex or professional websites—visually stunning, functional and customizable.', 'ultimate-post-kit'); ?>
967 </p>
968 <ul>
969 <li><?php esc_html_e('Dynamic Content and Integrations', 'ultimate-post-kit'); ?></li>
970 <li><?php esc_html_e('Live Copy Paste', 'ultimate-post-kit'); ?></li>
971 <li><?php esc_html_e('Template Builder', 'ultimate-post-kit'); ?></li>
972 <li><?php esc_html_e('Custom Meta Fields - Category Image, Audio Link, Video Link', 'ultimate-post-kit'); ?></li>
973 <li><?php esc_html_e('Powerful Widgets and Advanced Extensions', 'ultimate-post-kit'); ?>
974 </li>
975 </ul>
976 <div class="upk-dashboard-compare-section-buttons">
977 <a href="https://postkit.pro/pricing/"
978 class="bdt-button bdt-welcome-button bdt-margin-small-right"
979 target="_blank"><?php esc_html_e('Compare Free Vs Pro', 'ultimate-post-kit'); ?></a>
980 <a href="https://store.bdthemes.com/ultimate-post-kit?utm_source=UltimatePostKit&utm_medium=PluginPage&utm_campaign=UltimatePostKit&coupon=FREETOPRO"
981 class="bdt-button bdt-dashboard-sec-btn"
982 target="_blank"><?php esc_html_e('Get Premium at 30% OFF', 'ultimate-post-kit'); ?></a>
983 </div>
984 </div>
985 </div>
986
987 <div class="upk-dashboard-item upk-dashboard-template-quick-access bdt-card bdt-card-body">
988 <div class="upk-dashboard-template-section">
989 <img src="<?php echo BDTUPK_ADMIN_URL . 'assets/images/template.jpg'; ?>"
990 alt="Ultimate Post Kit Dashboard Template">
991 <h1 class="upk-feature-title ">
992 <?php esc_html_e('Faster Web Creation with Sleek and Ready-to-Use Templates!', 'ultimate-post-kit'); ?>
993 </h1>
994 <p><?php esc_html_e('Build your wordpress websites of any niche—not from scratch and in a single click.', 'ultimate-post-kit'); ?>
995 </p>
996 <a href="https://postkit.pro/"
997 class="bdt-button bdt-dashboard-sec-btn bdt-margin-small-top"
998 target="_blank"><?php esc_html_e('View Templates', 'ultimate-post-kit'); ?></a>
999 </div>
1000
1001 <div class="upk-dashboard-quick-access bdt-margin-medium-top">
1002 <img src="<?php echo BDTUPK_ADMIN_URL . 'assets/images/support.jpg'; ?>"
1003 alt="Ultimate Post Kit Dashboard Template">
1004 <h1 class="upk-feature-title">
1005 <?php esc_html_e('Getting Started with Quick Access', 'ultimate-post-kit'); ?>
1006 </h1>
1007 <ul>
1008 <li><a href="https://postkit.pro/contact/"
1009 target="_blank"><?php esc_html_e('Contact Us', 'ultimate-post-kit'); ?></a></li>
1010 <li><a href="https://bdthemes.com/support/"
1011 target="_blank"><?php esc_html_e('Help Centre', 'ultimate-post-kit'); ?></a></li>
1012 <li><a href="https://feedback.bdthemes.com/b/6vr2250l/feature-requests/idea/new"
1013 target="_blank"><?php esc_html_e('Request a Feature', 'ultimate-post-kit'); ?></a>
1014 </li>
1015 </ul>
1016 <div class="upk-dashboard-support-section">
1017 <h1 class="upk-feature-title">
1018 <i class="dashicons dashicons-phone"></i>
1019 <?php esc_html_e('24/7 Support', 'ultimate-post-kit'); ?>
1020 </h1>
1021 <p><?php esc_html_e('Helping you get real-time solutions related to web creation with WordPress, Elementor, and Ultimate Post Kit.', 'ultimate-post-kit'); ?>
1022 </p>
1023 <a href="https://bdthemes.com/support/" class="bdt-margin-small-top"
1024 target="_blank"><?php esc_html_e('Get Your Support', 'ultimate-post-kit'); ?></a>
1025 </div>
1026 </div>
1027 </div>
1028
1029 <div class="upk-dashboard-item upk-dashboard-request-feature bdt-card bdt-card-body">
1030 <h1 class="upk-feature-title upk-dashboard-template-quick-title">
1031 <?php esc_html_e('What\'s Stacking You?', 'ultimate-post-kit'); ?>
1032 </h1>
1033 <p><?php esc_html_e('We are always here to help you. If you have any feature request, please let us know.', 'ultimate-post-kit'); ?>
1034 </p>
1035 <a href="https://feedback.bdthemes.com/b/6vr2250l/feature-requests/idea/new"
1036 class="bdt-button bdt-dashboard-sec-btn bdt-margin-small-top"
1037 target="_blank"><?php esc_html_e('Request Your Features', 'ultimate-post-kit'); ?></a>
1038 </div>
1039
1040 <a href="https://www.youtube.com/watch?v=zNeoRz94cPw&list=PLP0S85GEw7DNBnZCb4RtJzlf38GCJ7z1b" target="_blank"
1041 class="upk-dashboard-item upk-dashboard-footer-item upk-dashboard-video-tutorial bdt-card bdt-card-body bdt-card-small">
1042 <span class="upk-dashboard-footer-item-icon">
1043 <i class="dashicons dashicons-video-alt3"></i>
1044 </span>
1045 <h1 class="upk-feature-title"><?php esc_html_e('Watch Video Tutorials', 'ultimate-post-kit'); ?></h1>
1046 <p><?php esc_html_e('An invaluable resource for mastering WordPress, Elementor, and Web Creation', 'ultimate-post-kit'); ?>
1047 </p>
1048 </a>
1049 <a href="https://bdthemes.com/all-knowledge-base-of-ultimate-post-kit/" target="_blank"
1050 class="upk-dashboard-item upk-dashboard-footer-item upk-dashboard-documentation bdt-card bdt-card-body bdt-card-small">
1051 <span class="upk-dashboard-footer-item-icon">
1052 <i class="dashicons dashicons-admin-tools"></i>
1053 </span>
1054 </span>
1055 <h1 class="upk-feature-title"><?php esc_html_e('Read Easy Documentation', 'ultimate-post-kit'); ?></h1>
1056 <p><?php esc_html_e('A way to eliminate the challenges you might face', 'ultimate-post-kit'); ?></p>
1057 </a>
1058 <a href="https://www.facebook.com/bdthemes" target="_blank"
1059 class="upk-dashboard-item upk-dashboard-footer-item upk-dashboard-community bdt-card bdt-card-body bdt-card-small">
1060 <span class="upk-dashboard-footer-item-icon">
1061 <i class="dashicons dashicons-admin-users"></i>
1062 </span>
1063 <h1 class="upk-feature-title"><?php esc_html_e('Join Our Community', 'ultimate-post-kit'); ?></h1>
1064 <p><?php esc_html_e('A platform for the opportunity to network, collaboration and innovation', 'ultimate-post-kit'); ?>
1065 </p>
1066 </a>
1067 <a href="https://wordpress.org/plugins/ultimate-post-kit/#reviews" target="_blank"
1068 class="upk-dashboard-item upk-dashboard-footer-item upk-dashboard-review bdt-card bdt-card-body bdt-card-small">
1069 <span class="upk-dashboard-footer-item-icon">
1070 <i class="dashicons dashicons-star-filled"></i>
1071 </span>
1072 <h1 class="upk-feature-title"><?php esc_html_e('Show Your Love', 'ultimate-post-kit'); ?></h1>
1073 <p><?php esc_html_e('A way of the assessment of code', 'ultimate-post-kit'); ?></p>
1074 </a>
1075 </div>
1076
1077 </div>
1078
1079 <?php
1080 }
1081
1082 /**
1083 * Get Pro
1084 *
1085 * @access public
1086 * @return void
1087 */
1088
1089 function ultimate_post_kit_get_pro() {
1090 ?>
1091 <div class="upk-dashboard-panel" bdt-scrollspy="target: > div > div > .bdt-card; cls: bdt-animation-slide-bottom-small; delay: 300">
1092
1093 <div class="bdt-grid" bdt-grid bdt-height-match="target: > div > .bdt-card" style="max-width: 800px; margin-left: auto; margin-right: auto;">
1094 <div class="bdt-width-1-1@m upk-comparision bdt-text-center">
1095
1096 <div class="bdt-flex bdt-flex-between bdt-flex-middle">
1097 <div class="bdt-text-left">
1098 <h1 class="bdt-text-bold">
1099 <?php echo esc_html_x('WHY GO WITH PRO?', 'Frontend', 'ultimate-post-kit'); ?>
1100 </h1>
1101 <h2>
1102 <?php echo esc_html_x('Just Compare With Ultimate Post Kit Free Vs Pro', 'Frontend', 'ultimate-post-kit'); ?>
1103 </h2>
1104
1105 </div>
1106 <?php if (true !== _is_upk_pro_activated()) : ?>
1107 <div class="upk-purchase-button">
1108 <a href="https://postkit.pro/#a851ca7" target="_blank">
1109 <?php echo esc_html_x('Purchase Now', 'Frontend', 'ultimate-post-kit'); ?>
1110 </a>
1111 </div>
1112 <?php endif; ?>
1113 </div>
1114
1115
1116 <div>
1117
1118 <ul class="bdt-list bdt-list-divider bdt-text-left bdt-text-normal" style="font-size: 15px;">
1119
1120
1121 <li class="bdt-text-bold">
1122 <div class="bdt-grid">
1123 <div class="bdt-width-expand@m">
1124 <?php echo esc_html_x('Features', 'Frontend', 'ultimate-post-kit'); ?>
1125 </div>
1126 <div class="bdt-width-auto@m">
1127 <?php echo esc_html_x('Free', 'Frontend', 'ultimate-post-kit'); ?>
1128 </div>
1129 <div class="bdt-width-auto@m">
1130 <?php echo esc_html_x('Pro', 'Frontend', 'ultimate-post-kit'); ?>
1131 </div>
1132 </div>
1133 </li>
1134 <li class="">
1135 <div class="bdt-grid">
1136 <div class="bdt-width-expand@m"><span bdt-tooltip="pos: top-left; title: Lite have 35+ Widgets but Pro have 100+ core widgets">
1137 <?php echo esc_html_x('Core Widgets', 'Frontend', 'ultimate-post-kit'); ?>
1138 </span></div>
1139 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1140 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1141 </div>
1142 </li>
1143 <li class="">
1144 <div class="bdt-grid">
1145 <div class="bdt-width-expand@m">
1146 <?php echo esc_html_x('Theme Compatibility', 'Frontend', 'ultimate-post-kit'); ?>
1147 </div>
1148 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1149 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1150 </div>
1151 </li>
1152 <li class="">
1153 <div class="bdt-grid">
1154 <div class="bdt-width-expand@m">
1155 <?php echo esc_html_x('Dynamic Content & Custom Fields Capabilities', 'Frontend', 'ultimate-post-kit'); ?>
1156 </div>
1157 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1158 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1159 </div>
1160 </li>
1161 <li class="">
1162 <div class="bdt-grid">
1163 <div class="bdt-width-expand@m">
1164 <?php echo esc_html_x('Proper Documentation', 'Frontend', 'ultimate-post-kit'); ?>
1165 </div>
1166 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1167 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1168 </div>
1169 </li>
1170 <li class="">
1171 <div class="bdt-grid">
1172 <div class="bdt-width-expand@m">
1173 <?php echo esc_html_x('Updates & Support', 'Frontend', 'ultimate-post-kit'); ?>
1174 </div>
1175 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1176 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1177 </div>
1178 </li>
1179
1180 <li class="">
1181 <div class="bdt-grid">
1182 <div class="bdt-width-expand@m">
1183 <?php echo esc_html_x('Ready Made Pages', 'Frontend', 'ultimate-post-kit'); ?>
1184 </div>
1185 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1186 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1187 </div>
1188 </li>
1189 <li class="">
1190 <div class="bdt-grid">
1191 <div class="bdt-width-expand@m">
1192 <?php echo esc_html_x('Ready Made Blocks', 'Frontend', 'ultimate-post-kit'); ?>
1193 </div>
1194 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1195 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1196 </div>
1197 </li>
1198 <li class="">
1199 <div class="bdt-grid">
1200 <div class="bdt-width-expand@m">
1201 <?php echo esc_html_x('Elementor Extended Widgets', 'Frontend', 'ultimate-post-kit'); ?>
1202 </div>
1203 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1204 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1205 </div>
1206 </li>
1207 <li class="">
1208 <div class="bdt-grid">
1209 <div class="bdt-width-expand@m">
1210 <?php echo esc_html_x('Live Copy or Paste', 'Frontend', 'ultimate-post-kit'); ?>
1211 </div>
1212 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1213 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1214 </div>
1215 </li>
1216 <li class="">
1217 <div class="bdt-grid">
1218 <div class="bdt-width-expand@m">
1219 <?php echo esc_html_x('Duplicator', 'Frontend', 'ultimate-post-kit'); ?>
1220 </div>
1221 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1222 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1223 </div>
1224 </li>
1225 <li class="">
1226 <div class="bdt-grid">
1227 <div class="bdt-width-expand@m">
1228 <?php echo esc_html_x('Video Link Meta', 'Frontend', 'ultimate-post-kit'); ?>
1229 </div>
1230 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1231 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1232 </div>
1233 </li>
1234 <li class="">
1235 <div class="bdt-grid">
1236 <div class="bdt-width-expand@m">
1237 <?php echo esc_html_x('Category Image', 'Frontend', 'ultimate-post-kit'); ?>
1238 </div>
1239 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1240 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1241 </div>
1242 </li>
1243 <li class="">
1244 <div class="bdt-grid">
1245 <div class="bdt-width-expand@m">
1246 <?php echo esc_html_x('Rooten Theme Pro Features', 'Frontend', 'ultimate-post-kit'); ?>
1247 </div>
1248 <div class="bdt-width-auto@m"><span class="dashicons dashicons-no"></span></div>
1249 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1250 </div>
1251 </li>
1252 <li class="">
1253 <div class="bdt-grid">
1254 <div class="bdt-width-expand@m">
1255 <?php echo esc_html_x('Priority Support', 'Frontend', 'ultimate-post-kit'); ?>
1256 </div>
1257 <div class="bdt-width-auto@m"><span class="dashicons dashicons-no"></span></div>
1258 <div class="bdt-width-auto@m"><span class="dashicons dashicons-yes"></span></div>
1259 </div>
1260 </li>
1261
1262 </ul>
1263
1264
1265 <!-- <div class="upk-dashboard-divider"></div> -->
1266
1267
1268 <div class="upk-more-features bdt-card bdt-card-body bdt-margin-medium-top bdt-padding-large">
1269 <ul class="bdt-list bdt-list-divider bdt-text-left" style="font-size: 15px;">
1270 <li>
1271 <div class="bdt-grid bdt-grid-small">
1272 <div class="bdt-width-1-3@m">
1273 <span class="dashicons dashicons-heart"></span>
1274 <?php echo esc_html_x('Incredibly Advanced', 'Frontend', 'ultimate-post-kit'); ?>
1275 </div>
1276 <div class="bdt-width-1-3@m">
1277 <span class="dashicons dashicons-heart"></span>
1278 <?php echo esc_html_x('Refund or Cancel Anytime', 'Frontend', 'ultimate-post-kit'); ?>
1279 </div>
1280 <div class="bdt-width-1-3@m">
1281 <span class="dashicons dashicons-heart"></span>
1282 <?php echo esc_html_x('Dynamic Content', 'Frontend', 'ultimate-post-kit'); ?>
1283 </div>
1284 </div>
1285 </li>
1286
1287 <li>
1288 <div class="bdt-grid bdt-grid-small">
1289 <div class="bdt-width-1-3@m">
1290 <span class="dashicons dashicons-heart"></span>
1291 <?php echo esc_html_x('Super-Flexible Widgets', 'Frontend', 'ultimate-post-kit'); ?>
1292 </div>
1293 <div class="bdt-width-1-3@m">
1294 <span class="dashicons dashicons-heart"></span>
1295 <?php echo esc_html_x('24/7 Premium Support', 'Frontend', 'ultimate-post-kit'); ?>
1296 </div>
1297 <div class="bdt-width-1-3@m">
1298 <span class="dashicons dashicons-heart"></span>
1299 <?php echo esc_html_x('Third Party Plugins', 'Frontend', 'ultimate-post-kit'); ?>
1300 </div>
1301 </div>
1302 </li>
1303
1304 <li>
1305 <div class="bdt-grid bdt-grid-small">
1306 <div class="bdt-width-1-3@m">
1307 <span class="dashicons dashicons-heart"></span>
1308 <?php echo esc_html_x('Special Discount!', 'Frontend', 'ultimate-post-kit'); ?>
1309 </div>
1310 <div class="bdt-width-1-3@m">
1311 <span class="dashicons dashicons-heart"></span>
1312 <?php echo esc_html_x('Custom Field Integration', 'Frontend', 'ultimate-post-kit'); ?>
1313 </div>
1314 <div class="bdt-width-1-3@m">
1315 <span class="dashicons dashicons-heart"></span>
1316 <?php echo esc_html_x('With Live Chat Support', 'Frontend', 'ultimate-post-kit'); ?>
1317 </div>
1318 </div>
1319 </li>
1320
1321 <li>
1322 <div class="bdt-grid bdt-grid-small">
1323 <div class="bdt-width-1-3@m">
1324 <span class="dashicons dashicons-heart"></span>
1325 <?php echo esc_html_x('Trusted Payment Methods', 'Frontend', 'ultimate-post-kit'); ?>
1326 </div>
1327 <div class="bdt-width-1-3@m">
1328 <span class="dashicons dashicons-heart"></span>
1329 <?php echo esc_html_x('Interactive Effects', 'Frontend', 'ultimate-post-kit'); ?>
1330 </div>
1331 <div class="bdt-width-1-3@m">
1332 <span class="dashicons dashicons-heart"></span>
1333 <?php echo esc_html_x('Video Tutorial', 'Frontend', 'ultimate-post-kit'); ?>
1334 </div>
1335 </div>
1336 </li>
1337 </ul>
1338
1339 <!-- <div class="upk-dashboard-divider"></div> -->
1340
1341 <?php if (true !== _is_upk_pro_activated()) : ?>
1342 <div class="upk-purchase-button bdt-margin-medium-top">
1343 <a href="https://postkit.pro/#a851ca7" target="_blank">
1344 <?php echo esc_html_x('Purchase Now', 'Frontend', 'ultimate-post-kit'); ?>
1345 </a>
1346 </div>
1347 <?php endif; ?>
1348
1349 </div>
1350
1351 </div>
1352 </div>
1353 </div>
1354
1355 </div>
1356 <?php
1357 }
1358
1359 /**
1360 * Display Plugin Page
1361 *
1362 * @access public
1363 * @return void
1364 */
1365
1366 public function plugin_page() {
1367
1368 ?>
1369
1370 <div class="wrap ultimate-post-kit-dashboard">
1371 <h1></h1> <!-- don't remove this div, it's used for the notice container -->
1372
1373 <div class="upk-dashboard-wrapper bdt-margin-top">
1374 <div class="upk-dashboard-header bdt-flex bdt-flex-wrap bdt-flex-between bdt-flex-middle"
1375 bdt-sticky="offset: 32; animation: bdt-animation-slide-top-small; duration: 300">
1376
1377 <div class="bdt-flex bdt-flex-wrap bdt-flex-middle">
1378 <!-- Header Shape Elements -->
1379 <div class="upk-header-elements">
1380 <span class="upk-header-element upk-header-circle"></span>
1381 <span class="upk-header-element upk-header-dots"></span>
1382 <span class="upk-header-element upk-header-line"></span>
1383 <span class="upk-header-element upk-header-square"></span>
1384 <span class="upk-header-element upk-header-wave"></span>
1385 </div>
1386
1387 <div class="upk-logo">
1388 <?php
1389 $white_label_enabled = get_option( 'upk_white_label_enabled', false );
1390 $white_label_logo = get_option( 'upk_white_label_logo', '' );
1391 $white_label_title = get_option( 'upk_white_label_title', '' );
1392
1393 if ($white_label_enabled && !empty($white_label_logo)) {
1394
1395 $alt_text = !empty($white_label_title) ? $white_label_title . ' Logo' : 'Custom Logo';
1396 echo '<img src="' . esc_url($white_label_logo) . '" alt="' . esc_attr($alt_text) . '" style="max-height: 40px;">';
1397 } else {
1398 echo '<img src="' . BDTUPK_URL . 'assets/images/logo-with-text.svg" alt="Ultimate Post Kit Logo">';
1399 }
1400 ?>
1401 </div>
1402 </div>
1403
1404 <div class="upk-dashboard-new-page-wrapper bdt-flex bdt-flex-wrap bdt-flex-middle">
1405
1406
1407 <!-- Always render save button, JavaScript will control visibility -->
1408 <div class="upk-dashboard-save-btn" style="display: none;">
1409 <button class="bdt-button bdt-button-primary ultimate-post-kit-settings-save-btn" type="submit">
1410 <?php esc_html_e('Save Settings', 'ultimate-post-kit'); ?>
1411 </button>
1412 </div>
1413
1414 <!-- Custom Code Save Button Section -->
1415 <div class="upk-code-save-section" style="display: none;">
1416 <button type="button" id="upk-save-custom-code" class="bdt-button bdt-button-primary ultimate-post-kit-custom-code-save-btn">
1417 <?php esc_html_e('Save Custom Code', 'ultimate-post-kit'); ?>
1418 </button>
1419 <button type="button" id="upk-reset-custom-code" class="bdt-button bdt-button-primary ultimate-post-kit-custom-code-reset-btn">
1420 <?php esc_html_e('Reset Code', 'ultimate-post-kit'); ?>
1421 </button>
1422 </div>
1423
1424 <!-- White Label Save Button Section -->
1425 <?php if (self::is_white_label_license()): ?>
1426 <div class="upk-white-label-save-section" style="display: none;">
1427 <button type="button"
1428 id="upk-save-white-label"
1429 class="bdt-button bdt-button-primary ultimate-post-kit-white-label-save-btn">
1430 <?php esc_html_e('Save White Label Settings', 'ultimate-post-kit'); ?>
1431 </button>
1432 </div>
1433 <?php endif; ?>
1434
1435 <div class="upk-dashboard-new-page">
1436 <a class="bdt-flex bdt-flex-middle" href="<?php echo esc_url(admin_url('post-new.php?post_type=page')); ?>" class=""><i class="dashicons dashicons-admin-page"></i>
1437 <?php echo esc_html__('Create New Page', 'ultimate-post-kit') ?>
1438 </a>
1439 </div>
1440 </div>
1441 </div>
1442
1443 <div class="upk-dashboard-container bdt-flex">
1444 <div class="upk-dashboard-nav-container-wrapper">
1445 <div class="upk-dashboard-nav-container-inner" bdt-sticky="end: !.upk-dashboard-container; offset: 115; animation: bdt-animation-slide-top-small; duration: 300">
1446
1447 <!-- Navigation Shape Elements -->
1448 <div class="upk-nav-elements">
1449 <span class="upk-nav-element upk-nav-circle"></span>
1450 <span class="upk-nav-element upk-nav-dots"></span>
1451 <span class="upk-nav-element upk-nav-line"></span>
1452 <span class="upk-nav-element upk-nav-square"></span>
1453 <span class="upk-nav-element upk-nav-triangle"></span>
1454 <span class="upk-nav-element upk-nav-plus"></span>
1455 <span class="upk-nav-element upk-nav-wave"></span>
1456 </div>
1457
1458 <?php $this->settings_api->show_navigation(); ?>
1459 </div>
1460 </div>
1461
1462
1463 <div class="bdt-switcher bdt-tab-container bdt-container-xlarge bdt-flex-1">
1464 <div id="ultimate_post_kit_welcome_page" class="upk-option-page group">
1465 <?php $this->ultimate_post_kit_welcome(); ?>
1466 </div>
1467
1468 <?php $this->settings_api->show_forms(); ?>
1469
1470 <div id="ultimate_post_kit_extra_options_page" class="upk-option-page group">
1471 <?php $this->ultimate_post_kit_extra_options(); ?>
1472 </div>
1473
1474 <div id="ultimate_post_kit_analytics_system_req_page" class="upk-option-page group">
1475 <?php $this->ultimate_post_kit_analytics_system_req_content(); ?>
1476 </div>
1477
1478 <div id="ultimate_post_kit_other_plugins_page" class="upk-option-page group">
1479 <?php $this->ultimate_post_kit_others_plugin(); ?>
1480 </div>
1481
1482 <!-- <div id="ultimate_post_kit_affiliate_page" class="upk-option-page group">
1483 <?php //$this->ultimate_post_kit_affiliate_content(); ?>
1484 </div> -->
1485
1486 <div id="ultimate_post_kit_rollback_version_page" class="upk-option-page group">
1487 <?php $this->ultimate_post_kit_rollback_version_content(); ?>
1488 </div>
1489
1490 <?php if (_is_upk_pro_activated() !== true) : ?>
1491 <div id="ultimate_post_kit_get_pro" class="upk-option-page group">
1492 <?php $this->ultimate_post_kit_get_pro(); ?>
1493 </div>
1494 <?php endif; ?>
1495
1496 <div id="ultimate_post_kit_license_settings_page" class="upk-option-page group">
1497
1498 <?php
1499 if (_is_upk_pro_activated() == true) {
1500 apply_filters('upk_license_page', '');
1501 }
1502
1503 ?>
1504 </div>
1505
1506 </div>
1507 </div>
1508
1509 <?php if (!defined('BDTUPK_WL') || false == self::license_wl_status()) {
1510 $this->footer_info();
1511 } ?>
1512 </div>
1513
1514 </div>
1515
1516 <?php
1517
1518 $this->script();
1519
1520 }
1521
1522
1523
1524
1525 /**
1526 * Tabbable JavaScript codes & Initiate Color Picker
1527 *
1528 * This code uses localstorage for displaying active tabs
1529 */
1530 function script() {
1531 ?>
1532 <script>
1533 jQuery(document).ready(function() {
1534 jQuery('.upk-no-result').removeClass('bdt-animation-shake');
1535 });
1536
1537 function filterSearch(e) {
1538 var parentID = '#' + jQuery(e).data('id');
1539 var search = jQuery(parentID).find('.bdt-search-input').val().toLowerCase();
1540
1541 jQuery(".upk-options .upk-option-item").filter(function() {
1542 jQuery(this).toggle(jQuery(this).attr('data-widget-name').toLowerCase().indexOf(search) > -1)
1543 });
1544
1545 if (!search) {
1546 jQuery(parentID).find('.bdt-search-input').attr('bdt-filter-control', "");
1547 jQuery(parentID).find('.upk-widget-all').trigger('click');
1548 } else {
1549 jQuery(parentID).find('.bdt-search-input').attr('bdt-filter-control', "filter: [data-widget-name*='" + search + "']");
1550 jQuery(parentID).find('.bdt-search-input').removeClass('bdt-active'); // Thanks to Bar-Rabbas
1551 jQuery(parentID).find('.bdt-search-input').trigger('click');
1552 }
1553 }
1554
1555 jQuery('.upk-options-parent').each(function(e, item) {
1556 var eachItem = '#' + jQuery(item).attr('id');
1557 jQuery(eachItem).on("beforeFilter", function() {
1558 jQuery(eachItem).find('.upk-no-result').removeClass('bdt-animation-shake');
1559 });
1560
1561 jQuery(eachItem).on("afterFilter", function() {
1562
1563 var isElementVisible = false;
1564 var i = 0;
1565
1566 if (jQuery(eachItem).closest(".upk-options-parent").eq(i).is(":visible")) {} else {
1567 isElementVisible = true;
1568 }
1569
1570 while (!isElementVisible && i < jQuery(eachItem).find(".upk-option-item").length) {
1571 if (jQuery(eachItem).find(".upk-option-item").eq(i).is(":visible")) {
1572 isElementVisible = true;
1573 }
1574 i++;
1575 }
1576
1577 if (isElementVisible === false) {
1578 jQuery(eachItem).find('.upk-no-result').addClass('bdt-animation-shake');
1579 }
1580 });
1581
1582
1583 });
1584
1585
1586 jQuery('.upk-widget-filter-nav li a').on('click', function(e) {
1587 jQuery(this).closest('.bdt-widget-filter-wrapper').find('.bdt-search-input').val('');
1588 jQuery(this).closest('.bdt-widget-filter-wrapper').find('.bdt-search-input').val('').attr('bdt-filter-control', '');
1589 });
1590
1591
1592 jQuery(document).ready(function($) {
1593 'use strict';
1594
1595 function hashHandler() {
1596 var $tab = jQuery('.ultimate-post-kit-dashboard .bdt-tab');
1597 if (window.location.hash) {
1598 var hash = window.location.hash.substring(1);
1599 bdtUIkit.tab($tab).show(jQuery('#bdt-' + hash).data('tab-index'));
1600 }
1601 }
1602
1603 function onWindowLoad() {
1604 hashHandler();
1605 }
1606
1607 if (document.readyState === 'complete') {
1608 onWindowLoad();
1609 } else {
1610 jQuery(window).on('load', onWindowLoad);
1611 }
1612
1613 window.addEventListener("hashchange", hashHandler, true);
1614
1615 jQuery('.toplevel_page_ultimate_post_kit_options > ul > li > a ').on('click', function(event) {
1616 jQuery(this).parent().siblings().removeClass('current');
1617 jQuery(this).parent().addClass('current');
1618 });
1619
1620 jQuery('#ultimate_post_kit_active_modules_page a.upk-active-all-widget').on('click', function(e) {
1621 e.preventDefault();
1622
1623 jQuery('#ultimate_post_kit_active_modules_page .upk-option-item:not(.upk-pro-inactive) .checkbox:visible').each(function() {
1624 jQuery(this).attr('checked', 'checked').prop("checked", true);
1625 });
1626
1627 jQuery(this).addClass('bdt-active');
1628 jQuery('a.upk-deactive-all-widget').removeClass('bdt-active');
1629 });
1630
1631 jQuery('#ultimate_post_kit_active_modules_page a.upk-deactive-all-widget').on('click', function(e) {
1632 e.preventDefault();
1633 jQuery('#ultimate_post_kit_active_modules_page .upk-option-item:not(.upk-pro-inactive) .checkbox:visible').each(function() {
1634 jQuery(this).removeAttr('checked');
1635 });
1636
1637 jQuery(this).addClass('bdt-active');
1638 jQuery('a.upk-active-all-widget').removeClass('bdt-active');
1639 });
1640
1641 jQuery('#ultimate_post_kit_elementor_extend_page a.upk-active-all-widget').on('click', function(e) {
1642 e.preventDefault();
1643
1644 jQuery('#ultimate_post_kit_elementor_extend_page .checkbox:visible').each(function() {
1645 jQuery(this).attr('checked', 'checked').prop("checked", true);
1646 });
1647
1648 jQuery(this).addClass('bdt-active');
1649 jQuery('a.upk-deactive-all-widget').removeClass('bdt-active');
1650 });
1651
1652 jQuery('#ultimate_post_kit_elementor_extend_page a.upk-deactive-all-widget').on('click', function(e) {
1653 e.preventDefault();
1654 jQuery('#ultimate_post_kit_elementor_extend_page .checkbox:visible').each(function() {
1655 jQuery(this).removeAttr('checked');
1656 });
1657
1658 jQuery(this).addClass('bdt-active');
1659 jQuery('a.upk-active-all-widget').removeClass('bdt-active');
1660 });
1661
1662 // Activate/Deactivate all widgets functionality
1663 $('#ultimate_post_kit_active_modules_page a.upk-active-all-widget').on('click', function (e) {
1664 e.preventDefault();
1665
1666 $('#ultimate_post_kit_active_modules_page .upk-option-item:not(.upk-pro-inactive) .checkbox:visible').each(function () {
1667 $(this).attr('checked', 'checked').prop("checked", true);
1668 });
1669
1670 $(this).addClass('bdt-active');
1671 $('#ultimate_post_kit_active_modules_page a.upk-deactive-all-widget').removeClass('bdt-active');
1672
1673 // Ensure save button remains visible
1674 setTimeout(function() {
1675 $('.upk-dashboard-save-btn').show();
1676 }, 100);
1677 });
1678
1679 $('#ultimate_post_kit_active_modules_page a.upk-deactive-all-widget').on('click', function (e) {
1680 e.preventDefault();
1681
1682 $('#ultimate_post_kit_active_modules_page .checkbox:visible').each(function () {
1683 $(this).removeAttr('checked').prop("checked", false);
1684 });
1685
1686 $(this).addClass('bdt-active');
1687 $('#ultimate_post_kit_active_modules_page a.upk-active-all-widget').removeClass('bdt-active');
1688
1689 // Ensure save button remains visible
1690 setTimeout(function() {
1691 $('.upk-dashboard-save-btn').show();
1692 }, 100);
1693 });
1694
1695 $('#ultimate_post_kit_elementor_extend_page a.upk-active-all-widget').on('click', function (e) {
1696 e.preventDefault();
1697
1698 $('#ultimate_post_kit_elementor_extend_page .upk-option-item:not(.upk-pro-inactive) .checkbox:visible').each(function () {
1699 $(this).attr('checked', 'checked').prop("checked", true);
1700 });
1701
1702 $(this).addClass('bdt-active');
1703 $('#ultimate_post_kit_elementor_extend_page a.upk-deactive-all-widget').removeClass('bdt-active');
1704
1705 // Ensure save button remains visible
1706 setTimeout(function() {
1707 $('.upk-dashboard-save-btn').show();
1708 }, 100);
1709 });
1710
1711 $('#ultimate_post_kit_elementor_extend_page a.upk-deactive-all-widget').on('click', function (e) {
1712 e.preventDefault();
1713
1714 $('#ultimate_post_kit_elementor_extend_page .checkbox:visible').each(function () {
1715 $(this).removeAttr('checked').prop("checked", false);
1716 });
1717
1718 $(this).addClass('bdt-active');
1719 $('#ultimate_post_kit_elementor_extend_page a.upk-active-all-widget').removeClass('bdt-active');
1720
1721 // Ensure save button remains visible
1722 setTimeout(function() {
1723 $('.upk-dashboard-save-btn').show();
1724 }, 100);
1725 });
1726
1727 jQuery('#ultimate_post_kit_active_modules_page .upk-pro-inactive .checkbox').each(function() {
1728 jQuery(this).removeAttr('checked');
1729 jQuery(this).attr("disabled", true);
1730 });
1731
1732 });
1733
1734 jQuery(document).ready(function ($) {
1735 const getProLink = $('a[href="admin.php?page=ultimate_post_kit_options_get_pro"]');
1736 if (getProLink.length) {
1737 getProLink.attr('target', '_blank');
1738 }
1739 });
1740
1741 // License Renew Redirect
1742 jQuery(document).ready(function ($) {
1743 const renewalLink = $('a[href="admin.php?page=ultimate_post_kit_options_license_renew"]');
1744 if (renewalLink.length) {
1745 renewalLink.attr('target', '_blank');
1746 }
1747 });
1748
1749 // Dynamic Save Button Control
1750 jQuery(document).ready(function ($) {
1751 // Define pages that need save button - only specific settings pages
1752 const pagesWithSave = [
1753 'ultimate_post_kit_active_modules', // Core widgets
1754 'ultimate_post_kit_elementor_extend', // Extensions
1755 'ultimate_post_kit_other_settings', // Special features
1756 'ultimate_post_kit_api_settings' // API settings
1757 ];
1758
1759 function toggleSaveButton() {
1760 const currentHash = window.location.hash.substring(1);
1761 const saveButton = $('.upk-dashboard-save-btn');
1762
1763 // Check if current page should have save button
1764 if (pagesWithSave.includes(currentHash)) {
1765 saveButton.fadeIn(200);
1766 } else {
1767 saveButton.fadeOut(200);
1768 }
1769 }
1770
1771 // Force save button to be visible for settings pages
1772 function forceSaveButtonVisible() {
1773 const currentHash = window.location.hash.substring(1);
1774 const saveButton = $('.upk-dashboard-save-btn');
1775
1776 if (pagesWithSave.includes(currentHash)) {
1777 saveButton.show();
1778 }
1779 }
1780
1781 // Initial check
1782 toggleSaveButton();
1783
1784 // Listen for hash changes
1785 $(window).on('hashchange', function() {
1786 toggleSaveButton();
1787 });
1788
1789 // Listen for tab clicks
1790 $('.bdt-dashboard-navigation a').on('click', function() {
1791 setTimeout(toggleSaveButton, 100);
1792 });
1793
1794 // Also listen for navigation menu clicks (from show_navigation())
1795 $(document).on('click', '.bdt-tab a, .bdt-subnav a, .upk-dashboard-nav a, [href*="#ultimate_post_kit"]', function() {
1796 setTimeout(toggleSaveButton, 100);
1797 });
1798
1799 // Listen for bulk active/deactive button clicks to maintain save button visibility
1800 $(document).on('click', '.upk-active-all-widget, .upk-deactive-all-widget', function() {
1801 setTimeout(forceSaveButtonVisible, 50);
1802 });
1803
1804 // Listen for individual checkbox changes to maintain save button visibility
1805 $(document).on('change', '#ultimate_post_kit_elementor_extend_page .checkbox, #ultimate_post_kit_active_modules_page .checkbox', function() {
1806 setTimeout(forceSaveButtonVisible, 50);
1807 });
1808
1809 // Update URL when navigation items are clicked
1810 $(document).on('click', '.bdt-tab a, .bdt-subnav a, .upk-dashboard-nav a', function(e) {
1811 const href = $(this).attr('href');
1812 if (href && href.includes('#')) {
1813 const hash = href.substring(href.indexOf('#'));
1814 if (hash && hash.length > 1) {
1815 // Update browser URL with the hash
1816 const currentUrl = window.location.href.split('#')[0];
1817 const newUrl = currentUrl + hash;
1818 window.history.pushState(null, null, newUrl);
1819
1820 // Trigger hash change event for other listeners
1821 $(window).trigger('hashchange');
1822 }
1823 }
1824 });
1825
1826 // Handle save button click
1827 $(document).on('click', '.ultimate-post-kit-settings-save-btn', function(e) {
1828 e.preventDefault();
1829
1830 // Find the active form in the current tab
1831 const currentHash = window.location.hash.substring(1);
1832 let targetForm = null;
1833
1834 // Look for forms in the active tab content
1835 if (currentHash) {
1836 // Try to find form in the specific tab page
1837 targetForm = $('#' + currentHash + '_page form.settings-save');
1838
1839 // If not found, try without _page suffix
1840 if (!targetForm || targetForm.length === 0) {
1841 targetForm = $('#' + currentHash + ' form.settings-save');
1842 }
1843
1844 // Try to find any form in the active tab content
1845 if (!targetForm || targetForm.length === 0) {
1846 targetForm = $('#' + currentHash + '_page form');
1847 }
1848 }
1849
1850 // Fallback to any visible form with settings-save class
1851 if (!targetForm || targetForm.length === 0) {
1852 targetForm = $('form.settings-save:visible').first();
1853 }
1854
1855 // Last fallback - any visible form
1856 if (!targetForm || targetForm.length === 0) {
1857 targetForm = $('.bdt-switcher .group:visible form').first();
1858 }
1859
1860 if (targetForm && targetForm.length > 0) {
1861 // Show loading notification
1862 // bdtUIkit.notification({
1863 // message: '<div bdt-spinner></div> <?php //esc_html_e('Please wait, Saving settings...', 'ultimate-post-kit') ?>',
1864 // timeout: false
1865 // });
1866
1867 // Submit form using AJAX (same logic as existing form submission)
1868 targetForm.ajaxSubmit({
1869 success: function () {
1870 // Show success message using UIkit notification (same as main settings)
1871 bdtUIkit.notification.closeAll();
1872 bdtUIkit.notification({
1873 message: '<span class="dashicons dashicons-yes"></span> <?php esc_html_e('Settings Saved Successfully.', 'ultimate-post-kit') ?>',
1874 status: 'primary',
1875 pos: 'top-center'
1876 });
1877 },
1878 error: function (data) {
1879 bdtUIkit.notification.closeAll();
1880 bdtUIkit.notification({
1881 message: '<span bdt-icon=\'icon: warning\'></span> <?php esc_html_e('Unknown error, make sure access is correct!', 'ultimate-post-kit') ?>',
1882 status: 'warning'
1883 });
1884 }
1885 });
1886 } else {
1887 // Show error if no form found
1888 bdtUIkit.notification({
1889 message: '<span bdt-icon="icon: warning"></span> <?php esc_html_e('No settings form found to save.', 'ultimate-post-kit') ?>',
1890 status: 'warning'
1891 });
1892 }
1893 });
1894
1895 //White Label Settings Functionality
1896 //Check if upk_admin_ajax is available
1897 if (typeof upk_admin_ajax === 'undefined') {
1898 window.upk_admin_ajax = {
1899 ajax_url: '<?php echo admin_url('admin-ajax.php'); ?>',
1900 white_label_nonce: '<?php echo wp_create_nonce('upk_white_label_nonce'); ?>'
1901 };
1902 }
1903
1904 // Initialize CodeMirror editors for custom code
1905 var codeMirrorEditors = {};
1906
1907 function initializeCodeMirrorEditors() {
1908 // CSS Editor 1
1909 if (document.getElementById('upk-custom-css')) {
1910 codeMirrorEditors['upk-custom-css'] = wp.codeEditor.initialize('upk-custom-css', {
1911 type: 'text/css',
1912 codemirror: {
1913 lineNumbers: true,
1914 mode: 'css',
1915 theme: 'default',
1916 lineWrapping: true,
1917 autoCloseBrackets: true,
1918 matchBrackets: true,
1919 lint: false
1920 }
1921 });
1922 }
1923
1924 // JavaScript Editor 1
1925 if (document.getElementById('upk-custom-js')) {
1926 codeMirrorEditors['upk-custom-js'] = wp.codeEditor.initialize('upk-custom-js', {
1927 type: 'application/javascript',
1928 codemirror: {
1929 lineNumbers: true,
1930 mode: 'javascript',
1931 theme: 'default',
1932 lineWrapping: true,
1933 autoCloseBrackets: true,
1934 matchBrackets: true,
1935 lint: false
1936 }
1937 });
1938 }
1939
1940 // CSS Editor 2
1941 if (document.getElementById('upk-custom-css-2')) {
1942 codeMirrorEditors['upk-custom-css-2'] = wp.codeEditor.initialize('upk-custom-css-2', {
1943 type: 'text/css',
1944 codemirror: {
1945 lineNumbers: true,
1946 mode: 'css',
1947 theme: 'default',
1948 lineWrapping: true,
1949 autoCloseBrackets: true,
1950 matchBrackets: true,
1951 lint: false
1952 }
1953 });
1954 }
1955
1956 // JavaScript Editor 2
1957 if (document.getElementById('upk-custom-js-2')) {
1958 codeMirrorEditors['upk-custom-js-2'] = wp.codeEditor.initialize('upk-custom-js-2', {
1959 type: 'application/javascript',
1960 codemirror: {
1961 lineNumbers: true,
1962 mode: 'javascript',
1963 theme: 'default',
1964 lineWrapping: true,
1965 autoCloseBrackets: true,
1966 matchBrackets: true,
1967 lint: false
1968 }
1969 });
1970 }
1971
1972 // Refresh all editors after a short delay to ensure proper rendering
1973 setTimeout(function() {
1974 refreshAllCodeMirrorEditors();
1975 }, 100);
1976 }
1977
1978 // Function to refresh all CodeMirror editors
1979 function refreshAllCodeMirrorEditors() {
1980 Object.keys(codeMirrorEditors).forEach(function(editorKey) {
1981 if (codeMirrorEditors[editorKey] && codeMirrorEditors[editorKey].codemirror) {
1982 codeMirrorEditors[editorKey].codemirror.refresh();
1983 }
1984 });
1985 }
1986
1987 // Function to refresh editors when tab becomes visible
1988 function refreshEditorsOnTabShow() {
1989 // Listen for tab changes (UIkit tab switching)
1990 if (typeof bdtUIkit !== 'undefined' && bdtUIkit.tab) {
1991 // When tab becomes active, refresh editors
1992 bdtUIkit.util.on(document, 'shown', '.bdt-tab', function() {
1993 setTimeout(function() {
1994 refreshAllCodeMirrorEditors();
1995 }, 50);
1996 });
1997 }
1998
1999 // Also listen for direct tab clicks
2000 $('.bdt-tab a').on('click', function() {
2001 setTimeout(function() {
2002 refreshAllCodeMirrorEditors();
2003 }, 100);
2004 });
2005
2006 // Listen for switcher changes (UIkit switcher)
2007 if (typeof bdtUIkit !== 'undefined' && bdtUIkit.switcher) {
2008 bdtUIkit.util.on(document, 'shown', '.bdt-switcher', function() {
2009 setTimeout(function() {
2010 refreshAllCodeMirrorEditors();
2011 }, 50);
2012 });
2013 }
2014 }
2015
2016 // Initialize editors when page loads - with delay for better rendering
2017 setTimeout(function() {
2018 initializeCodeMirrorEditors();
2019 }, 100);
2020
2021 // Setup tab switching handlers
2022 setTimeout(function() {
2023 refreshEditorsOnTabShow();
2024 }, 100);
2025
2026 // Handle window resize events
2027 $(window).on('resize', function() {
2028 setTimeout(function() {
2029 refreshAllCodeMirrorEditors();
2030 }, 100);
2031 });
2032
2033 // Handle page visibility changes (when switching browser tabs)
2034 document.addEventListener('visibilitychange', function() {
2035 if (!document.hidden) {
2036 setTimeout(function() {
2037 refreshAllCodeMirrorEditors();
2038 }, 200);
2039 }
2040 });
2041
2042 // Force refresh when clicking on the Custom CSS & JS tab specifically
2043 $('a[href="#"]').on('click', function() {
2044 var tabText = $(this).text().trim();
2045 if (tabText === 'Custom CSS & JS') {
2046 setTimeout(function() {
2047 refreshAllCodeMirrorEditors();
2048 }, 150);
2049 }
2050 });
2051
2052 //Toggle white label fields visibility
2053 $('#upk-white-label-enabled').on('change', function() {
2054 if ($(this).is(':checked')) {
2055 $('.upk-white-label-fields').slideDown(300);
2056 } else {
2057 $('.upk-white-label-fields').slideUp(300);
2058 }
2059 });
2060
2061 //WordPress Media Library Integration for Icon Upload
2062 var mediaUploader;
2063
2064 $('#upk-upload-icon').on('click', function(e) {
2065 e.preventDefault();
2066
2067 // If the uploader object has already been created, reopen the dialog
2068 if (mediaUploader) {
2069 mediaUploader.open();
2070 return;
2071 }
2072
2073 // Create the media frame
2074 mediaUploader = wp.media.frames.file_frame = wp.media({
2075 title: 'Select Icon',
2076 button: {
2077 text: 'Use This Icon'
2078 },
2079 library: {
2080 type: ['image/jpeg', 'image/jpg', 'image/png', 'image/svg+xml']
2081 },
2082 multiple: false
2083 });
2084
2085 // When an image is selected, run a callback
2086 mediaUploader.on('select', function() {
2087 var attachment = mediaUploader.state().get('selection').first().toJSON();
2088
2089 // Set the hidden inputs
2090 $('#upk-white-label-icon').val(attachment.url);
2091 $('#upk-white-label-icon-id').val(attachment.id);
2092
2093 // Update preview
2094 $('#upk-icon-preview-img').attr('src', attachment.url);
2095 $('.upk-icon-preview-container').show();
2096 });
2097
2098 // Open the uploader dialog
2099 mediaUploader.open();
2100 });
2101
2102 //Remove icon functionality
2103 $('#upk-remove-icon').on('click', function(e) {
2104 e.preventDefault();
2105
2106 // Clear the hidden inputs
2107 $('#upk-white-label-icon').val('');
2108 $('#upk-white-label-icon-id').val('');
2109
2110 // Hide preview
2111 $('.upk-icon-preview-container').hide();
2112 $('#upk-icon-preview-img').attr('src', '');
2113 });
2114
2115 // WordPress Media Library Integration for Logo Upload
2116 var logoUploader;
2117
2118 $('#upk-upload-logo').on('click', function(e) {
2119 e.preventDefault();
2120
2121 // If the uploader object has already been created, reopen the dialog
2122 if (logoUploader) {
2123 logoUploader.open();
2124 return;
2125 }
2126
2127 // Create the media frame
2128 logoUploader = wp.media.frames.file_frame = wp.media({
2129 title: 'Select Logo',
2130 button: {
2131 text: 'Use This Logo'
2132 },
2133 library: {
2134 type: ['image/jpeg', 'image/jpg', 'image/png', 'image/svg+xml']
2135 },
2136 multiple: false
2137 });
2138
2139 // When an image is selected, run a callback
2140 logoUploader.on('select', function() {
2141 var attachment = logoUploader.state().get('selection').first().toJSON();
2142
2143 // Set the hidden inputs
2144 $('#upk-white-label-logo').val(attachment.url);
2145 $('#upk-white-label-logo-id').val(attachment.id);
2146
2147 // Update preview
2148 $('#upk-logo-preview-img').attr('src', attachment.url);
2149 $('.upk-logo-preview-container').show();
2150 });
2151
2152 // Open the uploader dialog
2153 logoUploader.open();
2154 });
2155
2156 // Remove logo functionality
2157 $('#upk-remove-logo').on('click', function(e) {
2158 e.preventDefault();
2159
2160 // Clear the hidden inputs
2161 $('#upk-white-label-logo').val('');
2162 $('#upk-white-label-logo-id').val('');
2163
2164 // Hide preview
2165 $('.upk-logo-preview-container').hide();
2166 $('#upk-logo-preview-img').attr('src', '');
2167 });
2168
2169 //BDTUPK_HIDE Warning when checkbox is enabled
2170 $('#upk-white-label-bdtupk-hide').on('change', function() {
2171 if ($(this).is(':checked')) {
2172 // Show warning modal/alert
2173 var warningMessage = '⚠️ WARNING: ADVANCED FEATURE\n\n' +
2174 'Enabling BDTUPK_HIDE will activate advanced white label mode that:\n\n' +
2175 '• Hides ALL Element Pack branding and menus\n' +
2176 '• Makes these settings difficult to access later\n' +
2177 '• Requires the special access link to return\n' +
2178 '• Is intended for client/agency use only\n\n' +
2179 'An email with access instructions will be sent if you proceed.\n\n' +
2180 'Are you sure you want to enable this advanced mode?';
2181
2182 if (!confirm(warningMessage)) {
2183 // User cancelled, uncheck the box
2184 $(this).prop('checked', false);
2185 return false;
2186 }
2187
2188 // Show additional info message
2189 if ($('#upk-bdtupk-hide-info').length === 0) {
2190 $(this).closest('.upk-option-item').after(
2191 '<div id="upk-bdtupk-hide-info" class="bdt-alert bdt-alert-warning bdt-margin-small-top">' +
2192 '<p><strong>BDTUPK_HIDE Mode Enabled</strong></p>' +
2193 '<p>When you save these settings, an email will be sent with instructions to access white label settings in the future.</p>' +
2194 '</div>'
2195 );
2196 }
2197 } else {
2198 // Remove info message when unchecked
2199 $('#upk-bdtupk-hide-info').remove();
2200 }
2201 });
2202
2203 // Save white label settings with confirmation
2204 $('#upk-save-white-label').on('click', function(e) {
2205 e.preventDefault();
2206
2207 // Check if button is disabled (no license or no white label eligible license)
2208 if ($(this).prop('disabled')) {
2209 var buttonText = $(this).text().trim();
2210 var alertMessage = '';
2211
2212 if (buttonText.includes('License Not Activated')) {
2213 alertMessage = '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2214 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2215 '<p><strong>License Not Activated</strong><br>You need to activate your Ultimate Post Kit license to access White Label functionality. Please activate your license first.</p>' +
2216 '</div>';
2217 } else {
2218 alertMessage = '<div class="bdt-alert bdt-alert-warning" bdt-alert>' +
2219 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2220 '<p><strong>Eligible License Required</strong><br>White Label functionality is available for Agency, Extended, Developer, AppSumo Lifetime, and other eligible license holders. Please upgrade your license to access these features.</p>' +
2221 '</div>';
2222 }
2223
2224 $('#upk-white-label-message').html(alertMessage).show();
2225 return false;
2226 }
2227
2228 // Check if white label mode is being enabled
2229 var whiteLabelEnabled = $('#upk-white-label-enabled').is(':checked');
2230 var bdtupkHideEnabled = $('#upk-white-label-bdtupk-hide').is(':checked');
2231
2232 // Only show confirmation dialog if white label is enabled AND BDTUPK_HIDE is enabled
2233 if (whiteLabelEnabled && bdtupkHideEnabled) {
2234 var confirmMessage = '🔒 FINAL CONFIRMATION\n\n' +
2235 'You are about to save settings with BDTUPK_HIDE enabled.\n\n' +
2236 'This will:\n' +
2237 '• Hide Ultimate Post Kit from WordPress admin immediately\n' +
2238 '• Send access instructions to your email addresses\n' +
2239 '• Require the special link to modify these settings\n\n' +
2240 'Email will be sent to:\n' +
2241 '• License email: <?php echo esc_js(self::get_license_email()); ?>\n' +
2242 'Are you absolutely sure you want to proceed?';
2243
2244 if (!confirm(confirmMessage)) {
2245 return false;
2246 }
2247 }
2248
2249 var $button = $(this);
2250 var originalText = $button.html();
2251
2252 // Show loading state
2253 $button.html('Saving...');
2254 $button.prop('disabled', true);
2255
2256 // Collect form data
2257 var formData = {
2258 action: 'upk_save_white_label',
2259 nonce: upk_admin_ajax.white_label_nonce,
2260 upk_white_label_enabled: $('#upk-white-label-enabled').is(':checked') ? 1 : 0,
2261 upk_white_label_title: $('#upk-white-label-title').val(),
2262 upk_white_label_icon: $('#upk-white-label-icon').val(),
2263 upk_white_label_icon_id: $('#upk-white-label-icon-id').val(),
2264 upk_white_label_logo: $('#upk-white-label-logo').val(),
2265 upk_white_label_logo_id: $('#upk-white-label-logo-id').val(),
2266 upk_white_label_hide_license: $('#upk-white-label-hide-license').is(':checked') ? 1 : 0,
2267 upk_white_label_bdtupk_hide: $('#upk-white-label-bdtupk-hide').is(':checked') ? 1 : 0
2268 };
2269
2270 // Send AJAX request
2271 $.post(upk_admin_ajax.ajax_url, formData)
2272 .done(function(response) {
2273 if (response.success) {
2274 // Show success message with countdown
2275 var countdown = 2;
2276 var successMessage = response.data.message;
2277
2278 // Add email notification info if BDTUPK_HIDE was enabled
2279 if (response.data.bdtupk_hide && response.data.email_sent) {
2280 successMessage += '<br><br><strong>📧 Access Email Sent!</strong><br>Check your email for the access link to modify these settings in the future.';
2281 } else if (response.data.bdtupk_hide && !response.data.email_sent && response.data.access_url) {
2282 // Localhost scenario - show the access URL directly
2283 successMessage += '<br><br><strong>📧 Localhost Email Notice:</strong><br>Email functionality is not available on localhost.<br><strong>Your Access URL:</strong><br><a href="' + response.data.access_url + '" target="_blank">Click here to access white label settings</a><br><small>Save this URL - you\'ll need it to modify settings when BDTUPK_HIDE is active.</small>';
2284 } else if (response.data.bdtupk_hide && !response.data.email_sent) {
2285 successMessage += '<br><br><strong>⚠️ Email Notice:</strong><br>There was an issue sending the access email. Please check your email settings or contact support.';
2286 }
2287
2288 $('#upk-white-label-message').html(
2289 '<div class="bdt-alert bdt-alert-success" bdt-alert>' +
2290 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2291 '<p>' + successMessage + ' <span id="upk-reload-countdown">Reloading in ' + countdown + ' seconds...</span></p>' +
2292 '</div>'
2293 ).show();
2294
2295 // Update button text
2296 $button.html('Reloading...');
2297
2298 // Countdown timer
2299 var countdownInterval = setInterval(function() {
2300 countdown--;
2301 if (countdown > 0) {
2302 $('#upk-reload-countdown').text('Reloading in ' + countdown + ' seconds...');
2303 } else {
2304 $('#upk-reload-countdown').text('Reloading now...');
2305 clearInterval(countdownInterval);
2306 }
2307 }, 1000);
2308
2309 // Check if BDTUPK_HIDE is enabled and redirect accordingly
2310 setTimeout(function() {
2311 if (response.data.bdtupk_hide) {
2312 // Redirect to admin dashboard if BDTUPK_HIDE is enabled
2313 window.location.href = '<?php echo admin_url('index.php'); ?>';
2314 } else {
2315 // Reload current page if BDTUPK_HIDE is not enabled
2316 window.location.reload();
2317 }
2318 }, 1500);
2319 } else {
2320 // Show error message
2321 $('#upk-white-label-message').html(
2322 '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2323 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2324 '<p>Error: ' + (response.data.message || 'Unknown error occurred') + '</p>' +
2325 '</div>'
2326 ).show();
2327
2328 // Restore button state for error case
2329 $button.html(originalText);
2330 $button.prop('disabled', false);
2331 }
2332 })
2333 .fail(function(xhr, status, error) {
2334 // Show error message
2335 $('#upk-white-label-message').html(
2336 '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2337 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2338 '<p>Error: Failed to save settings. Please try again. (' + status + ')</p>' +
2339 '</div>'
2340 ).show();
2341
2342 // Restore button state for failure case
2343 $button.html(originalText);
2344 $button.prop('disabled', false);
2345 });
2346 });
2347
2348 // Save custom code functionality (updated for CodeMirror)
2349 $('#upk-save-custom-code').on('click', function(e) {
2350 e.preventDefault();
2351
2352 var $button = $(this);
2353 var originalText = $button.html();
2354
2355 // Check if upk_admin_ajax is available
2356 if (typeof upk_admin_ajax === 'undefined') {
2357 $('#upk-custom-code-message').html(
2358 '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2359 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2360 '<p>Error: AJAX configuration not loaded. Please refresh the page and try again.</p>' +
2361 '</div>'
2362 ).show();
2363 return;
2364 }
2365
2366 // Prevent multiple simultaneous saves
2367 if ($button.prop('disabled') || $button.hasClass('upk-saving')) {
2368 return;
2369 }
2370
2371 // Mark as saving
2372 $button.addClass('upk-saving');
2373
2374 // Get content from CodeMirror editors
2375 function getCodeMirrorContent(elementId) {
2376 if (codeMirrorEditors[elementId] && codeMirrorEditors[elementId].codemirror) {
2377 return codeMirrorEditors[elementId].codemirror.getValue();
2378 } else {
2379 // Fallback to textarea value
2380 return $('#' + elementId).val() || '';
2381 }
2382 }
2383
2384 var cssContent = getCodeMirrorContent('upk-custom-css');
2385 var jsContent = getCodeMirrorContent('upk-custom-js');
2386 var css2Content = getCodeMirrorContent('upk-custom-css-2');
2387 var js2Content = getCodeMirrorContent('upk-custom-js-2');
2388
2389 // Show loading state
2390 $button.prop('disabled', true);
2391
2392 // Timeout safeguard - if AJAX doesn't complete in 30 seconds, restore button
2393 var timeoutId = setTimeout(function() {
2394 $button.removeClass('upk-saving');
2395 $button.html(originalText);
2396 $button.prop('disabled', false);
2397 $('#upk-custom-code-message').html(
2398 '<div class="bdt-alert bdt-alert-warning" bdt-alert>' +
2399 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2400 '<p>Save operation timed out. Please try again.</p>' +
2401 '</div>'
2402 ).show();
2403 }, 30000);
2404
2405 // Collect form data
2406 var formData = {
2407 action: 'upk_save_custom_code',
2408 nonce: upk_admin_ajax.nonce,
2409 custom_css: cssContent,
2410 custom_js: jsContent,
2411 custom_css_2: css2Content,
2412 custom_js_2: js2Content,
2413 excluded_pages: $('#upk-excluded-pages').val() || []
2414 };
2415
2416
2417 // Verify we have some content before sending (optional check)
2418 var totalContentLength = cssContent.length + jsContent.length + css2Content.length + js2Content.length;
2419 if (totalContentLength === 0) {
2420 var confirmEmpty = confirm('No content detected in any editor. Do you want to save empty content (this will clear all custom code)?');
2421 if (!confirmEmpty) {
2422 // Restore button state
2423 $button.html(originalText);
2424 $button.prop('disabled', false);
2425 return;
2426 }
2427 }
2428
2429 // Send AJAX request
2430 $.post(upk_admin_ajax.ajax_url, formData)
2431 .done(function(response) {
2432 console.log('AJAX Response:', response); // Debug log
2433
2434 if (response && response.success) {
2435 // Show success message
2436 var successMessage = response.data.message;
2437 if (response.data.excluded_count) {
2438 successMessage += ' (' + response.data.excluded_count + ' pages excluded)';
2439 }
2440
2441 $('#upk-custom-code-message').html(
2442 '<div class="bdt-alert bdt-alert-success" bdt-alert>' +
2443 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2444 '<p>' + successMessage + '</p>' +
2445 '</div>'
2446 ).show();
2447
2448 // Auto-hide message after 5 seconds
2449 setTimeout(function() {
2450 $('#upk-custom-code-message').fadeOut();
2451 }, 5000);
2452
2453 } else {
2454 // Show error message
2455 var errorMessage = 'Unknown error occurred';
2456 if (response && response.data && response.data.message) {
2457 errorMessage = response.data.message;
2458 } else if (response && response.message) {
2459 errorMessage = response.message;
2460 }
2461
2462 $('#upk-custom-code-message').html(
2463 '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2464 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2465 '<p>Error: ' + errorMessage + '</p>' +
2466 '</div>'
2467 ).show();
2468 }
2469 })
2470 .fail(function(xhr, status, error) {
2471 console.log('AJAX Error:', xhr, status, error); // Debug log
2472
2473 // Try to parse error response
2474 var errorMessage = 'Failed to save custom code. Please try again.';
2475 try {
2476 var errorResponse = JSON.parse(xhr.responseText);
2477 if (errorResponse.data && errorResponse.data.message) {
2478 errorMessage = errorResponse.data.message;
2479 } else if (errorResponse.message) {
2480 errorMessage = errorResponse.message;
2481 }
2482 } catch (e) {
2483 // Use default error message
2484 }
2485
2486 // Show error message
2487 $('#upk-custom-code-message').html(
2488 '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2489 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2490 '<p>Error: ' + errorMessage + ' (' + status + ')</p>' +
2491 '</div>'
2492 ).show();
2493 })
2494 .always(function() {
2495
2496 // Clear the timeout since AJAX completed
2497 clearTimeout(timeoutId);
2498
2499 try {
2500 $button.removeClass('upk-saving');
2501 $button.html(originalText);
2502 $button.prop('disabled', false);
2503 } catch (e) {
2504 // Fallback: force button restoration
2505 $('#upk-save-custom-code').removeClass('upk-saving').html('<span class="dashicons dashicons-yes"></span> Save Custom Code').prop('disabled', false);
2506 }
2507 });
2508 });
2509
2510 // Reset custom code functionality (updated for CodeMirror)
2511 $('#upk-reset-custom-code').on('click', function(e) {
2512 e.preventDefault();
2513
2514 if (confirm('Are you sure you want to reset all custom code? This will clear all code.')) {
2515 var $button = $(this);
2516 var originalText = $button.html();
2517
2518 // Clear CodeMirror editors
2519 function clearCodeMirrorEditor(elementId) {
2520 if (codeMirrorEditors[elementId] && codeMirrorEditors[elementId].codemirror) {
2521 codeMirrorEditors[elementId].codemirror.setValue('');
2522 } else {
2523 // Fallback to clearing textarea
2524 $('#' + elementId).val('');
2525 }
2526 }
2527
2528 // Clear all editors
2529 clearCodeMirrorEditor('upk-custom-css');
2530 clearCodeMirrorEditor('upk-custom-js');
2531 clearCodeMirrorEditor('upk-custom-css-2');
2532 clearCodeMirrorEditor('upk-custom-js-2');
2533
2534 // Clear exclusions
2535 $('#upk-excluded-pages').val([]).trigger('change');
2536
2537 // Show clearing message
2538 $('#upk-custom-code-message').html(
2539 '<div class="bdt-alert bdt-alert-primary" bdt-alert>' +
2540 '<p><span bdt-spinner="ratio: 0.6"></span> Clearing custom code...</p>' +
2541 '</div>'
2542 ).show();
2543
2544 // Disable button during save
2545 $button.prop('disabled', true).html('<span bdt-spinner="ratio: 0.6"></span> Resetting...');
2546
2547 // Prepare empty data for AJAX save
2548 var formData = {
2549 action: 'upk_save_custom_code',
2550 nonce: upk_admin_ajax.nonce,
2551 custom_css: '',
2552 custom_js: '',
2553 custom_css_2: '',
2554 custom_js_2: '',
2555 excluded_pages: []
2556 };
2557
2558 // Send AJAX request to save empty values
2559 $.ajax({
2560 url: upk_admin_ajax.ajax_url,
2561 type: 'POST',
2562 data: formData,
2563 timeout: 30000,
2564 success: function(response) {
2565 if (response.success) {
2566 // Show success message
2567 $('#upk-custom-code-message').html(
2568 '<div class="bdt-alert bdt-alert-success" bdt-alert>' +
2569 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2570 '<p><span class="dashicons dashicons-yes"></span> All custom code has been reset successfully!</p>' +
2571 '</div>'
2572 ).show();
2573
2574 // Auto-hide message after 5 seconds
2575 setTimeout(function() {
2576 $('#upk-custom-code-message').fadeOut();
2577 }, 5000);
2578 } else {
2579 // Show error message
2580 $('#upk-custom-code-message').html(
2581 '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2582 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2583 '<p><span class="dashicons dashicons-warning"></span> ' + (response.data.message || 'Failed to save reset. Please try again.') + '</p>' +
2584 '</div>'
2585 ).show();
2586 }
2587
2588 // Restore button
2589 $button.prop('disabled', false).html(originalText);
2590 },
2591 error: function(xhr, status, error) {
2592 // Show error message
2593 $('#upk-custom-code-message').html(
2594 '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2595 '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2596 '<p><span class="dashicons dashicons-warning"></span> Failed to save reset: ' + error + '</p>' +
2597 '</div>'
2598 ).show();
2599
2600 // Restore button
2601 $button.prop('disabled', false).html(originalText);
2602 }
2603 });
2604 }
2605 });
2606 });
2607
2608 // Chart.js initialization for system status canvas charts
2609 function initUltimatePostKitCharts() {
2610 // Wait for Chart.js to be available
2611 if (typeof Chart === 'undefined') {
2612 setTimeout(initUltimatePostKitCharts, 500);
2613 return;
2614 }
2615
2616 // Chart instances storage
2617 window.upkChartInstances = window.upkChartInstances || {};
2618 window.upkChartsInitialized = false;
2619
2620 // Function to create a chart
2621 function createChart(canvasId) {
2622 var canvas = document.getElementById(canvasId);
2623 if (!canvas) {
2624 return;
2625 }
2626
2627 var $canvas = jQuery('#' + canvasId);
2628 var valueStr = $canvas.data('value');
2629 var labelsStr = $canvas.data('labels');
2630 var bgStr = $canvas.data('bg');
2631
2632 if (!valueStr || !labelsStr || !bgStr) {
2633 return;
2634 }
2635
2636 // Parse data
2637 var values = valueStr.toString().split(',').map(v => parseInt(v.trim()) || 0);
2638 var labels = labelsStr.toString().split(',').map(l => l.trim());
2639 var colors = bgStr.toString().split(',').map(c => c.trim());
2640
2641 // Destroy existing chart using Chart.js built-in method
2642 var existingChart = Chart.getChart(canvas);
2643 if (existingChart) {
2644 existingChart.destroy();
2645 }
2646
2647 // Also destroy from our instance storage
2648 if (window.upkChartInstances && window.upkChartInstances[canvasId]) {
2649 window.upkChartInstances[canvasId].destroy();
2650 delete window.upkChartInstances[canvasId];
2651 }
2652
2653 // Create new chart
2654 try {
2655 var newChart = new Chart(canvas, {
2656 type: 'doughnut',
2657 data: {
2658 labels: labels,
2659 datasets: [{
2660 data: values,
2661 backgroundColor: colors,
2662 borderWidth: 0
2663 }]
2664 },
2665 options: {
2666 responsive: true,
2667 maintainAspectRatio: false,
2668 plugins: {
2669 legend: { display: false },
2670 tooltip: { enabled: true }
2671 },
2672 cutout: '60%'
2673 }
2674 });
2675
2676 // Store in our instance storage
2677 if (!window.upkChartInstances) window.upkChartInstances = {};
2678 window.upkChartInstances[canvasId] = newChart;
2679 } catch (error) {
2680 // Do nothing
2681 }
2682 }
2683
2684 // Update total widgets status
2685 function updateTotalStatus() {
2686 var coreCount = jQuery('#ultimate_post_kit_active_modules_page input:checked').length;
2687 var extensionsCount = jQuery('#ultimate_post_kit_elementor_extend_page input:checked').length;
2688
2689 jQuery('#bdt-total-widgets-status-core').text(coreCount);
2690 jQuery('#bdt-total-widgets-status-extensions').text(extensionsCount);
2691 jQuery('#bdt-total-widgets-status-heading').text(coreCount + extensionsCount);
2692
2693 jQuery('#bdt-total-widgets-status').attr('data-value', [coreCount, extensionsCount].join(','));
2694 }
2695
2696 // Initialize all charts once
2697 function initAllCharts() {
2698 // Check if charts already exist and are properly rendered
2699 if (window.upkChartInstances && Object.keys(window.upkChartInstances).length >= 4) {
2700 return;
2701 }
2702
2703 // Update total status first
2704 updateTotalStatus();
2705
2706 // Create all charts
2707 var chartCanvases = [
2708 'bdt-db-total-status',
2709 'bdt-db-only-widget-status',
2710 'bdt-total-widgets-status'
2711 ];
2712
2713 var successfulCharts = 0;
2714 chartCanvases.forEach(function(canvasId) {
2715 var canvas = document.getElementById(canvasId);
2716 if (canvas && canvas.offsetParent !== null) { // Check if canvas is visible
2717 createChart(canvasId);
2718 if (window.upkChartInstances && window.upkChartInstances[canvasId]) {
2719 successfulCharts++;
2720 }
2721 }
2722 });
2723 }
2724
2725 // Check if we're currently on system status tab and initialize
2726 function checkAndInitIfOnSystemStatus() {
2727 if (window.location.hash === '#ultimate_post_kit_analytics_system_req') {
2728 setTimeout(initAllCharts, 300);
2729 }
2730 }
2731
2732 // Initialize charts when DOM is ready
2733 jQuery(document).ready(function() {
2734 // Only initialize if we're on the system status tab
2735 setTimeout(checkAndInitIfOnSystemStatus, 500);
2736 });
2737
2738 // Add click handler for System Status tab to create/refresh charts
2739 jQuery(document).on('click', 'a[href="#ultimate_post_kit_analytics_system_req"], a[href*="ultimate_post_kit_analytics_system_req"]', function() {
2740 setTimeout(function() {
2741 // Always recreate charts when tab is clicked to ensure they're visible
2742 initAllCharts();
2743 }, 200);
2744 });
2745 }
2746
2747 // Start the chart initialization
2748 setTimeout(initUltimatePostKitCharts, 1000);
2749
2750 // Handle plugin installation via AJAX
2751 jQuery(document).on('click', '.upk-install-plugin', function(e) {
2752 e.preventDefault();
2753
2754 var $button = jQuery(this);
2755 var pluginSlug = $button.data('plugin-slug');
2756 var nonce = $button.data('nonce');
2757 var originalText = $button.text();
2758
2759 // Disable button and show loading state
2760 $button.prop('disabled', true)
2761 .text('<?php echo esc_js(__('Installing...', 'ultimate-post-kit')); ?>')
2762 .addClass('bdt-installing');
2763
2764 // Perform AJAX request
2765 jQuery.ajax({
2766 url: '<?php echo admin_url('admin-ajax.php'); ?>',
2767 type: 'POST',
2768 data: {
2769 action: 'upk_install_plugin',
2770 plugin_slug: pluginSlug,
2771 nonce: nonce
2772 },
2773 success: function(response) {
2774 if (response.success) {
2775 // Show success message
2776 $button.text('<?php echo esc_js(__('Installed!', 'ultimate-post-kit')); ?>')
2777 .removeClass('bdt-installing')
2778 .addClass('bdt-installed');
2779
2780 // Show success notification
2781 if (typeof bdtUIkit !== 'undefined' && bdtUIkit.notification) {
2782 bdtUIkit.notification({
2783 message: '<span class="dashicons dashicons-yes"></span> ' + response.data.message,
2784 status: 'success'
2785 });
2786 }
2787
2788 // Reload the page after 2 seconds to update button states
2789 setTimeout(function() {
2790 window.location.reload();
2791 }, 2000);
2792
2793 } else {
2794 // Show error message
2795 $button.prop('disabled', false)
2796 .text(originalText)
2797 .removeClass('bdt-installing');
2798
2799 // Show error notification
2800 if (typeof bdtUIkit !== 'undefined' && bdtUIkit.notification) {
2801 bdtUIkit.notification({
2802 message: '<span class="dashicons dashicons-warning"></span> ' + response.data.message,
2803 status: 'danger'
2804 });
2805 }
2806 }
2807 },
2808 error: function() {
2809 // Handle network/server errors
2810 $button.prop('disabled', false)
2811 .text(originalText)
2812 .removeClass('bdt-installing');
2813
2814 // Show error notification
2815 if (typeof bdtUIkit !== 'undefined' && bdtUIkit.notification) {
2816 bdtUIkit.notification({
2817 message: '<span class="dashicons dashicons-warning"></span> <?php echo esc_js(__('Installation failed. Please try again.', 'ultimate-post-kit')); ?>',
2818 status: 'danger'
2819 });
2820 }
2821 }
2822 });
2823 });
2824
2825 // Show/hide white label & custom code save button based on active tab
2826 function toggleWhiteLabelSaveButton() {
2827
2828 // Check if we're on the extra options page
2829 if (window.location.hash === '#ultimate_post_kit_extra_options') {
2830 // Target specifically the tabs within the Extra Options section
2831 var extraOptionsTabs = jQuery('.upk-extra-options-tabs .bdt-tab li.bdt-active');
2832 var activeTab = extraOptionsTabs.index();
2833
2834 if (activeTab === 1) { // White Label tab is the second tab (index 1)
2835 jQuery('.upk-white-label-save-section').show();
2836 jQuery('.upk-code-save-section').hide();
2837 } else {
2838 jQuery('.upk-white-label-save-section').hide();
2839 jQuery('.upk-code-save-section').show();
2840 }
2841 } else {
2842 jQuery('.upk-white-label-save-section').hide();
2843 jQuery('.upk-code-save-section').hide();
2844 }
2845 }
2846
2847 // Wait for jQuery to be ready
2848 jQuery(document).ready(function($) {
2849
2850 // Check if we should automatically switch to White Label tab
2851 var urlParams = new URLSearchParams(window.location.search);
2852 if (urlParams.get('white_label_tab') === '1') {
2853 // Wait a bit for UIkit to be ready, then switch to White Label tab
2854 setTimeout(function() {
2855 // Use UIkit's API to switch to the second tab (index 1)
2856 var tabElement = document.querySelector('.upk-extra-options-tabs [bdt-tab]');
2857 if (tabElement && typeof UIkit !== 'undefined') {
2858 UIkit.tab(tabElement).show(1); // Show tab at index 1 (White Label tab)
2859 } else {
2860 // Fallback: simply click the White Label tab link
2861 var whiteLabelTab = $('.upk-extra-options-tabs .bdt-tab li').eq(1);
2862 if (whiteLabelTab.length > 0) {
2863 whiteLabelTab.find('a')[0].click(); // Use native click
2864 }
2865 }
2866
2867 // Check button visibility after tab switch
2868 setTimeout(function() {
2869 toggleWhiteLabelSaveButton();
2870 }, 300);
2871 }, 800);
2872 } else {
2873 toggleWhiteLabelSaveButton();
2874 }
2875
2876 // Check on hash change (when navigating to extra options page)
2877 $(window).on('hashchange', function() {
2878 toggleWhiteLabelSaveButton();
2879 });
2880
2881 // Listen for UIkit tab changes using multiple methods
2882 $(document).on('click', '.bdt-tab li a', function() {
2883 setTimeout(function() {
2884 toggleWhiteLabelSaveButton();
2885 }, 200);
2886 });
2887
2888 // Listen for UIkit's internal tab change events
2889 $(document).on('shown', '[bdt-tab]', function() {
2890 setTimeout(function() {
2891 toggleWhiteLabelSaveButton();
2892 }, 200);
2893 });
2894
2895 // Also listen for the specific tab content changes
2896 $(document).on('show', '#upk-extra-options-tab-content > div', function() {
2897 setTimeout(function() {
2898 toggleWhiteLabelSaveButton();
2899 }, 200);
2900 });
2901
2902 // Alternative: Check periodically for tab changes
2903 setInterval(function() {
2904 if (window.location.hash === '#ultimate_post_kit_extra_options') {
2905 var currentActiveTab = $('.bdt-tab li.bdt-active').index();
2906 if (typeof window.lastActiveTab === 'undefined') {
2907 window.lastActiveTab = currentActiveTab;
2908 } else if (window.lastActiveTab !== currentActiveTab) {
2909 window.lastActiveTab = currentActiveTab;
2910 toggleWhiteLabelSaveButton();
2911 }
2912 }
2913 }, 500);
2914 });
2915
2916 </script>
2917 <?php
2918 }
2919
2920 /**
2921 * Display Footer
2922 *
2923 * @access public
2924 * @return void
2925 */
2926
2927 function footer_info() {
2928 ?>
2929
2930 <div class="ultimate-post-kit-footer-info bdt-margin-medium-top">
2931
2932 <div class="bdt-grid ">
2933
2934 <div class="bdt-width-auto@s upk-setting-save-btn">
2935
2936
2937
2938 </div>
2939
2940 <div class="bdt-width-expand@s bdt-text-right">
2941 <p class="">
2942 Ultimate Post Kit Pro plugin made with love by <a target="_blank" href="https://bdthemes.com">BdThemes</a> Team.
2943 <br>All rights reserved by <a target="_blank" href="https://bdthemes.com">BdThemes.com</a>.
2944 </p>
2945 </div>
2946 </div>
2947
2948 </div>
2949
2950 <?php
2951 }
2952
2953 /**
2954 * Get all the pages
2955 *
2956 * @return array page names with key value pairs
2957 */
2958 function get_pages() {
2959 $pages = get_pages();
2960 $pages_options = [];
2961 if ($pages) {
2962 foreach ($pages as $page) {
2963 $pages_options[$page->ID] = $page->post_title;
2964 }
2965 }
2966
2967 return $pages_options;
2968 }
2969
2970 /**
2971 * Check if current license supports white label features
2972 * Now includes other_param checking for AppSumo WL flag
2973 *
2974 * @access public static
2975 * @return bool
2976 */
2977 public static function is_white_label_license() {
2978 // Check if pro version is activated first
2979 if (!function_exists('_is_upk_pro_activated') || !_is_upk_pro_activated()) {
2980 return false;
2981 }
2982
2983 // Since UltimatePostKitPro\Base doesn't exist, return false for now
2984 // This should be replaced with actual pro license checking logic when available
2985 $license_info = UltimatePostKitPro\Base\Ultimate_Post_Kit_Base::GetRegisterInfo();
2986
2987 // Security: Validate license info structure
2988 if (empty($license_info) ||
2989 !is_object($license_info) ||
2990 empty($license_info->license_title) ||
2991 empty($license_info->is_valid)) {
2992 return false;
2993 }
2994
2995 // Sanitize license title to prevent any potential issues
2996 $license_title = sanitize_text_field(strtolower($license_info->license_title));
2997
2998 // Check for other_param WL flag FIRST (for AppSumo and other special licenses)
2999 if (!empty($license_info->other_param)) {
3000 // Check if other_param contains WL flag
3001 if (is_array($license_info->other_param)) {
3002 if (in_array('WL', $license_info->other_param, true)) {
3003 return true;
3004 }
3005 } elseif (is_string($license_info->other_param)) {
3006 if (strpos($license_info->other_param, 'WL') !== false) {
3007 return true;
3008 }
3009 }
3010 }
3011
3012 // Check standard license types (but NOT AppSumo - AppSumo requires WL flag)
3013 $allowed_types = self::get_white_label_allowed_license_types();
3014 $allowed_hashes = array_values($allowed_types);
3015
3016 // Split license title into words and check each word
3017 $words = preg_split('/\s+/', $license_title, -1, PREG_SPLIT_NO_EMPTY);
3018 foreach ($words as $word) {
3019 $word = trim($word);
3020 if (empty($word) || strlen($word) > 50) { // Prevent extremely long strings
3021 continue;
3022 }
3023
3024 // Use SHA-256 for enhanced security
3025 $hash = hash('sha256', $word);
3026 if (in_array($hash, $allowed_hashes, true)) { // Strict comparison
3027 return true;
3028 }
3029 }
3030
3031 return false;
3032 }
3033
3034 /**
3035 * Render White Label Section
3036 *
3037 * @access public
3038 * @return void
3039 */
3040 public function render_white_label_section() {
3041 //// Safely check if helper functions exist
3042 $is_pro_installed = function_exists('_is_upk_pro_installed') ? _is_upk_pro_installed() : false;
3043 $is_pro_activated = function_exists('_is_upk_pro_activated') ? _is_upk_pro_activated() : false;
3044
3045 // Define plugin slug (adjust if needed)
3046 $plugin_slug = 'ultimate-post-kit-pro/ultimate-post-kit-pro.php';
3047
3048 // Case 1: Pro not installed
3049 if ( ! $is_pro_installed ) : ?>
3050 <div class="bdt-alert bdt-alert-danger bdt-margin-medium-top" bdt-alert>
3051 <p><?php esc_html_e( 'Ultimate Post Kit Pro is not installed. Please install it to access White Label functionality.', 'ultimate-post-kit' ); ?></p>
3052 <div class="bdt-margin-small-top">
3053 <a href="https://postkit.pro/pricing/" target="_blank" class="bdt-button bdt-btn-blue">
3054 <?php esc_html_e( 'Get Pro', 'ultimate-post-kit' ); ?>
3055 </a>
3056 </div>
3057 </div>
3058 <?php
3059 return;
3060 endif;
3061
3062 // Case 2: Installed but not active
3063 if ( $is_pro_installed && ! $is_pro_activated ) :
3064 // Generate secure activation link
3065 $activate_url = wp_nonce_url(
3066 add_query_arg(
3067 array(
3068 'action' => 'activate',
3069 'plugin' => $plugin_slug,
3070 ),
3071 admin_url( 'plugins.php' )
3072 ),
3073 'activate-plugin_' . $plugin_slug
3074 );
3075 ?>
3076 <div class="bdt-alert bdt-alert-warning bdt-margin-medium-top" bdt-alert>
3077 <p><?php esc_html_e( 'Ultimate Post Kit Pro is installed but not activated. Please activate it to access White Label functionality.', 'ultimate-post-kit' ); ?></p>
3078 <div class="bdt-margin-small-top">
3079 <a href="<?php echo esc_url( $activate_url ); ?>" class="bdt-button bdt-btn-blue">
3080 <?php esc_html_e( 'Activate Pro', 'ultimate-post-kit' ); ?>
3081 </a>
3082 </div>
3083 </div>
3084 <?php
3085 return;
3086 endif;
3087 ?>
3088 <div class="upk-white-label-section">
3089 <h1 class="upk-feature-title"><?php esc_html_e('White Label Settings', 'ultimate-post-kit'); ?></h1>
3090 <p><?php esc_html_e('Enable white label mode to hide Ultimate Post Kit branding from the admin interface and widgets.', 'ultimate-post-kit'); ?></p>
3091
3092 <?php
3093
3094 $is_license_active = false;
3095 if ( function_exists( 'upk_license_validation' ) && true === upk_license_validation() ) {
3096 $is_license_active = true;
3097 }
3098 $is_white_label_eligible = self::is_white_label_license();
3099
3100 // Show appropriate notices based on license status
3101 if (!$is_license_active): ?>
3102 <div class="bdt-alert bdt-alert-danger bdt-margin-medium-top" bdt-alert>
3103 <p><strong><?php esc_html_e('License Not Activated', 'ultimate-post-kit'); ?></strong></p>
3104 <p><?php esc_html_e('You need to activate your Ultimate Post Kit license to access White Label functionality. Please activate your license first.', 'ultimate-post-kit'); ?></p>
3105 <div class="bdt-margin-small-top">
3106 <a href="<?php echo esc_url(admin_url('admin.php?page=ultimate_post_kit_options#ultimate_post_kit_license_settings')); ?>" class="bdt-button bdt-btn-blue bdt-margin-small-right">
3107 <?php esc_html_e('Activate License', 'ultimate-post-kit'); ?>
3108 </a>
3109 <a href="https://postkit.pro/pricing/" target="_blank" class="bdt-button bdt-btn-blue">
3110 <?php esc_html_e('Get License', 'ultimate-post-kit'); ?>
3111 </a>
3112 </div>
3113 </div>
3114 <?php elseif ($is_license_active && !$is_white_label_eligible): ?>
3115 <div class="bdt-alert bdt-alert-warning bdt-margin-medium-top" bdt-alert>
3116 <p><strong><?php esc_html_e('Eligible License Required', 'ultimate-post-kit'); ?></strong></p>
3117 <p><?php esc_html_e('White Label functionality is available for Agency, Extended, Developer, AppSumo Lifetime, and other eligible license holders. Some licenses may include special white label permissions.', 'ultimate-post-kit'); ?></p>
3118 <a href="https://postkit.pro/pricing/" target="_blank" class="bdt-button bdt-btn-blue bdt-margin-small-top">
3119 <?php esc_html_e('Upgrade License', 'ultimate-post-kit'); ?>
3120 </a>
3121 </div>
3122 <?php endif; ?>
3123
3124 <div class="upk-white-label-options <?php echo (!$is_license_active || !$is_white_label_eligible) ? 'upk-white-label-locked' : ''; ?>">
3125 <div class="upk-option-item ">
3126 <div class="upk-option-item-inner bdt-card">
3127 <div class="bdt-flex bdt-flex-between bdt-flex-middle">
3128 <div>
3129 <h3 class="upk-option-title"><?php esc_html_e('Enable White Label Mode', 'ultimate-post-kit'); ?></h3>
3130 <p class="upk-option-description">
3131 <?php if ($is_license_active && $is_white_label_eligible): ?>
3132 <?php esc_html_e('When enabled, Ultimate Post Kit branding will be hidden from the admin interface and widgets.', 'ultimate-post-kit'); ?>
3133 <?php elseif (!$is_license_active): ?>
3134 <?php esc_html_e('This feature requires an active Ultimate Post Kit license. Please activate your license first.', 'ultimate-post-kit'); ?>
3135 <?php else: ?>
3136 <?php esc_html_e('This feature requires an eligible license (Agency, Extended, Developer, AppSumo Lifetime, etc.). Upgrade your license to access white label functionality.', 'ultimate-post-kit'); ?>
3137 <?php endif; ?>
3138 </p>
3139 </div>
3140 <div class="upk-option-switch">
3141 <?php
3142 $white_label_enabled = ($is_license_active && $is_white_label_eligible) ? get_option('upk_white_label_enabled', false) : false;
3143 // Convert to boolean to ensure proper comparison
3144 $white_label_enabled = (bool) $white_label_enabled;
3145 ?>
3146 <label class="switch">
3147 <input type="checkbox"
3148 id="upk-white-label-enabled"
3149 name="upk_white_label_enabled"
3150 <?php checked($white_label_enabled, true); ?>
3151 <?php disabled(!$is_license_active || !$is_white_label_eligible); ?>>
3152 <span class="slider"></span>
3153 </label>
3154 </div>
3155 </div>
3156 </div>
3157 </div>
3158
3159 <!-- White Label Title Field (conditional) -->
3160 <div class="upk-option-item upk-white-label-fields" style="<?php echo ($white_label_enabled && $is_license_active && $is_white_label_eligible) ? '' : 'display: none;'; ?>">
3161 <div class="upk-option-item-inner bdt-card">
3162 <div class="upk-white-label-title-section bdt-margin-medium-bottom">
3163 <h3 class="upk-option-title"><?php esc_html_e('White Label Title', 'ultimate-post-kit'); ?></h3>
3164 <p class="upk-option-description"><?php esc_html_e('Enter a custom title to replace "Ultimate Post Kit" branding throughout the plugin.', 'ultimate-post-kit'); ?></p>
3165 <div class="upk-white-label-input-wrapper bdt-margin-small-top">
3166 <input type="text"
3167 id="upk-white-label-title"
3168 name="upk_white_label_title"
3169 class="upk-white-label-input"
3170 placeholder="<?php esc_attr_e('Enter your custom title...', 'ultimate-post-kit'); ?>"
3171 value="<?php echo esc_attr(get_option('upk_white_label_title', '')); ?>"
3172 <?php disabled(!$is_license_active || !$is_white_label_eligible); ?>>
3173 </div>
3174 </div>
3175
3176 <hr class="bdt-divider-small">
3177
3178 <!-- White Label Title Icon Field -->
3179 <div class="upk-white-label-icon-section bdt-margin-medium-top">
3180 <h3 class="upk-option-title"><?php esc_html_e('White Label Title Icon', 'ultimate-post-kit'); ?></h3>
3181 <p class="upk-option-description"><?php esc_html_e('Upload a custom icon to replace the Ultimate Post Kit menu icon. Supports JPG, PNG, and SVG formats.', 'ultimate-post-kit'); ?></p>
3182
3183 <div class="upk-icon-upload-wrapper bdt-margin-small-top">
3184 <?php
3185 $icon_url = get_option('upk_white_label_icon', '');
3186 $icon_id = get_option('upk_white_label_icon_id', '');
3187 ?>
3188 <div class="upk-icon-preview-container" style="<?php echo $icon_url ? '' : 'display: none;'; ?>">
3189 <div class="upk-icon-preview">
3190 <img id="upk-icon-preview-img" src="<?php echo esc_url($icon_url); ?>" alt="Icon Preview" style="max-width: 64px; max-height: 64px; border: 1px solid #ddd; border-radius: 4px; padding: 8px; background: #fff;">
3191 </div>
3192 <button type="button" id="upk-remove-icon" class="bdt-button bdt-btn-grey bdt-flex bdt-flex-middle bdt-margin-small-top" style="padding: 8px 12px; font-size: 12px;">
3193 <span class="dashicons dashicons-trash"></span>
3194 <?php esc_html_e('Remove', 'ultimate-post-kit'); ?>
3195 </button>
3196 </div>
3197
3198 <div class="upk-icon-upload-container">
3199 <button type="button" id="upk-upload-icon" class="bdt-button bdt-btn-blue bdt-margin-small-top" <?php disabled(!$is_license_active || !$is_white_label_eligible); ?>>
3200 <span class="dashicons dashicons-cloud-upload"></span>
3201 <?php esc_html_e('Upload Icon', 'ultimate-post-kit'); ?>
3202 </button>
3203 <input type="hidden" id="upk-white-label-icon" name="upk_white_label_icon" value="<?php echo esc_attr($icon_url); ?>">
3204 <input type="hidden" id="upk-white-label-icon-id" name="upk_white_label_icon_id" value="<?php echo esc_attr($icon_id); ?>">
3205 </div>
3206 </div>
3207
3208 <p class="upk-input-help">
3209 <?php esc_html_e('Recommended size: 20x20 pixels. The icon will be automatically resized to fit the WordPress admin menu. Supported formats: JPG, PNG, SVG.', 'ultimate-post-kit'); ?>
3210 </p>
3211 </div>
3212
3213 <!-- White Label Plugin Logo Field -->
3214 <div class="upk-white-label-logo-section bdt-margin-medium-top">
3215 <h3 class="upk-option-title"><?php esc_html_e('Plugin Logo', 'ultimate-post-kit'); ?></h3>
3216 <p class="upk-option-description"><?php esc_html_e('Upload a custom logo to replace the Ultimate Post Kit logo in the admin header. Supports JPG, PNG, and SVG formats.', 'ultimate-post-kit'); ?></p>
3217 <div class="upk-logo-upload-wrapper-inner">
3218 <div class="upk-logo-upload-wrapper bdt-margin-small-top">
3219 <?php
3220 $logo_url = get_option('upk_white_label_logo', '');
3221 $logo_id = get_option('upk_white_label_logo_id', '');
3222 ?>
3223 <div class="upk-logo-preview-container" style="<?php echo $logo_url ? '' : 'display: none;'; ?>">
3224 <div class="upk-logo-preview">
3225 <img id="upk-logo-preview-img" src="<?php echo esc_url($logo_url); ?>" alt="Logo Preview" style="max-width: 200px; max-height: 64px; border: 1px solid #ddd; border-radius: 4px; padding: 8px; background: #fff;">
3226 </div>
3227 <button type="button" id="upk-remove-logo" class="bdt-button bdt-btn-grey bdt-flex bdt-flex-middle bdt-margin-small-top" style="padding: 8px 12px; font-size: 12px;">
3228 <span class="dashicons dashicons-trash"></span>
3229 </button>
3230 </div>
3231
3232 <div class="upk-logo-upload-container">
3233 <button type="button" id="upk-upload-logo" class="bdt-button bdt-btn-blue bdt-margin-small-top" <?php disabled(!$is_license_active || !$is_white_label_eligible); ?>>
3234 <span class="dashicons dashicons-cloud-upload"></span>
3235 <?php esc_html_e('Upload Logo', 'ultimate-post-kit'); ?>
3236 </button>
3237 <input type="hidden" id="upk-white-label-logo" name="upk_white_label_logo" value="<?php echo esc_attr($logo_url); ?>">
3238 <input type="hidden" id="upk-white-label-logo-id" name="upk_white_label_logo_id" value="<?php echo esc_attr($logo_id); ?>">
3239 </div>
3240 </div>
3241 <p class="upk-input-help">
3242 <?php esc_html_e('Recommended size: 200x40 pixels. The logo will be displayed in the admin header. Supported formats: JPG, PNG, SVG.', 'ultimate-post-kit'); ?>
3243 </p>
3244 </div>
3245 </div>
3246 </div>
3247 </div>
3248
3249 <!-- License Hide Option (conditional) -->
3250 <div class="upk-option-item upk-white-label-fields" style="<?php echo ($white_label_enabled && $is_license_active && $is_white_label_eligible) ? '' : 'display: none;'; ?>">
3251 <div class="upk-option-item-inner bdt-card">
3252 <div class="bdt-flex bdt-flex-between bdt-flex-middle">
3253 <div>
3254 <h3 class="upk-option-title"><?php esc_html_e('Hide License Menu', 'ultimate-post-kit'); ?></h3>
3255 <p class="upk-option-description"><?php esc_html_e('Hide the license menu from the admin sidebar when white label mode is enabled.', 'ultimate-post-kit'); ?></p>
3256 </div>
3257 <div class="upk-option-switch">
3258 <?php
3259 $hide_license = get_option('upk_white_label_hide_license', false);
3260 // Convert to boolean to ensure proper comparison
3261 $hide_license = (bool) $hide_license;
3262 ?>
3263 <label class="switch">
3264 <input type="checkbox"
3265 id="upk-white-label-hide-license"
3266 name="upk_white_label_hide_license"
3267 <?php checked($hide_license, true); ?>
3268 <?php disabled(!$is_license_active || !$is_white_label_eligible); ?>>
3269 <span class="slider"></span>
3270 </label>
3271 </div>
3272 </div>
3273 </div>
3274 </div>
3275
3276 <!-- BDTUPK_HIDE Option (conditional) -->
3277 <div class="upk-option-item upk-white-label-fields" style="<?php echo ($white_label_enabled && $is_license_active && $is_white_label_eligible) ? '' : 'display: none;'; ?>">
3278 <div class="upk-option-item-inner bdt-card">
3279 <div class="bdt-flex bdt-flex-between bdt-flex-middle">
3280 <div>
3281 <h3 class="upk-option-title"><?php esc_html_e('Enable BDTUPK_HIDE Constant', 'ultimate-post-kit'); ?></h3>
3282 <p class="upk-option-description"><?php esc_html_e('Define the BDTUPK_HIDE constant to hide additional Ultimate Post Kit branding and features throughout the plugin.', 'ultimate-post-kit'); ?></p>
3283 <?php
3284 $bdtupk_hide = get_option('upk_white_label_bdtupk_hide', false);
3285 if ($bdtupk_hide): ?>
3286 <div class="bdt-alert bdt-alert-warning bdt-margin-small-top">
3287 <p><strong>⚠️ BDTUPK_HIDE Currently Active</strong></p>
3288 <p>Advanced white label mode is currently enabled. Ultimate Post Kit menus are hidden from the admin interface.</p>
3289 </div>
3290 <?php endif; ?>
3291 </div>
3292 <div class="upk-option-switch">
3293 <?php
3294 // Convert to boolean to ensure proper comparison
3295 $bdtupk_hide = (bool) $bdtupk_hide;
3296 ?>
3297 <label class="switch">
3298 <input type="checkbox"
3299 id="upk-white-label-bdtupk-hide"
3300 name="upk_white_label_bdtupk_hide"
3301 <?php checked($bdtupk_hide, true); ?>
3302 <?php disabled(!$is_license_active || !$is_white_label_eligible); ?>>
3303 <span class="slider"></span>
3304 </label>
3305 </div>
3306 </div>
3307 </div>
3308 </div>
3309
3310 <?php if (!$bdtupk_hide && $is_license_active && $is_white_label_eligible): ?>
3311 <div class="bdt-margin-small-top">
3312 <div class="bdt-alert bdt-alert-danger">
3313 <h4>📧 Email Access System</h4>
3314 <p>When you enable BDTUPK_HIDE, an email will be automatically sent to:</p>
3315 <ul style="margin: 10px 0;">
3316 <li><strong>License Email:</strong> <?php echo esc_html(self::get_license_email()); ?></li>
3317 <?php if (get_bloginfo('admin_email') !== self::get_license_email()): ?>
3318 <li><strong>Admin Email:</strong> <?php echo esc_html(get_bloginfo('admin_email')); ?></li>
3319 <?php endif; ?>
3320 </ul>
3321 <p>This email will contain a special access link that allows you to return to these settings even when BDTUPK_HIDE is active.</p>
3322 </div>
3323 </div>
3324 <?php endif; ?>
3325
3326 <!-- Success/Error Messages -->
3327 <div id="upk-white-label-message" class="upk-white-label-message bdt-margin-small-top" style="display: none;">
3328 <div class="bdt-alert bdt-alert-success" bdt-alert>
3329 <a href class="bdt-alert-close" bdt-close></a>
3330 <p><?php esc_html_e('White label settings saved successfully!', 'ultimate-post-kit'); ?></p>
3331 </div>
3332 </div>
3333 </div>
3334 </div>
3335 <?php
3336 }
3337
3338 public static function license_wl_status() {
3339 $status = get_option('ultimate_post_kit_license_title_status');
3340
3341 if ($status) {
3342 return true;
3343 }
3344
3345 return false;
3346 }
3347
3348
3349
3350 /**
3351 * Display Analytics and System Requirements
3352 *
3353 * @access public
3354 * @return void
3355 */
3356
3357 public function ultimate_post_kit_analytics_system_req_content() {
3358 ?>
3359 <div class="upk-dashboard-panel"
3360 bdt-scrollspy="target: > div > div > .bdt-card; cls: bdt-animation-slide-bottom-small; delay: 300">
3361 <div class="upk-dashboard-analytics-system">
3362
3363 <?php $this->ultimate_post_kit_widgets_status(); ?>
3364
3365 <div class="bdt-grid bdt-grid-medium bdt-margin-medium-top" bdt-grid
3366 bdt-height-match="target: > div > .bdt-card">
3367 <div class="bdt-width-1-1">
3368 <div class="bdt-card bdt-card-body upk-system-requirement">
3369 <h1 class="upk-feature-title bdt-margin-small-bottom">
3370 <?php esc_html_e('System Requirement', 'ultimate-post-kit'); ?>
3371 </h1>
3372 <?php $this->ultimate_post_kit_system_requirement(); ?>
3373 </div>
3374 </div>
3375 </div>
3376
3377 </div>
3378 </div>
3379 <?php
3380 }
3381
3382 /**
3383 * Widgets Status
3384 */
3385
3386 public function ultimate_post_kit_widgets_status() {
3387 $track_nw_msg = '';
3388 if (!Tracker::is_allow_track()) {
3389 $track_nw = esc_html__('This feature is not working because the Elementor Usage Data Sharing feature is Not Enabled.', 'ultimate-post-kit');
3390 $track_nw_msg = 'bdt-tooltip="' . $track_nw . '"';
3391 }
3392 ?>
3393 <div class="upk-dashboard-widgets-status">
3394 <div class="bdt-grid bdt-grid-medium" bdt-grid bdt-height-match="target: > div > .bdt-card">
3395 <div class="bdt-width-1-2@m bdt-width-1-4@xl">
3396 <div class="upk-widget-status bdt-card bdt-card-body" <?php echo wp_kses_post($track_nw_msg); ?>>
3397
3398 <?php
3399 $used_widgets = count(self::get_used_widgets());
3400 $un_used_widgets = count(self::get_unused_widgets());
3401 ?>
3402
3403 <div class="upk-count-canvas-wrap">
3404 <h1 class="upk-feature-title"><?php esc_html_e('All Widgets', 'ultimate-post-kit'); ?></h1>
3405 <div class="bdt-flex bdt-flex-between bdt-flex-middle">
3406 <div class="upk-count-wrap">
3407 <div class="upk-widget-count"><?php esc_html_e('Used:', 'ultimate-post-kit'); ?> <b>
3408 <?php echo esc_html($used_widgets); ?>
3409 </b></div>
3410 <div class="upk-widget-count"><?php esc_html_e('Unused:', 'ultimate-post-kit'); ?> <b>
3411 <?php echo esc_html($un_used_widgets); ?>
3412 </b>
3413 </div>
3414 <div class="upk-widget-count"><?php esc_html_e('Total:', 'ultimate-post-kit'); ?>
3415 <b>
3416 <?php echo esc_html($used_widgets + $un_used_widgets); ?>
3417 </b>
3418 </div>
3419 </div>
3420
3421 <div class="upk-canvas-wrap">
3422 <canvas id="bdt-db-total-status" style="height: 100px; width: 100px;"
3423 data-label="Total Widgets Status - (<?php echo esc_html($used_widgets + $un_used_widgets); ?>)"
3424 data-labels="<?php echo esc_attr('Used, Unused'); ?>"
3425 data-value="<?php echo esc_attr($used_widgets) . ',' . esc_attr($un_used_widgets); ?>"
3426 data-bg="#FFD166, #fff4d9" data-bg-hover="#0673e1, #e71522"></canvas>
3427 </div>
3428 </div>
3429 </div>
3430
3431 </div>
3432 </div>
3433 <div class="bdt-width-1-2@m bdt-width-1-4@xl">
3434 <div class="upk-widget-status bdt-card bdt-card-body" <?php echo wp_kses_post($track_nw_msg); ?>>
3435
3436 <?php
3437 $used_only_widgets = count(self::get_used_only_widgets());
3438 $unused_only_widgets = count(self::get_unused_only_widgets());
3439 ?>
3440
3441
3442 <div class="upk-count-canvas-wrap">
3443 <h1 class="upk-feature-title"><?php esc_html_e('Core', 'ultimate-post-kit'); ?></h1>
3444 <div class="bdt-flex bdt-flex-between bdt-flex-middle">
3445 <div class="upk-count-wrap">
3446 <div class="upk-widget-count"><?php esc_html_e('Used:', 'ultimate-post-kit'); ?> <b>
3447 <?php echo esc_html($used_only_widgets); ?>
3448 </b></div>
3449 <div class="upk-widget-count"><?php esc_html_e('Unused:', 'ultimate-post-kit'); ?> <b>
3450 <?php echo esc_html($unused_only_widgets); ?>
3451 </b></div>
3452 <div class="upk-widget-count"><?php esc_html_e('Total:', 'ultimate-post-kit'); ?>
3453 <b>
3454 <?php echo esc_html($used_only_widgets + $unused_only_widgets); ?>
3455 </b>
3456 </div>
3457 </div>
3458
3459 <div class="upk-canvas-wrap">
3460 <canvas id="bdt-db-only-widget-status" style="height: 100px; width: 100px;"
3461 data-label="Core Widgets Status - (<?php echo esc_html($used_only_widgets + $unused_only_widgets); ?>)"
3462 data-labels="<?php echo esc_attr('Used, Unused'); ?>"
3463 data-value="<?php echo esc_attr($used_only_widgets) . ',' . esc_attr($unused_only_widgets); ?>"
3464 data-bg="#EF476F, #ffcdd9" data-bg-hover="#0673e1, #e71522"></canvas>
3465 </div>
3466 </div>
3467 </div>
3468
3469 </div>
3470 </div>
3471
3472 <div class="bdt-width-1-2@m bdt-width-1-4@xl">
3473 <div class="upk-widget-status bdt-card bdt-card-body" <?php echo wp_kses_post($track_nw_msg); ?>>
3474
3475 <div class="upk-count-canvas-wrap">
3476 <h1 class="upk-feature-title"><?php esc_html_e('Active', 'ultimate-post-kit'); ?></h1>
3477 <div class="bdt-flex bdt-flex-between bdt-flex-middle">
3478 <div class="upk-count-wrap">
3479 <div class="upk-widget-count"><?php esc_html_e('Core:', 'ultimate-post-kit'); ?>
3480 <b id="bdt-total-widgets-status-core">0</b>
3481 </div>
3482 <div class="upk-widget-count"><?php esc_html_e('Extensions:', 'ultimate-post-kit'); ?>
3483 <b id="bdt-total-widgets-status-extensions">0</b>
3484 </div>
3485 <div class="upk-widget-count"><?php esc_html_e('Total:', 'ultimate-post-kit'); ?> <b
3486 id="bdt-total-widgets-status-heading">0</b></div>
3487 </div>
3488
3489 <div class="upk-canvas-wrap">
3490 <canvas id="bdt-total-widgets-status" style="height: 100px; width: 100px;"
3491 data-label="Total Active Widgets Status"
3492 data-labels="<?php echo esc_attr('Core, Extensions'); ?>"
3493 data-value="0,0,0"
3494 data-bg="#0680d6, #B0EBFF" data-bg-hover="#0673e1, #B0EBFF">
3495 </canvas>
3496 </div>
3497 </div>
3498 </div>
3499
3500 </div>
3501 </div>
3502 </div>
3503 </div>
3504
3505 <?php if (!Tracker::is_allow_track()): ?>
3506 <div class="bdt-border-rounded bdt-box-shadow-small bdt-alert-warning" bdt-alert>
3507 <a href class="bdt-alert-close" bdt-close></a>
3508 <div class="bdt-text-default">
3509 <?php
3510 printf(
3511 esc_html__('To view widgets analytics, Elementor %1$sUsage Data Sharing%2$s feature by Elementor needs to be activated. Please activate the feature to get widget analytics instantly ', 'ultimate-post-kit'),
3512 '<b>', '</b>'
3513 );
3514
3515 echo ' <a href="' . esc_url(admin_url('admin.php?page=elementor-settings')) . '">' . esc_html__('from here.', 'ultimate-post-kit') . '</a>';
3516 ?>
3517 </div>
3518 </div>
3519 <?php endif; ?>
3520
3521 <?php
3522 }
3523
3524 /**
3525 * Display System Requirement
3526 *
3527 * @access public
3528 * @return void
3529 */
3530
3531 public function ultimate_post_kit_system_requirement() {
3532 $php_version = phpversion();
3533 $max_execution_time = ini_get('max_execution_time');
3534 $memory_limit = ini_get('memory_limit');
3535 $post_limit = ini_get('post_max_size');
3536 $uploads = wp_upload_dir();
3537 $upload_path = $uploads['basedir'];
3538 $yes_icon = '<span class="valid"><i class="dashicons-before dashicons-yes"></i></span>';
3539 $no_icon = '<span class="invalid"><i class="dashicons-before dashicons-no-alt"></i></span>';
3540
3541 $environment = Utils::get_environment_info();
3542
3543 ?>
3544 <ul class="check-system-status bdt-grid bdt-child-width-1-2@m bdt-grid-small ">
3545 <li>
3546 <div>
3547 <span class="label1"><?php esc_html_e('PHP Version:', 'ultimate-post-kit'); ?></span>
3548
3549 <?php
3550 if (version_compare($php_version, '7.4.0', '<')) {
3551 echo wp_kses_post($no_icon);
3552 echo '<span class="label2" title="' . esc_attr__('Min: 7.4 Recommended', 'ultimate-post-kit') . '" bdt-tooltip>' . esc_html__('Currently:', 'ultimate-post-kit') . ' ' . esc_html($php_version) . '</span>';
3553 } else {
3554 echo wp_kses_post($yes_icon);
3555 echo '<span class="label2">' . esc_html__('Currently:', 'ultimate-post-kit') . ' ' . esc_html($php_version) . '</span>';
3556 }
3557 ?>
3558 </div>
3559
3560 </li>
3561
3562 <li>
3563 <div>
3564 <span class="label1"><?php esc_html_e('Max execution time:', 'ultimate-post-kit'); ?> </span>
3565 <?php
3566 if ($max_execution_time < '90') {
3567 echo wp_kses_post($no_icon);
3568 echo '<span class="label2" title="Min: 90 Recommended" bdt-tooltip>Currently: ' . esc_html($max_execution_time) . '</span>';
3569 } else {
3570 echo wp_kses_post($yes_icon);
3571 echo '<span class="label2">Currently: ' . esc_html($max_execution_time) . '</span>';
3572 }
3573 ?>
3574 </div>
3575 </li>
3576 <li>
3577 <div>
3578 <span class="label1"><?php esc_html_e('Memory Limit:', 'ultimate-post-kit'); ?> </span>
3579
3580 <?php
3581 if (intval($memory_limit) < '512') {
3582 echo wp_kses_post($no_icon);
3583 echo '<span class="label2" title="Min: 512M Recommended" bdt-tooltip>Currently: ' . esc_html($memory_limit) . '</span>';
3584 } else {
3585 echo wp_kses_post($yes_icon);
3586 echo '<span class="label2">Currently: ' . esc_html($memory_limit) . '</span>';
3587 }
3588 ?>
3589 </div>
3590 </li>
3591
3592 <li>
3593 <div>
3594 <span class="label1"><?php esc_html_e('Max Post Limit:', 'ultimate-post-kit'); ?> </span>
3595
3596 <?php
3597 if (intval($post_limit) < '32') {
3598 echo wp_kses_post($no_icon);
3599 echo '<span class="label2" title="Min: 32M Recommended" bdt-tooltip>Currently: ' . wp_kses_post($post_limit) . '</span>';
3600 } else {
3601 echo wp_kses_post($yes_icon);
3602 echo '<span class="label2">Currently: ' . wp_kses_post($post_limit) . '</span>';
3603 }
3604 ?>
3605 </div>
3606 </li>
3607
3608 <li>
3609 <div>
3610 <span class="label1"><?php esc_html_e('Uploads folder writable:', 'ultimate-post-kit'); ?></span>
3611
3612 <?php
3613 if (!is_writable($upload_path)) {
3614 echo wp_kses_post($no_icon);
3615 } else {
3616 echo wp_kses_post($yes_icon);
3617 }
3618 ?>
3619 </div>
3620
3621 </li>
3622
3623 <li>
3624 <div>
3625 <span class="label1"><?php esc_html_e('MultiSite:', 'ultimate-post-kit'); ?></span>
3626
3627 <?php
3628 if ($environment['wp_multisite']) {
3629 echo wp_kses_post($yes_icon);
3630 echo '<span class="label2">' . esc_html__('MultiSite Enabled', 'ultimate-post-kit') . '</span>';
3631 } else {
3632 echo wp_kses_post($yes_icon);
3633 echo '<span class="label2">' . esc_html__('Single Site', 'ultimate-post-kit') . '</span>';
3634 }
3635 ?>
3636 </div>
3637 </li>
3638
3639 <li>
3640 <div>
3641 <span class="label1"><?php esc_html_e('GZip Enabled:', 'ultimate-post-kit'); ?></span>
3642
3643 <?php
3644 if ($environment['gzip_enabled']) {
3645 echo wp_kses_post($yes_icon);
3646 } else {
3647 echo wp_kses_post($no_icon);
3648 }
3649 ?>
3650 </div>
3651
3652 </li>
3653
3654 <li>
3655 <div>
3656 <span class="label1"><?php esc_html_e('Debug Mode:', 'ultimate-post-kit'); ?></span>
3657 <?php
3658 if ($environment['wp_debug_mode']) {
3659 echo wp_kses_post($no_icon);
3660 echo '<span class="label2">' . esc_html__('Currently Turned On', 'ultimate-post-kit') . '</span>';
3661 } else {
3662 echo wp_kses_post($yes_icon);
3663 echo '<span class="label2">' . esc_html__('Currently Turned Off', 'ultimate-post-kit') . '</span>';
3664 }
3665 ?>
3666 </div>
3667
3668 </li>
3669
3670 </ul>
3671
3672 <div class="bdt-admin-alert">
3673 <strong><?php esc_html_e('Note:', 'ultimate-post-kit'); ?></strong>
3674 <?php
3675 /* translators: %s: Plugin name 'Ultimate Post Kit' */
3676 printf(
3677 esc_html__('If you have multiple addons like %s so you may need to allocate additional memory for other addons as well.', 'ultimate-post-kit'),
3678 '<b>Ultimate Post Kit</b>'
3679 );
3680 ?>
3681 </div>
3682
3683 <?php
3684 }
3685
3686 /**
3687 * Others Plugin
3688 */
3689
3690 public function ultimate_post_kit_others_plugin() {
3691 // Include the Plugin Integration Helper and API Fetcher
3692 require_once BDTUPK_INC_PATH . 'setup-wizard/class-plugin-api-fetcher.php';
3693 require_once BDTUPK_INC_PATH . 'setup-wizard/class-plugin-integration-helper.php';
3694
3695 // Define plugin slugs to fetch data for (same as integration view)
3696 $plugin_slugs = array(
3697 'bdthemes-element-pack-lite',
3698 'bdthemes-prime-slider-lite',
3699 'ultimate-store-kit',
3700 'zoloblocks',
3701 'pixel-gallery',
3702 'live-copy-paste',
3703 'spin-wheel',
3704 'ai-image',
3705 'dark-reader',
3706 'ar-viewer',
3707 'smart-admin-assistant',
3708 'website-accessibility',
3709 );
3710
3711 // Get plugin data using the helper (same as integration view)
3712 $upk_plugins = \UltimatePostKit\SetupWizard\Plugin_Integration_Helper::build_plugin_data($plugin_slugs);
3713
3714 // Helper function for time formatting (same as integration view)
3715 if (!function_exists('format_last_updated')) {
3716 function format_last_updated($date_string) {
3717 if (empty($date_string)) {
3718 return __('Unknown', 'ultimate-post-kit');
3719 }
3720
3721 $date = strtotime($date_string);
3722 if (!$date) {
3723 return __('Unknown', 'ultimate-post-kit');
3724 }
3725
3726 $diff = current_time('timestamp') - $date;
3727
3728 if ($diff < 60) {
3729 return __('Just now', 'ultimate-post-kit');
3730 } elseif ($diff < 3600) {
3731 $minutes = floor($diff / 60);
3732 return sprintf(_n('%d minute ago', '%d minutes ago', $minutes, 'ultimate-post-kit'), $minutes);
3733 } elseif ($diff < 86400) {
3734 $hours = floor($diff / 3600);
3735 return sprintf(_n('%d hour ago', '%d hours ago', $hours, 'ultimate-post-kit'), $hours);
3736 } elseif ($diff < 2592000) { // 30 days
3737 $days = floor($diff / 86400);
3738 return sprintf(_n('%d day ago', '%d days ago', $days, 'ultimate-post-kit'), $days);
3739 } elseif ($diff < 31536000) { // 1 year
3740 $months = floor($diff / 2592000);
3741 return sprintf(_n('%d month ago', '%d months ago', $months, 'ultimate-post-kit'), $months);
3742 } else {
3743 $years = floor($diff / 31536000);
3744 return sprintf(_n('%d year ago', '%d years ago', $years, 'ultimate-post-kit'), $years);
3745 }
3746 }
3747 }
3748
3749 // Helper function for fallback URLs (same as integration view)
3750 if (!function_exists('get_plugin_fallback_urls')) {
3751 function get_plugin_fallback_urls($plugin_slug) {
3752 // Handle different plugin slug formats
3753 if (strpos($plugin_slug, '/') !== false) {
3754 // If it's a file path like 'plugin-name/plugin-name.php', extract directory
3755 $plugin_slug_clean = dirname($plugin_slug);
3756 } else {
3757 // If it's just the plugin directory name, use it directly
3758 $plugin_slug_clean = $plugin_slug;
3759 }
3760
3761 // Custom icon URLs for specific plugins that might not be on WordPress.org
3762 $custom_icons = [
3763 'bdthemes-element-pack-lite' => [
3764 'https://ps.w.org/bdthemes-element-pack-lite/assets/icon-256x256.png',
3765 'https://ps.w.org/bdthemes-element-pack-lite/assets/icon-128x128.png',
3766 ],
3767 'live-copy-paste' => [
3768 'https://ps.w.org/live-copy-paste/assets/icon-256x256.png',
3769 'https://ps.w.org/live-copy-paste/assets/icon-128x128.png',
3770 ],
3771 'spin-wheel' => [
3772 'https://ps.w.org/spin-wheel/assets/icon-256x256.png',
3773 'https://ps.w.org/spin-wheel/assets/icon-128x128.png',
3774 ],
3775 'ai-image' => [
3776 'https://ps.w.org/ai-image/assets/icon-256x256.png',
3777 'https://ps.w.org/ai-image/assets/icon-128x128.png',
3778 ],
3779 'smart-admin-assistant' => [
3780 'https://ps.w.org/smart-admin-assistant/assets/icon-256x256.png',
3781 'https://ps.w.org/smart-admin-assistant/assets/icon-128x128.png',
3782 ],
3783 'website-accessibility' => [
3784 'https://ps.w.org/website-accessibility/assets/icon-256x256.png',
3785 'https://ps.w.org/website-accessibility/assets/icon-128x128.png',
3786 ],
3787 ];
3788
3789 // Return custom icons if available, otherwise use default WordPress.org URLs
3790 if (isset($custom_icons[$plugin_slug_clean])) {
3791 return $custom_icons[$plugin_slug_clean];
3792 }
3793
3794 return [
3795 "https://ps.w.org/{$plugin_slug_clean}/assets/icon-256x256.gif", // Try GIF first
3796 "https://ps.w.org/{$plugin_slug_clean}/assets/icon-256x256.png", // Then PNG
3797 "https://ps.w.org/{$plugin_slug_clean}/assets/icon-128x128.gif", // Medium GIF
3798 "https://ps.w.org/{$plugin_slug_clean}/assets/icon-128x128.png", // Medium PNG
3799 ];
3800 }
3801 }
3802 ?>
3803 <div class="upk-dashboard-panel"
3804 bdt-scrollspy="target: > div > div > .bdt-card; cls: bdt-animation-slide-bottom-small; delay: 300">
3805 <div class="upk-dashboard-others-plugin">
3806
3807 <?php foreach ($upk_plugins as $plugin) :
3808 $is_active = is_plugin_active($plugin['slug']);
3809 // $is_recommended = $plugin['recommended'] && !$is_active;
3810
3811 // Get plugin logo with fallback
3812 $logo_url = $plugin['logo'] ?? '';
3813 $plugin_name = $plugin['name'] ?? '';
3814 $plugin_slug = $plugin['slug'] ?? '';
3815
3816 if (empty($logo_url) || !filter_var($logo_url, FILTER_VALIDATE_URL)) {
3817 // Generate fallback URLs for WordPress.org
3818 $actual_slug = str_replace('.php', '', basename($plugin_slug));
3819 $fallback_urls = get_plugin_fallback_urls($actual_slug);
3820 $logo_url = $fallback_urls[0];
3821 }
3822 ?>
3823
3824 <div class="bdt-card bdt-card-body bdt-flex bdt-flex-middle bdt-flex-between">
3825 <div class="bdt-others-plugin-content bdt-flex bdt-flex-middle">
3826 <div class="bdt-plugin-logo-wrap bdt-flex bdt-flex-middle">
3827 <div class="bdt-plugin-logo-container">
3828 <img src="<?php echo esc_url($logo_url); ?>"
3829 alt="<?php echo esc_attr($plugin_name); ?>"
3830 class="bdt-plugin-logo"
3831 onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
3832 <div class="default-plugin-icon" style="display:none;">📦</div>
3833 </div>
3834
3835 <div class="bdt-others-plugin-user-wrap bdt-flex bdt-flex-middle">
3836 <h1 class="upk-feature-title"><?php echo esc_html($plugin_name); ?></h1>
3837
3838 <!-- <?php //if ($is_active) : ?>
3839 <span class="bdt-others-plugin-active"><?php //esc_html_e('ACTIVE', 'ultimate-post-kit'); ?></span>
3840 <?php //endif; ?> -->
3841
3842 </div>
3843 </div>
3844 <div class="bdt-others-plugin-content-text">
3845
3846
3847
3848
3849
3850 <?php if (!empty($plugin['description'])) : ?>
3851 <p><?php echo esc_html($plugin['description']); ?></p>
3852 <?php endif; ?>
3853
3854 <span class="active-installs bdt-margin-small-top">
3855 <?php esc_html_e('Active Installs: ', 'ultimate-post-kit');
3856 // echo wp_kses_post($plugin['active_installs'] ?? '0');
3857 if (isset($plugin['active_installs_count']) && $plugin['active_installs_count'] > 0) {
3858 echo ' <span class="installs-count">' . number_format($plugin['active_installs_count']) . '+' . '</span>';
3859 } else {
3860 echo ' <span class="installs-count">Fewer than 10' . '</span>';
3861 }
3862 ?>
3863 </span>
3864
3865 <?php if (isset($plugin['downloaded_formatted']) && !empty($plugin['downloaded_formatted'])): ?>
3866 <div class="downloads bdt-margin-small-top">
3867 <span><?php esc_html_e('Downloads: ', 'ultimate-post-kit'); ?><?php echo esc_html($plugin['downloaded_formatted']); ?></span>
3868 </div>
3869 <?php endif; ?>
3870
3871 <div class="bdt-others-plugin-rating bdt-margin-small-top bdt-flex bdt-flex-middle">
3872 <span class="bdt-others-plugin-rating-stars">
3873 <?php
3874 $rating = floatval($plugin['rating'] ?? 0);
3875 $full_stars = floor($rating);
3876 $has_half_star = ($rating - $full_stars) >= 0.5;
3877 $empty_stars = 5 - $full_stars - ($has_half_star ? 1 : 0);
3878
3879 // Full stars
3880 for ($i = 0; $i < $full_stars; $i++) {
3881 echo '<i class="dashicons dashicons-star-filled"></i>';
3882 }
3883
3884 // Half star
3885 if ($has_half_star) {
3886 echo '<i class="dashicons dashicons-star-half"></i>';
3887 }
3888
3889 // Empty stars
3890 for ($i = 0; $i < $empty_stars; $i++) {
3891 echo '<i class="dashicons dashicons-star-empty"></i>';
3892 }
3893 ?>
3894 </span>
3895 <span class="bdt-others-plugin-rating-text bdt-margin-small-left">
3896 <?php echo esc_html($plugin['rating'] ?? '0'); ?> <?php esc_html_e('out of 5 stars.', 'ultimate-post-kit'); ?>
3897 <?php if (isset($plugin['num_ratings']) && $plugin['num_ratings'] > 0): ?>
3898 <span class="rating-count">(<?php echo number_format($plugin['num_ratings']); ?> <?php esc_html_e('ratings', 'ultimate-post-kit'); ?>)</span>
3899 <?php endif; ?>
3900 </span>
3901 </div>
3902
3903 <?php if (isset($plugin['last_updated']) && !empty($plugin['last_updated'])): ?>
3904 <div class="bdt-others-plugin-updated bdt-margin-small-top">
3905 <span><?php esc_html_e('Last Updated: ', 'ultimate-post-kit'); ?><?php echo esc_html(format_last_updated($plugin['last_updated'])); ?></span>
3906 </div>
3907 <?php endif; ?>
3908 </div>
3909 </div>
3910
3911 <div class="bdt-others-plugins-link">
3912 <?php echo $this->get_plugin_action_button($plugin['slug'], 'https://wordpress.org/plugins/' . dirname($plugin['slug']) . '/'); ?>
3913 <?php if (!empty($plugin['homepage'])) : ?>
3914 <a class="bdt-button bdt-dashboard-sec-btn" target="_blank" href="<?php echo esc_url($plugin['homepage']); ?>">
3915 <?php esc_html_e('Learn More', 'ultimate-post-kit'); ?>
3916 </a>
3917 <?php endif; ?>
3918 </div>
3919 </div>
3920
3921 <?php endforeach; ?>
3922 </div>
3923 </div>
3924 <?php
3925 }
3926
3927 /**
3928 * Check plugin status (installed, active, or not installed)
3929 *
3930 * @param string $plugin_path Plugin file path
3931 * @return string 'active', 'installed', or 'not_installed'
3932 */
3933 private function get_plugin_status($plugin_path) {
3934 // Check if plugin is active
3935 if (is_plugin_active($plugin_path)) {
3936 return 'active';
3937 }
3938
3939 // Check if plugin is installed but not active
3940 $installed_plugins = get_plugins();
3941 if (isset($installed_plugins[$plugin_path])) {
3942 return 'installed';
3943 }
3944
3945 // Plugin is not installed
3946 return 'not_installed';
3947 }
3948
3949 /**
3950 * AJAX handler for saving custom code
3951 *
3952 * @access public
3953 * @return void
3954 */
3955 public function save_custom_code_ajax() {
3956 // Verify nonce
3957 if ( ! wp_verify_nonce( $_POST['nonce'] ?? '', 'upk_custom_code_nonce' ) ) {
3958 wp_send_json_error( [ 'message' => 'Invalid security token.' ] );
3959 }
3960
3961 // Check user capability
3962 if ( ! current_user_can( 'manage_options' ) ) {
3963 wp_send_json_error( [ 'message' => 'Insufficient permissions.' ] );
3964 }
3965
3966 // Sanitize and save the custom code
3967 $custom_css = isset( $_POST['custom_css'] ) ? wp_unslash( $_POST['custom_css'] ) : '';
3968 $custom_js = isset( $_POST['custom_js'] ) ? wp_unslash( $_POST['custom_js'] ) : '';
3969 $custom_css_2 = isset( $_POST['custom_css_2'] ) ? wp_unslash( $_POST['custom_css_2'] ) : '';
3970 $custom_js_2 = isset( $_POST['custom_js_2'] ) ? wp_unslash( $_POST['custom_js_2'] ) : '';
3971
3972 // Handle excluded pages - ensure we get proper array format
3973 $excluded_pages = array();
3974 if ( isset( $_POST['excluded_pages'] ) ) {
3975 if ( is_array( $_POST['excluded_pages'] ) ) {
3976 $excluded_pages = $_POST['excluded_pages'];
3977 } elseif ( is_string( $_POST['excluded_pages'] ) && ! empty( $_POST['excluded_pages'] ) ) {
3978 // Handle case where it might be a single value
3979 $excluded_pages = [ $_POST['excluded_pages'] ];
3980 }
3981 }
3982
3983 // Sanitize excluded pages - convert to integers and remove empty values
3984 $excluded_pages = array_map( 'intval', $excluded_pages );
3985 $excluded_pages = array_filter( $excluded_pages, function( $page_id ) {
3986 return $page_id > 0;
3987 } );
3988
3989 // Save to database
3990 update_option( 'upk_custom_css', $custom_css );
3991 update_option( 'upk_custom_js', $custom_js );
3992 update_option( 'upk_custom_css_2', $custom_css_2 );
3993 update_option( 'upk_custom_js_2', $custom_js_2 );
3994 update_option( 'upk_excluded_pages', $excluded_pages );
3995
3996 wp_send_json_success( [
3997 'message' => 'Custom code saved successfully!',
3998 'excluded_count' => count( $excluded_pages )
3999 ] );
4000 }
4001
4002 /**
4003 * Handle AJAX plugin installation
4004 *
4005 * @access public
4006 * @return void
4007 */
4008 public function install_plugin_ajax() {
4009 // Check nonce
4010 if (!wp_verify_nonce($_POST['nonce'], 'upk_install_plugin_nonce')) {
4011 wp_send_json_error(['message' => __('Security check failed', 'ultimate-post-kit')]);
4012 }
4013
4014 // Check user capability
4015 if (!current_user_can('install_plugins')) {
4016 wp_send_json_error(['message' => __('You do not have permission to install plugins', 'ultimate-post-kit')]);
4017 }
4018
4019 $plugin_slug = sanitize_text_field($_POST['plugin_slug']);
4020
4021 if (empty($plugin_slug)) {
4022 wp_send_json_error(['message' => __('Plugin slug is required', 'ultimate-post-kit')]);
4023 }
4024
4025 // Include necessary WordPress files
4026 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
4027 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
4028 require_once ABSPATH . 'wp-admin/includes/class-wp-ajax-upgrader-skin.php';
4029
4030 // Get plugin information
4031 $api = plugins_api('plugin_information', [
4032 'slug' => $plugin_slug,
4033 'fields' => [
4034 'sections' => false,
4035 ],
4036 ]);
4037
4038 if (is_wp_error($api)) {
4039 wp_send_json_error(['message' => __('Plugin not found: ', 'ultimate-post-kit') . $api->get_error_message()]);
4040 }
4041
4042 // Install the plugin
4043 $skin = new \WP_Ajax_Upgrader_Skin();
4044 $upgrader = new \Plugin_Upgrader($skin);
4045 $result = $upgrader->install($api->download_link);
4046
4047 if (is_wp_error($result)) {
4048 wp_send_json_error(['message' => __('Installation failed: ', 'ultimate-post-kit') . $result->get_error_message()]);
4049 } elseif ($skin->get_errors()->has_errors()) {
4050 wp_send_json_error(['message' => __('Installation failed: ', 'ultimate-post-kit') . $skin->get_error_messages()]);
4051 } elseif (is_null($result)) {
4052 wp_send_json_error(['message' => __('Installation failed: Unable to connect to filesystem', 'ultimate-post-kit')]);
4053 }
4054
4055 // Get installation status
4056 $install_status = install_plugin_install_status($api);
4057
4058 wp_send_json_success([
4059 'message' => __('Plugin installed successfully!', 'ultimate-post-kit'),
4060 'plugin_file' => $install_status['file'],
4061 'plugin_name' => $api->name
4062 ]);
4063 }
4064
4065 /**
4066 * Extract plugin slug from plugin path
4067 *
4068 * @param string $plugin_path Plugin file path
4069 * @return string Plugin slug
4070 */
4071 private function extract_plugin_slug_from_path($plugin_path) {
4072 $parts = explode('/', $plugin_path);
4073 return isset($parts[0]) ? $parts[0] : '';
4074 }
4075
4076 /**
4077 * Get plugin action button HTML based on plugin status
4078 *
4079 * @param string $plugin_path Plugin file path
4080 * @param string $install_url Plugin installation URL
4081 * @param string $plugin_slug Plugin slug for activation
4082 * @return string Button HTML
4083 */
4084 private function get_plugin_action_button($plugin_path, $install_url, $plugin_slug = '') {
4085 $status = $this->get_plugin_status($plugin_path);
4086
4087 switch ($status) {
4088 case 'active':
4089 return '';
4090
4091 case 'installed':
4092 $activate_url = wp_nonce_url(
4093 add_query_arg([
4094 'action' => 'activate',
4095 'plugin' => $plugin_path
4096 ], admin_url('plugins.php')),
4097 'activate-plugin_' . $plugin_path
4098 );
4099 return '<a class="bdt-button bdt-welcome-button" href="' . esc_url($activate_url) . '">' .
4100 __('Activate', 'ultimate-post-kit') . '</a>';
4101
4102 case 'not_installed':
4103 default:
4104 $plugin_slug = $this->extract_plugin_slug_from_path($plugin_path);
4105 $nonce = wp_create_nonce('upk_install_plugin_nonce');
4106 return '<a class="bdt-button bdt-welcome-button upk-install-plugin"
4107 data-plugin-slug="' . esc_attr($plugin_slug) . '"
4108 data-nonce="' . esc_attr($nonce) . '"
4109 href="#">' .
4110 __('Install', 'ultimate-post-kit') . '</a>';
4111 }
4112 }
4113
4114 /**
4115 * Extra Options Start Here
4116 */
4117
4118 /**
4119 * Render Custom CSS & JS Section
4120 *
4121 * @access public
4122 * @return void
4123 */
4124 public function render_custom_css_js_section() {
4125 ?>
4126 <div class="upk-custom-code-section">
4127 <!-- Header Section -->
4128 <div class="upk-code-section-header">
4129 <h2 class="upk-section-title"><?php esc_html_e('Header Code Injection', 'ultimate-post-kit'); ?></h2>
4130 <p class="upk-section-description"><?php esc_html_e('Code added here will be injected into the &lt;head&gt; section of your website.', 'ultimate-post-kit'); ?></p>
4131 </div>
4132 <div class="upk-code-row bdt-grid bdt-grid-small" bdt-grid>
4133 <div class="bdt-width-1-2@m">
4134 <div class="upk-code-editor-wrapper">
4135 <h3 class="upk-code-editor-title"><?php esc_html_e('CSS', 'ultimate-post-kit'); ?></h3>
4136 <p class="upk-code-editor-description"><?php esc_html_e('Enter raw CSS code without &lt;style&gt; tags.', 'ultimate-post-kit'); ?></p>
4137 <div class="upk-codemirror-editor-container">
4138 <textarea id="upk-custom-css" name="upk_custom_css" class="upk-code-editor" data-mode="css" placeholder=".example {&#10; background: red;&#10; border-radius: 5px;&#10; padding: 15px;&#10;}&#10;&#10;"><?php echo esc_textarea(get_option('upk_custom_css', '')); ?></textarea>
4139 </div>
4140 </div>
4141 </div>
4142 <div class="bdt-width-1-2@m">
4143 <div class="upk-code-editor-wrapper">
4144 <h3 class="upk-code-editor-title"><?php esc_html_e('JS', 'ultimate-post-kit'); ?></h3>
4145 <p class="upk-code-editor-description"><?php esc_html_e('Enter raw JavaScript code without &lt;script&gt; tags.', 'ultimate-post-kit'); ?></p>
4146 <div class="upk-codemirror-editor-container">
4147 <textarea id="upk-custom-js" name="upk_custom_js" class="upk-code-editor" data-mode="javascript" placeholder="alert('Hello, Ultimate Post Kit!');"><?php echo esc_textarea(get_option('upk_custom_js', '')); ?></textarea>
4148 </div>
4149 </div>
4150 </div>
4151 </div>
4152
4153 <!-- Footer Section -->
4154 <div class="upk-code-section-header bdt-margin-medium-top">
4155 <h2 class="upk-section-title"><?php esc_html_e('Footer Code Injection', 'ultimate-post-kit'); ?></h2>
4156 <p class="upk-section-description"><?php esc_html_e('Code added here will be injected before the closing &lt;/body&gt; tag of your website.', 'ultimate-post-kit'); ?></p>
4157 </div>
4158 <div class="upk-code-row bdt-grid bdt-grid-small bdt-margin-small-top" bdt-grid>
4159 <div class="bdt-width-1-2@m">
4160 <div class="upk-code-editor-wrapper">
4161 <h3 class="upk-code-editor-title"><?php esc_html_e('CSS', 'ultimate-post-kit'); ?></h3>
4162 <p class="upk-code-editor-description"><?php esc_html_e('Enter raw CSS code without &lt;style&gt; tags.', 'ultimate-post-kit'); ?></p>
4163 <div class="upk-codemirror-editor-container">
4164 <textarea id="upk-custom-css-2" name="upk_custom_css_2" class="upk-code-editor" data-mode="css" placeholder=".example {&#10; background: green;&#10;}&#10;&#10;"><?php echo esc_textarea(get_option('upk_custom_css_2', '')); ?></textarea>
4165 </div>
4166 </div>
4167 </div>
4168 <div class="bdt-width-1-2@m">
4169 <div class="upk-code-editor-wrapper">
4170 <h3 class="upk-code-editor-title"><?php esc_html_e('JS', 'ultimate-post-kit'); ?></h3>
4171 <p class="upk-code-editor-description"><?php esc_html_e('Enter raw JavaScript code without &lt;script&gt; tags.', 'ultimate-post-kit'); ?></p>
4172 <div class="upk-codemirror-editor-container">
4173 <textarea id="upk-custom-js-2" name="upk_custom_js_2" class="upk-code-editor" data-mode="javascript" placeholder="console.log('Hello, Ultimate Post Kit!');"><?php echo esc_textarea(get_option('upk_custom_js_2', '')); ?></textarea>
4174 </div>
4175 </div>
4176 </div>
4177 </div>
4178
4179 <!-- Page Exclusion Section -->
4180 <div class="upk-code-section-header bdt-margin-medium-top">
4181 <h2 class="upk-section-title"><?php esc_html_e('Page & Post Exclusion Settings', 'ultimate-post-kit'); ?></h2>
4182 <p class="upk-section-description"><?php esc_html_e('Select pages and posts where you don\'t want any custom code to be injected. This applies to all sections above.', 'ultimate-post-kit'); ?></p>
4183 </div>
4184 <div class="upk-page-exclusion-wrapper">
4185 <label for="upk-excluded-pages" class="upk-exclusion-label">
4186 <?php esc_html_e('Exclude Pages & Posts:', 'ultimate-post-kit'); ?>
4187 </label>
4188 <select id="upk-excluded-pages" name="upk_excluded_pages[]" multiple class="upk-page-select">
4189 <option value=""><?php esc_html_e('-- Select pages/posts to exclude --', 'ultimate-post-kit'); ?></option>
4190 <?php
4191 $excluded_pages = get_option('upk_excluded_pages', array());
4192 if (!is_array($excluded_pages)) {
4193 $excluded_pages = array();
4194 }
4195
4196 // Get all published pages
4197 $pages = get_pages(array(
4198 'sort_order' => 'ASC',
4199 'sort_column' => 'post_title',
4200 'post_status' => 'publish'
4201 ));
4202
4203 // Get recent posts (last 50)
4204 $posts = get_posts(array(
4205 'numberposts' => 50,
4206 'post_status' => 'publish',
4207 'post_type' => 'post',
4208 'orderby' => 'date',
4209 'order' => 'DESC'
4210 ));
4211
4212 // Display pages first
4213 if (!empty($pages)) {
4214 echo '<optgroup label="' . esc_attr__('Pages', 'ultimate-post-kit') . '">';
4215 foreach ($pages as $page) {
4216 $selected = in_array($page->ID, $excluded_pages) ? 'selected' : '';
4217 echo '<option value="' . esc_attr($page->ID) . '" ' . $selected . '>' . esc_html($page->post_title) . '</option>';
4218 }
4219 echo '</optgroup>';
4220 }
4221
4222 // Then display posts
4223 if (!empty($posts)) {
4224 echo '<optgroup label="' . esc_attr__('Recent Posts', 'ultimate-post-kit') . '">';
4225 foreach ($posts as $post) {
4226 $selected = in_array($post->ID, $excluded_pages) ? 'selected' : '';
4227 $post_date = date('M j, Y', strtotime($post->post_date));
4228 echo '<option value="' . esc_attr($post->ID) . '" ' . $selected . '>' . esc_html($post->post_title) . ' (' . $post_date . ')</option>';
4229 }
4230 echo '</optgroup>';
4231 }
4232 ?>
4233 </select>
4234 <p class="upk-exclusion-help">
4235 <?php esc_html_e('Hold Ctrl (or Cmd on Mac) to select multiple items. Selected pages and posts will not load any custom CSS or JavaScript code. The list shows all pages and the 50 most recent posts.', 'ultimate-post-kit'); ?>
4236 </p>
4237 </div>
4238
4239 <!-- Success/Error Messages -->
4240 <div id="upk-custom-code-message" class="upk-code-message bdt-margin-small-top" style="display: none;">
4241 <div class="bdt-alert bdt-alert-success" bdt-alert>
4242 <a href class="bdt-alert-close" bdt-close></a>
4243 <p><?php esc_html_e('Custom code saved successfully!', 'ultimate-post-kit'); ?></p>
4244 </div>
4245 </div>
4246 </div>
4247 <?php
4248 }
4249
4250 /**
4251 * Extra Options Start Here
4252 */
4253
4254 public function ultimate_post_kit_extra_options() {
4255 ?>
4256 <div class="upk-dashboard-panel"
4257 bdt-scrollspy="target: > div > div > .bdt-card; cls: bdt-animation-slide-bottom-small; delay: 300">
4258 <div class="upk-dashboard-extra-options">
4259 <div class="bdt-card bdt-card-body">
4260 <h1 class="upk-feature-title"><?php esc_html_e('Extra Options', 'ultimate-post-kit'); ?></h1>
4261
4262 <div class="upk-extra-options-tabs">
4263 <ul class="bdt-tab" bdt-tab="connect: #upk-extra-options-tab-content; animation: bdt-animation-fade">
4264 <li class="bdt-active"><a
4265 href="#"><?php esc_html_e('Custom CSS & JS', 'ultimate-post-kit'); ?></a></li>
4266 <li><a href="#"><?php esc_html_e('White Label', 'ultimate-post-kit'); ?></a></li>
4267 </ul>
4268
4269 <div id="upk-extra-options-tab-content" class="bdt-switcher">
4270 <!-- Custom CSS & JS Tab -->
4271 <div>
4272 <?php $this->render_custom_css_js_section(); ?>
4273 </div>
4274
4275 <!-- White Label Tab -->
4276 <div>
4277 <?php $this->render_white_label_section(); ?>
4278 </div>
4279 </div>
4280 </div>
4281 </div>
4282 </div>
4283 </div>
4284 <?php
4285 }
4286
4287
4288 /**
4289 * Rollback Version Content
4290 *
4291 * @access public
4292 * @return void
4293 */
4294 public function ultimate_post_kit_rollback_version_content() {
4295 // Use the already initialized rollback version instance
4296 $this->rollback_version->ultimate_post_kit_rollback_version_content();
4297 }
4298
4299 /**
4300 * Get allowed white label license types (SHA-256 hashes)
4301 * This centralized method makes it easy to add new license types in the future
4302 * Note: AppSumo and Lifetime licenses require WL flag in other_param instead of automatic access
4303 *
4304 * @access public static
4305 * @return array Array of SHA-256 hashes for allowed license types
4306 */
4307 public static function get_white_label_allowed_license_types() {
4308 $allowed_types = [
4309 'agency' => 'c4b2af4722ee54e317672875b2d8cf49aa884bf5820ec6091114fea5ec6560e4',
4310 'extended' => '4d7120eb6c796b04273577476eb2e20c34c51d7fa1025ec19c3414448abc241e',
4311 'developer' => '88fa0d759f845b47c044c2cd44e29082cf6fea665c30c146374ec7c8f3d699e3',
4312 // Note: AppSumo and Lifetime licenses removed from automatic access
4313 // They require WL flag in other_param for white label functionality
4314 ];
4315
4316 return $allowed_types;
4317 }
4318
4319 /**
4320 * Revoke white label access token
4321 *
4322 * @access public
4323 * @return bool
4324 */
4325 public function revoke_white_label_access_token() {
4326 $token_data = get_option( 'upk_white_label_access_token', [] );
4327
4328 if ( ! empty( $token_data ) ) {
4329 delete_option( 'upk_white_label_access_token' );
4330 return true;
4331 }
4332
4333 return false;
4334 }
4335
4336 /**
4337 * Validate white label access token
4338 *
4339 * @access public
4340 * @param string $token
4341 * @return bool
4342 */
4343 public function validate_white_label_access_token( $token ) {
4344 $stored_token_data = get_option( 'upk_white_label_access_token', [] );
4345
4346 if ( empty( $stored_token_data ) || ! isset( $stored_token_data['token'] ) ) {
4347 return false;
4348 }
4349
4350 // Check token match
4351 if ( $stored_token_data['token'] !== $token ) {
4352 return false;
4353 }
4354
4355 // Check if token was generated for current license
4356 $current_license_key = self::get_license_key();
4357 if ( $stored_token_data['license_key'] !== $current_license_key ) {
4358 return false;
4359 }
4360
4361 return true;
4362 }
4363
4364 /**
4365 * AJAX handler for revoking white label access token
4366 *
4367 * @access public
4368 * @return void
4369 */
4370 public function revoke_white_label_token_ajax() {
4371 // Check nonce and permissions
4372 if (!wp_verify_nonce($_POST['nonce'], 'upk_white_label_nonce')) {
4373 wp_send_json_error(['message' => __('Security check failed', 'ultimate-post-kit')]);
4374 }
4375
4376 if (!current_user_can('manage_options')) {
4377 wp_send_json_error(['message' => __('You do not have permission to manage white label settings', 'ultimate-post-kit')]);
4378 }
4379
4380 // Check license eligibility
4381 if (!self::is_white_label_license()) {
4382 wp_send_json_error(['message' => __('Your license does not support white label features', 'ultimate-post-kit')]);
4383 }
4384
4385 // Revoke the token
4386 $revoked = $this->revoke_white_label_access_token();
4387
4388 if ($revoked) {
4389 wp_send_json_success([
4390 'message' => __('White label access token has been revoked successfully', 'ultimate-post-kit')
4391 ]);
4392 } else {
4393 wp_send_json_error([
4394 'message' => __('No active access token found to revoke', 'ultimate-post-kit')
4395 ]);
4396 }
4397 }
4398
4399 /**
4400 * Get License Key
4401 *
4402 * @access public
4403 * @return string
4404 */
4405
4406 public static function get_license_key() {
4407 $license_key = get_option('ultimate_post_kit_license_key');
4408 return trim($license_key);
4409 }
4410
4411 /**
4412 * Get License Email
4413 *
4414 * @access public
4415 * @return string
4416 */
4417
4418 public static function get_license_email() {
4419 return trim(get_option('ultimate_post_kit_license_email', get_bloginfo('admin_email')));
4420 }
4421
4422 }
4423
4424 new UltimatePostKit_Admin_Settings();
4425