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