PluginProbe
Post Grid Gutenberg Blocks – PostX / 5.1.0
Post Grid Gutenberg Blocks – PostX v5.1.0
5.1.1 5.1.0 5.0.41 5.0.39 5.0.38 5.0.37 5.0.36 5.0.35 5.0.34 5.0.33 5.0.32 5.0.31 5.0.30 5.0.29 5.0.28 5.0.27 5.0.26 5.0.25 5.0.23 5.0.24 5.0.22 5.0.21 5.0.20 5.0.19 5.0.18 All 240 releases
← All changes | includes/notice/class-notice.php +364 -328 5.0.19 → 5.1.0 View file →
@@ -25,10 +25,23 @@
25 25 * @var boolean
26 26 */
27 27 private $notice_js_css_applied = false;
28 28
29 + /**
30 + * Notice Priority
31 + *
32 + * @var string $plugin_notice_priority
33 + */
34 + private $plugin_notice_priority = 1;
29 35
30 36 /**
37 + * Notice Priority
38 + *
39 + * @var string $plugin_notice_priority
40 + */
41 + private $plugin_notice_priority_key = 'postx';
42 +
43 + /**
31 44 * Notice Constructor
32 45 */
33 46 public function __construct() {
34 47 add_action( 'admin_notices', array( $this, 'admin_notices_callback' ) );
@@ -38,8 +51,9 @@
38 51 add_action( 'rest_api_init', array( $this, 'register_rest_route' ) );
39 52
40 53 // Woocommerce Install Action
41 54 // add_action( 'wp_ajax_ultp_install', array( $this, 'install_activate_plugin' ) ); // this ajax not called anywhere in future need to removed, that is arise patchstack security issue
55 + add_filter( 'xpo_active_notice_lists', array( $this, 'handle_xpo_active_notice_lists' ), 99, 1 );
42 56 }
43 57
44 58 /**
45 59 * Registers REST API endpoints.
@@ -80,19 +94,12 @@
80 94 * @return array
81 95 */
82 96 public static function get_hellobar_config() {
83 97 return array(
84 - 'ultp_helloBar_spring_sale_2026_1' => Xpo::get_transient_without_cache( 'ultp_helloBar_spring_sale_2026_1' ),
85 - 'ultp_helloBar_spring_sale_2026_2' => Xpo::get_transient_without_cache( 'ultp_helloBar_spring_sale_2026_2' ),
86 - 'ultp_helloBar_spring_sale_2026_3' => Xpo::get_transient_without_cache( 'ultp_helloBar_spring_sale_2026_3' ),
87 - // Flash sale
88 - 'ultp_helloBar_flash_sale_2026_4' => Xpo::get_transient_without_cache( 'ultp_helloBar_flash_sale_2026_4' ),
89 - // Surprise sale
90 - 'ultp_helloBar_surprise_sale_2026_5' => Xpo::get_transient_without_cache( 'ultp_helloBar_surprise_sale_2026_5' ),
91 - // Massive sale
92 - 'ultp_helloBar_massive_sale_2026_6' => Xpo::get_transient_without_cache( 'ultp_helloBar_massive_sale_2026_6' ),
93 - // Final hours sale
94 - 'ultp_helloBar_final_hours_sale_2026_7' => Xpo::get_transient_without_cache( 'ultp_helloBar_final_hours_sale_2026_7' ),
98 + // Final hours sale.
99 + 'ultp_helloBar_summer_sale_2026_v1' => Xpo::get_transient_without_cache( 'ultp_helloBar_summer_sale_2026_v1' ),
100 + 'ultp_helloBar_summer_sale_2026_v1_2' => Xpo::get_transient_without_cache( 'ultp_helloBar_summer_sale_2026_v1_2' ),
101 + 'ultp_helloBar_base_price_2026' => Xpo::get_transient_without_cache( 'ultp_helloBar_base_price_2026' ),
95 102 );
96 103 }
97 104
98 105 /**
@@ -105,10 +112,17 @@
105 112 $request_params = $request->get_params();
106 113 $type = isset( $request_params['type'] ) ? $request_params['type'] : '';
107 114 $id = isset( $request_params['id'] ) ? $request_params['id'] : '';
108 115
109 - if ( 'hello_bar' === $type && ! empty( $id ) ) {
110 - Xpo::set_transient_without_cache( $id, 'hide', 1296000 );
116 + // Guideline 11 — a dismissal must stick. This previously expired after 15
117 + // days (1296000s), so a dismissed sale bar came back on its own. Passing 0
118 + // stores it with no timeout, which Xpo::get_transient_without_cache() reads
119 + // back indefinitely.
120 + //
121 + // $id names the option that gets written, so it is checked against the
122 + // known hellobar keys rather than trusted from the request.
123 + if ( 'hello_bar' === $type && ! empty( $id ) && array_key_exists( $id, self::get_hellobar_config() ) ) {
124 + Xpo::set_transient_without_cache( $id, 'hide', 0 );
111 125 }
112 126
113 127 return new \WP_REST_Response(
114 128 array(
@@ -125,9 +139,9 @@
125 139 * @return void
126 140 */
127 141 public function set_dismiss_notice_callback() {
128 142
129 - if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['wpnonce'] ?? '' ) ), 'ultp-nonce' ) ) {
143 + if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['wpnonce'] ?? '' ) ), 'ultp-admin-nonce' ) ) {
130 144 return;
131 145 }
132 146
133 147 $durbin_key = sanitize_text_field( wp_unslash( $_GET['ultp_durbin_key'] ?? '' ) );
@@ -172,10 +186,14 @@
172 186 *
173 187 * @return void
174 188 */
175 189 public function ultp_dashboard_notice_callback() {
176 - $this->ultp_dashboard_banner_notice();
177 - $this->ultp_dashboard_content_notice();
190 + if ( $this->is_available_for_notice() ) {
191 + $this->ultp_dashboard_banner_notice();
192 + $this->ultp_dashboard_content_notice();
193 + $this->ultp_dashboard_image_banner_notice();
194 +
195 + }
178 196 }
179 197
180 198 /**
181 199 * Dashboard Banner Notice
@@ -181,74 +199,13 @@
181 199 * Dashboard Banner Notice
182 200 *
183 201 * @return void
184 202 */
185 - public function ultp_dashboard_banner_notice() {
186 - $ultp_db_nonce = wp_create_nonce( 'ultp-nonce' );
203 + public function ultp_dashboard_banner_notice( $return_bool = false ) {
204 + $ultp_db_nonce = wp_create_nonce( 'ultp-admin-nonce' );
187 205 $banner_notices = array(
206 + // FLash sale.
188 207 array(
189 - 'key' => 'ultp_flash_sale_2026_1',
190 - 'start' => '2026-02-19 00:00 Asia/Dhaka',
191 - 'end' => '2026-02-23 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka.
192 - 'countdown_duration' => 259200, // Duration in seconds.
193 - 'brand_color' => '#0322ff',
194 -
195 - 'left_image' => ULTP_URL . 'assets/img/dashboard_banner/2026_flash_sale_logo.png',
196 - 'right_image' => ULTP_URL . 'assets/img/dashboard_banner/2026_final_hours_and_flash_sale_right_btn.png',
197 - 'bg_image' => ULTP_URL . 'assets/img/dashboard_banner/2026_spring_sale_bg.png',
198 - 'text' => 'Hurry Before It Ends!',
199 - 'countdown_color' => '#3CF357',
200 - 'url' => Xpo::generate_utm_link(
201 - array(
202 - 'utmKey' => 'flash_sale',
203 - )
204 - ),
205 -
206 - 'visibility' => ! Xpo::is_lc_active(),
207 - ),
208 - array(
209 - 'key' => 'ultp_final_hour_sale_2026_1',
210 - 'start' => '2026-02-25 00:00 Asia/Dhaka',
211 - 'end' => '2026-03-01 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka.
212 - 'brand_color' => '#0322ff',
213 - 'left_image' => ULTP_URL . 'assets/img/dashboard_banner/2026_final_hours_sale_logo.png',
214 - 'right_image' => ULTP_URL . 'assets/img/dashboard_banner/2026_final_hours_and_flash_sale_right_btn.png',
215 - 'bg_image' => ULTP_URL . 'assets/img/dashboard_banner/2026_final_hours_and_flash_sale_bg.png',
216 - 'text' => 'Hurry Before It Ends!',
217 - 'countdown_duration' => 172800, // Duration in seconds.
218 - 'countdown_color' => '#0322ff',
219 - 'url' => Xpo::generate_utm_link(
220 - array(
221 - 'utmKey' => 'final_hour',
222 - )
223 - ),
224 -
225 - 'visibility' => ! Xpo::is_lc_active(),
226 - ),
227 - array(
228 - 'key' => 'ultp_banner_spring_sale_2026_1',
229 - 'start' => '2026-04-05 00:00 Asia/Dhaka',
230 - 'end' => '2026-04-14 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka.
231 -
232 - 'brand_color' => '#0322ff',
233 -
234 - 'left_image' => ULTP_URL . 'assets/img/dashboard_banner/spring_sale/2026_spring_sale_offer.png',
235 - 'right_image' => ULTP_URL . 'assets/img/dashboard_banner/spring_sale/2026_spring_sale_button.png',
236 - 'bg_image' => ULTP_URL . 'assets/img/dashboard_banner/spring_sale/2026_spring_sale_bg.png',
237 - 'text' => 'Hurry Before It Ends!',
238 - 'countdown_duration' => 259200, // Duration in seconds.
239 - // 'countdown_color' => '#0322ff',
240 - 'countdown_color' => '#000',
241 - 'url' => Xpo::generate_utm_link(
242 - array(
243 - 'utmKey' => 'spring_sale',
244 - )
245 - ),
246 -
247 - 'visibility' => ! Xpo::is_lc_active(),
248 - ),
249 - // FLash sale
250 - array(
251 208 'key' => 'ultp_banner_flash_sale_2026_1',
252 209 'start' => '2026-05-18 00:00 Asia/Dhaka',
253 210 'end' => '2026-05-21 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka.
254 211
@@ -258,15 +215,15 @@
258 215 'right_image' => ULTP_URL . 'assets/img/dashboard_banner/flash_sale/btn.png',
259 216 'bg_image' => ULTP_URL . 'assets/img/dashboard_banner/flash_sale/bg.png',
260 217 'text' => 'Deal ending soon',
261 218 'countdown_duration' => 259200, // Duration in seconds.
262 - // 'countdown_color' => '#0322ff',
219 + // 'countdown_color' => '#0322ff',
263 220 'countdown_color' => '#3CF357',
264 221 'url' => Xpo::generate_utm_link(
265 222 array(
266 - 'utmKey' => 'flash_sale',
223 + 'utmKey' => 'flash_sale_content',
267 224 )
268 - ),
225 + ),
269 226
270 227 'visibility' => ! Xpo::is_lc_active(),
271 228 ),
272 229 // surprise sale
@@ -285,9 +242,9 @@
285 242 // 'countdown_color' => '#0322ff',
286 243 'countdown_color' => '#3CF357',
287 244 'url' => Xpo::generate_utm_link(
288 245 array(
289 - 'utmKey' => 'surprise_sale',
246 + 'utmKey' => 'surprise_sale_content',
290 247 )
291 248 ),
292 249
293 250 'visibility' => ! Xpo::is_lc_active(),
@@ -308,9 +265,9 @@
308 265 // 'countdown_color' => '#0322ff',
309 266 'countdown_color' => '#3CF357',
310 267 'url' => Xpo::generate_utm_link(
311 268 array(
312 - 'utmKey' => 'massive_sale',
269 + 'utmKey' => 'massive_sale_content',
313 270 )
314 271 ),
315 272
316 273 'visibility' => ! Xpo::is_lc_active(),
@@ -331,9 +288,9 @@
331 288 // 'countdown_color' => '#0322ff',
332 289 'countdown_color' => '#3CF357',
333 290 'url' => Xpo::generate_utm_link(
334 291 array(
335 - 'utmKey' => 'final_hours_sale',
292 + 'utmKey' => 'final_hours_content',
336 293 )
337 294 ),
338 295 'visibility' => ! Xpo::is_lc_active(),
339 296 ),
@@ -354,9 +311,11 @@
354 311
355 312 if ( 'off' === $notice_transient ) {
356 313 continue;
357 314 }
358 -
315 + if ( $return_bool ) { // Early return for Other plugin notice.
316 + return true;
317 + }
359 318 if ( ! $this->notice_js_css_applied ) {
360 319 $this->ultp_banner_notice_js();
361 320 $this->notice_js_css_applied = true;
362 321 }
@@ -367,32 +326,90 @@
367 326 if ( isset( $notice['repeat_interval'] ) && $notice['repeat_interval'] ) {
368 327 $query_args['ultp_interval'] = $notice['repeat_interval'];
369 328 }
370 329 ?>
371 - <style>
372 - @media only screen and (max-width: 1200px) {
373 - .ultp-notice-wrapper.notice .ultp-banner-logo-img {
374 - max-width: 230px;
330 + <style type="text/css">
331 + .ultp-notice-wrapper.ultp-banner-notice {
332 + height: auto !important;
333 + padding: 0 !important;
334 + position: relative;
335 + box-sizing: border-box;
336 + background-repeat: no-repeat;
337 + background-size: cover;
338 + background-position: center;
339 + }
340 + .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-link {
341 + width: 100%;
342 + text-decoration: none;
343 + display: block;
344 + }
345 + .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-content {
346 + display: flex;
347 + justify-content: space-between;
348 + align-items: center;
349 + max-width: 700px;
350 + margin: 0 auto;
351 + padding: 10px 16px;
352 + gap: 16px;
353 + }
354 + .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-side-image {
355 + display: block;
356 + max-width: 100%;
357 + height: auto;
358 + max-height: 32px;
359 + }
360 + .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-main .ultp-banner-main-text {
361 + color: #ffffff;
362 + }
363 + .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-main {
364 + display: flex;
365 + flex-direction: column;
366 + gap: 4px;
367 + align-items: center;
368 + justify-content: center;
369 + font-weight: 700;
370 + font-size: 18px;
371 + color: #333333;
372 + line-height: 1.2;
373 + text-align: center;
374 + }
375 +
376 + @media screen and (max-width: 1100px) {
377 + /* .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-content {
378 + flex-direction: column;
379 + } */
380 + .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-content .ultp-banner-main-text {
381 + display: none;
375 382 }
376 - .ultp-banner-grab-btn-img {
377 - max-width: 130px;
383 + }
384 + @media screen and (max-width: 490px) {
385 + .ultp-notice-wrapper.ultp-banner-notice {
386 + display: none;
378 387 }
379 - .ultp-notice-countdown {
388 + }
389 + @media screen and (max-width: 782px) {
390 + .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-content {
391 + justify-content: center;
392 + padding: 12px 32px 12px 12px;
393 + }
394 + .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-main {
395 + font-size: 22px;
396 + line-height: 28px;
397 + }
398 + }
399 + @media screen and (max-width: 480px) {
400 + .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-content {
401 + padding: 10px 32px 10px 10px;
402 + }
403 + .ultp-notice-wrapper.ultp-banner-notice .ultp-banner-main {
380 404 font-size: 18px;
405 + line-height: 24px;
381 406 }
382 - .ultp-notice-banner-title {
383 - font-size: 20px;
384 - }
385 407 }
386 408 </style>
387 409 <div
388 - class="ultp-notice-wrapper notice"
410 + class="ultp-notice-wrapper ultp-banner-notice notice"
389 411 style="
390 - height:90px;
391 - border-radius: 7px 0px 0px 7px;
392 - padding:0;
393 - position:relative;
394 - box-sizing: border-box;
395 412 border-left: 3px solid <?php echo esc_attr( $notice['brand_color'] ); ?>;
396 413 background-image: url('<?php echo esc_attr( $notice['bg_image'] ); ?>');
397 414 ">
398 415 <a
@@ -412,33 +429,13 @@
412 429 aria-label="<?php esc_html_e( 'Close Banner', 'ultimate-post' ); ?>"
413 430 href="<?php echo esc_url( add_query_arg( $query_args ) ); ?>">
414 431 </a>
415 432
416 - <a style="width:100%;text-decoration: none;" target="_blank" href="<?php echo esc_url( $notice['url'] ); ?>">
417 - <div style="
418 - display: flex;
419 - justify-content: space-between;
420 - align-items: center;
421 - max-width: 1358px;
422 - margin: 0px auto;
423 - padding: 10px 15px;
424 - height: 90px;
425 - box-sizing: border-box;
426 -
427 - ">
428 - <img class="ultp-banner-logo-img" style="" loading="lazy" src="<?php echo esc_url( $notice['left_image'] ); ?>" />
429 - <div style="
430 - display: flex;
431 - flex-direction: column;
432 - gap: 4px;
433 - align-items: center;
434 - justify-content: center;
435 - font-weight: 700;
436 - font-size: 28px;
437 - color: #000;
438 - line-height: 32px;
439 - ">
440 - <span class="ultp-notice-banner-title evgn-titile-text-white" style="color: #fff;">
433 + <a class="ultp-banner-link" target="_blank" href="<?php echo esc_url( $notice['url'] ); ?>">
434 + <div class="ultp-banner-content">
435 + <img class="ultp-banner-side-image" loading="lazy" src="<?php echo esc_url( $notice['left_image'] ); ?>" />
436 + <div class="ultp-banner-main">
437 + <span class="ultp-banner-main-text">
441 438 <?php echo esc_html( $notice['text'] ); ?>
442 439 </span>
443 440 <div
444 441 class="ultp-notice-countdown"
@@ -449,9 +446,9 @@
449 446 data-duration="<?php echo esc_attr( $notice['countdown_duration'] ); ?>">
450 447 00:00:00:00
451 448 </div>
452 449 </div>
453 - <img class="ultp-banner-grab-btn-img" style="" loading="lazy" src="<?php echo esc_url( $notice['right_image'] ); ?>" />
450 + <img class="ultp-banner-side-image" loading="lazy" src="<?php echo esc_url( $notice['right_image'] ); ?>" />
454 451 </div>
455 452 </a>
456 453 </div>
457 454 <?php
@@ -572,8 +569,15 @@
572 569 */
573 570 public function ultp_dashboard_durbin_notice_callback() {
574 571 $durbin_key = 'ultp_durbin_dc1';
575 572
573 + // Guideline 11 — the consent notice is allowed on PostX's own screens and,
574 + // as is standard immediately after activation, on plugins.php. Nowhere else.
575 + global $pagenow;
576 + if ( ! $this->is_postx_screen() && 'plugins.php' !== $pagenow ) {
577 + return;
578 + }
579 +
576 580 if (
577 581 isset( $_GET['ultp_durbin_key'] ) || // phpcs:ignore
578 582 'off' === Xpo::get_transient_without_cache( 'ultp_durbin_notice_' . $durbin_key )
579 583 ) {
@@ -583,9 +587,9 @@
583 587 if ( ! $this->notice_js_css_applied ) {
584 588 $this->notice_js_css_applied = true;
585 589 }
586 590
587 - $ultp_db_nonce = wp_create_nonce( 'ultp-nonce' );
591 + $ultp_db_nonce = wp_create_nonce( 'ultp-admin-nonce' );
588 592
589 593 ?>
590 594 <style>
591 595 .ultp-consent-box {
@@ -618,9 +622,9 @@
618 622 }
619 623
620 624 .ultp-consent-accept {
621 625 background-color: #070707;
622 - color: #fff;
626 + color: #fff !important;
623 627 border: none;
624 628 padding: 6px 10px;
625 629 border-radius: 4px;
626 630 cursor: pointer;
@@ -694,216 +698,56 @@
694 698 * Dashboard Content Notice
695 699 *
696 700 * @return void
697 701 */
698 - public function ultp_dashboard_content_notice() {
702 + public function ultp_dashboard_content_notice( $return_bool = false ) {
699 703 $content_notices = array(
700 704 array(
701 - 'key' => 'ultp_dashboard_content_notice_spring_sale_v1',
702 - 'start' => '2026-03-16 00:00 Asia/Dhaka',
703 - 'end' => '2026-03-25 23:59 Asia/Dhaka',
705 + 'key' => 'ultp_dashboard_content_notice_summer_sale_2026_vv1',
706 + 'start' => '2026-07-06 00:00 Asia/Dhaka',
707 + 'end' => '2026-07-12 23:59 Asia/Dhaka',
704 708 'url' => Xpo::generate_utm_link(
705 709 array(
706 - 'utmKey' => 'content_notice',
710 + 'utmKey' => 'summer_db',
707 711 )
708 712 ),
709 713 'visibility' => ! Xpo::is_lc_active(),
710 - 'content_heading' => __( 'Spring Sale:', 'ultimate-post' ),
711 - 'content_subheading' => __( 'PostX offers are live - Enjoy %s off on PostX Pro.', 'ultimate-post' ),
712 - 'discount_content' => ' up to 50% OFF',
713 - 'brand_color' => '#0322ff',
714 - 'icon' => ULTP_URL . 'assets/img/dashboard_banner/spring_sale/2026_spring_sale_brand_logo.png',
715 - 'button_text' => __( 'Claim Your Discount!', 'ultimate-post' ),
716 - 'is_discount_logo' => true,
714 + 'content_heading' => __( 'Summer Sale:', 'ultimate-post' ),
715 + /* translators: %s: discount percentage */
716 + 'content_subheading' => __( 'Enjoy up to %s on PostX Pro.', 'ultimate-post' ),
717 + 'discount_content' => ' 50% OFF',
717 718 'border_color' => '#0322ff',
718 - ),
719 - array(
720 - 'key' => 'ultp_dashboard_content_notice_spring_sale_v2',
721 - 'start' => '2026-03-26 00:00 Asia/Dhaka',
722 - 'end' => '2026-04-04 23:59 Asia/Dhaka',
723 - 'url' => Xpo::generate_utm_link(
724 - array(
725 - 'utmKey' => 'content_notice',
726 - )
727 - ),
728 - 'visibility' => ! Xpo::is_lc_active(),
729 - 'content_heading' => __( 'Spring Sale:', 'ultimate-post' ),
730 - 'content_subheading' => __( 'PostX offers are live - Enjoy %s off on PostX Pro.', 'ultimate-post' ),
731 - 'discount_content' => ' up to 50% OFF',
732 - 'brand_color' => '#0322ff',
733 - 'icon' => ULTP_URL . 'assets/img/dashboard_banner/spring_sale/2026_spring_discount_logo.png',
734 - 'button_text' => __( 'Claim Your Discount!', 'ultimate-post' ),
735 - 'is_discount_logo' => true,
736 - 'border_color' => '#0322ff',
737 - ),
738 -
739 - // Flash sale
740 - array(
741 - 'key' => 'ultp_dashboard_content_notice_flash_sale_brand_logo',
742 - 'start' => '2026-05-07 00:00 Asia/Dhaka',
743 - 'end' => '2026-05-12 23:59 Asia/Dhaka',
744 - 'url' => Xpo::generate_utm_link(
745 - array(
746 - 'utmKey' => 'flash_sale_content',
747 - )
748 - ),
749 - 'visibility' => ! Xpo::is_lc_active(),
750 - 'content_heading' => __( 'Flash Sale:', 'ultimate-post' ),
751 - 'content_subheading' => __( 'Enjoy %s on PostX Pro.', 'ultimate-post' ),
752 - 'discount_content' => ' up to 45% Off',
753 - 'brand_color' => '#0322ff',
754 719 'icon' => ULTP_URL . 'assets/img/dashboard_banner/brand_logo.svg',
755 - 'button_text' => __( 'Claim Your Discount!', 'ultimate-post' ),
756 - 'is_discount_logo' => true,
757 - 'border_color' => '#0322ff',
758 - ),
759 - array(
760 - 'key' => 'ultp_dashboard_content_notice_flash_sale_discount_logo',
761 - 'start' => '2026-05-13 00:00 Asia/Dhaka',
762 - 'end' => '2026-05-17 23:59 Asia/Dhaka',
763 - 'url' => Xpo::generate_utm_link(
764 - array(
765 - 'utmKey' => 'flash_sale_content',
766 - )
767 - ),
768 - 'visibility' => ! Xpo::is_lc_active(),
769 - 'content_heading' => __( 'Flash Sale:', 'ultimate-post' ),
770 - 'content_subheading' => __( 'Enjoy %s on PostX Pro.', 'ultimate-post' ),
771 - 'discount_content' => ' up to 45% Off',
772 - 'brand_color' => '#0322ff',
773 - 'icon' => ULTP_URL . 'assets/img/dashboard_banner/flash_sale_45_discount_logo.png',
774 720 'button_text' => __( 'Upgrade Now!', 'ultimate-post' ),
775 721 'is_discount_logo' => true,
776 - 'border_color' => '#0322ff',
777 722 ),
778 -
779 - // Surprise Sale
780 723 array(
781 - 'key' => 'ultp_dashboard_content_notice_surprise_sale_brand_logo',
782 - 'start' => '2026-05-22 00:00 Asia/Dhaka',
783 - 'end' => '2026-05-25 23:59 Asia/Dhaka',
724 + 'key' => 'ultp_dashboard_content_notice_summer_sale_2026_vv3',
725 + 'start' => '2026-08-02 00:00 Asia/Dhaka',
726 + 'end' => '2026-08-08 23:59 Asia/Dhaka',
784 727 'url' => Xpo::generate_utm_link(
785 728 array(
786 - 'utmKey' => 'surprise_sale_content',
729 + 'utmKey' => 'summer_db',
787 730 )
788 731 ),
789 732 'visibility' => ! Xpo::is_lc_active(),
790 - 'content_heading' => __( 'Surprise Sale:', 'ultimate-post' ),
791 - 'content_subheading' => __( 'Enjoy %s on PostX Pro.', 'ultimate-post' ),
792 - 'discount_content' => ' up to 50% Off',
793 - 'brand_color' => '#0322ff',
794 - 'icon' => ULTP_URL . 'assets/img/dashboard_banner/brand_logo.svg',
795 - 'button_text' => __( 'Claim Your Discount!', 'ultimate-post' ),
796 - 'is_discount_logo' => true,
733 + 'content_heading' => __( 'Summer Sale:', 'ultimate-post' ),
734 + /* translators: %s: discount percentage */
735 + 'content_subheading' => __( 'Enjoy up to %s on PostX Pro.', 'ultimate-post' ),
736 + 'discount_content' => ' 50% OFF',
797 737 'border_color' => '#0322ff',
798 - ),
799 - array(
800 - 'key' => 'ultp_dashboard_content_notice_surprise_sale_discount_logo',
801 - 'start' => '2026-05-26 00:00 Asia/Dhaka',
802 - 'end' => '2026-05-28 23:59 Asia/Dhaka',
803 - 'url' => Xpo::generate_utm_link(
804 - array(
805 - 'utmKey' => 'surprise_sale_content',
806 - )
807 - ),
808 - 'visibility' => ! Xpo::is_lc_active(),
809 - 'content_heading' => __( 'Surprise Sale:', 'ultimate-post' ),
810 - 'content_subheading' => __( 'Enjoy %s on PostX Pro.', 'ultimate-post' ),
811 - 'discount_content' => ' up to 50% Off',
812 - 'brand_color' => '#0322ff',
813 738 'icon' => ULTP_URL . 'assets/img/dashboard_banner/flash_sale_50_discount_logo.png',
814 739 'button_text' => __( 'Upgrade Now!', 'ultimate-post' ),
815 740 'is_discount_logo' => true,
816 - 'border_color' => '#0322ff',
817 741 ),
818 742
819 - // Massive Sale
820 - array(
821 - 'key' => 'ultp_dashboard_content_notice_massive_sale_brand_logo',
822 - 'start' => '2026-06-02 00:00 Asia/Dhaka',
823 - 'end' => '2026-06-10 23:59 Asia/Dhaka',
824 - 'url' => Xpo::generate_utm_link(
825 - array(
826 - 'utmKey' => 'massive_sale_content',
827 - )
828 - ),
829 - 'visibility' => ! Xpo::is_lc_active(),
830 - 'content_heading' => __( 'Massive Sale:', 'ultimate-post' ),
831 - 'content_subheading' => __( 'Enjoy %s on PostX Pro.', 'ultimate-post' ),
832 - 'discount_content' => ' up to 50% Off',
833 - 'brand_color' => '#0322ff',
834 - 'icon' => ULTP_URL . 'assets/img/dashboard_banner/brand_logo.svg',
835 - 'button_text' => __( 'Claim Your Discount!', 'ultimate-post' ),
836 - 'is_discount_logo' => true,
837 - 'border_color' => '#0322ff',
838 - ),
839 - array(
840 - 'key' => 'ultp_dashboard_content_notice_massive_sale_discount_logo',
841 - 'start' => '2026-06-11 00:00 Asia/Dhaka',
842 - 'end' => '2026-06-16 23:59 Asia/Dhaka',
843 - 'url' => Xpo::generate_utm_link(
844 - array(
845 - 'utmKey' => 'massive_sale_content',
846 - )
847 - ),
848 - 'visibility' => ! Xpo::is_lc_active(),
849 - 'content_heading' => __( 'Massive Sale:', 'ultimate-post' ),
850 - 'content_subheading' => __( 'Enjoy %s on PostX Pro.', 'ultimate-post' ),
851 - 'discount_content' => ' up to 50% Off',
852 - 'brand_color' => '#0322ff',
853 - 'icon' => ULTP_URL . 'assets/img/dashboard_banner/flash_sale_50_discount_logo.png',
854 - 'button_text' => __( 'Upgrade Now!', 'ultimate-post' ),
855 - 'is_discount_logo' => true,
856 - 'border_color' => '#0322ff',
857 - ),
858 -
859 - // Final Hours Sale
860 - array(
861 - 'key' => 'ultp_dashboard_content_notice_final_hours_sale_brand_logo',
862 - 'start' => '2026-06-21 00:00 Asia/Dhaka',
863 - 'end' => '2026-06-24 23:59 Asia/Dhaka',
864 - 'url' => Xpo::generate_utm_link(
865 - array(
866 - 'utmKey' => 'final_hour_content',
867 - )
868 - ),
869 - 'visibility' => ! Xpo::is_lc_active(),
870 - 'content_heading' => __( 'Final Hours Sale:', 'ultimate-post' ),
871 - 'content_subheading' => __( 'Enjoy %s on PostX Pro.', 'ultimate-post' ),
872 - 'discount_content' => ' up to 50% Off',
873 - 'brand_color' => '#0322ff',
874 - 'icon' => ULTP_URL . 'assets/img/dashboard_banner/brand_logo.svg',
875 - 'button_text' => __( 'Claim Your Discount!', 'ultimate-post' ),
876 - 'is_discount_logo' => true,
877 - 'border_color' => '#0322ff',
878 - ),
879 - array(
880 - 'key' => 'ultp_dashboard_content_notice_final_hours_sale_discount_logo',
881 - 'start' => '2026-06-25 00:00 Asia/Dhaka',
882 - 'end' => '2026-06-27 23:59 Asia/Dhaka',
883 - 'url' => Xpo::generate_utm_link(
884 - array(
885 - 'utmKey' => 'final_hour_content',
886 - )
887 - ),
888 - 'visibility' => ! Xpo::is_lc_active(),
889 - 'content_heading' => __( 'Final Hours Sale:', 'ultimate-post' ),
890 - 'content_subheading' => __( 'Enjoy %s on PostX Pro.', 'ultimate-post' ),
891 - 'discount_content' => ' up to 50% Off',
892 - 'brand_color' => '#0322ff',
893 - 'icon' => ULTP_URL . 'assets/img/dashboard_banner/flash_sale_50_discount_logo.png',
894 - 'button_text' => __( 'Upgrade Now!', 'ultimate-post' ),
895 - 'is_discount_logo' => true,
896 - 'border_color' => '#0322ff',
897 - ),
898 -
899 743 );
900 744
901 - $ultp_db_nonce = wp_create_nonce( 'ultp-nonce' );
745 + $ultp_db_nonce = wp_create_nonce( 'ultp-admin-nonce' );
902 746
903 747 foreach ( $content_notices as $key => $notice ) {
904 748 $notice_key = isset( $notice['key'] ) ? $notice['key'] : $this->notice_version;
905 - if ( isset( $_GET['ultp_notice'] ) && $notice_key === $_GET['ultp_notice'] ) {
749 + if ( isset( $_GET['ultp_notice'] ) && $notice_key === sanitize_text_field( wp_unslash( $_GET['ultp_notice'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only; hides the notice on this page view.
906 750 continue;
907 751 } else {
908 752 $border_color = $notice['border_color'];
909 753
@@ -913,9 +757,11 @@
913 757 if ( $current_time >= $notice_start && $current_time <= $notice_end && $notice['visibility'] ) {
914 758 $notice_transient = Xpo::get_transient_without_cache( 'ultp_get_pro_notice_' . $notice_key );
915 759
916 760 if ( 'off' !== $notice_transient ) {
917 -
761 + if ( $return_bool ) { // Early return for Other plugin notice.
762 + return true;
763 + }
918 764 $query_args = array(
919 765 'ultp_notice' => $notice_key,
920 766 'wpnonce' => $ultp_db_nonce,
921 767 );
@@ -1024,32 +870,32 @@
1024 870 </style>
1025 871 <div class="ultp-content-notice-wrapper notice data_collection_notice"
1026 872 style="border-left: 3px solid <?php echo esc_attr( $border_color ); ?>;"
1027 873 >
1028 - <?php
1029 - if ( $notice['is_discount_logo'] ) {
1030 - ?>
874 + <?php
875 + if ( $notice['is_discount_logo'] ) {
876 + ?>
1031 877 <div class="ultp-content-notice-discout-icon"> <img src="<?php echo esc_url( $notice['icon'] ); ?>"/> </div>
1032 - <?php
1033 - } else {
878 + <?php
879 + } else {
880 + ?>
881 + <div class="ultp-content-notice-icon"> <img src="<?php echo esc_url( $notice['icon'] ); ?>"/> </div>
882 + <?php
883 + }
1034 884 ?>
1035 - <div class="ultp-content-notice-icon"> <img src="<?php echo esc_url( $notice['icon'] ); ?>"/> </div>
1036 - <?php
1037 - }
1038 - ?>
1039 885
1040 886 <div class="ultp-notice-content-wrapper">
1041 887 <div class="">
1042 888 <strong><?php printf( esc_html( $notice['content_heading'] ) ); ?> </strong>
1043 - <?php
1044 - printf(
1045 - wp_kses_post( $notice['content_subheading'] ),
1046 - '<strong>' . esc_html( $notice['discount_content'] ) . '</strong>'
1047 - );
1048 - ?>
889 + <?php
890 + printf(
891 + wp_kses_post( $notice['content_subheading'] ),
892 + '<strong>' . esc_html( $notice['discount_content'] ) . '</strong>'
893 + );
894 + ?>
1049 895 </div>
1050 896 <div class="ultp-content-notice-buttons">
1051 - <?php if ( isset( $notice['is_discount_logo'] ) && $notice['is_discount_logo'] ) : ?>
897 + <?php if ( isset( $notice['is_discount_logo'] ) && $notice['is_discount_logo'] ) : ?>
1052 898 <a class="ultp-content-discount_btn" href="<?php echo esc_url( $url ); ?>" target="_blank">
1053 899 <?php echo esc_html( $notice['button_text'] ); ?>
1054 900 </a>
1055 901 <?php else : ?>
@@ -1069,11 +915,201 @@
1069 915 );
1070 916 ?>
1071 917 class="ultp-content-notice-close"><span class="ultp-content-notice-close-icon dashicons dashicons-dismiss"> </span></a>
1072 918 </div>
1073 - <?php
919 + <?php
1074 920 }
1075 921 }
922 + }
923 + }
924 + }
925 +
926 + /**
927 + * Handle Plugin Notice for all plugins
928 + *
929 + * @param array $active_lists Lists of all active plugin notice.
930 + * @return array
931 + */
932 + public function handle_xpo_active_notice_lists( $active_lists ) {
933 + if ( $this->ultp_dashboard_banner_notice( true ) || $this->ultp_dashboard_content_notice( true ) || $this->ultp_dashboard_image_banner_notice( true ) ) {
934 + $active_lists[ $this->plugin_notice_priority_key ] = $this->plugin_notice_priority;
935 + }
936 + return $active_lists;
937 + }
938 +
939 + /**
940 + * Handle Plugin Notice for all plugins
941 + *
942 + * @return bool
943 + */
944 + /**
945 + * Whether the current admin screen belongs to PostX.
946 + *
947 + * Guideline 11 limits promotional UI to the plugin's own screens. Every PostX
948 + * screen carries `ultp` in its screen id — `toplevel_page_ultp-settings`,
949 + * `postx_page_ultp-setup-wizard`, and the `ultp_builder` / `ultp_templates` /
950 + * `ultp_custom_font` post-type screens.
951 + *
952 + * @return BOOL True when the current screen is a PostX screen.
953 + */
954 + public function is_postx_screen() {
955 + if ( ! function_exists( 'get_current_screen' ) ) {
956 + return false;
957 + }
958 + $screen = get_current_screen();
959 + return $screen && false !== strpos( $screen->id, 'ultp' );
960 + }
961 +
962 + public function is_available_for_notice() {
963 + // Guideline 11 — sale banners and upgrade prompts belong on PostX's own
964 + // screens, not on core screens or other plugins' pages.
965 + if ( ! $this->is_postx_screen() ) {
966 + return false;
967 + }
968 +
969 + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Shared across WPXPO plugins (ProductX, WholesaleX, …); renaming breaks them.
970 + $active_notices = apply_filters( 'xpo_active_notice_lists', array() );
971 + if ( empty( $active_notices ) ) {
972 + return true;
973 + }
974 + asort( $active_notices );
975 + return array_key_first( $active_notices ) === $this->plugin_notice_priority_key;
976 + }
977 +
978 + public function ultp_dashboard_image_banner_notice( $return_bool = false ) {
979 + $ultp_db_nonce = wp_create_nonce( 'ultp-admin-nonce' );
980 + $banner_notices = array(
981 + array(
982 + 'key' => 'ultp_summer_sale_2612',
983 + 'start' => '2026-07-20 00:00 Asia/Dhaka', // format YY-MM-DD always set time 00:00 and zone Asia/Dhaka
984 + 'end' => '2026-08-01 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka
985 + 'banner_src' => ULTP_URL . 'assets/img/dashboard_banner/dashboard_banner_summer_sale.png',
986 + 'url' => Xpo::generate_utm_link(
987 + array(
988 + 'utmKey' => 'sub_menu_offer',
989 + )
990 + ),
991 + 'close_color' => '#000000',
992 + 'visibility' => ! Xpo::is_lc_active(),
993 + ),
994 + array(
995 + 'key' => 'ultp_summer_sale_2613',
996 + 'start' => '2026-08-09 00:00 Asia/Dhaka', // format YY-MM-DD always set time 00:00 and zone Asia/Dhaka
997 + 'end' => '2026-08-16 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka
998 + 'banner_src' => ULTP_URL . 'assets/img/dashboard_banner/dashboard_banner_summer_sale.png',
999 + 'url' => Xpo::generate_utm_link(
1000 + array(
1001 + 'utmKey' => 'sub_menu_offer',
1002 + )
1003 + ),
1004 + 'close_color' => '#000000',
1005 + 'visibility' => ! Xpo::is_lc_active(),
1006 + ),
1007 + array(
1008 + 'key' => 'ultp_preco_sale_campaign_262_1',
1009 + 'start' => '2026-08-23 00:00 Asia/Dhaka', // format YY-MM-DD always set time 00:00 and zone Asia/Dhaka
1010 + 'end' => '2026-08-29 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka
1011 + 'banner_src' => ULTP_URL . 'assets/img/dashboard_banner/preco_banner_insider_deal.png',
1012 + 'url' => 'https://www.wpxpo.com/product/wowrecommend/?utm_source=db-postx-notice&utm_medium=insider-deal&utm_campaign=postx-dashboard/#pricing',
1013 + 'close_color' => '#ffffff',
1014 + 'visibility' => ! Xpo::is_lc_active(),
1015 + ),
1016 + array(
1017 + 'key' => 'ultp_preco_sale_campaign_262_2',
1018 + 'start' => '2026-08-30 00:00 Asia/Dhaka', // format YY-MM-DD always set time 00:00 and zone Asia/Dhaka.
1019 + 'end' => '2026-09-19 23:59 Asia/Dhaka', // format YY-MM-DD always set time 23:59 and zone Asia/Dhaka.
1020 + 'banner_src' => ULTP_URL . 'assets/img/dashboard_banner/preco_banner_early_bird.png',
1021 + 'url' => 'https://www.wpxpo.com/product/wowrecommend/?utm_source=db-postx-notice&utm_medium=early-bird&utm_campaign=postx-dashboard/#pricing',
1022 + 'close_color' => '#ffffff',
1023 + 'visibility' => ! Xpo::is_lc_active(),
1024 + ),
1025 + );
1026 +
1027 + foreach ( $banner_notices as $notice ) {
1028 + $notice_key = isset( $notice['key'] ) ? $notice['key'] : $this->notice_version;
1029 + if ( isset( $_GET['ultp_notice'] ) && $notice_key === sanitize_text_field(wp_unslash($_GET['ultp_notice'])) ) { // phpcs:ignore
1030 + continue;
1031 + }
1032 +
1033 + $current_time = gmdate( 'U' );
1034 + $notice_start = gmdate( 'U', strtotime( $notice['start'] ) );
1035 + $notice_end = gmdate( 'U', strtotime( $notice['end'] ) );
1036 + if ( $current_time >= $notice_start && $current_time <= $notice_end && $notice['visibility'] ) {
1037 +
1038 + $notice_transient = Xpo::get_transient_without_cache( 'ultp_get_pro_notice_' . $notice_key );
1039 +
1040 + if ( 'off' === $notice_transient ) {
1041 + continue;
1042 + }
1043 +
1044 + if ( $return_bool ) { // Early return for Other plugin notice.
1045 + return true;
1046 + }
1047 +
1048 + if ( ! $this->notice_js_css_applied ) {
1049 + $this->ultp_banner_notice_js();
1050 + $this->notice_js_css_applied = true;
1051 + }
1052 + $query_args = array(
1053 + 'ultp_notice' => $notice_key,
1054 + 'wpnonce' => $ultp_db_nonce,
1055 + );
1056 + if ( isset( $notice['repeat_interval'] ) && $notice['repeat_interval'] ) {
1057 + $query_args['ultp_interval'] = $notice['repeat_interval'];
1058 + }
1059 + ?>
1060 + <style type="text/css">
1061 + .ultp-notice-wrapper.ultp-image-notice-wrapper {
1062 + padding: 0 !important;
1063 + position: relative;
1064 + box-sizing: border-box;
1065 + overflow: hidden;
1066 + border-radius: 0px;
1067 + border: none !important;
1068 + }
1069 + .ultp-notice-wrapper.ultp-image-notice-wrapper .ultp-image-banner {
1070 + position: relative;
1071 + line-height: 0;
1072 + }
1073 + .ultp-notice-wrapper.ultp-image-notice-wrapper .ultp-btn-image {
1074 + display: block;
1075 + }
1076 + .ultp-notice-wrapper.ultp-image-notice-wrapper .ultp-btn-image img {
1077 + display: block;
1078 + width: 100%;
1079 + height: auto;
1080 + border-radius: 0;
1081 + }
1082 + .ultp-notice-wrapper.ultp-image-notice-wrapper .ultp-content-notice-close {
1083 + top: 4px;
1084 + right: 4px;
1085 + position: absolute;
1086 + z-index: 999;
1087 + }
1088 + @media screen and (max-width: 650px) {
1089 + .ultp-image-notice-wrapper {
1090 + display: none;
1091 + }
1092 + }
1093 + </style>
1094 + <div class="ultp-notice-wrapper ultp-image-notice-wrapper notice wc-install ultp-free-notice">
1095 + <div class="wc-install-body ultp-image-banner">
1096 + <a class="wc-dismiss-notice ultp-content-notice-close" href="
1097 + <?php
1098 + echo esc_url(
1099 + add_query_arg(
1100 + $query_args
1101 + )
1102 + );
1103 + ?>
1104 + "><span class="ultp-content-notice-close-icon dashicons dashicons-dismiss" style="color: <?php echo esc_attr( $notice['close_color'] ); ?>;"> </span></a>
1105 + <a class="ultp-btn-image" target="_blank" href="<?php echo esc_url( $notice['url'] ); ?>">
1106 + <img loading="lazy" src="<?php echo esc_url( $notice['banner_src'] ); ?>" alt="Discount Banner"/>
1107 + </a>
1108 + </div>
1109 + </div>
1110 +
1111 + <?php
1076 1112 }
1077 1113 }
1078 1114 }
1079 1115 }