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