PluginProbe
WowAddons – Product Addons and Product Options With Custom Fields / trunk
WowAddons – Product Addons and Product Options With Custom Fields vtrunk
1.7.2 1.7.1 1.7.0 1.6.21 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.5.10 1.5.11 1.5.2 1.5.3 1.5.4 1.5.5 All 57 releases
product-addons / includes / admin / class-notice.php

class-notice.php in WowAddons – Product Addons and Product Options With Custom Fields trunk, at includes/admin/class-notice.php

1,088 lines 33.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php //phpcs:ignore
2 namespace PRAD\Includes\Admin;
3
4 use PRAD\Includes\Admin\Durbin\DurbinClient;
5 use PRAD\Includes\Xpo;
6
7 defined( 'ABSPATH' ) || exit;
8
9 /**
10 * Plugin Notice
11 */
12 class Notice {
13
14 /**
15 * Notice version
16 *
17 * @var string $notice_version
18 */
19 private $notice_version = 'v1511';
20
21 /**
22 * Flag to check if notice JS and CSS have been applied
23 *
24 * @var bool $notice_js_css_applied
25 */
26 private $notice_js_css_applied = false;
27 /**
28 * Constructor for the Notice class.
29 *
30 * Initializes admin notice hooks and REST API routes.
31 */
32
33 /**
34 * Notice Priority
35 *
36 * @var string $plugin_notice_priority
37 */
38 private $plugin_notice_priority = 2;
39
40 /**
41 * Notice Priority
42 *
43 * @var string $plugin_notice_priority
44 */
45 private $plugin_notice_priority_key = 'wow_addons';
46
47 public function __construct() {
48 add_action( 'admin_notices', array( $this, 'admin_notices_callback' ) );
49 add_action( 'admin_init', array( $this, 'set_dismiss_notice_callback' ) );
50
51 // REST API routes.
52 add_action( 'rest_api_init', array( $this, 'register_rest_route' ) );
53
54 add_filter( 'xpo_active_notice_lists', array( $this, 'handle_xpo_active_notice_lists' ), 99, 1 );
55 }
56
57 /**
58 * Registers REST API endpoints.
59 *
60 * @return void
61 */
62 public function register_rest_route() {
63 $routes = array(
64 // Hello Bar.
65 array(
66 'endpoint' => 'hello_bar',
67 'methods' => 'POST',
68 'callback' => array( $this, 'hello_bar_callback' ),
69 'permission_callback' => function () {
70 return current_user_can( Xpo::prad_manage_admin_permisson_handler() );
71 },
72 ),
73 );
74
75 foreach ( $routes as $route ) {
76 register_rest_route(
77 'prad/v1',
78 $route['endpoint'],
79 array(
80 array(
81 'methods' => $route['methods'],
82 'callback' => $route['callback'],
83 'permission_callback' => $route['permission_callback'],
84 ),
85 )
86 );
87 }
88 }
89
90 /**
91 * Handle Plugin Notice for all plugins
92 *
93 * @param array $active_lists Lists of all active plugin notice.
94 * @return array
95 */
96 public function handle_xpo_active_notice_lists( $active_lists ) {
97
98 if ( $this->prad_dashboard_banner_notice( true ) || $this->prad_dashboard_content_notice( true ) || $this->prad_dashboard_image_banner_notice( true ) ) {
99 $active_lists[ $this->plugin_notice_priority_key ] = $this->plugin_notice_priority;
100 }
101
102 return $active_lists;
103 }
104
105 /**
106 * Handle Plugin Notice for all plugins
107 *
108 * @return bool
109 */
110 public function is_available_for_notice() {
111 $active_notices = apply_filters( 'xpo_active_notice_lists', array() );
112
113 if ( empty( $active_notices ) ) {
114 return true;
115 }
116
117 asort( $active_notices );
118
119 return array_key_first( $active_notices ) === $this->plugin_notice_priority_key;
120 }
121
122 /**
123 * Hellobar config
124 *
125 * @return array
126 */
127 public static function get_hellobar_config() {
128 return array(
129 'prad_helloBar_summer_sale_2026_vv1' => Xpo::get_transient_without_cache( 'prad_helloBar_summer_sale_2026_vv1' ),
130 'prad_helloBar_summer_sale_2026_vv1_x1' => Xpo::get_transient_without_cache( 'prad_helloBar_summer_sale_2026_vv1_x1' ),
131 'prad_helloBar_summer1_flash_sale_2026_2' => Xpo::get_transient_without_cache( 'prad_helloBar_summer1_flash_sale_2026_2' ),
132 'prad_helloBar_base_price_sale_26' => Xpo::get_transient_without_cache( 'prad_helloBar_base_price_sale_26' ),
133 );
134 }
135
136 /**
137 * Handles Hello Bar dismissal action via REST API .
138 *
139 * @param \WP_REST_Request $request REST request object .
140 * @return \WP_REST_Response
141 */
142 public function hello_bar_callback( \WP_REST_Request $request ) {
143 $request_params = $request->get_params();
144 $type = isset( $request_params['type'] ) ? sanitize_text_field( $request_params['type'] ) : '';
145 $id = isset( $request_params['id'] ) ? sanitize_key( $request_params['id'] ) : '';
146
147 if ( 'hello_bar' === $type && ! empty( $id ) ) {
148 Xpo::set_transient_without_cache( $id, 'hide', 1296000 );
149 }
150
151 return new \WP_REST_Response(
152 array(
153 'success' => true,
154 'message' => __( 'Hello Bar Action performed', 'product-addons' ),
155 ),
156 200
157 );
158 }
159
160 /**
161 * Admin Notices Callback
162 *
163 * @return void
164 */
165 public function admin_notices_callback() {
166 $this->prad_dashboard_notice_callback();
167 $this->prad_dashboard_durbin_notice_callback();
168 }
169
170 /**
171 * Admin Dashboard Notice Callback
172 *
173 * @return void
174 */
175 public function prad_dashboard_notice_callback() {
176 if ( $this->is_available_for_notice() ) {
177 $this->prad_dashboard_banner_notice();
178 $this->prad_dashboard_content_notice();
179 $this->prad_dashboard_image_banner_notice();
180 }
181 }
182
183 /**
184 * Dashboard Banner Notice
185 *
186 * @return void
187 */
188 public function prad_dashboard_banner_notice( $return_bool = false ) {
189 $prad_db_nonce = wp_create_nonce( 'prad-nonce' );
190 $banner_notices = array(
191 array(
192 'key' => 'prad_banner_summer_flash_sale_2026_v1',
193 'start' => '2026-05-18 00:00 Asia/Dhaka',
194 'end' => '2026-05-21 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka.
195
196 'brand_color' => '#86a62c',
197
198 'left_image' => PRAD_URL . 'assets/img/dashboard_banner/flash_sale/left_image.png',
199 'right_image' => PRAD_URL . 'assets/img/dashboard_banner/flash_sale/right_image.png',
200 'bg_image' => PRAD_URL . 'assets/img/dashboard_banner/flash_sale/bg.png',
201 'text' => 'Hurry Before It Ends!',
202 'countdown_duration' => 259200, // Duration in seconds.
203 'countdown_color' => '#3CF357',
204 'url' => Xpo::generate_utm_link(
205 array(
206 'utmKey' => 'flash_sale',
207 )
208 ),
209
210 'visibility' => ! Xpo::is_lc_active(),
211 ),
212 array(
213 'key' => 'prad_banner_summer_surprise_sale_2026_v1',
214 'start' => '2026-05-29 00:00 Asia/Dhaka',
215 'end' => '2026-06-01 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka.
216
217 'brand_color' => '#86a62c',
218
219 'left_image' => PRAD_URL . 'assets/img/dashboard_banner/surprise_sale/left_image.png',
220 'right_image' => PRAD_URL . 'assets/img/dashboard_banner/surprise_sale/right_image.png',
221 'bg_image' => PRAD_URL . 'assets/img/dashboard_banner/surprise_sale/bg.png',
222 'text' => 'Hurry Before It Ends!',
223 'countdown_duration' => 259200, // Duration in seconds.
224 'countdown_color' => '#3CF357',
225 'url' => Xpo::generate_utm_link(
226 array(
227 'utmKey' => 'surprise_sale',
228 )
229 ),
230
231 'visibility' => ! Xpo::is_lc_active(),
232 ),
233 array(
234 'key' => 'prad_banner_summer_massive_sale_2026_v1',
235 'start' => '2026-06-17 00:00 Asia/Dhaka',
236 'end' => '2026-06-20 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka.
237
238 'brand_color' => '#86a62c',
239
240 'left_image' => PRAD_URL . 'assets/img/dashboard_banner/massive_sale/left_image.png',
241 'right_image' => PRAD_URL . 'assets/img/dashboard_banner/massive_sale/right_image.png',
242 'bg_image' => PRAD_URL . 'assets/img/dashboard_banner/massive_sale/bg.png',
243 'text' => 'Hurry Before It Ends!',
244 'countdown_duration' => 259200, // Duration in seconds.
245 'countdown_color' => '#3CF357',
246 'url' => Xpo::generate_utm_link(
247 array(
248 'utmKey' => 'massive_sale',
249 )
250 ),
251
252 'visibility' => ! Xpo::is_lc_active(),
253 ),
254 array(
255 'key' => 'prad_summer_final_hours_sale_2026_v1',
256 'start' => '2026-06-28 00:00 Asia/Dhaka',
257 'end' => '2026-06-30 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka.
258
259 'brand_color' => '#86a62c',
260
261 'left_image' => PRAD_URL . 'assets/img/dashboard_banner/final_hours_sale/left_image.png',
262 'right_image' => PRAD_URL . 'assets/img/dashboard_banner/final_hours_sale/right_image.png',
263 'bg_image' => PRAD_URL . 'assets/img/dashboard_banner/final_hours_sale/bg.png',
264 'text' => 'Hurry Before It Ends!',
265 'countdown_duration' => 259200, // Duration in seconds.
266 'countdown_color' => '#3CF357',
267 'url' => Xpo::generate_utm_link(
268 array(
269 'utmKey' => 'final_hour_sale',
270 )
271 ),
272
273 'visibility' => ! Xpo::is_lc_active(),
274 ),
275 );
276
277 foreach ( $banner_notices as $notice ) {
278 $notice_key = isset( $notice['key'] ) ? $notice['key'] : $this->notice_version;
279 if ( isset( $_GET['disable_prad_notice'] ) && $notice_key === sanitize_text_field(wp_unslash($_GET['disable_prad_notice'])) ) { // phpcs:ignore
280 continue;
281 }
282
283 $current_time = gmdate( 'U' );
284 $notice_start = gmdate( 'U', strtotime( $notice['start'] ) );
285 $notice_end = gmdate( 'U', strtotime( $notice['end'] ) );
286 if ( $current_time >= $notice_start && $current_time <= $notice_end && $notice['visibility'] ) {
287
288 $notice_transient = Xpo::get_transient_without_cache( 'prad_get_pro_notice_' . $notice_key );
289
290 if ( 'off' === $notice_transient ) {
291 continue;
292 }
293
294 if ( $return_bool ) { // Early return for Other plugin notice.
295 return true;
296 }
297
298 if ( ! $this->notice_js_css_applied ) {
299 $this->prad_banner_notice_js();
300 $this->notice_js_css_applied = true;
301 }
302 $query_args = array(
303 'disable_prad_notice' => $notice_key,
304 'prad_db_nonce' => $prad_db_nonce,
305 );
306 if ( isset( $notice['repeat_interval'] ) && $notice['repeat_interval'] ) {
307 $query_args['prad_interval'] = $notice['repeat_interval'];
308 }
309 ?>
310 <style type="text/css">
311 .prad-notice-wrapper.prad-banner-notice {
312 height: auto !important;
313 padding: 0 !important;
314 position: relative;
315 box-sizing: border-box;
316 background-repeat: no-repeat;
317 background-size: cover;
318 background-position: center;
319 }
320 .prad-notice-wrapper.prad-banner-notice .prad-banner-link {
321 width: 100%;
322 text-decoration: none;
323 display: block;
324 }
325 .prad-notice-wrapper.prad-banner-notice .prad-banner-content {
326 display: flex;
327 justify-content: space-between;
328 align-items: center;
329 max-width: 700px;
330 margin: 0 auto;
331 padding: 10px 16px;
332 gap: 16px;
333 }
334 .prad-notice-wrapper.prad-banner-notice .prad-banner-side-image {
335 display: block;
336 max-width: 100%;
337 height: auto;
338 max-height: 32px;
339 }
340 .prad-notice-wrapper.prad-banner-notice .prad-banner-main .prad-banner-main-text {
341 color: #ffffff;
342 }
343 .prad-notice-wrapper.prad-banner-notice .prad-banner-main {
344 display: flex;
345 flex-direction: column;
346 gap: 4px;
347 align-items: center;
348 justify-content: center;
349 font-weight: 700;
350 font-size: 18px;
351 color: #333333;
352 line-height: 1.2;
353 text-align: center;
354 }
355
356 @media screen and (max-width: 1100px) {
357 /* .prad-notice-wrapper.prad-banner-notice .prad-banner-content {
358 flex-direction: column;
359 } */
360 .prad-notice-wrapper.prad-banner-notice .prad-banner-content .prad-banner-main-text {
361 display: none;
362 }
363 }
364 @media screen and (max-width: 490px) {
365 .prad-notice-wrapper.prad-banner-notice {
366 display: none;
367 }
368 }
369 @media screen and (max-width: 782px) {
370 .prad-notice-wrapper.prad-banner-notice .prad-banner-content {
371 justify-content: center;
372 padding: 12px 32px 12px 12px;
373 }
374 .prad-notice-wrapper.prad-banner-notice .prad-banner-main {
375 font-size: 22px;
376 line-height: 28px;
377 }
378 }
379 @media screen and (max-width: 480px) {
380 .prad-notice-wrapper.prad-banner-notice .prad-banner-content {
381 padding: 10px 32px 10px 10px;
382 }
383 .prad-notice-wrapper.prad-banner-notice .prad-banner-main {
384 font-size: 18px;
385 line-height: 24px;
386 }
387 }
388 </style>
389 <div
390 class="prad-notice-wrapper prad-banner-notice notice"
391 style="
392 border-left: 3px solid <?php echo esc_attr( $notice['brand_color'] ); ?>;
393 background-image: url('<?php echo esc_attr( $notice['bg_image'] ); ?>');
394 ">
395 <a
396 class="wc-dismiss-notice dashicons dashicons-no-alt"
397 style="
398 position: absolute;
399 top: 1px;
400 right: 1px;
401 border-radius: 50%;
402 background-color: black;
403 color: white;
404 font-size: 14px;
405 display: flex;
406 align-items: center;
407 justify-content: center;
408 "
409 aria-label="<?php esc_html_e( 'Close Banner', 'product-addons' ); ?>"
410 href="<?php echo esc_url( add_query_arg( $query_args ) ); ?>">
411 </a>
412
413 <a class="prad-banner-link" target="_blank" href="<?php echo esc_url( $notice['url'] ); ?>">
414 <div class="prad-banner-content">
415 <img class="prad-banner-side-image" loading="lazy" src="<?php echo esc_url( $notice['left_image'] ); ?>" />
416 <div class="prad-banner-main">
417 <span class="prad-banner-main-text">
418 <?php echo esc_html( $notice['text'] ); ?>
419 </span>
420 <div
421 class="prad-notice-countdown"
422 style="
423 color: <?php echo esc_attr( $notice['countdown_color'] ); ?>;
424 "
425 data-notice-key="<?php echo esc_attr( $notice_key . '-countdown' ); ?>"
426 data-duration="<?php echo esc_attr( $notice['countdown_duration'] ); ?>">
427 00:00:00:00
428 </div>
429 </div>
430 <img class="prad-banner-side-image" loading="lazy" src="<?php echo esc_url( $notice['right_image'] ); ?>" />
431 </div>
432 </a>
433 </div>
434
435 <?php
436 }
437 }
438 }
439
440 /**
441 * Dashboard Content Notice
442 *
443 * @param boolean $return_bool
444 * @return void
445 */
446 public function prad_dashboard_content_notice( $return_bool = false ) {
447
448 $content_notices = array(
449 array(
450 'key' => 'prad_dashboard_content_notice_summer_sale_2026_vv1',
451 'start' => '2026-07-06 00:00 Asia/Dhaka',
452 'end' => '2026-07-12 23:59 Asia/Dhaka',
453 'url' => Xpo::generate_utm_link(
454 array(
455 'utmKey' => 'summer_db',
456 )
457 ),
458 'visibility' => ! Xpo::is_lc_active(),
459 'content_heading' => __( '', 'product-addons' ),
460 /* translators: %s: discount percentage */
461 'content_subheading' => __( 'WowAddons Summer Sale Offer is Live - Enjoy up to %s on WowAddons Pro.', 'product-addons' ),
462 'discount_content' => ' 50% OFF',
463 'border_color' => '#86a62c',
464 'icon' => PRAD_URL . 'assets/img/dashboard_banner/logo.svg',
465 'button_text' => __( 'Upgrade Now!', 'product-addons' ),
466 'is_discount_logo' => true,
467 ),
468 array(
469 'key' => 'prad_dashboard_content_notice_summer_sale_2026_vv2_1',
470 'start' => '2026-08-02 00:00 Asia/Dhaka',
471 'end' => '2026-08-08 23:59 Asia/Dhaka',
472 'url' => Xpo::generate_utm_link(
473 array(
474 'utmKey' => 'summer_db',
475 )
476 ),
477 'visibility' => ! Xpo::is_lc_active(),
478 'content_heading' => __( '', 'product-addons' ),
479 /* translators: %s: discount percentage */
480 'content_subheading' => __( 'WowAddons Summer Sale Offer is Live - Enjoy up to %s on WowAddons Pro.', 'product-addons' ),
481 'discount_content' => ' 50% OFF',
482 'border_color' => '#86a62c',
483 'icon' => PRAD_URL . 'assets/img/dashboard_banner/discount_50.svg',
484 'button_text' => __( 'Upgrade Now!', 'product-addons' ),
485 'is_discount_logo' => true,
486 ),
487
488 );
489
490 $prad_db_nonce = wp_create_nonce( 'prad-nonce' );
491
492 foreach ( $content_notices as $key => $notice ) {
493 $notice_key = isset( $notice['key'] ) ? $notice['key'] : $this->notice_version;
494 if (
495 isset( $_GET['disable_prad_notice'] ) &&
496 $notice_key === $_GET['disable_prad_notice'] &&
497 isset( $_GET['prad_db_nonce'] ) &&
498 wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['prad_db_nonce'] ) ), 'prad-dashboard-nonce' )
499 ) {
500 continue;
501 } else {
502 $border_color = $notice['border_color'];
503
504 $current_time = gmdate( 'U' );
505 $notice_start = gmdate( 'U', strtotime( $notice['start'] ) );
506 $notice_end = gmdate( 'U', strtotime( $notice['end'] ) );
507 if ( $current_time >= $notice_start && $current_time <= $notice_end && $notice['visibility'] ) {
508 $notice_transient = Xpo::get_transient_without_cache( 'prad_get_pro_notice_' . $notice_key );
509
510 if ( 'off' !== $notice_transient ) {
511
512 if ( $return_bool ) { // Early return for Other plugin notice.
513 return true;
514 }
515
516 $query_args = array(
517 'disable_prad_notice' => $notice_key,
518 'prad_db_nonce' => $prad_db_nonce,
519 );
520 if ( isset( $notice['repeat_interval'] ) && $notice['repeat_interval'] ) {
521 $query_args['prad_interval'] = $notice['repeat_interval'];
522 }
523
524 $url = isset( $notice['url'] ) ? $notice['url'] : Xpo::generate_utm_link(
525 array(
526 'utmKey' => 'content_notice',
527 )
528 );
529
530 ?>
531
532 <style id="prad-notice-css" type="text/css">
533 .prad-content-notice-wrapper {
534 border: 1px solid #c3c4c7;
535 border-left: 3px solid #037fff;
536 margin: 15px 0 !important;
537 display: flex;
538 align-items: center;
539 background: #ffffff;
540 width: 100%;
541 padding: 10px 0;
542 position: relative;
543 box-sizing: border-box;
544 }
545
546 .prad-content-notice-wrapper.notice {
547 margin: 10px 0;
548 width: calc(100% - 20px);
549 }
550
551 .wrap .prad-content-notice-wrapper.notice {
552 width: 100%;
553 }
554
555 .prad-content-notice-icon {
556 margin-left: 15px;
557 }
558
559 .prad-content-notice-discout-icon {
560 margin-left: 10px;
561 }
562
563 .prad-content-notice-icon img {
564 max-width: 42px;
565 height: 70px;
566 }
567
568 .prad-content-notice-discout-icon img {
569 height: 70px;
570 width: 70px;
571 }
572
573 .prad-notice-content-wrapper {
574 display: flex;
575 flex-direction: column;
576 gap: 8px;
577 font-size: 14px;
578 line-height: 20px;
579 margin-left: 15px;
580 }
581
582 .prad-content-notice-buttons {
583 display: flex;
584 align-items: center;
585 gap: 15px;
586 }
587
588 .prad-content-notice-btn {
589 font-weight: 600;
590 text-transform: uppercase !important;
591 padding: 2px 10px !important;
592 background-color: #86a62c;
593 border: none !important;
594 }
595
596 .prad-content-discount_btn {
597 background-color: #ffffff;
598 text-decoration: none;
599 border: 1px solid #86a62c;
600 padding: 5px 10px;
601 border-radius: 5px;
602 font-weight: 500;
603 text-transform: uppercase;
604 color: #86a62c !important;
605 }
606
607 .prad-content-notice-close {
608 position: absolute;
609 right: 2px;
610 top: 5px;
611 text-decoration: none;
612 color: #b6b6b6;
613 font-family: dashicons;
614 font-size: 16px;
615 line-height: 20px;
616 }
617
618 .prad-content-notice-close-icon {
619 font-size: 14px;
620 }
621 </style>
622 <div class="prad-content-notice-wrapper notice data_collection_notice"
623 style="border-left: 3px solid <?php echo esc_attr( $border_color ); ?>;"
624 >
625 <?php
626 if ( $notice['is_discount_logo'] ) {
627 ?>
628 <div class="prad-content-notice-discout-icon"> <img src="<?php echo esc_url( $notice['icon'] ); ?>"/> </div>
629 <?php
630 } else {
631 ?>
632 <div class="prad-content-notice-icon"> <img src="<?php echo esc_url( $notice['icon'] ); ?>"/> </div>
633 <?php
634 }
635 ?>
636
637 <div class="prad-notice-content-wrapper">
638 <div class="">
639 <strong><?php printf( esc_html( $notice['content_heading'] ) ); ?> </strong>
640 <?php
641 printf(
642 wp_kses_post( $notice['content_subheading'] ),
643 '<strong>' . esc_html( $notice['discount_content'] ) . '</strong>'
644 );
645 ?>
646 </div>
647 <div class="prad-content-notice-buttons">
648 <?php if ( isset( $notice['is_discount_logo'] ) && $notice['is_discount_logo'] ) : ?>
649 <a class="prad-content-discount_btn" href="<?php echo esc_url( $url ); ?>" target="_blank">
650 <?php echo esc_html( $notice['button_text'] ); ?>
651 </a>
652 <?php else : ?>
653 <a class="prad-content-notice-btn button button-primary" href="<?php echo esc_url( $url ); ?>" target="_blank" style="background-color: <?php echo ! empty( $notice['background_color'] ) ? esc_attr( $notice['background_color'] ) : '#86a62c'; ?>;">
654 <?php echo esc_html( $notice['button_text'] ); ?>
655
656 </a>
657 <?php endif; ?>
658 </div>
659 </div>
660 <a href=
661 <?php
662 echo esc_url(
663 add_query_arg(
664 $query_args
665 )
666 );
667 ?>
668 class="prad-content-notice-close"><span class="prad-content-notice-close-icon dashicons dashicons-dismiss"> </span></a>
669 </div>
670 <?php
671 }
672 }
673 }
674 }
675 }
676
677 public function prad_dashboard_image_banner_notice( $return_bool = false ) {
678 $prad_db_nonce = wp_create_nonce( 'prad-nonce' );
679 $banner_notices = array(
680 array(
681 'key' => 'prad_summer_sale_2612',
682 'start' => '2026-07-20 00:00 Asia/Dhaka', // format YY-MM-DD always set time 00:00 and zone Asia/Dhaka
683 'end' => '2026-08-01 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka
684 'banner_src' => PRAD_URL . 'assets/img/dashboard_banner/summer_sale/summer_sale_26.png',
685 'url' => Xpo::generate_utm_link(
686 array(
687 'utmKey' => 'summer_db',
688 )
689 ),
690 'close_color' => '#000000',
691 'visibility' => ! Xpo::is_lc_active(),
692 ),
693 array(
694 'key' => 'prad_summer_sale_2613',
695 'start' => '2026-08-09 00:00 Asia/Dhaka', // format YY-MM-DD always set time 00:00 and zone Asia/Dhaka
696 'end' => '2026-08-16 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka
697 'banner_src' => PRAD_URL . 'assets/img/dashboard_banner/summer_sale/summer_sale_26.png',
698 'url' => Xpo::generate_utm_link(
699 array(
700 'utmKey' => 'summer_db',
701 )
702 ),
703 'close_color' => '#000000',
704 'visibility' => ! Xpo::is_lc_active(),
705 ),
706 array(
707 'key' => 'prad_preco_sale_campaign_262_1',
708 'start' => '2026-08-23 00:00 Asia/Dhaka', // format YY-MM-DD always set time 00:00 and zone Asia/Dhaka
709 'end' => '2026-08-29 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka
710 'banner_src' => PRAD_URL . 'assets/img/dashboard_banner/preco_banner_insider_deal.png',
711 'url' => 'https://www.wpxpo.com/product/wowrecommend/?utm_source=db-wowaddons-notice&utm_medium=insider-deal&utm_campaign=wowaddons-dashboard/#pricing',
712 'close_color' => '#ffffff',
713 'visibility' => ! Xpo::is_lc_active(),
714 ),
715 array(
716 'key' => 'prad_preco_sale_campaign_262_2',
717 'start' => '2026-08-30 00:00 Asia/Dhaka', // format YY-MM-DD always set time 00:00 and zone Asia/Dhaka.
718 'end' => '2026-09-19 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka.
719 'banner_src' => PRAD_URL . 'assets/img/dashboard_banner/preco_banner_early_bird.png',
720 'url' => 'https://www.wpxpo.com/product/wowrecommend/?utm_source=db-wowaddons-notice&utm_medium=early-bird&utm_campaign=wowaddons-dashboard/#pricing',
721 'close_color' => '#ffffff',
722 'visibility' => ! Xpo::is_lc_active(),
723 ),
724 );
725
726 foreach ( $banner_notices as $notice ) {
727 $notice_key = isset( $notice['key'] ) ? $notice['key'] : $this->notice_version;
728 if ( isset( $_GET['disable_prad_notice'] ) && $notice_key === sanitize_text_field(wp_unslash($_GET['disable_prad_notice'])) ) { // phpcs:ignore
729 continue;
730 }
731
732 $current_time = gmdate( 'U' );
733 $notice_start = gmdate( 'U', strtotime( $notice['start'] ) );
734 $notice_end = gmdate( 'U', strtotime( $notice['end'] ) );
735 if ( $current_time >= $notice_start && $current_time <= $notice_end && $notice['visibility'] ) {
736
737 $notice_transient = Xpo::get_transient_without_cache( 'prad_get_pro_notice_' . $notice_key );
738
739 if ( 'off' === $notice_transient ) {
740 continue;
741 }
742
743 if ( $return_bool ) { // Early return for Other plugin notice.
744 return true;
745 }
746
747 if ( ! $this->notice_js_css_applied ) {
748 $this->prad_banner_notice_js();
749 $this->notice_js_css_applied = true;
750 }
751 $query_args = array(
752 'disable_prad_notice' => $notice_key,
753 'prad_db_nonce' => $prad_db_nonce,
754 );
755 if ( isset( $notice['repeat_interval'] ) && $notice['repeat_interval'] ) {
756 $query_args['prad_interval'] = $notice['repeat_interval'];
757 }
758 ?>
759 <style type="text/css">
760 .prad-notice-wrapper.prad-image-notice-wrapper {
761 padding: 0 !important;
762 position: relative;
763 box-sizing: border-box;
764 overflow: hidden;
765 border-radius: 0px;
766 border: none !important;
767 }
768 .prad-notice-wrapper.prad-image-notice-wrapper .prad-image-banner {
769 position: relative;
770 line-height: 0;
771 }
772 .prad-notice-wrapper.prad-image-notice-wrapper .prad-btn-image {
773 display: block;
774 }
775 .prad-notice-wrapper.prad-image-notice-wrapper .prad-btn-image img {
776 display: block;
777 width: 100%;
778 height: auto;
779 border-radius: 0;
780 }
781 .prad-notice-wrapper.prad-image-notice-wrapper .prad-content-notice-close {
782 top: 4px;
783 right: 4px;
784 position: absolute;
785 z-index: 999;
786 }
787 @media screen and (max-width: 650px) {
788 .prad-image-notice-wrapper {
789 display: none;
790 }
791 }
792 </style>
793 <div class="prad-notice-wrapper prad-image-notice-wrapper notice wc-install prad-free-notice">
794 <div class="wc-install-body prad-image-banner">
795 <a class="wc-dismiss-notice prad-content-notice-close" href="
796 <?php
797 echo esc_url(
798 add_query_arg(
799 $query_args
800 )
801 );
802 ?>
803 "><span class="prad-content-notice-close-icon dashicons dashicons-dismiss" style="color: <?php echo esc_attr( $notice['close_color'] ); ?>;"> </span></a>
804 <a class="prad-btn-image" target="_blank" href="<?php echo esc_url( $notice['url'] ); ?>">
805 <img loading="lazy" src="<?php echo esc_url( $notice['banner_src'] ); ?>" alt="Discount Banner"/>
806 </a>
807 </div>
808 </div>
809
810 <?php
811 }
812 }
813 }
814
815
816 /**
817 * Banner JS
818 *
819 * @return void
820 */
821 public function prad_banner_notice_js() {
822 ?>
823 <script type="text/javascript">
824 jQuery(function($) {
825 'use strict';
826
827 const storagePrefix = 'prad_notice_countdown_';
828
829 const formatCountdown = function(seconds) {
830 const days = Math.floor(seconds / 86400);
831 const hours = Math.floor((seconds % 86400) / 3600);
832 const minutes = Math.floor((seconds % 3600) / 60);
833 const secs = seconds % 60;
834
835 return String(days).padStart(2, '0') + ':' + String(hours).padStart(2, '0') + ':' + String(minutes).padStart(2, '0') + ':' + String(secs).padStart(2, '0');
836 };
837
838 const parseDurationToSeconds = function(duration) {
839 if (typeof duration === 'number' && Number.isFinite(duration) && duration > 0) {
840 return Math.floor(duration);
841 }
842
843 const durationString = String(duration || '').trim();
844 if (/^\d+$/.test(durationString)) {
845 return parseInt(durationString, 10);
846 }
847
848 return 0;
849 };
850
851 const nowInSeconds = function() {
852 return Math.floor(Date.now() / 1000);
853 };
854
855 $('.prad-notice-countdown').each(function() {
856 const countdownElement = $(this);
857 const noticeKey = String(countdownElement.data('noticeKey') || '');
858 const duration = parseDurationToSeconds(countdownElement.data('duration'));
859
860 if (!noticeKey || duration <= 0) {
861 return;
862 }
863
864 const storageKey = storagePrefix + noticeKey;
865 let endAt = 0;
866
867 try {
868 const storedDataRaw = window.localStorage.getItem(storageKey);
869 if (storedDataRaw) {
870 const storedData = JSON.parse(storedDataRaw);
871 if (storedData && parseInt(storedData.duration, 10) === duration) {
872 endAt = parseInt(storedData.endAt, 10) || 0;
873 }
874 }
875 } catch (error) {
876 endAt = 0;
877 }
878
879 const saveTimerState = function(nextEndAt) {
880 try {
881 window.localStorage.setItem(
882 storageKey,
883 JSON.stringify({
884 endAt: nextEndAt,
885 duration: duration,
886 })
887 );
888 } catch (error) {
889 // No-op.
890 }
891 };
892
893 const resetTimer = function(currentTime) {
894 endAt = currentTime + duration;
895 saveTimerState(endAt);
896 };
897
898 const tick = function() {
899 const currentTime = nowInSeconds();
900
901 if (endAt <= currentTime) {
902 resetTimer(currentTime);
903 }
904
905 const remaining = Math.max(endAt - currentTime, 0);
906 countdownElement.text(formatCountdown(remaining));
907 };
908
909 if (endAt <= nowInSeconds()) {
910 resetTimer(nowInSeconds());
911 }
912
913 tick();
914 window.setInterval(tick, 1000);
915 });
916 });
917 </script>
918 <?php
919 }
920
921 /**
922 * Set Notice Dismiss Callback
923 *
924 * @return void
925 */
926 public function set_dismiss_notice_callback() {
927 $prad_db_nonce = sanitize_text_field( wp_unslash( $_GET['prad_db_nonce'] ?? '' ) );
928
929 if ( ! ( ! empty( $prad_db_nonce ) && wp_verify_nonce( $prad_db_nonce, 'prad-nonce' ) ) ) {
930 return;
931 }
932
933 $durbin_key = sanitize_text_field( wp_unslash( $_GET['prad_durbin_key'] ?? '' ) );
934
935 // Durbin notice dismiss.
936 if ( ! empty( $durbin_key ) ) {
937 Xpo::set_transient_without_cache( 'prad_durbin_notice_' . $durbin_key, 'off' );
938
939 if ( 'get' === sanitize_text_field( wp_unslash( $_GET['prad_get_durbin'] ?? '' ) ) ) {
940 DurbinClient::send( DurbinClient::ACTIVATE_ACTION );
941 }
942 }
943
944 // Install notice dismiss.
945 $install_key = sanitize_text_field( wp_unslash( $_GET['prad_install_key'] ?? '' ) );
946 if ( ! empty( $install_key ) ) {
947 Xpo::set_transient_without_cache( 'prad_install_notice_' . $install_key, 'off' );
948 }
949
950 $notice_key = sanitize_text_field( wp_unslash( $_GET['disable_prad_notice'] ?? '' ) );
951 if ( ! empty( $notice_key ) ) {
952 $interval = (int) sanitize_text_field( wp_unslash( $_GET['prad_interval'] ?? '' ) );
953 if ( ! empty( $interval ) ) {
954 Xpo::set_transient_without_cache( 'prad_get_pro_notice_' . $notice_key, 'off', $interval );
955 } else {
956 Xpo::set_transient_without_cache( 'prad_get_pro_notice_' . $notice_key, 'off' );
957 }
958 }
959 }
960
961
962 /**
963 * The Durbin Html
964 *
965 * @return string | HTML
966 */
967 public function prad_dashboard_durbin_notice_callback() {
968 $durbin_key = 'prad_durbin_dc2x';
969
970 if (
971 isset( $_GET['prad_durbin_key'] ) || // phpcs:ignore
972 'off' === Xpo::get_transient_without_cache( 'prad_durbin_notice_' . $durbin_key )
973 ) {
974 return;
975 }
976
977 if ( ! $this->notice_js_css_applied ) {
978 $this->notice_js_css_applied = true;
979 }
980
981 $prad_db_nonce = wp_create_nonce( 'prad-nonce' );
982
983 ?>
984 <style>
985 .prad-consent-box {
986 width: 656px;
987 padding: 16px !important;
988 border: 1px solid #070707;
989 border-left-width: 4px;
990 border-radius: 4px;
991 background-color: #fff;
992 position: relative;
993 width: 100%;
994 box-sizing: border-box;
995 }
996 .prad-consent-content {
997 display: flex;
998 justify-content: flex-start;
999 align-items: flex-end;
1000 gap: 26px;
1001 }
1002
1003 .prad-consent-text-first {
1004 font-size: 14px;
1005 font-weight: 600;
1006 color: #070707;
1007 }
1008 .prad-consent-text-last {
1009 margin: 4px 0 0;
1010 font-size: 14px;
1011 color: #070707;
1012 }
1013
1014 .prad-consent-accept {
1015 background-color: #070707;
1016 color: #fff;
1017 border: none;
1018 padding: 6px 10px;
1019 border-radius: 4px;
1020 cursor: pointer;
1021 font-size: 12px;
1022 font-weight: 600;
1023 text-decoration: none;
1024 }
1025 .prad-consent-accept:hover {
1026 background-color:rgb(38, 38, 38);
1027 color: #fff;
1028 }
1029 </style>
1030 <div class="prad-consent-box prad-notice-wrapper notice data_collection_notice">
1031 <div class="prad-consent-content">
1032 <div class="prad-consent-text">
1033 <div class="prad-consent-text-first"><?php esc_html_e( 'Want to help make WowAddons even more awesome?', 'product-addons' ); ?></div>
1034 <div class="prad-consent-text-last">
1035 <?php esc_html_e( 'Allow us to collect diagnostic data and usage information. see ', 'product-addons' ); ?>
1036 <a href="https://www.wpxpo.com/data-collection-policy/" target="_blank" ><?php esc_html_e( 'what we collect.', 'product-addons' ); ?></a>
1037 </div>
1038 </div>
1039 <a
1040 class="prad-consent-accept"
1041 href=
1042 <?php
1043 echo esc_url(
1044 add_query_arg(
1045 array(
1046 'prad_durbin_key' => $durbin_key,
1047 'prad_get_durbin' => 'get',
1048 'prad_db_nonce' => $prad_db_nonce,
1049 )
1050 )
1051 );
1052 ?>
1053 class="prad-notice-close"
1054 ><?php esc_html_e( 'Accept & Close', 'product-addons' ); ?></a>
1055 </div>
1056 <a href=
1057 <?php
1058 echo esc_url(
1059 add_query_arg(
1060 array(
1061 'prad_durbin_key' => $durbin_key,
1062 'prad_db_nonce' => $prad_db_nonce,
1063 )
1064 )
1065 );
1066 ?>
1067 class="prad-notice-close"
1068 style="
1069 position: absolute;
1070 right: 2px;
1071 top: 5px;
1072 text-decoration: unset;
1073 color: #b6b6b6;
1074 font-family: dashicons;
1075 font-size: 16px;
1076 font-style: normal;
1077 font-weight: 400;
1078 line-height: 20px;
1079 "
1080 >
1081 <span
1082 style="font-size: 14px;"
1083 class="prad-notice-close-icon dashicons dashicons-dismiss"> </span></a>
1084 </div>
1085 <?php
1086 }
1087 }
1088