PluginProbe
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets / trunk
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets vtrunk
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
← All changes | admin/admin-settings.php +85 -2034 4.1.14trunk View file →
@@ -5,9 +5,13 @@
5 5 use UltimatePostKit\Admin\ModuleService;
6 6 use Elementor\Modules\Usage\Module;
7 7 use Elementor\Tracker;
8 8
9 +if (!defined('ABSPATH')) {
10 + exit; // Exit if accessed directly.
11 +}
9 12
13 +
10 14 /**
11 15 * Ultimate Post Kit Admin Settings Class
12 16 */
13 17
@@ -45,19 +49,8 @@
45 49 add_action('admin_init', [$this, 'admin_init']);
46 50 add_action('admin_menu', [$this, 'admin_menu'], 201);
47 51 }
48 52
49 - // Handle white label access link
50 - $this->handle_white_label_access();
51 -
52 - // Add custom CSS/JS functionality
53 - $this->init_custom_code_functionality();
54 -
55 - // White label settings (admin only)
56 - add_action( 'wp_ajax_upk_save_white_label', [ $this, 'save_white_label_ajax' ] );
57 - add_action( 'wp_ajax_upk_revoke_white_label_token', [ $this, 'revoke_white_label_token_ajax' ] );
58 - add_action( 'admin_head', [ $this, 'inject_white_label_icon_css' ] );
59 -
60 53 // Plugin installation (admin only)
61 54 add_action('wp_ajax_upk_install_plugin', [$this, 'install_plugin_ajax']);
62 55
63 56
@@ -74,441 +67,8 @@
74 67 $this->rollback_version = new \UltimatePostKitPro\Rollback_Version();
75 68 }
76 69 }
77 70
78 -
79 -
80 -
81 - /**
82 - * Initialize Custom Code Functionality
83 - *
84 - * @access public
85 - * @return void
86 - */
87 - public function init_custom_code_functionality() {
88 - // AJAX handler for saving custom code (admin only)
89 - add_action( 'wp_ajax_upk_save_custom_code', [ $this, 'save_custom_code_ajax' ] );
90 -
91 -
92 - // Admin scripts (admin only)
93 - add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_custom_code_scripts' ] );
94 -
95 - // Frontend injection is now handled by global functions in the main plugin file
96 - self::init_frontend_injection();
97 - }
98 -
99 - /**
100 - * Initialize frontend injection hooks (works on both admin and frontend)
101 - *
102 - * @access public static
103 - * @return void
104 - */
105 - public static function init_frontend_injection() {
106 - // Frontend hooks are now registered in the main plugin file
107 - // This method is kept for backwards compatibility but does nothing
108 - }
109 -
110 - /**
111 - * Enqueue scripts for custom code editor
112 - *
113 - * @access public
114 - * @return void
115 - */
116 - public function enqueue_custom_code_scripts( $hook ) {
117 - if ( $hook !== 'toplevel_page_ultimate_post_kit_options' ) {
118 - return;
119 - }
120 -
121 - // Enqueue WordPress built-in CodeMirror
122 - wp_enqueue_code_editor( array( 'type' => 'text/css' ) );
123 - wp_enqueue_code_editor( array( 'type' => 'application/javascript' ) );
124 -
125 - // Enqueue WordPress media library scripts
126 - wp_enqueue_media();
127 -
128 - // Enqueue the admin script if it exists
129 - $admin_script_path = BDTUPK_ASSETS_PATH . 'js/upk-admin.js';
130 - if ( file_exists( $admin_script_path ) ) {
131 - wp_enqueue_script(
132 - 'upk-admin-script',
133 - BDTUPK_ASSETS_URL . 'js/upk-admin.js',
134 - [ 'jquery', 'media-upload', 'media-views', 'code-editor' ],
135 - BDTUPK_VER,
136 - true
137 - );
138 -
139 - // Localize script with AJAX data
140 - wp_localize_script( 'upk-admin-script', 'upk_admin_ajax', [
141 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
142 - 'nonce' => wp_create_nonce( 'upk_custom_code_nonce' ),
143 - 'white_label_nonce' => wp_create_nonce( 'upk_white_label_nonce' )
144 - ] );
145 - } else {
146 - // Fallback: localize to jquery if the admin script doesn't exist
147 - wp_localize_script( 'jquery', 'upk_admin_ajax', [
148 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
149 - 'nonce' => wp_create_nonce( 'upk_custom_code_nonce' ),
150 - 'white_label_nonce' => wp_create_nonce( 'upk_white_label_nonce' )
151 - ] );
152 - }
153 - }
154 -
155 - /**
156 - * AJAX handler for saving white label settings
157 - *
158 - * @access public
159 - * @return void
160 - */
161 - public function save_white_label_ajax() {
162 -
163 - // Check nonce and permissions
164 - if (!wp_verify_nonce($_POST['nonce'], 'upk_white_label_nonce')) {
165 - wp_send_json_error(['message' => __('Security check failed', 'ultimate-post-kit')]);
166 - }
167 -
168 - if (!current_user_can('manage_options')) {
169 - wp_send_json_error(['message' => __('You do not have permission to manage white label settings', 'ultimate-post-kit')]);
170 - }
171 -
172 - // Check license eligibility
173 - if (!self::is_white_label_license()) {
174 - wp_send_json_error(['message' => __('Your license does not support white label features', 'ultimate-post-kit')]);
175 - }
176 -
177 - // Get white label settings
178 - $white_label_enabled = isset($_POST['upk_white_label_enabled']) ? (bool) $_POST['upk_white_label_enabled'] : false;
179 - $hide_license = isset($_POST['upk_white_label_hide_license']) ? (bool) $_POST['upk_white_label_hide_license'] : false;
180 - $bdtupk_hide = isset($_POST['upk_white_label_bdtupk_hide']) ? (bool) $_POST['upk_white_label_bdtupk_hide'] : false;
181 - $white_label_title = isset($_POST['upk_white_label_title']) ? sanitize_text_field($_POST['upk_white_label_title']) : '';
182 - $white_label_icon = isset($_POST['upk_white_label_icon']) ? esc_url_raw($_POST['upk_white_label_icon']) : '';
183 - $white_label_icon_id = isset($_POST['upk_white_label_icon_id']) ? absint($_POST['upk_white_label_icon_id']) : 0;
184 - $white_label_logo = isset($_POST['upk_white_label_logo']) ? esc_url_raw($_POST['upk_white_label_logo']) : '';
185 - $upk_white_label_logo_id = isset($_POST['upk_white_label_logo_id']) ? absint($_POST['upk_white_label_logo_id']) : 0;
186 -
187 - // Save settings
188 - update_option('upk_white_label_enabled', $white_label_enabled);
189 - update_option('upk_white_label_hide_license', $hide_license);
190 - update_option('upk_white_label_bdtupk_hide', $bdtupk_hide);
191 - update_option('upk_white_label_title', $white_label_title);
192 - update_option('upk_white_label_icon', $white_label_icon);
193 - update_option('upk_white_label_icon_id', $white_label_icon_id);
194 - update_option('upk_white_label_logo', $white_label_logo);
195 - update_option('upk_white_label_logo_id', $upk_white_label_logo_id);
196 -
197 - // Set license title status
198 - if ($white_label_enabled) {
199 - update_option('ultimate_post_kit_license_title_status', true);
200 - } else {
201 - delete_option('ultimate_post_kit_license_title_status');
202 - }
203 -
204 - // Only send access email if both white label mode AND BDTUPK_HIDE are enabled
205 - if ($white_label_enabled && $bdtupk_hide) {
206 - $email_sent = $this->send_white_label_access_email();
207 - }
208 -
209 - wp_send_json_success([
210 - 'message' => __('White label settings saved successfully', 'ultimate-post-kit'),
211 - 'bdtupk_hide' => $bdtupk_hide,
212 - 'email_sent' => isset($email_sent) ? $email_sent : false
213 - ]);
214 - }
215 -
216 - /**
217 - * Send white label access email with special link
218 - *
219 - * @access private
220 - * @return bool
221 - */
222 - private function send_white_label_access_email() {
223 -
224 - $license_email = self::get_license_email();
225 - $admin_email = get_bloginfo( 'admin_email' );
226 - $license_key = self::get_license_key();
227 - $site_name = get_bloginfo( 'name' );
228 - $site_url = get_bloginfo( 'url' );
229 -
230 - // Generate secure access token with additional entropy
231 - $access_token = wp_hash( $license_key . time() . wp_salt() . wp_generate_password( 32, false ) );
232 -
233 - // Store access token in database with no expiration
234 - $token_data = [
235 - 'token' => $access_token,
236 - 'license_key' => $license_key,
237 - 'created_at' => current_time( 'timestamp' ),
238 - 'user_id' => get_current_user_id()
239 - ];
240 -
241 - update_option( 'upk_white_label_access_token', $token_data );
242 -
243 - // Generate access URL using token instead of license key for security
244 - // Add white_label_tab=1 parameter to automatically switch to White Label tab
245 - $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' );
246 -
247 - // Email subject
248 - $subject = sprintf(
249 - /* translators: %s: Site name. */
250 - __( '[%s] Ultimate Post Kit White Label Access Instructions', 'ultimate-post-kit' ),
251 - $site_name
252 - );
253 -
254 - // Email message
255 - $message = $this->get_white_label_email_template( $site_name, $site_url, $access_url, $license_key );
256 -
257 - // Email headers
258 - $headers = [
259 - 'Content-Type: text/html; charset=UTF-8',
260 - 'From: ' . $site_name . ' <' . $admin_email . '>'
261 - ];
262 -
263 - $email_sent = false;
264 -
265 - // Send to license email
266 - if ( ! empty( $license_email ) && is_email( $license_email ) ) {
267 - $email_sent = wp_mail( $license_email, $subject, $message, $headers );
268 -
269 - // If on localhost or email failed, save email content for manual access
270 - if ( ! $email_sent || $this->is_localhost() ) {
271 - $this->save_email_content_for_localhost( $access_url, $message, $license_email );
272 - }
273 - }
274 -
275 - return $email_sent;
276 - }
277 -
278 - /**
279 - * Check if running on localhost
280 - *
281 - * @access private
282 - * @return bool
283 - */
284 - private function is_localhost() {
285 - $server_name = $_SERVER['SERVER_NAME'] ?? '';
286 - $server_addr = $_SERVER['SERVER_ADDR'] ?? '';
287 -
288 - $localhost_indicators = [
289 - 'localhost',
290 - '127.0.0.1',
291 - '::1',
292 - '.local',
293 - '.test',
294 - '.dev'
295 - ];
296 -
297 - foreach ( $localhost_indicators as $indicator ) {
298 - if ( strpos( $server_name, $indicator ) !== false ||
299 - strpos( $server_addr, $indicator ) !== false ) {
300 - return true;
301 - }
302 - }
303 -
304 - return false;
305 - }
306 -
307 - /**
308 - * Save email content for localhost testing
309 - *
310 - * @access private
311 - * @param string $access_url
312 - * @param string $email_content
313 - * @param string $recipient_email
314 - * @return void
315 - */
316 - private function save_email_content_for_localhost( $access_url, $email_content, $recipient_email ) {
317 - $email_data = [
318 - 'access_url' => $access_url,
319 - 'email_content' => $email_content,
320 - 'recipient_email' => $recipient_email,
321 - 'message' => __( 'Email functionality is not available on localhost. Use the access URL below:', 'ultimate-post-kit' ),
322 - ];
323 -
324 - // Save for admin notice display
325 - update_option( 'upk_localhost_email_data', $email_data );
326 - }
327 -
328 - /**
329 - * Get white label email template
330 - *
331 - * @access private
332 - * @param string $site_name
333 - * @param string $site_url
334 - * @param string $access_url
335 - * @param string $license_key
336 - * @return string
337 - */
338 - private function get_white_label_email_template( $site_name, $site_url, $access_url, $license_key ) {
339 - $masked_license = substr( $license_key, 0, 8 ) . '****-****-****-' . substr( $license_key, -4 );
340 -
341 - ob_start();
342 - ?>
343 - <!DOCTYPE html>
344 - <html>
345 - <head>
346 - <meta charset="UTF-8">
347 - <title><?php echo esc_html__( 'Ultimate Post Kit White Label Access', 'ultimate-post-kit' ); ?></title>
348 - <style>
349 - body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
350 - .container { max-width: 600px; margin: 0 auto; padding: 20px; }
351 - .header { background: #2196F3; color: white; padding: 20px; text-align: center; border-radius: 8px 8px 0 0; }
352 - .content { background: #f9f9f9; padding: 30px; border-radius: 0 0 8px 8px; }
353 - .access-link { background: #2196F3; color: white; padding: 15px 25px; text-decoration: none; border-radius: 5px; display: inline-block; margin: 20px 0; }
354 - .warning { background: #fff3cd; border: 1px solid #ffeaa7; padding: 15px; border-radius: 5px; margin: 20px 0; }
355 - .footer { margin-top: 30px; padding-top: 20px; border-top: 1px solid #ddd; font-size: 12px; color: #666; }
356 - </style>
357 - </head>
358 - <body>
359 - <div class="container">
360 - <div class="header">
361 - <h1><?php echo esc_html__( '🔒 Ultimate Post Kit White Label Access', 'ultimate-post-kit' ); ?></h1>
362 - </div>
363 - <div class="content">
364 - <h2><?php echo esc_html__( 'Important: Save This Email!', 'ultimate-post-kit' ); ?></h2>
365 -
366 - <p><?php echo esc_html__( 'Hello,', 'ultimate-post-kit' ); ?></p>
367 -
368 - <p>
369 - <?php
370 - printf(
371 - wp_kses_post( __( 'You have successfully enabled <strong>%1$s</strong> for Ultimate Post Kit Pro on <strong>%2$s</strong>.', 'ultimate-post-kit' ) ),
372 - esc_html__( 'BDTUPK_HIDE mode', 'ultimate-post-kit' ),
373 - esc_html( $site_name )
374 - );
375 - ?>
376 - </p>
377 -
378 - <div class="warning">
379 - <h3><?php echo esc_html__( '⚠️ IMPORTANT', 'ultimate-post-kit' ); ?></h3>
380 - <p><?php echo esc_html__( 'The plugin interface is hidden from your WordPress admin. Use the link below to modify white label settings.', 'ultimate-post-kit' ); ?></p>
381 -
382 - <p style="text-align: center;">
383 - <a href="<?php echo esc_url( $access_url ); ?>" class="access-link"><?php echo esc_html__( 'Access White Label Settings', 'ultimate-post-kit' ); ?></a>
384 - </p>
385 - </div>
386 -
387 - <p>
388 - <strong><?php echo esc_html__( 'Direct Link:', 'ultimate-post-kit' ); ?></strong><br>
389 - <a href="<?php echo esc_url( $access_url ); ?>"><?php echo esc_html( $access_url ); ?></a>
390 - </p>
391 -
392 -
393 - <h3><?php echo esc_html__( '🔧 What You Can Do', 'ultimate-post-kit' ); ?></h3>
394 - <p><?php echo esc_html__( 'Using the access link above, you can:', 'ultimate-post-kit' ); ?></p>
395 - <ul>
396 - <li><?php echo esc_html__( 'Disable BDTUPK_HIDE mode', 'ultimate-post-kit' ); ?></li>
397 - <li><?php echo esc_html__( 'Modify white label settings', 'ultimate-post-kit' ); ?></li>
398 - </ul>
399 -
400 - <p>
401 - <?php
402 - printf(
403 - wp_kses_post( __( 'Need help? %1$sContact support%2$s with your license key.', 'ultimate-post-kit' ) ),
404 - '<a href="' . esc_url( 'https://bdthemes.com/support/' ) . '" target="_blank" rel="noopener noreferrer">',
405 - '</a>'
406 - );
407 - ?>
408 - </p>
409 -
410 - </div>
411 - </div>
412 - </body>
413 - </html>
414 - <?php
415 - return ob_get_clean();
416 - }
417 -
418 - /**
419 - * Handle white label access link
420 - *
421 - * @access private
422 - * @return void
423 - */
424 - private function handle_white_label_access() {
425 - // Check if this is a white label access request
426 - if ( ! isset( $_GET['upk_wl'] ) || ! isset( $_GET['token'] ) ) {
427 - return;
428 - }
429 -
430 - // Check user capability
431 - if ( ! current_user_can( 'manage_options' ) ) {
432 - wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'ultimate-post-kit' ) );
433 - }
434 -
435 - $upk_wl = sanitize_text_field( $_GET['upk_wl'] );
436 - $access_token = sanitize_text_field( $_GET['token'] );
437 -
438 - // Check if upk_wl is set to 1
439 - if ( $upk_wl !== '1' ) {
440 - $this->show_access_error( esc_html__( 'Invalid access parameter. Please use the correct link from your email.', 'ultimate-post-kit' ) );
441 - return;
442 - }
443 -
444 - // Validate the access token
445 - if ( ! $this->validate_white_label_access_token( $access_token ) ) {
446 - $this->show_access_error( esc_html__( 'Invalid or expired access token. Please use the correct access link from your email.', 'ultimate-post-kit' ) );
447 - return;
448 - }
449 -
450 - // Valid access - temporarily allow access by setting a flag
451 - add_action('admin_init', [$this, 'admin_init']);
452 - add_action('admin_menu', [$this, 'admin_menu'], 201);
453 -
454 - // Add success notice
455 - add_action( 'admin_notices', function() {
456 - echo '<div class="notice notice-success is-dismissible">';
457 - echo '<p><strong>' . esc_html__( '✅ White Label Access Granted!', 'ultimate-post-kit' ) . '</strong> ' . esc_html__( 'You can now modify white label settings.', 'ultimate-post-kit' ) . '</p>';
458 - echo '</div>';
459 - } );
460 - }
461 -
462 - /**
463 - * Show access error page
464 - *
465 - * @access private
466 - * @param string $message
467 - * @return void
468 - */
469 - private function show_access_error( $message ) {
470 - wp_die(
471 - '<h1>' . esc_html__( '🔒 Ultimate Post Kit White Label Access', 'ultimate-post-kit' ) . '</h1>' .
472 - '<p><strong>' . esc_html__( 'Access Denied:', 'ultimate-post-kit' ) . '</strong> ' . esc_html( $message ) . '</p>' .
473 - '<p>' . esc_html__( 'If you need assistance, please contact support with your license information.', 'ultimate-post-kit' ) . '</p>' .
474 - '<p><a href="' . esc_url( admin_url() ) . '" class="button button-primary">' . esc_html__( '← Return to Dashboard', 'ultimate-post-kit' ) . '</a></p>',
475 - esc_html__( 'Access Denied', 'ultimate-post-kit' ),
476 - [ 'response' => 403 ]
477 - );
478 - }
479 -
480 - /**
481 - * Inject white label icon CSS
482 - *
483 - * @access public
484 - * @return void
485 - */
486 - public function inject_white_label_icon_css() {
487 - $white_label_enabled = get_option('upk_white_label_enabled', false);
488 - $white_label_icon = get_option('upk_white_label_icon', '');
489 -
490 - // Only inject CSS when white label is enabled AND a custom icon is set
491 - if ( $white_label_enabled && ! empty( $white_label_icon ) ) {
492 - echo '<style type="text/css">';
493 - echo '#toplevel_page_ultimate_post_kit_options .wp-menu-image {';
494 - echo 'background-image: url(' . esc_url( $white_label_icon ) . ') !important;';
495 - echo 'background-size: 20px 20px !important;';
496 - echo 'background-repeat: no-repeat !important;';
497 - echo 'background-position: center !important;';
498 - echo '}';
499 - echo '#toplevel_page_ultimate_post_kit_options .wp-menu-image:before {';
500 - echo 'display: none !important;';
501 - echo '}';
502 - echo '#toplevel_page_ultimate_post_kit_options .wp-menu-image img {';
503 - echo 'display: none !important;';
504 - echo '}';
505 - echo '</style>';
506 - }
507 - // When white label is disabled or no icon is set, don't inject any CSS
508 - // This allows WordPress's original icon to display naturally
509 - }
510 -
511 71 /**
512 72 * Get used widgets.
513 73 *
514 74 * @access public
@@ -523,12 +83,9 @@
523 83 if (class_exists('Elementor\Modules\Usage\Module')) {
524 84
525 85 $module = Module::instance();
526 86
527 - $old_error_level = error_reporting();
528 - error_reporting(E_ALL & ~E_WARNING); // Suppress warnings
529 87 $elements = $module->get_formatted_usage('raw');
530 - error_reporting($old_error_level); // Restore
531 88
532 89 $upk_widgets = self::get_upk_widgets_names();
533 90
534 91 if (is_array($elements) || is_object($elements)) {
@@ -566,12 +123,9 @@
566 123 if (class_exists('Elementor\Modules\Usage\Module')) {
567 124
568 125 $module = Module::instance();
569 126
570 - $old_error_level = error_reporting();
571 - error_reporting(E_ALL & ~E_WARNING); // Suppress warnings
572 127 $elements = $module->get_formatted_usage('raw');
573 - error_reporting($old_error_level); // Restore
574 128
575 129 $upk_widgets = self::get_upk_only_widgets();
576 130
577 131 if (is_array($elements) || is_object($elements)) {
@@ -753,9 +307,11 @@
753 307 */
754 308
755 309 // Redirect to Ultimate Post Kit Pro pricing page
756 310 public function upk_redirect_to_get_pro() {
311 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check of the current admin page slug for display routing, no form data processed.
757 312 if (isset($_GET['page']) && $_GET['page'] === self::PAGE_ID . '_get_pro') {
313 + // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- Intentional redirect to a fixed, hardcoded external URL; wp_safe_redirect would block off-site hosts.
758 314 wp_redirect('https://postkit.pro/pricing/');
759 315 exit;
760 316 }
761 317 }
@@ -766,9 +322,11 @@
766 322 * @access public
767 323 *
768 324 */
769 325 public function bdt_redirect_to_renew_link() {
326 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check of the current admin page slug for display routing, no form data processed.
770 327 if (isset($_GET['page']) && $_GET['page'] === self::PAGE_ID . '_license_renew') {
328 + // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- Intentional redirect to a fixed, hardcoded external URL; wp_safe_redirect would block off-site hosts.
771 329 wp_redirect('https://account.bdthemes.com/');
772 330 exit;
773 331 }
774 332 }
@@ -829,17 +387,8 @@
829 387
830 388 add_submenu_page(
831 389 self::PAGE_ID,
832 390 BDTUPK_TITLE,
833 - esc_html__('Extra Options', 'ultimate-post-kit'),
834 - 'manage_options',
835 - self::PAGE_ID . '#ultimate_post_kit_extra_options',
836 - [$this, 'plugin_page']
837 - );
838 -
839 - add_submenu_page(
840 - self::PAGE_ID,
841 - BDTUPK_TITLE,
842 391 esc_html__('System Status', 'ultimate-post-kit'),
843 392 'manage_options',
844 393 self::PAGE_ID . '#ultimate_post_kit_analytics_system_req',
845 394 [$this, 'plugin_page']
@@ -976,9 +525,11 @@
976 525 target="_blank"><?php esc_html_e('Setup Ultimate Post Kit', 'ultimate-post-kit'); ?></a>
977 526
978 527 <div class="upk-dashboard-compare-section">
979 528 <h4 class="upk-feature-sub-title">
980 - <?php printf(esc_html__('Unlock %sPremium Features%s', 'ultimate-post-kit'), '<strong class="upk-highlight-text">', '</strong>'); ?>
529 + <?php
530 + /* translators: 1: opening strong tag, 2: closing strong tag */
531 + printf(esc_html__('Unlock %1$sPremium Features%2$s', 'ultimate-post-kit'), '<strong class="upk-highlight-text">', '</strong>'); ?>
981 532 </h4>
982 533 <h1 class="upk-feature-title upk-dashboard-compare-title">
983 534 <?php esc_html_e('Create Your Sleek Website with Ultimate Post Kit Pro!', 'ultimate-post-kit'); ?>
984 535 </h1>
@@ -1064,9 +615,9 @@
1064 615 <h1 class="upk-feature-title"><?php esc_html_e('Watch Video Tutorials', 'ultimate-post-kit'); ?></h1>
1065 616 <p><?php esc_html_e('An invaluable resource for mastering WordPress, Elementor, and Web Creation', 'ultimate-post-kit'); ?>
1066 617 </p>
1067 618 </a>
1068 - <a href="https://bdthemes.com/all-knowledge-base-of-ultimate-post-kit/" target="_blank"
619 + <a href="https://bdthemes.com/knowledge-base/ultimate-post-kit/" target="_blank"
1069 620 class="upk-dashboard-item upk-dashboard-footer-item upk-dashboard-documentation bdt-card bdt-card-body bdt-card-small">
1070 621 <span class="upk-dashboard-footer-item-icon">
1071 622 <i class="dashicons dashicons-admin-tools"></i>
1072 623 </span>
@@ -1403,26 +954,10 @@
1403 954 <span class="upk-header-element upk-header-wave"></span>
1404 955 </div>
1405 956
1406 957 <div class="upk-logo">
1407 - <?php
1408 - $white_label_enabled = get_option( 'upk_white_label_enabled', false );
1409 - $white_label_logo = get_option( 'upk_white_label_logo', '' );
1410 - $white_label_title = get_option( 'upk_white_label_title', '' );
1411 -
1412 - if ($white_label_enabled && !empty($white_label_logo)) {
1413 -
1414 - $alt_text = ! empty( $white_label_title )
1415 - ? sprintf(
1416 - /* translators: %s: White label plugin name/title. */
1417 - __( '%s Logo', 'ultimate-post-kit' ),
1418 - $white_label_title
1419 - )
1420 - : __( 'Custom Logo', 'ultimate-post-kit' );
1421 - echo '<img src="' . esc_url( $white_label_logo ) . '" alt="' . esc_attr( $alt_text ) . '" style="max-height: 40px;">';
1422 - } else {
1423 - echo '<img src="' . esc_url( BDTUPK_URL . 'assets/images/logo-with-text.svg' ) . '" alt="' . esc_attr__( 'Ultimate Post Kit Logo', 'ultimate-post-kit' ) . '">';
1424 - }
958 + <?php
959 + echo '<img src="' . esc_url( BDTUPK_URL . 'assets/images/logo-with-text.svg' ) . '" alt="' . esc_attr__( 'Ultimate Post Kit Logo', 'ultimate-post-kit' ) . '">';
1425 960 ?>
1426 961 </div>
1427 962 </div>
1428 963
@@ -1435,29 +970,9 @@
1435 970 <?php esc_html_e('Save Settings', 'ultimate-post-kit'); ?>
1436 971 </button>
1437 972 </div>
1438 973
1439 - <!-- Custom Code Save Button Section -->
1440 - <div class="upk-code-save-section" style="display: none;">
1441 - <button type="button" id="upk-save-custom-code" class="bdt-button bdt-button-primary ultimate-post-kit-custom-code-save-btn">
1442 - <?php esc_html_e('Save Custom Code', 'ultimate-post-kit'); ?>
1443 - </button>
1444 - <button type="button" id="upk-reset-custom-code" class="bdt-button bdt-button-primary ultimate-post-kit-custom-code-reset-btn">
1445 - <?php esc_html_e('Reset Code', 'ultimate-post-kit'); ?>
1446 - </button>
1447 - </div>
1448 974
1449 - <!-- White Label Save Button Section -->
1450 - <?php if (self::is_white_label_license()): ?>
1451 - <div class="upk-white-label-save-section" style="display: none;">
1452 - <button type="button"
1453 - id="upk-save-white-label"
1454 - class="bdt-button bdt-button-primary ultimate-post-kit-white-label-save-btn">
1455 - <?php esc_html_e('Save White Label Settings', 'ultimate-post-kit'); ?>
1456 - </button>
1457 - </div>
1458 - <?php endif; ?>
1459 -
1460 975 <div class="upk-dashboard-new-page">
1461 976 <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>
1462 977 <?php echo esc_html__('Create New Page', 'ultimate-post-kit') ?>
1463 978 </a>
@@ -1491,12 +1006,8 @@
1491 1006 </div>
1492 1007
1493 1008 <?php $this->settings_api->show_forms(); ?>
1494 1009
1495 - <div id="ultimate_post_kit_extra_options_page" class="upk-option-page group">
1496 - <?php $this->ultimate_post_kit_extra_options(); ?>
1497 - </div>
1498 -
1499 1010 <div id="ultimate_post_kit_analytics_system_req_page" class="upk-option-page group">
1500 1011 <?php $this->ultimate_post_kit_analytics_system_req_content(); ?>
1501 1012 </div>
1502 1013
@@ -1519,12 +1030,29 @@
1519 1030 <?php $this->ultimate_post_kit_get_pro(); ?>
1520 1031 </div>
1521 1032 <?php endif; ?>
1522 1033
1034 + <?php
1035 + // Render tab bodies for any add-on-registered dashboard tabs.
1036 + // The core plugin provides only this extension point; the tab
1037 + // ids/order match the nav items built in show_navigation().
1038 + foreach ($this->settings_api->get_extra_dashboard_tabs() as $upk_extra_tab) {
1039 + if (empty($upk_extra_tab['id'])) {
1040 + continue;
1041 + }
1042 + echo '<div id="' . esc_attr($upk_extra_tab['id']) . '_page" class="upk-option-page group">';
1043 + if (isset($upk_extra_tab['callback']) && is_callable($upk_extra_tab['callback'])) {
1044 + call_user_func($upk_extra_tab['callback']);
1045 + }
1046 + echo '</div>';
1047 + }
1048 + ?>
1049 +
1523 1050 <div id="ultimate_post_kit_license_settings_page" class="upk-option-page group">
1524 1051
1525 1052 <?php
1526 1053 if (_is_upk_pro_activated() == true) {
1054 + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- established hook name relied on across the plugin family; renaming would break integration.
1527 1055 apply_filters('upk_license_page', '');
1528 1056 }
1529 1057
1530 1058 ?>
@@ -1560,23 +1088,42 @@
1560 1088 jQuery(document).ready(function() {
1561 1089 jQuery('.upk-no-result').removeClass('bdt-animation-shake');
1562 1090 });
1563 1091
1092 + // Selector of the filter controls that are currently active (Free is active by default).
1093 + function activeFilterSelector($parent) {
1094 + return $parent.find('.upk-widget-filter li.bdt-active')
1095 + .map(function() {
1096 + var control = jQuery(this).attr('bdt-filter-control') || '';
1097 + var matched = control.match(/filter:\s*([^;]+)/);
1098 + return matched ? jQuery.trim(matched[1]) : null;
1099 + })
1100 + .get()
1101 + .join('');
1102 + }
1103 +
1564 1104 function filterSearch(e) {
1565 1105 var parentID = '#' + jQuery(e).data('id');
1566 - var search = jQuery(parentID).find('.bdt-search-input').val().toLowerCase();
1106 + var $parent = jQuery(parentID);
1107 + var search = $parent.find('.bdt-search-input').val().toLowerCase();
1567 1108
1568 - jQuery(".upk-options .upk-option-item").filter(function() {
1569 - jQuery(this).toggle(jQuery(this).attr('data-widget-name').toLowerCase().indexOf(search) > -1)
1109 + // Search runs on top of the active filter and only inside its own tab, so clearing
1110 + // the search never falls back to showing every widget.
1111 + var filterSelector = activeFilterSelector($parent);
1112 +
1113 + $parent.find('.upk-options .upk-option-item').each(function() {
1114 + var name = (jQuery(this).attr('data-widget-name') || '').toLowerCase();
1115 + var matchesSearch = name.indexOf(search) > -1;
1116 + var matchesFilter = !filterSelector || jQuery(this).is(filterSelector);
1117 +
1118 + jQuery(this).toggle(matchesSearch && matchesFilter);
1570 1119 });
1571 1120
1572 1121 if (!search) {
1573 - jQuery(parentID).find('.bdt-search-input').attr('bdt-filter-control', "");
1574 - jQuery(parentID).find('.upk-widget-all').trigger('click');
1122 + $parent.find('.bdt-search-input').attr('bdt-filter-control', "");
1575 1123 } else {
1576 - jQuery(parentID).find('.bdt-search-input').attr('bdt-filter-control', "filter: [data-widget-name*='" + search + "']");
1577 - jQuery(parentID).find('.bdt-search-input').removeClass('bdt-active'); // Thanks to Bar-Rabbas
1578 - jQuery(parentID).find('.bdt-search-input').trigger('click');
1124 + $parent.find('.bdt-search-input').attr('bdt-filter-control', "filter: [data-widget-name*='" + search + "']");
1125 + $parent.find('.bdt-search-input').removeClass('bdt-active'); // Thanks to Bar-Rabbas
1579 1126 }
1580 1127 }
1581 1128
1582 1129 jQuery('.upk-options-parent').each(function(e, item) {
@@ -1918,719 +1465,8 @@
1918 1465 });
1919 1466 }
1920 1467 });
1921 1468
1922 - //White Label Settings Functionality
1923 - //Check if upk_admin_ajax is available
1924 - if (typeof upk_admin_ajax === 'undefined') {
1925 - window.upk_admin_ajax = {
1926 - ajax_url: '<?php echo admin_url('admin-ajax.php'); ?>',
1927 - white_label_nonce: '<?php echo wp_create_nonce('upk_white_label_nonce'); ?>'
1928 - };
1929 - }
1930 -
1931 - // Initialize CodeMirror editors for custom code
1932 - var codeMirrorEditors = {};
1933 -
1934 - function initializeCodeMirrorEditors() {
1935 - // CSS Editor 1
1936 - if (document.getElementById('upk-custom-css')) {
1937 - codeMirrorEditors['upk-custom-css'] = wp.codeEditor.initialize('upk-custom-css', {
1938 - type: 'text/css',
1939 - codemirror: {
1940 - lineNumbers: true,
1941 - mode: 'css',
1942 - theme: 'default',
1943 - lineWrapping: true,
1944 - autoCloseBrackets: true,
1945 - matchBrackets: true,
1946 - lint: false
1947 - }
1948 - });
1949 - }
1950 -
1951 - // JavaScript Editor 1
1952 - if (document.getElementById('upk-custom-js')) {
1953 - codeMirrorEditors['upk-custom-js'] = wp.codeEditor.initialize('upk-custom-js', {
1954 - type: 'application/javascript',
1955 - codemirror: {
1956 - lineNumbers: true,
1957 - mode: 'javascript',
1958 - theme: 'default',
1959 - lineWrapping: true,
1960 - autoCloseBrackets: true,
1961 - matchBrackets: true,
1962 - lint: false
1963 - }
1964 - });
1965 - }
1966 -
1967 - // CSS Editor 2
1968 - if (document.getElementById('upk-custom-css-2')) {
1969 - codeMirrorEditors['upk-custom-css-2'] = wp.codeEditor.initialize('upk-custom-css-2', {
1970 - type: 'text/css',
1971 - codemirror: {
1972 - lineNumbers: true,
1973 - mode: 'css',
1974 - theme: 'default',
1975 - lineWrapping: true,
1976 - autoCloseBrackets: true,
1977 - matchBrackets: true,
1978 - lint: false
1979 - }
1980 - });
1981 - }
1982 -
1983 - // JavaScript Editor 2
1984 - if (document.getElementById('upk-custom-js-2')) {
1985 - codeMirrorEditors['upk-custom-js-2'] = wp.codeEditor.initialize('upk-custom-js-2', {
1986 - type: 'application/javascript',
1987 - codemirror: {
1988 - lineNumbers: true,
1989 - mode: 'javascript',
1990 - theme: 'default',
1991 - lineWrapping: true,
1992 - autoCloseBrackets: true,
1993 - matchBrackets: true,
1994 - lint: false
1995 - }
1996 - });
1997 - }
1998 -
1999 - // Refresh all editors after a short delay to ensure proper rendering
2000 - setTimeout(function() {
2001 - refreshAllCodeMirrorEditors();
2002 - }, 100);
2003 - }
2004 -
2005 - // Function to refresh all CodeMirror editors
2006 - function refreshAllCodeMirrorEditors() {
2007 - Object.keys(codeMirrorEditors).forEach(function(editorKey) {
2008 - if (codeMirrorEditors[editorKey] && codeMirrorEditors[editorKey].codemirror) {
2009 - codeMirrorEditors[editorKey].codemirror.refresh();
2010 - }
2011 - });
2012 - }
2013 -
2014 - // Function to refresh editors when tab becomes visible
2015 - function refreshEditorsOnTabShow() {
2016 - // Listen for tab changes (UIkit tab switching)
2017 - if (typeof bdtUIkit !== 'undefined' && bdtUIkit.tab) {
2018 - // When tab becomes active, refresh editors
2019 - bdtUIkit.util.on(document, 'shown', '.bdt-tab', function() {
2020 - setTimeout(function() {
2021 - refreshAllCodeMirrorEditors();
2022 - }, 50);
2023 - });
2024 - }
2025 -
2026 - // Also listen for direct tab clicks
2027 - $('.bdt-tab a').on('click', function() {
2028 - setTimeout(function() {
2029 - refreshAllCodeMirrorEditors();
2030 - }, 100);
2031 - });
2032 -
2033 - // Listen for switcher changes (UIkit switcher)
2034 - if (typeof bdtUIkit !== 'undefined' && bdtUIkit.switcher) {
2035 - bdtUIkit.util.on(document, 'shown', '.bdt-switcher', function() {
2036 - setTimeout(function() {
2037 - refreshAllCodeMirrorEditors();
2038 - }, 50);
2039 - });
2040 - }
2041 - }
2042 -
2043 - // Initialize editors when page loads - with delay for better rendering
2044 - setTimeout(function() {
2045 - initializeCodeMirrorEditors();
2046 - }, 100);
2047 -
2048 - // Setup tab switching handlers
2049 - setTimeout(function() {
2050 - refreshEditorsOnTabShow();
2051 - }, 100);
2052 -
2053 - // Handle window resize events
2054 - $(window).on('resize', function() {
2055 - setTimeout(function() {
2056 - refreshAllCodeMirrorEditors();
2057 - }, 100);
2058 - });
2059 -
2060 - // Handle page visibility changes (when switching browser tabs)
2061 - document.addEventListener('visibilitychange', function() {
2062 - if (!document.hidden) {
2063 - setTimeout(function() {
2064 - refreshAllCodeMirrorEditors();
2065 - }, 200);
2066 - }
2067 - });
2068 -
2069 - // Force refresh when clicking on the Custom CSS & JS tab specifically
2070 - $('a[href="#"]').on('click', function() {
2071 - var tabText = $(this).text().trim();
2072 - if (tabText === 'Custom CSS & JS') {
2073 - setTimeout(function() {
2074 - refreshAllCodeMirrorEditors();
2075 - }, 150);
2076 - }
2077 - });
2078 -
2079 - //Toggle white label fields visibility
2080 - $('#upk-white-label-enabled').on('change', function() {
2081 - if ($(this).is(':checked')) {
2082 - $('.upk-white-label-fields').slideDown(300);
2083 - } else {
2084 - $('.upk-white-label-fields').slideUp(300);
2085 - }
2086 - });
2087 -
2088 - //WordPress Media Library Integration for Icon Upload
2089 - var mediaUploader;
2090 -
2091 - $('#upk-upload-icon').on('click', function(e) {
2092 - e.preventDefault();
2093 -
2094 - // If the uploader object has already been created, reopen the dialog
2095 - if (mediaUploader) {
2096 - mediaUploader.open();
2097 - return;
2098 - }
2099 -
2100 - // Create the media frame
2101 - mediaUploader = wp.media.frames.file_frame = wp.media({
2102 - title: 'Select Icon',
2103 - button: {
2104 - text: 'Use This Icon'
2105 - },
2106 - library: {
2107 - type: ['image/jpeg', 'image/jpg', 'image/png', 'image/svg+xml']
2108 - },
2109 - multiple: false
2110 - });
2111 -
2112 - // When an image is selected, run a callback
2113 - mediaUploader.on('select', function() {
2114 - var attachment = mediaUploader.state().get('selection').first().toJSON();
2115 -
2116 - // Set the hidden inputs
2117 - $('#upk-white-label-icon').val(attachment.url);
2118 - $('#upk-white-label-icon-id').val(attachment.id);
2119 -
2120 - // Update preview
2121 - $('#upk-icon-preview-img').attr('src', attachment.url);
2122 - $('.upk-icon-preview-container').show();
2123 - });
2124 -
2125 - // Open the uploader dialog
2126 - mediaUploader.open();
2127 - });
2128 -
2129 - //Remove icon functionality
2130 - $('#upk-remove-icon').on('click', function(e) {
2131 - e.preventDefault();
2132 -
2133 - // Clear the hidden inputs
2134 - $('#upk-white-label-icon').val('');
2135 - $('#upk-white-label-icon-id').val('');
2136 -
2137 - // Hide preview
2138 - $('.upk-icon-preview-container').hide();
2139 - $('#upk-icon-preview-img').attr('src', '');
2140 - });
2141 -
2142 - // WordPress Media Library Integration for Logo Upload
2143 - var logoUploader;
2144 -
2145 - $('#upk-upload-logo').on('click', function(e) {
2146 - e.preventDefault();
2147 -
2148 - // If the uploader object has already been created, reopen the dialog
2149 - if (logoUploader) {
2150 - logoUploader.open();
2151 - return;
2152 - }
2153 -
2154 - // Create the media frame
2155 - logoUploader = wp.media.frames.file_frame = wp.media({
2156 - title: 'Select Logo',
2157 - button: {
2158 - text: 'Use This Logo'
2159 - },
2160 - library: {
2161 - type: ['image/jpeg', 'image/jpg', 'image/png', 'image/svg+xml']
2162 - },
2163 - multiple: false
2164 - });
2165 -
2166 - // When an image is selected, run a callback
2167 - logoUploader.on('select', function() {
2168 - var attachment = logoUploader.state().get('selection').first().toJSON();
2169 -
2170 - // Set the hidden inputs
2171 - $('#upk-white-label-logo').val(attachment.url);
2172 - $('#upk-white-label-logo-id').val(attachment.id);
2173 -
2174 - // Update preview
2175 - $('#upk-logo-preview-img').attr('src', attachment.url);
2176 - $('.upk-logo-preview-container').show();
2177 - });
2178 -
2179 - // Open the uploader dialog
2180 - logoUploader.open();
2181 - });
2182 -
2183 - // Remove logo functionality
2184 - $('#upk-remove-logo').on('click', function(e) {
2185 - e.preventDefault();
2186 -
2187 - // Clear the hidden inputs
2188 - $('#upk-white-label-logo').val('');
2189 - $('#upk-white-label-logo-id').val('');
2190 -
2191 - // Hide preview
2192 - $('.upk-logo-preview-container').hide();
2193 - $('#upk-logo-preview-img').attr('src', '');
2194 - });
2195 -
2196 - //BDTUPK_HIDE Warning when checkbox is enabled
2197 - $('#upk-white-label-bdtupk-hide').on('change', function() {
2198 - if ($(this).is(':checked')) {
2199 - // Show warning modal/alert
2200 - var warningMessage = '⚠️ WARNING: ADVANCED FEATURE\n\n' +
2201 - 'Enabling BDTUPK_HIDE will activate advanced white label mode that:\n\n' +
2202 - '• Hides ALL Element Pack branding and menus\n' +
2203 - '• Makes these settings difficult to access later\n' +
2204 - '• Requires the special access link to return\n' +
2205 - '• Is intended for client/agency use only\n\n' +
2206 - 'An email with access instructions will be sent if you proceed.\n\n' +
2207 - 'Are you sure you want to enable this advanced mode?';
2208 -
2209 - if (!confirm(warningMessage)) {
2210 - // User cancelled, uncheck the box
2211 - $(this).prop('checked', false);
2212 - return false;
2213 - }
2214 -
2215 - // Show additional info message
2216 - if ($('#upk-bdtupk-hide-info').length === 0) {
2217 - $(this).closest('.upk-option-item').after(
2218 - '<div id="upk-bdtupk-hide-info" class="bdt-alert bdt-alert-warning bdt-margin-small-top">' +
2219 - '<p><strong>BDTUPK_HIDE Mode Enabled</strong></p>' +
2220 - '<p>When you save these settings, an email will be sent with instructions to access white label settings in the future.</p>' +
2221 - '</div>'
2222 - );
2223 - }
2224 - } else {
2225 - // Remove info message when unchecked
2226 - $('#upk-bdtupk-hide-info').remove();
2227 - }
2228 - });
2229 -
2230 - // Save white label settings with confirmation
2231 - $('#upk-save-white-label').on('click', function(e) {
2232 - e.preventDefault();
2233 -
2234 - // Check if button is disabled (no license or no white label eligible license)
2235 - if ($(this).prop('disabled')) {
2236 - var buttonText = $(this).text().trim();
2237 - var alertMessage = '';
2238 -
2239 - if (buttonText.includes('License Not Activated')) {
2240 - alertMessage = '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2241 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2242 - '<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>' +
2243 - '</div>';
2244 - } else {
2245 - alertMessage = '<div class="bdt-alert bdt-alert-warning" bdt-alert>' +
2246 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2247 - '<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>' +
2248 - '</div>';
2249 - }
2250 -
2251 - $('#upk-white-label-message').html(alertMessage).show();
2252 - return false;
2253 - }
2254 -
2255 - // Check if white label mode is being enabled
2256 - var whiteLabelEnabled = $('#upk-white-label-enabled').is(':checked');
2257 - var bdtupkHideEnabled = $('#upk-white-label-bdtupk-hide').is(':checked');
2258 -
2259 - // Only show confirmation dialog if white label is enabled AND BDTUPK_HIDE is enabled
2260 - if (whiteLabelEnabled && bdtupkHideEnabled) {
2261 - var confirmMessage = '🔒 FINAL CONFIRMATION\n\n' +
2262 - 'You are about to save settings with BDTUPK_HIDE enabled.\n\n' +
2263 - 'This will:\n' +
2264 - '• Hide Ultimate Post Kit from WordPress admin immediately\n' +
2265 - '• Send access instructions to your email addresses\n' +
2266 - '• Require the special link to modify these settings\n\n' +
2267 - 'Email will be sent to:\n' +
2268 - '• License email: <?php echo esc_js(self::get_license_email()); ?>\n' +
2269 - 'Are you absolutely sure you want to proceed?';
2270 -
2271 - if (!confirm(confirmMessage)) {
2272 - return false;
2273 - }
2274 - }
2275 -
2276 - var $button = $(this);
2277 - var originalText = $button.html();
2278 -
2279 - // Show loading state
2280 - $button.html('Saving...');
2281 - $button.prop('disabled', true);
2282 -
2283 - // Collect form data
2284 - var formData = {
2285 - action: 'upk_save_white_label',
2286 - nonce: upk_admin_ajax.white_label_nonce,
2287 - upk_white_label_enabled: $('#upk-white-label-enabled').is(':checked') ? 1 : 0,
2288 - upk_white_label_title: $('#upk-white-label-title').val(),
2289 - upk_white_label_icon: $('#upk-white-label-icon').val(),
2290 - upk_white_label_icon_id: $('#upk-white-label-icon-id').val(),
2291 - upk_white_label_logo: $('#upk-white-label-logo').val(),
2292 - upk_white_label_logo_id: $('#upk-white-label-logo-id').val(),
2293 - upk_white_label_hide_license: $('#upk-white-label-hide-license').is(':checked') ? 1 : 0,
2294 - upk_white_label_bdtupk_hide: $('#upk-white-label-bdtupk-hide').is(':checked') ? 1 : 0
2295 - };
2296 -
2297 - // Send AJAX request
2298 - $.post(upk_admin_ajax.ajax_url, formData)
2299 - .done(function(response) {
2300 - if (response.success) {
2301 - // Show success message with countdown
2302 - var countdown = 2;
2303 - var successMessage = response.data.message;
2304 -
2305 - // Add email notification info if BDTUPK_HIDE was enabled
2306 - if (response.data.bdtupk_hide && response.data.email_sent) {
2307 - successMessage += '<br><br><strong>📧 Access Email Sent!</strong><br>Check your email for the access link to modify these settings in the future.';
2308 - } else if (response.data.bdtupk_hide && !response.data.email_sent && response.data.access_url) {
2309 - // Localhost scenario - show the access URL directly
2310 - 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>';
2311 - } else if (response.data.bdtupk_hide && !response.data.email_sent) {
2312 - successMessage += '<br><br><strong>⚠️ Email Notice:</strong><br>There was an issue sending the access email. Please check your email settings or contact support.';
2313 - }
2314 -
2315 - $('#upk-white-label-message').html(
2316 - '<div class="bdt-alert bdt-alert-success" bdt-alert>' +
2317 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2318 - '<p>' + successMessage + ' <span id="upk-reload-countdown">Reloading in ' + countdown + ' seconds...</span></p>' +
2319 - '</div>'
2320 - ).show();
2321 -
2322 - // Update button text
2323 - $button.html('Reloading...');
2324 -
2325 - // Countdown timer
2326 - var countdownInterval = setInterval(function() {
2327 - countdown--;
2328 - if (countdown > 0) {
2329 - $('#upk-reload-countdown').text('Reloading in ' + countdown + ' seconds...');
2330 - } else {
2331 - $('#upk-reload-countdown').text('Reloading now...');
2332 - clearInterval(countdownInterval);
2333 - }
2334 - }, 1000);
2335 -
2336 - // Check if BDTUPK_HIDE is enabled and redirect accordingly
2337 - setTimeout(function() {
2338 - if (response.data.bdtupk_hide) {
2339 - // Redirect to admin dashboard if BDTUPK_HIDE is enabled
2340 - window.location.href = '<?php echo admin_url('index.php'); ?>';
2341 - } else {
2342 - // Reload current page if BDTUPK_HIDE is not enabled
2343 - window.location.reload();
2344 - }
2345 - }, 1500);
2346 - } else {
2347 - // Show error message
2348 - $('#upk-white-label-message').html(
2349 - '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2350 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2351 - '<p>Error: ' + (response.data.message || 'Unknown error occurred') + '</p>' +
2352 - '</div>'
2353 - ).show();
2354 -
2355 - // Restore button state for error case
2356 - $button.html(originalText);
2357 - $button.prop('disabled', false);
2358 - }
2359 - })
2360 - .fail(function(xhr, status, error) {
2361 - // Show error message
2362 - $('#upk-white-label-message').html(
2363 - '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2364 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2365 - '<p>Error: Failed to save settings. Please try again. (' + status + ')</p>' +
2366 - '</div>'
2367 - ).show();
2368 -
2369 - // Restore button state for failure case
2370 - $button.html(originalText);
2371 - $button.prop('disabled', false);
2372 - });
2373 - });
2374 -
2375 - // Save custom code functionality (updated for CodeMirror)
2376 - $('#upk-save-custom-code').on('click', function(e) {
2377 - e.preventDefault();
2378 -
2379 - var $button = $(this);
2380 - var originalText = $button.html();
2381 -
2382 - // Check if upk_admin_ajax is available
2383 - if (typeof upk_admin_ajax === 'undefined') {
2384 - $('#upk-custom-code-message').html(
2385 - '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2386 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2387 - '<p>Error: AJAX configuration not loaded. Please refresh the page and try again.</p>' +
2388 - '</div>'
2389 - ).show();
2390 - return;
2391 - }
2392 -
2393 - // Prevent multiple simultaneous saves
2394 - if ($button.prop('disabled') || $button.hasClass('upk-saving')) {
2395 - return;
2396 - }
2397 -
2398 - // Mark as saving
2399 - $button.addClass('upk-saving');
2400 -
2401 - // Get content from CodeMirror editors
2402 - function getCodeMirrorContent(elementId) {
2403 - if (codeMirrorEditors[elementId] && codeMirrorEditors[elementId].codemirror) {
2404 - return codeMirrorEditors[elementId].codemirror.getValue();
2405 - } else {
2406 - // Fallback to textarea value
2407 - return $('#' + elementId).val() || '';
2408 - }
2409 - }
2410 -
2411 - var cssContent = getCodeMirrorContent('upk-custom-css');
2412 - var jsContent = getCodeMirrorContent('upk-custom-js');
2413 - var css2Content = getCodeMirrorContent('upk-custom-css-2');
2414 - var js2Content = getCodeMirrorContent('upk-custom-js-2');
2415 -
2416 - // Show loading state
2417 - $button.prop('disabled', true);
2418 -
2419 - // Timeout safeguard - if AJAX doesn't complete in 30 seconds, restore button
2420 - var timeoutId = setTimeout(function() {
2421 - $button.removeClass('upk-saving');
2422 - $button.html(originalText);
2423 - $button.prop('disabled', false);
2424 - $('#upk-custom-code-message').html(
2425 - '<div class="bdt-alert bdt-alert-warning" bdt-alert>' +
2426 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2427 - '<p>Save operation timed out. Please try again.</p>' +
2428 - '</div>'
2429 - ).show();
2430 - }, 30000);
2431 -
2432 - // Collect form data
2433 - var formData = {
2434 - action: 'upk_save_custom_code',
2435 - nonce: upk_admin_ajax.nonce,
2436 - custom_css: cssContent,
2437 - custom_js: jsContent,
2438 - custom_css_2: css2Content,
2439 - custom_js_2: js2Content,
2440 - excluded_pages: $('#upk-excluded-pages').val() || []
2441 - };
2442 -
2443 -
2444 - // Verify we have some content before sending (optional check)
2445 - var totalContentLength = cssContent.length + jsContent.length + css2Content.length + js2Content.length;
2446 - if (totalContentLength === 0) {
2447 - var confirmEmpty = confirm('No content detected in any editor. Do you want to save empty content (this will clear all custom code)?');
2448 - if (!confirmEmpty) {
2449 - // Restore button state
2450 - $button.html(originalText);
2451 - $button.prop('disabled', false);
2452 - return;
2453 - }
2454 - }
2455 -
2456 - // Send AJAX request
2457 - $.post(upk_admin_ajax.ajax_url, formData)
2458 - .done(function(response) {
2459 - console.log('AJAX Response:', response); // Debug log
2460 -
2461 - if (response && response.success) {
2462 - // Show success message
2463 - var successMessage = response.data.message;
2464 - if (response.data.excluded_count) {
2465 - successMessage += ' (' + response.data.excluded_count + ' pages excluded)';
2466 - }
2467 -
2468 - $('#upk-custom-code-message').html(
2469 - '<div class="bdt-alert bdt-alert-success" bdt-alert>' +
2470 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2471 - '<p>' + successMessage + '</p>' +
2472 - '</div>'
2473 - ).show();
2474 -
2475 - // Auto-hide message after 5 seconds
2476 - setTimeout(function() {
2477 - $('#upk-custom-code-message').fadeOut();
2478 - }, 5000);
2479 -
2480 - } else {
2481 - // Show error message
2482 - var errorMessage = 'Unknown error occurred';
2483 - if (response && response.data && response.data.message) {
2484 - errorMessage = response.data.message;
2485 - } else if (response && response.message) {
2486 - errorMessage = response.message;
2487 - }
2488 -
2489 - $('#upk-custom-code-message').html(
2490 - '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2491 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2492 - '<p>Error: ' + errorMessage + '</p>' +
2493 - '</div>'
2494 - ).show();
2495 - }
2496 - })
2497 - .fail(function(xhr, status, error) {
2498 - console.log('AJAX Error:', xhr, status, error); // Debug log
2499 -
2500 - // Try to parse error response
2501 - var errorMessage = 'Failed to save custom code. Please try again.';
2502 - try {
2503 - var errorResponse = JSON.parse(xhr.responseText);
2504 - if (errorResponse.data && errorResponse.data.message) {
2505 - errorMessage = errorResponse.data.message;
2506 - } else if (errorResponse.message) {
2507 - errorMessage = errorResponse.message;
2508 - }
2509 - } catch (e) {
2510 - // Use default error message
2511 - }
2512 -
2513 - // Show error message
2514 - $('#upk-custom-code-message').html(
2515 - '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2516 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2517 - '<p>Error: ' + errorMessage + ' (' + status + ')</p>' +
2518 - '</div>'
2519 - ).show();
2520 - })
2521 - .always(function() {
2522 -
2523 - // Clear the timeout since AJAX completed
2524 - clearTimeout(timeoutId);
2525 -
2526 - try {
2527 - $button.removeClass('upk-saving');
2528 - $button.html(originalText);
2529 - $button.prop('disabled', false);
2530 - } catch (e) {
2531 - // Fallback: force button restoration
2532 - $('#upk-save-custom-code').removeClass('upk-saving').html('<span class="dashicons dashicons-yes"></span> Save Custom Code').prop('disabled', false);
2533 - }
2534 - });
2535 - });
2536 -
2537 - // Reset custom code functionality (updated for CodeMirror)
2538 - $('#upk-reset-custom-code').on('click', function(e) {
2539 - e.preventDefault();
2540 -
2541 - if (confirm('Are you sure you want to reset all custom code? This will clear all code.')) {
2542 - var $button = $(this);
2543 - var originalText = $button.html();
2544 -
2545 - // Clear CodeMirror editors
2546 - function clearCodeMirrorEditor(elementId) {
2547 - if (codeMirrorEditors[elementId] && codeMirrorEditors[elementId].codemirror) {
2548 - codeMirrorEditors[elementId].codemirror.setValue('');
2549 - } else {
2550 - // Fallback to clearing textarea
2551 - $('#' + elementId).val('');
2552 - }
2553 - }
2554 -
2555 - // Clear all editors
2556 - clearCodeMirrorEditor('upk-custom-css');
2557 - clearCodeMirrorEditor('upk-custom-js');
2558 - clearCodeMirrorEditor('upk-custom-css-2');
2559 - clearCodeMirrorEditor('upk-custom-js-2');
2560 -
2561 - // Clear exclusions
2562 - $('#upk-excluded-pages').val([]).trigger('change');
2563 -
2564 - // Show clearing message
2565 - $('#upk-custom-code-message').html(
2566 - '<div class="bdt-alert bdt-alert-primary" bdt-alert>' +
2567 - '<p><span bdt-spinner="ratio: 0.6"></span> Clearing custom code...</p>' +
2568 - '</div>'
2569 - ).show();
2570 -
2571 - // Disable button during save
2572 - $button.prop('disabled', true).html('<span bdt-spinner="ratio: 0.6"></span> Resetting...');
2573 -
2574 - // Prepare empty data for AJAX save
2575 - var formData = {
2576 - action: 'upk_save_custom_code',
2577 - nonce: upk_admin_ajax.nonce,
2578 - custom_css: '',
2579 - custom_js: '',
2580 - custom_css_2: '',
2581 - custom_js_2: '',
2582 - excluded_pages: []
2583 - };
2584 -
2585 - // Send AJAX request to save empty values
2586 - $.ajax({
2587 - url: upk_admin_ajax.ajax_url,
2588 - type: 'POST',
2589 - data: formData,
2590 - timeout: 30000,
2591 - success: function(response) {
2592 - if (response.success) {
2593 - // Show success message
2594 - $('#upk-custom-code-message').html(
2595 - '<div class="bdt-alert bdt-alert-success" bdt-alert>' +
2596 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2597 - '<p><span class="dashicons dashicons-yes"></span> All custom code has been reset successfully!</p>' +
2598 - '</div>'
2599 - ).show();
2600 -
2601 - // Auto-hide message after 5 seconds
2602 - setTimeout(function() {
2603 - $('#upk-custom-code-message').fadeOut();
2604 - }, 5000);
2605 - } else {
2606 - // Show error message
2607 - $('#upk-custom-code-message').html(
2608 - '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2609 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2610 - '<p><span class="dashicons dashicons-warning"></span> ' + (response.data.message || 'Failed to save reset. Please try again.') + '</p>' +
2611 - '</div>'
2612 - ).show();
2613 - }
2614 -
2615 - // Restore button
2616 - $button.prop('disabled', false).html(originalText);
2617 - },
2618 - error: function(xhr, status, error) {
2619 - // Show error message
2620 - $('#upk-custom-code-message').html(
2621 - '<div class="bdt-alert bdt-alert-danger" bdt-alert>' +
2622 - '<a href="#" class="bdt-alert-close" onclick="$(this).parent().parent().hide(); return false;">&times;</a>' +
2623 - '<p><span class="dashicons dashicons-warning"></span> Failed to save reset: ' + error + '</p>' +
2624 - '</div>'
2625 - ).show();
2626 -
2627 - // Restore button
2628 - $button.prop('disabled', false).html(originalText);
2629 - }
2630 - });
2631 - }
2632 - });
2633 1469 });
2634 1470
2635 1471 // Chart.js initialization for system status canvas charts
2636 1472 function initUltimatePostKitCharts() {
@@ -2789,9 +1625,9 @@
2789 1625 .addClass('bdt-installing');
2790 1626
2791 1627 // Perform AJAX request
2792 1628 jQuery.ajax({
2793 - url: '<?php echo admin_url('admin-ajax.php'); ?>',
1629 + url: '<?php echo esc_url(admin_url('admin-ajax.php')); ?>',
2794 1630 type: 'POST',
2795 1631 data: {
2796 1632 action: 'upk_install_plugin',
2797 1633 plugin_slug: pluginSlug,
@@ -2848,98 +1684,8 @@
2848 1684 }
2849 1685 });
2850 1686 });
2851 1687
2852 - // Show/hide white label & custom code save button based on active tab
2853 - function toggleWhiteLabelSaveButton() {
2854 -
2855 - // Check if we're on the extra options page
2856 - if (window.location.hash === '#ultimate_post_kit_extra_options') {
2857 - // Target specifically the tabs within the Extra Options section
2858 - var extraOptionsTabs = jQuery('.upk-extra-options-tabs .bdt-tab li.bdt-active');
2859 - var activeTab = extraOptionsTabs.index();
2860 -
2861 - if (activeTab === 1) { // White Label tab is the second tab (index 1)
2862 - jQuery('.upk-white-label-save-section').show();
2863 - jQuery('.upk-code-save-section').hide();
2864 - } else {
2865 - jQuery('.upk-white-label-save-section').hide();
2866 - jQuery('.upk-code-save-section').show();
2867 - }
2868 - } else {
2869 - jQuery('.upk-white-label-save-section').hide();
2870 - jQuery('.upk-code-save-section').hide();
2871 - }
2872 - }
2873 -
2874 - // Wait for jQuery to be ready
2875 - jQuery(document).ready(function($) {
2876 -
2877 - // Check if we should automatically switch to White Label tab
2878 - var urlParams = new URLSearchParams(window.location.search);
2879 - if (urlParams.get('white_label_tab') === '1') {
2880 - // Wait a bit for UIkit to be ready, then switch to White Label tab
2881 - setTimeout(function() {
2882 - // Use UIkit's API to switch to the second tab (index 1)
2883 - var tabElement = document.querySelector('.upk-extra-options-tabs [bdt-tab]');
2884 - if (tabElement && typeof UIkit !== 'undefined') {
2885 - UIkit.tab(tabElement).show(1); // Show tab at index 1 (White Label tab)
2886 - } else {
2887 - // Fallback: simply click the White Label tab link
2888 - var whiteLabelTab = $('.upk-extra-options-tabs .bdt-tab li').eq(1);
2889 - if (whiteLabelTab.length > 0) {
2890 - whiteLabelTab.find('a')[0].click(); // Use native click
2891 - }
2892 - }
2893 -
2894 - // Check button visibility after tab switch
2895 - setTimeout(function() {
2896 - toggleWhiteLabelSaveButton();
2897 - }, 300);
2898 - }, 800);
2899 - } else {
2900 - toggleWhiteLabelSaveButton();
2901 - }
2902 -
2903 - // Check on hash change (when navigating to extra options page)
2904 - $(window).on('hashchange', function() {
2905 - toggleWhiteLabelSaveButton();
2906 - });
2907 -
2908 - // Listen for UIkit tab changes using multiple methods
2909 - $(document).on('click', '.bdt-tab li a', function() {
2910 - setTimeout(function() {
2911 - toggleWhiteLabelSaveButton();
2912 - }, 200);
2913 - });
2914 -
2915 - // Listen for UIkit's internal tab change events
2916 - $(document).on('shown', '[bdt-tab]', function() {
2917 - setTimeout(function() {
2918 - toggleWhiteLabelSaveButton();
2919 - }, 200);
2920 - });
2921 -
2922 - // Also listen for the specific tab content changes
2923 - $(document).on('show', '#upk-extra-options-tab-content > div', function() {
2924 - setTimeout(function() {
2925 - toggleWhiteLabelSaveButton();
2926 - }, 200);
2927 - });
2928 -
2929 - // Alternative: Check periodically for tab changes
2930 - setInterval(function() {
2931 - if (window.location.hash === '#ultimate_post_kit_extra_options') {
2932 - var currentActiveTab = $('.bdt-tab li.bdt-active').index();
2933 - if (typeof window.lastActiveTab === 'undefined') {
2934 - window.lastActiveTab = currentActiveTab;
2935 - } else if (window.lastActiveTab !== currentActiveTab) {
2936 - window.lastActiveTab = currentActiveTab;
2937 - toggleWhiteLabelSaveButton();
2938 - }
2939 - }
2940 - }, 500);
2941 - });
2942 1688
2943 1689 </script>
2944 1690 <?php
2945 1691 }
@@ -2965,10 +1711,22 @@
2965 1711 </div>
2966 1712
2967 1713 <div class="bdt-width-expand@s bdt-text-right">
2968 1714 <p class="">
2969 - Ultimate Post Kit Pro plugin made with love by <a target="_blank" href="https://bdthemes.com">BdThemes</a> Team.
2970 - <br>All rights reserved by <a target="_blank" href="https://bdthemes.com">BdThemes.com</a>.
1715 + <?php
1716 + printf(
1717 + /* translators: %s: link to the BdThemes website. */
1718 + esc_html__('Ultimate Post Kit Pro plugin made with love by %s Team.', 'ultimate-post-kit'),
1719 + '<a target="_blank" href="' . esc_url('https://bdthemes.com') . '">BdThemes</a>'
1720 + );
1721 + ?>
1722 + <br><?php
1723 + printf(
1724 + /* translators: %s: link to the BdThemes website. */
1725 + esc_html__('All rights reserved by %s.', 'ultimate-post-kit'),
1726 + '<a target="_blank" href="' . esc_url('https://bdthemes.com') . '">BdThemes.com</a>'
1727 + );
1728 + ?>
2971 1729 </p>
2972 1730 </div>
2973 1731 </div>
2974 1732
@@ -2993,376 +1751,9 @@
2993 1751
2994 1752 return $pages_options;
2995 1753 }
2996 1754
2997 - /**
2998 - * Check if current license supports white label features
2999 - * Now includes other_param checking for AppSumo WL flag
3000 - *
3001 - * @access public static
3002 - * @return bool
3003 - */
3004 - public static function is_white_label_license() {
3005 - // Check if pro version is activated first
3006 - if (!function_exists('_is_upk_pro_activated') || !_is_upk_pro_activated()) {
3007 - return false;
3008 - }
3009 -
3010 - // Since UltimatePostKitPro\Base doesn't exist, return false for now
3011 - // This should be replaced with actual pro license checking logic when available
3012 - $license_info = UltimatePostKitPro\Base\Ultimate_Post_Kit_Base::GetRegisterInfo();
3013 -
3014 - // Security: Validate license info structure
3015 - if (empty($license_info) ||
3016 - !is_object($license_info) ||
3017 - empty($license_info->license_title) ||
3018 - empty($license_info->is_valid)) {
3019 - return false;
3020 - }
3021 -
3022 - // Sanitize license title to prevent any potential issues
3023 - $license_title = sanitize_text_field(strtolower($license_info->license_title));
3024 -
3025 - // Check for other_param WL flag FIRST (for AppSumo and other special licenses)
3026 - if (!empty($license_info->other_param)) {
3027 - // Check if other_param contains WL flag
3028 - if (is_array($license_info->other_param)) {
3029 - if (in_array('WL', $license_info->other_param, true)) {
3030 - return true;
3031 - }
3032 - } elseif (is_string($license_info->other_param)) {
3033 - if (strpos($license_info->other_param, 'WL') !== false) {
3034 - return true;
3035 - }
3036 - }
3037 - }
3038 -
3039 - // Check standard license types (but NOT AppSumo - AppSumo requires WL flag)
3040 - $allowed_types = self::get_white_label_allowed_license_types();
3041 - $allowed_hashes = array_values($allowed_types);
3042 -
3043 - // Split license title into words and check each word
3044 - $words = preg_split('/\s+/', $license_title, -1, PREG_SPLIT_NO_EMPTY);
3045 - foreach ($words as $word) {
3046 - $word = trim($word);
3047 - if (empty($word) || strlen($word) > 50) { // Prevent extremely long strings
3048 - continue;
3049 - }
3050 -
3051 - // Use SHA-256 for enhanced security
3052 - $hash = hash('sha256', $word);
3053 - if (in_array($hash, $allowed_hashes, true)) { // Strict comparison
3054 - return true;
3055 - }
3056 - }
3057 -
3058 - return false;
3059 - }
3060 1755
3061 - /**
3062 - * Render White Label Section
3063 - *
3064 - * @access public
3065 - * @return void
3066 - */
3067 - public function render_white_label_section() {
3068 - //// Safely check if helper functions exist
3069 - $is_pro_installed = function_exists('_is_upk_pro_installed') ? _is_upk_pro_installed() : false;
3070 - $is_pro_activated = function_exists('_is_upk_pro_activated') ? _is_upk_pro_activated() : false;
3071 -
3072 - // Define plugin slug (adjust if needed)
3073 - $plugin_slug = 'ultimate-post-kit-pro/ultimate-post-kit-pro.php';
3074 -
3075 - // Case 1: Pro not installed
3076 - if ( ! $is_pro_installed ) : ?>
3077 - <div class="bdt-alert bdt-alert-danger bdt-margin-medium-top" bdt-alert>
3078 - <p><?php esc_html_e( 'Ultimate Post Kit Pro is not installed. Please install it to access White Label functionality.', 'ultimate-post-kit' ); ?></p>
3079 - <div class="bdt-margin-small-top">
3080 - <a href="https://postkit.pro/pricing/" target="_blank" class="bdt-button bdt-btn-blue">
3081 - <?php esc_html_e( 'Get Pro', 'ultimate-post-kit' ); ?>
3082 - </a>
3083 - </div>
3084 - </div>
3085 - <?php
3086 - return;
3087 - endif;
3088 -
3089 - // Case 2: Installed but not active
3090 - if ( $is_pro_installed && ! $is_pro_activated ) :
3091 - // Generate secure activation link
3092 - $activate_url = wp_nonce_url(
3093 - add_query_arg(
3094 - array(
3095 - 'action' => 'activate',
3096 - 'plugin' => $plugin_slug,
3097 - ),
3098 - admin_url( 'plugins.php' )
3099 - ),
3100 - 'activate-plugin_' . $plugin_slug
3101 - );
3102 - ?>
3103 - <div class="bdt-alert bdt-alert-warning bdt-margin-medium-top" bdt-alert>
3104 - <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>
3105 - <div class="bdt-margin-small-top">
3106 - <a href="<?php echo esc_url( $activate_url ); ?>" class="bdt-button bdt-btn-blue">
3107 - <?php esc_html_e( 'Activate Pro', 'ultimate-post-kit' ); ?>
3108 - </a>
3109 - </div>
3110 - </div>
3111 - <?php
3112 - return;
3113 - endif;
3114 - ?>
3115 - <div class="upk-white-label-section">
3116 - <h1 class="upk-feature-title"><?php esc_html_e('White Label Settings', 'ultimate-post-kit'); ?></h1>
3117 - <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>
3118 -
3119 - <?php
3120 -
3121 - $is_license_active = false;
3122 - if ( function_exists( 'upk_license_validation' ) && true === upk_license_validation() ) {
3123 - $is_license_active = true;
3124 - }
3125 - $is_white_label_eligible = self::is_white_label_license();
3126 -
3127 - // Show appropriate notices based on license status
3128 - if (!$is_license_active): ?>
3129 - <div class="bdt-alert bdt-alert-danger bdt-margin-medium-top" bdt-alert>
3130 - <p><strong><?php esc_html_e('License Not Activated', 'ultimate-post-kit'); ?></strong></p>
3131 - <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>
3132 - <div class="bdt-margin-small-top">
3133 - <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">
3134 - <?php esc_html_e('Activate License', 'ultimate-post-kit'); ?>
3135 - </a>
3136 - <a href="https://postkit.pro/pricing/" target="_blank" class="bdt-button bdt-btn-blue">
3137 - <?php esc_html_e('Get License', 'ultimate-post-kit'); ?>
3138 - </a>
3139 - </div>
3140 - </div>
3141 - <?php elseif ($is_license_active && !$is_white_label_eligible): ?>
3142 - <div class="bdt-alert bdt-alert-warning bdt-margin-medium-top" bdt-alert>
3143 - <p><strong><?php esc_html_e('Eligible License Required', 'ultimate-post-kit'); ?></strong></p>
3144 - <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>
3145 - <a href="https://postkit.pro/pricing/" target="_blank" class="bdt-button bdt-btn-blue bdt-margin-small-top">
3146 - <?php esc_html_e('Upgrade License', 'ultimate-post-kit'); ?>
3147 - </a>
3148 - </div>
3149 - <?php endif; ?>
3150 -
3151 - <div class="upk-white-label-options <?php echo (!$is_license_active || !$is_white_label_eligible) ? 'upk-white-label-locked' : ''; ?>">
3152 - <div class="upk-option-item ">
3153 - <div class="upk-option-item-inner bdt-card">
3154 - <div class="bdt-flex bdt-flex-between bdt-flex-middle">
3155 - <div>
3156 - <h3 class="upk-option-title"><?php esc_html_e('Enable White Label Mode', 'ultimate-post-kit'); ?></h3>
3157 - <p class="upk-option-description">
3158 - <?php if ($is_license_active && $is_white_label_eligible): ?>
3159 - <?php esc_html_e('When enabled, Ultimate Post Kit branding will be hidden from the admin interface and widgets.', 'ultimate-post-kit'); ?>
3160 - <?php elseif (!$is_license_active): ?>
3161 - <?php esc_html_e('This feature requires an active Ultimate Post Kit license. Please activate your license first.', 'ultimate-post-kit'); ?>
3162 - <?php else: ?>
3163 - <?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'); ?>
3164 - <?php endif; ?>
3165 - </p>
3166 - </div>
3167 - <div class="upk-option-switch">
3168 - <?php
3169 - $white_label_enabled = ($is_license_active && $is_white_label_eligible) ? get_option('upk_white_label_enabled', false) : false;
3170 - // Convert to boolean to ensure proper comparison
3171 - $white_label_enabled = (bool) $white_label_enabled;
3172 - ?>
3173 - <label class="switch">
3174 - <input type="checkbox"
3175 - id="upk-white-label-enabled"
3176 - name="upk_white_label_enabled"
3177 - <?php checked($white_label_enabled, true); ?>
3178 - <?php disabled(!$is_license_active || !$is_white_label_eligible); ?>>
3179 - <span class="slider"></span>
3180 - </label>
3181 - </div>
3182 - </div>
3183 - </div>
3184 - </div>
3185 -
3186 - <!-- White Label Title Field (conditional) -->
3187 - <div class="upk-option-item upk-white-label-fields" style="<?php echo ($white_label_enabled && $is_license_active && $is_white_label_eligible) ? '' : 'display: none;'; ?>">
3188 - <div class="upk-option-item-inner bdt-card">
3189 - <div class="upk-white-label-title-section bdt-margin-medium-bottom">
3190 - <h3 class="upk-option-title"><?php esc_html_e('White Label Title', 'ultimate-post-kit'); ?></h3>
3191 - <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>
3192 - <div class="upk-white-label-input-wrapper bdt-margin-small-top">
3193 - <input type="text"
3194 - id="upk-white-label-title"
3195 - name="upk_white_label_title"
3196 - class="upk-white-label-input"
3197 - placeholder="<?php esc_attr_e('Enter your custom title...', 'ultimate-post-kit'); ?>"
3198 - value="<?php echo esc_attr(get_option('upk_white_label_title', '')); ?>"
3199 - <?php disabled(!$is_license_active || !$is_white_label_eligible); ?>>
3200 - </div>
3201 - </div>
3202 -
3203 - <hr class="bdt-divider-small">
3204 -
3205 - <!-- White Label Title Icon Field -->
3206 - <div class="upk-white-label-icon-section bdt-margin-medium-top">
3207 - <h3 class="upk-option-title"><?php esc_html_e('White Label Title Icon', 'ultimate-post-kit'); ?></h3>
3208 - <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>
3209 -
3210 - <div class="upk-icon-upload-wrapper bdt-margin-small-top">
3211 - <?php
3212 - $icon_url = get_option('upk_white_label_icon', '');
3213 - $icon_id = get_option('upk_white_label_icon_id', '');
3214 - ?>
3215 - <div class="upk-icon-preview-container" style="<?php echo $icon_url ? '' : 'display: none;'; ?>">
3216 - <div class="upk-icon-preview">
3217 - <img id="upk-icon-preview-img" src="<?php echo esc_url($icon_url); ?>" alt="<?php echo esc_attr__( 'Icon Preview', 'ultimate-post-kit' ); ?>" style="max-width: 64px; max-height: 64px; border: 1px solid #ddd; border-radius: 4px; padding: 8px; background: #fff;">
3218 - </div>
3219 - <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;">
3220 - <span class="dashicons dashicons-trash"></span>
3221 - <?php esc_html_e('Remove', 'ultimate-post-kit'); ?>
3222 - </button>
3223 - </div>
3224 -
3225 - <div class="upk-icon-upload-container">
3226 - <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); ?>>
3227 - <span class="dashicons dashicons-cloud-upload"></span>
3228 - <?php esc_html_e('Upload Icon', 'ultimate-post-kit'); ?>
3229 - </button>
3230 - <input type="hidden" id="upk-white-label-icon" name="upk_white_label_icon" value="<?php echo esc_attr($icon_url); ?>">
3231 - <input type="hidden" id="upk-white-label-icon-id" name="upk_white_label_icon_id" value="<?php echo esc_attr($icon_id); ?>">
3232 - </div>
3233 - </div>
3234 -
3235 - <p class="upk-input-help">
3236 - <?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'); ?>
3237 - </p>
3238 - </div>
3239 -
3240 - <!-- White Label Plugin Logo Field -->
3241 - <div class="upk-white-label-logo-section bdt-margin-medium-top">
3242 - <h3 class="upk-option-title"><?php esc_html_e('Plugin Logo', 'ultimate-post-kit'); ?></h3>
3243 - <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>
3244 - <div class="upk-logo-upload-wrapper-inner">
3245 - <div class="upk-logo-upload-wrapper bdt-margin-small-top">
3246 - <?php
3247 - $logo_url = get_option('upk_white_label_logo', '');
3248 - $logo_id = get_option('upk_white_label_logo_id', '');
3249 - ?>
3250 - <div class="upk-logo-preview-container" style="<?php echo $logo_url ? '' : 'display: none;'; ?>">
3251 - <div class="upk-logo-preview">
3252 - <img id="upk-logo-preview-img" src="<?php echo esc_url($logo_url); ?>" alt="<?php echo esc_attr__( 'Logo Preview', 'ultimate-post-kit' ); ?>" style="max-width: 200px; max-height: 64px; border: 1px solid #ddd; border-radius: 4px; padding: 8px; background: #fff;">
3253 - </div>
3254 - <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;">
3255 - <span class="dashicons dashicons-trash"></span>
3256 - </button>
3257 - </div>
3258 -
3259 - <div class="upk-logo-upload-container">
3260 - <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); ?>>
3261 - <span class="dashicons dashicons-cloud-upload"></span>
3262 - <?php esc_html_e('Upload Logo', 'ultimate-post-kit'); ?>
3263 - </button>
3264 - <input type="hidden" id="upk-white-label-logo" name="upk_white_label_logo" value="<?php echo esc_attr($logo_url); ?>">
3265 - <input type="hidden" id="upk-white-label-logo-id" name="upk_white_label_logo_id" value="<?php echo esc_attr($logo_id); ?>">
3266 - </div>
3267 - </div>
3268 - <p class="upk-input-help">
3269 - <?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'); ?>
3270 - </p>
3271 - </div>
3272 - </div>
3273 - </div>
3274 - </div>
3275 -
3276 - <!-- License 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('Hide License Menu', 'ultimate-post-kit'); ?></h3>
3282 - <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>
3283 - </div>
3284 - <div class="upk-option-switch">
3285 - <?php
3286 - $hide_license = get_option('upk_white_label_hide_license', false);
3287 - // Convert to boolean to ensure proper comparison
3288 - $hide_license = (bool) $hide_license;
3289 - ?>
3290 - <label class="switch">
3291 - <input type="checkbox"
3292 - id="upk-white-label-hide-license"
3293 - name="upk_white_label_hide_license"
3294 - <?php checked($hide_license, true); ?>
3295 - <?php disabled(!$is_license_active || !$is_white_label_eligible); ?>>
3296 - <span class="slider"></span>
3297 - </label>
3298 - </div>
3299 - </div>
3300 - </div>
3301 - </div>
3302 -
3303 - <!-- BDTUPK_HIDE Option (conditional) -->
3304 - <div class="upk-option-item upk-white-label-fields" style="<?php echo ($white_label_enabled && $is_license_active && $is_white_label_eligible) ? '' : 'display: none;'; ?>">
3305 - <div class="upk-option-item-inner bdt-card">
3306 - <div class="bdt-flex bdt-flex-between bdt-flex-middle">
3307 - <div>
3308 - <h3 class="upk-option-title"><?php esc_html_e('Enable BDTUPK_HIDE Constant', 'ultimate-post-kit'); ?></h3>
3309 - <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>
3310 - <?php
3311 - $bdtupk_hide = get_option('upk_white_label_bdtupk_hide', false);
3312 - if ($bdtupk_hide): ?>
3313 - <div class="bdt-alert bdt-alert-warning bdt-margin-small-top">
3314 - <p><strong>⚠️ BDTUPK_HIDE Currently Active</strong></p>
3315 - <p>Advanced white label mode is currently enabled. Ultimate Post Kit menus are hidden from the admin interface.</p>
3316 - </div>
3317 - <?php endif; ?>
3318 - </div>
3319 - <div class="upk-option-switch">
3320 - <?php
3321 - // Convert to boolean to ensure proper comparison
3322 - $bdtupk_hide = (bool) $bdtupk_hide;
3323 - ?>
3324 - <label class="switch">
3325 - <input type="checkbox"
3326 - id="upk-white-label-bdtupk-hide"
3327 - name="upk_white_label_bdtupk_hide"
3328 - <?php checked($bdtupk_hide, true); ?>
3329 - <?php disabled(!$is_license_active || !$is_white_label_eligible); ?>>
3330 - <span class="slider"></span>
3331 - </label>
3332 - </div>
3333 - </div>
3334 - </div>
3335 - </div>
3336 -
3337 - <?php if (!$bdtupk_hide && $is_license_active && $is_white_label_eligible): ?>
3338 - <div class="bdt-margin-small-top">
3339 - <div class="bdt-alert bdt-alert-danger">
3340 - <h4>📧 Email Access System</h4>
3341 - <p>When you enable BDTUPK_HIDE, an email will be automatically sent to:</p>
3342 - <ul style="margin: 10px 0;">
3343 - <li><strong>License Email:</strong> <?php echo esc_html(self::get_license_email()); ?></li>
3344 - <?php if (get_bloginfo('admin_email') !== self::get_license_email()): ?>
3345 - <li><strong>Admin Email:</strong> <?php echo esc_html(get_bloginfo('admin_email')); ?></li>
3346 - <?php endif; ?>
3347 - </ul>
3348 - <p>This email will contain a special access link that allows you to return to these settings even when BDTUPK_HIDE is active.</p>
3349 - </div>
3350 - </div>
3351 - <?php endif; ?>
3352 -
3353 - <!-- Success/Error Messages -->
3354 - <div id="upk-white-label-message" class="upk-white-label-message bdt-margin-small-top" style="display: none;">
3355 - <div class="bdt-alert bdt-alert-success" bdt-alert>
3356 - <a href class="bdt-alert-close" bdt-close></a>
3357 - <p><?php esc_html_e('White label settings saved successfully!', 'ultimate-post-kit'); ?></p>
3358 - </div>
3359 - </div>
3360 - </div>
3361 - </div>
3362 - <?php
3363 - }
3364 -
3365 1756 public static function license_wl_status() {
3366 1757 $status = get_option('ultimate_post_kit_license_title_status');
3367 1758
3368 1759 if ($status) {
@@ -3457,9 +1848,11 @@
3457 1848 </div>
3458 1849
3459 1850 <div class="upk-canvas-wrap">
3460 1851 <canvas id="bdt-db-total-status" style="height: 100px; width: 100px;"
3461 - data-label="<?php echo esc_attr( sprintf( __( 'Total Widgets Status - (%s)', 'ultimate-post-kit' ), $used_widgets + $un_used_widgets ) ); ?>"
1852 + data-label="<?php
1853 + /* translators: %s: Total number of widgets */
1854 + echo esc_attr( sprintf( __( 'Total Widgets Status - (%s)', 'ultimate-post-kit' ), $used_widgets + $un_used_widgets ) ); ?>"
3462 1855 data-labels="<?php echo esc_attr( sprintf( '%1$s, %2$s', __( 'Used', 'ultimate-post-kit' ), __( 'Unused', 'ultimate-post-kit' ) ) ); ?>"
3463 1856 data-value="<?php echo esc_attr($used_widgets) . ',' . esc_attr($un_used_widgets); ?>"
3464 1857 data-bg="#FFD166, #fff4d9" data-bg-hover="#0673e1, #e71522"></canvas>
3465 1858 </div>
@@ -3495,9 +1888,11 @@
3495 1888 </div>
3496 1889
3497 1890 <div class="upk-canvas-wrap">
3498 1891 <canvas id="bdt-db-only-widget-status" style="height: 100px; width: 100px;"
3499 - data-label="<?php echo esc_attr( sprintf( __( 'Core Widgets Status - (%s)', 'ultimate-post-kit' ), $used_only_widgets + $unused_only_widgets ) ); ?>"
1892 + data-label="<?php
1893 + /* translators: %s: Total number of core widgets */
1894 + echo esc_attr( sprintf( __( 'Core Widgets Status - (%s)', 'ultimate-post-kit' ), $used_only_widgets + $unused_only_widgets ) ); ?>"
3500 1895 data-labels="<?php echo esc_attr( sprintf( '%1$s, %2$s', __( 'Used', 'ultimate-post-kit' ), __( 'Unused', 'ultimate-post-kit' ) ) ); ?>"
3501 1896 data-value="<?php echo esc_attr($used_only_widgets) . ',' . esc_attr($unused_only_widgets); ?>"
3502 1897 data-bg="#EF476F, #ffcdd9" data-bg-hover="#0673e1, #e71522"></canvas>
3503 1898 </div>
@@ -3545,8 +1940,9 @@
3545 1940 <a href class="bdt-alert-close" bdt-close></a>
3546 1941 <div class="bdt-text-default">
3547 1942 <?php
3548 1943 printf(
1944 + /* translators: 1: opening bold tag, 2: closing bold tag */
3549 1945 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'),
3550 1946 '<b>', '</b>'
3551 1947 );
3552 1948
@@ -3647,9 +2043,9 @@
3647 2043 <div>
3648 2044 <span class="label1"><?php esc_html_e('Uploads folder writable:', 'ultimate-post-kit'); ?></span>
3649 2045
3650 2046 <?php
3651 - if (!is_writable($upload_path)) {
2047 + if (!wp_is_writable($upload_path)) {
3652 2048 echo wp_kses_post($no_icon);
3653 2049 } else {
3654 2050 echo wp_kses_post($yes_icon);
3655 2051 }
@@ -3709,10 +2105,10 @@
3709 2105
3710 2106 <div class="bdt-admin-alert">
3711 2107 <strong><?php esc_html_e('Note:', 'ultimate-post-kit'); ?></strong>
3712 2108 <?php
3713 - /* translators: %s: Plugin name 'Ultimate Post Kit' */
3714 2109 printf(
2110 + /* translators: %s: Plugin name 'Ultimate Post Kit' */
3715 2111 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'),
3716 2112 '<b>Ultimate Post Kit</b>'
3717 2113 );
3718 2114 ?>
@@ -3742,61 +2138,9 @@
3742 2138 // Plugin is not installed
3743 2139 return 'not_installed';
3744 2140 }
3745 2141
3746 - /**
3747 - * AJAX handler for saving custom code
3748 - *
3749 - * @access public
3750 - * @return void
3751 - */
3752 - public function save_custom_code_ajax() {
3753 - // Verify nonce
3754 - if ( ! wp_verify_nonce( $_POST['nonce'] ?? '', 'upk_custom_code_nonce' ) ) {
3755 - wp_send_json_error( [ 'message' => 'Invalid security token.' ] );
3756 - }
3757 2142
3758 - // Check user capability
3759 - if ( ! current_user_can( 'manage_options' ) ) {
3760 - wp_send_json_error( [ 'message' => 'Insufficient permissions.' ] );
3761 - }
3762 -
3763 - // Sanitize and save the custom code
3764 - $custom_css = isset( $_POST['custom_css'] ) ? wp_unslash( $_POST['custom_css'] ) : '';
3765 - $custom_js = isset( $_POST['custom_js'] ) ? wp_unslash( $_POST['custom_js'] ) : '';
3766 - $custom_css_2 = isset( $_POST['custom_css_2'] ) ? wp_unslash( $_POST['custom_css_2'] ) : '';
3767 - $custom_js_2 = isset( $_POST['custom_js_2'] ) ? wp_unslash( $_POST['custom_js_2'] ) : '';
3768 -
3769 - // Handle excluded pages - ensure we get proper array format
3770 - $excluded_pages = array();
3771 - if ( isset( $_POST['excluded_pages'] ) ) {
3772 - if ( is_array( $_POST['excluded_pages'] ) ) {
3773 - $excluded_pages = $_POST['excluded_pages'];
3774 - } elseif ( is_string( $_POST['excluded_pages'] ) && ! empty( $_POST['excluded_pages'] ) ) {
3775 - // Handle case where it might be a single value
3776 - $excluded_pages = [ $_POST['excluded_pages'] ];
3777 - }
3778 - }
3779 -
3780 - // Sanitize excluded pages - convert to integers and remove empty values
3781 - $excluded_pages = array_map( 'intval', $excluded_pages );
3782 - $excluded_pages = array_filter( $excluded_pages, function( $page_id ) {
3783 - return $page_id > 0;
3784 - } );
3785 -
3786 - // Save to database
3787 - update_option( 'upk_custom_css', $custom_css );
3788 - update_option( 'upk_custom_js', $custom_js );
3789 - update_option( 'upk_custom_css_2', $custom_css_2 );
3790 - update_option( 'upk_custom_js_2', $custom_js_2 );
3791 - update_option( 'upk_excluded_pages', $excluded_pages );
3792 -
3793 - wp_send_json_success( [
3794 - 'message' => 'Custom code saved successfully!',
3795 - 'excluded_count' => count( $excluded_pages )
3796 - ] );
3797 - }
3798 -
3799 2143 /**
3800 2144 * Handle AJAX plugin installation
3801 2145 *
3802 2146 * @access public
@@ -3803,9 +2147,10 @@
3803 2147 * @return void
3804 2148 */
3805 2149 public function install_plugin_ajax() {
3806 2150 // Check nonce
3807 - if (!wp_verify_nonce($_POST['nonce'], 'upk_install_plugin_nonce')) {
2151 + $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
2152 + if (!wp_verify_nonce( $nonce, 'upk_install_plugin_nonce')) {
3808 2153 wp_send_json_error(['message' => __('Security check failed', 'ultimate-post-kit')]);
3809 2154 }
3810 2155
3811 2156 // Check user capability
@@ -3812,9 +2157,9 @@
3812 2157 if (!current_user_can('install_plugins')) {
3813 2158 wp_send_json_error(['message' => __('You do not have permission to install plugins', 'ultimate-post-kit')]);
3814 2159 }
3815 2160
3816 - $plugin_slug = sanitize_text_field($_POST['plugin_slug']);
2161 + $plugin_slug = isset($_POST['plugin_slug']) ? sanitize_text_field(wp_unslash($_POST['plugin_slug'])) : '';
3817 2162
3818 2163 if (empty($plugin_slug)) {
3819 2164 wp_send_json_error(['message' => __('Plugin slug is required', 'ultimate-post-kit')]);
3820 2165 }
@@ -3907,183 +2252,11 @@
3907 2252 __('Install', 'ultimate-post-kit') . '</a>';
3908 2253 }
3909 2254 }
3910 2255
3911 - /**
3912 - * Extra Options Start Here
3913 - */
3914 2256
3915 - /**
3916 - * Render Custom CSS & JS Section
3917 - *
3918 - * @access public
3919 - * @return void
3920 - */
3921 - public function render_custom_css_js_section() {
3922 - ?>
3923 - <div class="upk-custom-code-section">
3924 - <!-- Header Section -->
3925 - <div class="upk-code-section-header">
3926 - <h2 class="upk-section-title"><?php esc_html_e('Header Code Injection', 'ultimate-post-kit'); ?></h2>
3927 - <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>
3928 - </div>
3929 - <div class="upk-code-row bdt-grid bdt-grid-small" bdt-grid>
3930 - <div class="bdt-width-1-2@m">
3931 - <div class="upk-code-editor-wrapper">
3932 - <h3 class="upk-code-editor-title"><?php esc_html_e('CSS', 'ultimate-post-kit'); ?></h3>
3933 - <p class="upk-code-editor-description"><?php esc_html_e('Enter raw CSS code without &lt;style&gt; tags.', 'ultimate-post-kit'); ?></p>
3934 - <div class="upk-codemirror-editor-container">
3935 - <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>
3936 - </div>
3937 - </div>
3938 - </div>
3939 - <div class="bdt-width-1-2@m">
3940 - <div class="upk-code-editor-wrapper">
3941 - <h3 class="upk-code-editor-title"><?php esc_html_e('JS', 'ultimate-post-kit'); ?></h3>
3942 - <p class="upk-code-editor-description"><?php esc_html_e('Enter raw JavaScript code without &lt;script&gt; tags.', 'ultimate-post-kit'); ?></p>
3943 - <div class="upk-codemirror-editor-container">
3944 - <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>
3945 - </div>
3946 - </div>
3947 - </div>
3948 - </div>
3949 2257
3950 - <!-- Footer Section -->
3951 - <div class="upk-code-section-header bdt-margin-medium-top">
3952 - <h2 class="upk-section-title"><?php esc_html_e('Footer Code Injection', 'ultimate-post-kit'); ?></h2>
3953 - <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>
3954 - </div>
3955 - <div class="upk-code-row bdt-grid bdt-grid-small bdt-margin-small-top" bdt-grid>
3956 - <div class="bdt-width-1-2@m">
3957 - <div class="upk-code-editor-wrapper">
3958 - <h3 class="upk-code-editor-title"><?php esc_html_e('CSS', 'ultimate-post-kit'); ?></h3>
3959 - <p class="upk-code-editor-description"><?php esc_html_e('Enter raw CSS code without &lt;style&gt; tags.', 'ultimate-post-kit'); ?></p>
3960 - <div class="upk-codemirror-editor-container">
3961 - <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>
3962 - </div>
3963 - </div>
3964 - </div>
3965 - <div class="bdt-width-1-2@m">
3966 - <div class="upk-code-editor-wrapper">
3967 - <h3 class="upk-code-editor-title"><?php esc_html_e('JS', 'ultimate-post-kit'); ?></h3>
3968 - <p class="upk-code-editor-description"><?php esc_html_e('Enter raw JavaScript code without &lt;script&gt; tags.', 'ultimate-post-kit'); ?></p>
3969 - <div class="upk-codemirror-editor-container">
3970 - <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>
3971 - </div>
3972 - </div>
3973 - </div>
3974 - </div>
3975 -
3976 - <!-- Page Exclusion Section -->
3977 - <div class="upk-code-section-header bdt-margin-medium-top">
3978 - <h2 class="upk-section-title"><?php esc_html_e('Page & Post Exclusion Settings', 'ultimate-post-kit'); ?></h2>
3979 - <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>
3980 - </div>
3981 - <div class="upk-page-exclusion-wrapper">
3982 - <label for="upk-excluded-pages" class="upk-exclusion-label">
3983 - <?php esc_html_e('Exclude Pages & Posts:', 'ultimate-post-kit'); ?>
3984 - </label>
3985 - <select id="upk-excluded-pages" name="upk_excluded_pages[]" multiple class="upk-page-select">
3986 - <option value=""><?php esc_html_e('-- Select pages/posts to exclude --', 'ultimate-post-kit'); ?></option>
3987 - <?php
3988 - $excluded_pages = get_option('upk_excluded_pages', array());
3989 - if (!is_array($excluded_pages)) {
3990 - $excluded_pages = array();
3991 - }
3992 -
3993 - // Get all published pages
3994 - $pages = get_pages(array(
3995 - 'sort_order' => 'ASC',
3996 - 'sort_column' => 'post_title',
3997 - 'post_status' => 'publish'
3998 - ));
3999 -
4000 - // Get recent posts (last 50)
4001 - $posts = get_posts(array(
4002 - 'numberposts' => 50,
4003 - 'post_status' => 'publish',
4004 - 'post_type' => 'post',
4005 - 'orderby' => 'date',
4006 - 'order' => 'DESC'
4007 - ));
4008 -
4009 - // Display pages first
4010 - if (!empty($pages)) {
4011 - echo '<optgroup label="' . esc_attr__('Pages', 'ultimate-post-kit') . '">';
4012 - foreach ($pages as $page) {
4013 - $selected = in_array($page->ID, $excluded_pages) ? 'selected' : '';
4014 - echo '<option value="' . esc_attr($page->ID) . '" ' . $selected . '>' . esc_html($page->post_title) . '</option>';
4015 - }
4016 - echo '</optgroup>';
4017 - }
4018 -
4019 - // Then display posts
4020 - if (!empty($posts)) {
4021 - echo '<optgroup label="' . esc_attr__('Recent Posts', 'ultimate-post-kit') . '">';
4022 - foreach ($posts as $post) {
4023 - $selected = in_array($post->ID, $excluded_pages) ? 'selected' : '';
4024 - $post_date = date('M j, Y', strtotime($post->post_date));
4025 - echo '<option value="' . esc_attr($post->ID) . '" ' . $selected . '>' . esc_html($post->post_title) . ' (' . $post_date . ')</option>';
4026 - }
4027 - echo '</optgroup>';
4028 - }
4029 - ?>
4030 - </select>
4031 - <p class="upk-exclusion-help">
4032 - <?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'); ?>
4033 - </p>
4034 - </div>
4035 -
4036 - <!-- Success/Error Messages -->
4037 - <div id="upk-custom-code-message" class="upk-code-message bdt-margin-small-top" style="display: none;">
4038 - <div class="bdt-alert bdt-alert-success" bdt-alert>
4039 - <a href class="bdt-alert-close" bdt-close></a>
4040 - <p><?php esc_html_e('Custom code saved successfully!', 'ultimate-post-kit'); ?></p>
4041 - </div>
4042 - </div>
4043 - </div>
4044 - <?php
4045 - }
4046 -
4047 2258 /**
4048 - * Extra Options Start Here
4049 - */
4050 -
4051 - public function ultimate_post_kit_extra_options() {
4052 - ?>
4053 - <div class="upk-dashboard-panel"
4054 - bdt-scrollspy="target: > div > div > .bdt-card; cls: bdt-animation-slide-bottom-small; delay: 300">
4055 - <div class="upk-dashboard-extra-options">
4056 - <div class="bdt-card bdt-card-body">
4057 - <h1 class="upk-feature-title"><?php esc_html_e('Extra Options', 'ultimate-post-kit'); ?></h1>
4058 -
4059 - <div class="upk-extra-options-tabs">
4060 - <ul class="bdt-tab" bdt-tab="connect: #upk-extra-options-tab-content; animation: bdt-animation-fade">
4061 - <li class="bdt-active"><a
4062 - href="#"><?php esc_html_e('Custom CSS & JS', 'ultimate-post-kit'); ?></a></li>
4063 - <li><a href="#"><?php esc_html_e('White Label', 'ultimate-post-kit'); ?></a></li>
4064 - </ul>
4065 -
4066 - <div id="upk-extra-options-tab-content" class="bdt-switcher">
4067 - <!-- Custom CSS & JS Tab -->
4068 - <div>
4069 - <?php $this->render_custom_css_js_section(); ?>
4070 - </div>
4071 -
4072 - <!-- White Label Tab -->
4073 - <div>
4074 - <?php $this->render_white_label_section(); ?>
4075 - </div>
4076 - </div>
4077 - </div>
4078 - </div>
4079 - </div>
4080 - </div>
4081 - <?php
4082 - }
4083 -
4084 -
4085 - /**
4086 2259 * Rollback Version Content
4087 2260 *
4088 2261 * @access public
4089 2262 * @return void
@@ -4092,130 +2265,8 @@
4092 2265 // Use the already initialized rollback version instance
4093 2266 $this->rollback_version->upk_rollback_version_content();
4094 2267 }
4095 2268
4096 - /**
4097 - * Get allowed white label license types (SHA-256 hashes)
4098 - * This centralized method makes it easy to add new license types in the future
4099 - * Note: AppSumo and Lifetime licenses require WL flag in other_param instead of automatic access
4100 - *
4101 - * @access public static
4102 - * @return array Array of SHA-256 hashes for allowed license types
4103 - */
4104 - public static function get_white_label_allowed_license_types() {
4105 - $allowed_types = [
4106 - 'agency' => 'c4b2af4722ee54e317672875b2d8cf49aa884bf5820ec6091114fea5ec6560e4',
4107 - 'extended' => '4d7120eb6c796b04273577476eb2e20c34c51d7fa1025ec19c3414448abc241e',
4108 - 'developer' => '88fa0d759f845b47c044c2cd44e29082cf6fea665c30c146374ec7c8f3d699e3',
4109 - // Note: AppSumo and Lifetime licenses removed from automatic access
4110 - // They require WL flag in other_param for white label functionality
4111 - ];
4112 -
4113 - return $allowed_types;
4114 - }
4115 -
4116 - /**
4117 - * Revoke white label access token
4118 - *
4119 - * @access public
4120 - * @return bool
4121 - */
4122 - public function revoke_white_label_access_token() {
4123 - $token_data = get_option( 'upk_white_label_access_token', [] );
4124 -
4125 - if ( ! empty( $token_data ) ) {
4126 - delete_option( 'upk_white_label_access_token' );
4127 - return true;
4128 - }
4129 -
4130 - return false;
4131 - }
4132 -
4133 - /**
4134 - * Validate white label access token
4135 - *
4136 - * @access public
4137 - * @param string $token
4138 - * @return bool
4139 - */
4140 - public function validate_white_label_access_token( $token ) {
4141 - $stored_token_data = get_option( 'upk_white_label_access_token', [] );
4142 -
4143 - if ( empty( $stored_token_data ) || ! isset( $stored_token_data['token'] ) ) {
4144 - return false;
4145 - }
4146 -
4147 - // Check token match
4148 - if ( $stored_token_data['token'] !== $token ) {
4149 - return false;
4150 - }
4151 -
4152 - // Check if token was generated for current license
4153 - $current_license_key = self::get_license_key();
4154 - if ( $stored_token_data['license_key'] !== $current_license_key ) {
4155 - return false;
4156 - }
4157 -
4158 - return true;
4159 - }
4160 -
4161 - /**
4162 - * AJAX handler for revoking white label access token
4163 - *
4164 - * @access public
4165 - * @return void
4166 - */
4167 - public function revoke_white_label_token_ajax() {
4168 - // Check nonce and permissions
4169 - if (!wp_verify_nonce($_POST['nonce'], 'upk_white_label_nonce')) {
4170 - wp_send_json_error(['message' => __('Security check failed', 'ultimate-post-kit')]);
4171 - }
4172 -
4173 - if (!current_user_can('manage_options')) {
4174 - wp_send_json_error(['message' => __('You do not have permission to manage white label settings', 'ultimate-post-kit')]);
4175 - }
4176 -
4177 - // Check license eligibility
4178 - if (!self::is_white_label_license()) {
4179 - wp_send_json_error(['message' => __('Your license does not support white label features', 'ultimate-post-kit')]);
4180 - }
4181 -
4182 - // Revoke the token
4183 - $revoked = $this->revoke_white_label_access_token();
4184 -
4185 - if ($revoked) {
4186 - wp_send_json_success([
4187 - 'message' => __('White label access token has been revoked successfully', 'ultimate-post-kit')
4188 - ]);
4189 - } else {
4190 - wp_send_json_error([
4191 - 'message' => __('No active access token found to revoke', 'ultimate-post-kit')
4192 - ]);
4193 - }
4194 - }
4195 -
4196 - /**
4197 - * Get License Key
4198 - *
4199 - * @access public
4200 - * @return string
4201 - */
4202 -
4203 - public static function get_license_key() {
4204 - $license_key = get_option('ultimate_post_kit_license_key');
4205 - return trim($license_key);
4206 - }
4207 -
4208 - /**
4209 - * Get License Email
4210 - *
4211 - * @access public
4212 - * @return string
4213 - */
4214 -
4215 - public static function get_license_email() {
4216 - return trim(get_option('ultimate_post_kit_license_email', get_bloginfo('admin_email')));
4217 - }
4218 2269
4219 2270 }
4220 2271
4221 2272 new UltimatePostKit_Admin_Settings();