PluginProbe
Pixel Gallery Addons for Elementor – Easy Grid, Creative Gallery, Drag and Drop Grid, Custom Grid Layout, Portfolio Gallery / 2.1.13
Pixel Gallery Addons for Elementor – Easy Grid, Creative Gallery, Drag and Drop Grid, Custom Grid Layout, Portfolio Gallery v2.1.13
2.1.14 2.1.13 2.1.12 2.1.11 2.1.10 2.1.9 2.1.8 2.1.7 trunk 1.2.2 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.4.0 1.4.1 1.4.10 1.4.11 1.4.2 1.4.3 1.4.5 1.4.6 All 74 releases
pixel-gallery / admin / admin-settings.php

admin-settings.php in Pixel Gallery Addons for Elementor – Easy Grid, Creative Gallery, Drag and Drop Grid, Custom Grid Layout, Portfolio Gallery 2.1.13, at admin/admin-settings.php

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