PluginProbe
BetterLinks – Link Shortener, Link Cloaking, Redirects, Affiliate Link Manager & MCP / trunk
BetterLinks – Link Shortener, Link Cloaking, Redirects, Affiliate Link Manager & MCP vtrunk
3.1.3 3.1.2 3.1.1 3.1.0 3.0.1 3.0.0 2.4.13 2.4.12 2.4.11 2.4.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 All 110 releases
betterlinks / includes / Admin / Notice.php

Notice.php in BetterLinks – Link Shortener, Link Cloaking, Redirects, Affiliate Link Manager & MCP trunk, at includes/Admin/Notice.php

411 lines 15.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace BetterLinks\Admin;
4 if ( ! defined( 'ABSPATH' ) ) { exit; }
5
6 use BetterLinks\Admin\WPDev\PluginUsageTracker;
7 use Exception;
8 use PriyoMukul\WPNotice\Notices;
9 use PriyoMukul\WPNotice\Utils\CacheBank;
10 use PriyoMukul\WPNotice\Utils\NoticeRemover;
11
12 class Notice {
13 /**
14 * @var CacheBank
15 */
16 private static $cache_bank;
17
18 /**
19 * @var PluginUsageTracker
20 */
21 private $opt_in_tracker;
22
23 /**
24 * @var bool Flag to prevent duplicate notice display
25 */
26 private static $black_friday_notice_displayed = false;
27
28 const ASSET_URL = BETTERLINKS_ASSETS_URI;
29
30 public function __construct() {
31 $this->usage_tracker();
32
33 self::$cache_bank = CacheBank::get_instance();
34 try {
35 $this->notices();
36 } catch ( Exception $e ) {
37 unset( $e );
38 }
39
40 add_action( 'in_admin_header', [ $this, 'remove_admin_notice' ] );
41 add_action( 'btl_compatibity_notices', [ $this, 'btlpro_compatibility_notices' ] );
42 // Use multiple hooks for better compatibility across different WordPress setups
43 add_action( 'admin_footer', [ $this, 'black_friday_pointer_notice' ], 999 );
44 }
45
46 public function btlpro_compatibility_notices() {
47 global $wp_version;
48
49 if ( ! defined( 'BETTERLINKS_PRO_VERSION' ) ) {
50 return;
51 }
52
53 if ( version_compare( $wp_version, '6.6', '>=' ) && version_compare( BETTERLINKS_PRO_VERSION, '2.0.0', '<=' ) ) {
54 $message = sprintf( '
55 <strong>%1$s</strong>: %2$s <strong>v2.0.1</strong> %3$s <strong>6.6 or later</strong>',
56 __( 'Warning', 'betterlinks' ),
57 __( 'Please update your BetterLinks Pro plugin to atleast', 'betterlinks' ),
58 __( 'to ensure compatibility with WordPress', 'betterlinks' )
59 );
60
61 $notice = sprintf( '<div style="padding: 10px;" class="notice notice-warning">%2$s</div>', 'betterlinks', $message );
62
63 echo wp_kses_post( $notice );
64 }
65 }
66
67 /**
68 * Display Black Friday pointer notice
69 * Shows only once per user with date range validation
70 * Only displays for free users (without BetterLinks Pro)
71 * Only shows on BetterLinks pages and WordPress dashboard
72 *
73 * @return void
74 */
75 public function black_friday_pointer_notice() {
76 // Prevent duplicate display when hooked to multiple actions
77 if ( self::$black_friday_notice_displayed ) {
78 return;
79 }
80
81 // Check if notice is dismissed
82 if ( get_transient( 'betterlinks_black_friday_pointer_dismissed' ) ) {
83 return;
84 }
85
86 // Check date range: November 16, 2025 to December 4, 2025
87 $start_date = strtotime( '11:59:59pm 16th November, 2025' );
88 $end_date = strtotime( '11:59:59pm 4th December, 2025' );
89 $current_time = current_time( 'timestamp' );
90
91 // Only show if within date range
92 if ( $current_time < $start_date || $current_time > $end_date ) {
93 return;
94 }
95
96 // Don't show if Pro is already active or installed
97 if ( defined( 'BETTERLINKS_PRO_VERSION' ) || is_plugin_active( 'betterlinks-pro/betterlinks-pro.php' ) ) {
98 return;
99 }
100
101 // Check plugin pointer priority system
102 // BetterLinks priority is 7
103 $betterlinks_priority = 7;
104 $current_priority = get_option( '_wpdeveloper_plugin_pointer_priority' );
105 // If priority option doesn't exist, create it with BetterLinks priority
106 if ( false === $current_priority || null === $current_priority || '' === $current_priority ) {
107 update_option( '_wpdeveloper_plugin_pointer_priority', $betterlinks_priority );
108 } elseif ( $current_priority > $betterlinks_priority ) {
109 // If current priority is higher than BetterLinks priority, update it
110 update_option( '_wpdeveloper_plugin_pointer_priority', $betterlinks_priority );
111 $current_priority = $betterlinks_priority;
112 }
113
114 if ( $current_priority < $betterlinks_priority ) {
115 return;
116 }
117
118 // Only show on BetterLinks pages, WordPress dashboard, and plugins directory
119 $current_screen = get_current_screen();
120 $is_betterlinks_page = ( 0 === strpos( $current_screen->id, 'toplevel_page_betterlinks' ) || 0 === strpos( $current_screen->id, 'betterlinks_page_' ) );
121 $is_dashboard = ( 'dashboard' === $current_screen->id );
122 $is_plugins_page = ( 'plugins' === $current_screen->id );
123
124 if ( ! $is_betterlinks_page && ! $is_dashboard && ! $is_plugins_page ) {
125 return;
126 }
127
128 // Enqueue pointer styles and scripts
129 wp_enqueue_style( 'wp-pointer' );
130 wp_enqueue_script( 'wp-pointer' );
131 wp_enqueue_script( 'jquery' );
132
133 // Create nonce for AJAX
134 $nonce = wp_create_nonce( 'betterlinks_dismiss_black_friday_notice' );
135
136 // Mark notice as displayed to prevent duplicates
137 self::$black_friday_notice_displayed = true;
138
139 // Output the notice markup
140 ?>
141
142 <script type="text/javascript">
143 (function($) {
144 $(document).ready(function() {
145
146 const target = jQuery("#toplevel_page_betterlinks" || 'body');
147
148 if (target.length === 0) {
149 return;
150 }
151
152 // Prepare content with optional button
153 let content = '<h3><?php esc_html_e( 'BetterLinks Black Friday Sale', 'betterlinks' ); ?></h3><p><?php esc_html_e( 'Shorten and redirect links & analyze website performance efficiently.', 'betterlinks' ); ?> </p>' || '';
154 content += '<p style="margin-top: 15px;"><a href="https://betterlinks.io/bfcm-wp-admin-pointer" class="button button-primary" target="_blank" rel="noopener"><?php esc_html_e( 'Save 40%', 'betterlinks' ); ?></a></p>';
155
156 // Default pointer options
157 const options = {
158 content: content,
159 position: {
160 edge: "left",
161 align: 'center'
162 },
163 close: function() {
164 // dismissPointer(pointerId);
165 var nonce = '<?php echo esc_js($nonce); ?>';
166 // Send AJAX request to set transient
167 $.ajax({
168 url: '<?php echo esc_url(admin_url( 'admin-ajax.php' )); ?>',
169 type: 'POST',
170 data: {
171 action: 'betterlinks_dismiss_black_friday_notice',
172 nonce: nonce
173 },
174 });
175 }
176 };
177
178 // Show the pointer
179 target.pointer(options).pointer('open');
180 });
181 })(jQuery);
182 </script>
183 <?php
184 }
185
186 public function remove_admin_notice() {
187 $current_screen = get_current_screen();
188 $dashboard_notice = get_option( 'betterlinks_dashboard_notice' );
189
190 if ( ! empty( strpos( $current_screen->id, 'betterlinks-quick-setup' ) ) ) {
191 remove_all_actions( 'admin_notices' );
192
193 return;
194 }
195
196 if ( 0 === strpos( $current_screen->id, "toplevel_page_betterlinks" ) || 0 === strpos( $current_screen->id, "betterlinks_page_" ) ) {
197 remove_all_actions( 'admin_notices' );
198 if ( BETTERLINKS_MENU_NOTICE !== $dashboard_notice ) {
199 add_action( 'admin_notices', array( $this, 'new_feature_notice' ), - 1 );
200 }
201 // To showing notice in BetterLinks page
202 add_action( 'admin_notices', function () {
203 do_action( 'btl_admin_notices' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
204 do_action( 'btl_compatibity_notices' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
205 Notice\PrettyLinks::init();
206 Notice\Simple301::init();
207 Notice\ThirstyAffiliates::init();
208 // Remove OLD notice from 1.0.0 (if other WPDeveloper plugin has notice)
209 NoticeRemover::get_instance( '1.0.0' );
210 } );
211 }
212 }
213
214 /**
215 * The "what's new in Pro" bar above the BetterLinks navbar.
216 *
217 * Keeps `notice is-dismissible` and the `btl-dashboard-notice` id: WordPress
218 * injects the dismiss button into `.notice.is-dismissible`, and `App.js` binds
219 * the persistence AJAX call to that injected `.notice-dismiss` element. The
220 * `btl-notice` classes are what `_admin-notices.scss` styles; without that
221 * stylesheet this still degrades to an ordinary WordPress success notice.
222 */
223 public function new_feature_notice() {
224 printf(
225 '<div class="notice notice-success is-dismissible btl-dashboard-notice btl-notice btl-notice--new" id="btl-dashboard-notice">
226 <p class="btl-notice__body">
227 <span class="btl-notice__pill">%1$s</span>
228 <span class="btl-notice__text"><strong>%2$s</strong>%3$s<a class="btl-notice__link" target="_blank" rel="noopener noreferrer" href="%4$s">%5$s</a>%6$s<a class="btl-notice__link" target="_blank" rel="noopener noreferrer" href="%7$s">%8$s</a>%9$s<a class="btl-notice__link" target="_blank" rel="noopener noreferrer" href="%10$s">%11$s</a>%12$s</span>
229 </p>
230 </div>',
231 esc_html__( 'NEW', 'betterlinks' ),
232 esc_html__( 'BetterLinks Pro 3.0 New UI is here!', 'betterlinks' ),
233 esc_html__( ' Explore ', 'betterlinks' ),
234 esc_url( 'https://betterlinks.io/docs/create-promo-cards-with-betterlinks' ),
235 esc_html__( 'Promo Cards', 'betterlinks' ),
236 esc_html__( ', ', 'betterlinks' ),
237 esc_url( 'https://betterlinks.io/docs/create-link-in-bio-betterlinks' ),
238 esc_html__( 'Bio Links', 'betterlinks' ),
239 esc_html__( ', and a refreshed experience. See the ', 'betterlinks' ),
240 esc_url( 'https://betterlinks.io/changelog/' ),
241 esc_html__( 'changelog', 'betterlinks' ),
242 esc_html__( '.', 'betterlinks' )
243 );
244 }
245
246 public function usage_tracker() {
247 $this->opt_in_tracker = PluginUsageTracker::get_instance( BETTERLINKS_PLUGIN_FILE, [
248 'opt_in' => true,
249 'goodbye_form' => true,
250 'item_id' => '720bbe6537bffcb73f37',
251 ] );
252 $this->opt_in_tracker->set_notice_options( array(
253 'notice' => __( 'Want to help make <strong>BetterLinks</strong> even more awesome? Be the first to get access to <strong>BetterLinks PRO</strong> with a huge <strong>50% Early Bird Discount</strong> if you allow us to track the non-sensitive usage data.', 'betterlinks' ),
254 'extra_notice' => __( 'We collect non-sensitive diagnostic data and plugin usage information. Your site URL, WordPress & PHP version, plugins & themes and email address to send you the discount coupon. This data lets us make sure this plugin always stays compatible with the most popular plugins and themes. No spam, I promise.', 'betterlinks' ),
255 ) );
256 $this->opt_in_tracker->init();
257 }
258
259 /**
260 * @throws Exception
261 */
262 public function notices() {
263 $notices = new Notices( [
264 'id' => 'betterlinks',
265 'storage_key' => 'notices',
266 'lifetime' => 3,
267 'stylesheet_url' => self::ASSET_URL . 'css/betterlinks-admin-notice.css',
268 'styles' => self::ASSET_URL . 'css/betterlinks-admin-notice.css',
269 'priority' => 7
270 ] );
271
272 global $betterlinks;
273 $current_user = wp_get_current_user();
274 $total_links = ( is_array( $betterlinks ) && isset( $betterlinks['links'] ) ? count( $betterlinks['links'] ) : 0 );
275
276 $review_notice = sprintf(
277 '%s, %s! %s',
278 __( 'Howdy', 'betterlinks' ),
279 $current_user->user_login,
280 sprintf(
281 /* translators: %s = placeholder values supplied by WordPress */
282 __( '👋 You have created %d Shortened URLs so far 🎉 If you are enjoying using BetterLinks, feel free to leave a 5* Review on the WordPress Forum.', 'betterlinks' ),
283 $total_links
284 )
285 );
286
287 $_review_notice = [
288 'thumbnail' => self::ASSET_URL . 'images/logo-large.svg',
289 'html' => '<p>' . $review_notice . '</p>',
290 'links' => [
291 'later' => array(
292 'link' => 'https://wordpress.org/plugins/betterlinks/#reviews',
293 'target' => '_blank',
294 'label' => __( 'Ok, you deserve it!', 'betterlinks' ),
295 'icon_class' => 'dashicons dashicons-external',
296 ),
297 'allready' => array(
298 'label' => __( 'I already did', 'betterlinks' ),
299 'icon_class' => 'dashicons dashicons-smiley',
300 'attributes' => [
301 'data-dismiss' => true
302 ],
303 ),
304 'maybe_later' => array(
305 'label' => __( 'Maybe Later', 'betterlinks' ),
306 'icon_class' => 'dashicons dashicons-calendar-alt',
307 'attributes' => [
308 'data-later' => true
309 ],
310 ),
311 'support' => array(
312 'link' => 'https://wpdeveloper.com/support',
313 'label' => __( 'I need help', 'betterlinks' ),
314 'icon_class' => 'dashicons dashicons-sos',
315 ),
316 'never_show_again' => array(
317 'label' => __( 'Never show again', 'betterlinks' ),
318 'icon_class' => 'dashicons dashicons-dismiss',
319 'attributes' => [
320 'data-dismiss' => true
321 ],
322 )
323 ]
324 ];
325
326 $notices->add(
327 'review',
328 $_review_notice,
329 [
330 'start' => $notices->strtotime( '+20 day' ),
331 'recurrence' => 30,
332 'refresh' => BETTERLINKS_VERSION,
333 'dismissible' => true,
334 ]
335 );
336
337 $notices->add(
338 'opt_in',
339 [ $this->opt_in_tracker, 'notice' ],
340 [
341 'classes' => 'updated put-dismiss-notice',
342 'start' => $notices->strtotime( '+25 day' ),
343 // 'start' => $notices->time(),
344 'refresh' => BETTERLINKS_VERSION,
345 'dismissible' => true,
346 'do_action' => 'wpdeveloper_notice_clicked_for_betterlinks',
347 'display_if' => ! is_plugin_active( 'betterlinks-pro/betterlinks-pro.php' )
348 ]
349 );
350
351 // Holiday Notice 2024
352 $crown_icon = self::ASSET_URL . 'images/crown.svg';
353 $b_message = "<p style='margin-top: 0; margin-bottom: 0;'>🎁 <strong>Holiday Gifts:</strong> Get Flat 25% OFF on every <strong>BetterLinks PRO</strong> plans & upgrade your WordPress links.</p><a style='display: inline-flex;align-items:center;column-gap:5px;' class='button button-primary' href='https://betterlinks.io/holiday24-admin-notice' target='_blank'><img style='width:15px;' src='{$crown_icon}'/>Upgrade To PRO</a>";
354 $_holiday_notices = [
355 'thumbnail' => self::ASSET_URL . 'images/full-logo.svg',
356 'html' => $b_message,
357 ];
358
359 $notices->add(
360 'betterlinks_holiday_24_25',
361 $_holiday_notices,
362 [
363 'start' => $notices->time(),
364 'recurrence' => false,
365 'dismissible' => true,
366 'refresh' => BETTERLINKS_VERSION,
367 "expire" => strtotime( '11:59:59pm 10th January, 2025' ),
368 'display_if' => ! is_plugin_active( 'betterlinks-pro/betterlinks-pro.php' )
369 ]
370 );
371
372 // Black Friday Mega Sale Notice
373 $black_friday_icon = self::ASSET_URL . 'images/full-logo.svg';
374 $black_friday_message = "<style>#wpnotice-betterlinks-betterlinks_summer_camp_2026_deal { border-left: 3px solid #5252DC !important; } .notice-betterlinks-betterlinks_summer_camp_2026_deal { border-left: 4px solid #FF6B6B !important; }</style><div> <p style='margin-top: 0; margin-bottom: 10px; font-size: 14px;'><strong>🏖️ Summer Savings: </strong>Get AI-powered features to manage, shorten & track every click – now <strong> up to $150 OFF! </strong></p><a style='display: inline-flex;align-items:center;column-gap:5px; background: #5252DC; color: #FFFFFF; font-size: 14px; border-radius: 6px; border-color: unset; font-weight: 500;' class='button button-primary' href='https://betterlinks.io/summer2026-admin-notice' target='_blank'>Upgrade To Pro Now</a><a style='display: inline-flex;align-items:center;column-gap:5px;margin-left:10px; background: unset; box-shadow: unset; border-style: unset; color: #424242; font-size: 14px; text-decoration: underline;' class='button dismiss-btn' href='#' data-dismiss='true'>I Don’t Want Any Discount</a> </div>";
375 $_black_friday_notices = [
376 'thumbnail' => $black_friday_icon,
377 'html' => $black_friday_message,
378 ];
379 // 'betterlinks_black_friday_2025',
380 // 'betterlinks_feb_camp_2026',
381 // 'betterlinks_spring_camp_2026_deal',
382 $notices->add(
383 'betterlinks_summer_camp_2026_deal',
384 $_black_friday_notices,
385 [
386 'start' => strtotime( '12:00:00am 20th May, 2026' ),
387 'recurrence' => false,
388 'dismissible' => true,
389 'refresh' => BETTERLINKS_VERSION,
390 "expire" => strtotime( '12:00:00am 25th June, 2026' ),
391 'display_if' => ! is_plugin_active( 'betterlinks-pro/betterlinks-pro.php' ),
392 'priority' => 7
393 ]
394 );
395 self::$cache_bank->create_account( $notices );
396 self::$cache_bank->calculate_deposits( $notices );
397
398 if ( method_exists( self::$cache_bank, 'clear_notices_in_' ) ) {
399 self::$cache_bank->clear_notices_in_( [
400 'toplevel_page_betterlinks',
401 'betterlinks_page_betterlinks-keywords-linking',
402 'betterlinks_page_betterlinks-manage-tags-and-categories',
403 'betterlinks_page_betterlinks-custom-domain',
404 'betterlinks_page_betterlinks-analytics',
405 'betterlinks_page_betterlinks-settings',
406 ], $notices, true );
407 }
408 }
409
410 }
411