PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.2.11
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.2.11
3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 All 156 releases
notificationx / includes / Admin / MilestoneNotification.php

MilestoneNotification.php in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar 3.2.11, at includes/Admin/MilestoneNotification.php

597 lines 24.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Milestone Notification for WordPress Admin Dashboard
5 *
6 * Displays a beautiful animated notification on the main WordPress dashboard (/wp-admin/)
7 * showing milestone achievements and encouraging premium upgrades.
8 *
9 * Features:
10 * - Automatically appears on dashboard after 2 seconds
11 * - Slides in from bottom-right with smooth animation
12 * - Fully responsive design
13 * - Close on button click, overlay click, or Escape key
14 * - Customizable milestone data and stats
15 *
16 * Usage:
17 * - Automatically initialized in NotificationX main class
18 * - Only loads on WordPress dashboard (index.php)
19 * - Customize data in get_milestone_data() method
20 * - Control display logic in should_show_milestone() method
21 *
22 * @package NotificationX
23 * @author NotificationX <help@notificationx.com>
24 * @copyright Copyright (C) 2023 WPDeveloper. All rights reserved.
25 * @license GPLv3 or later
26 * @since 1.0.0
27 */
28
29 namespace NotificationX\Admin;
30
31 use NotificationX\NotificationX;
32 use NotificationX\GetInstance;
33 use NotificationX\Core\Analytics;
34 use NotificationX\Core\Helper;
35
36 defined('ABSPATH') or die("No direct script access allowed.");
37
38 class MilestoneNotification
39 {
40 use GetInstance;
41
42 /**
43 * Constructor - Initialize the milestone notification
44 */
45 public function __construct()
46 {
47 // Hook into admin footer to inject the notification
48 add_action('admin_footer', [$this, 'render_milestone_notification']);
49
50 // Enqueue styles and scripts
51 add_action('admin_enqueue_scripts', [$this, 'enqueue_assets']);
52
53 // AJAX handler to mark milestone as seen
54 add_action('wp_ajax_notificationx_mark_milestone_seen', [$this, 'ajax_mark_milestone_seen']);
55 }
56
57 /**
58 * Enqueue CSS and JS for milestone notification
59 */
60 public function enqueue_assets($hook)
61 {
62 // Only load on main dashboard page
63 if ($hook !== 'index.php') {
64 return;
65 }
66
67 // Enqueue the milestone CSS - use existing admin CSS file
68 wp_enqueue_style(
69 'notificationx-milestone',
70 Helper::file('admin/css/admin.css', true),
71 [],
72 NOTIFICATIONX_VERSION
73 );
74
75 // Enqueue inline script for milestone functionality
76 wp_add_inline_script('jquery', $this->get_milestone_script());
77 }
78
79 /**
80 * Get the JavaScript for milestone functionality
81 */
82 private function get_milestone_script()
83 {
84 return "
85 jQuery(document).ready(function($) {
86 // Auto-show milestone after 2 seconds
87 setTimeout(function() {
88 showNotificationXMilestone();
89 }, 2000);
90 });
91
92 function showNotificationXMilestone() {
93 var container = document.getElementById('notificationx-milestone-container');
94 if (!container) return;
95
96 container.style.display = 'block';
97
98 // Trigger animation
99 setTimeout(function() {
100 var overlay = container.querySelector('.milestone-overlay');
101 var notification = container.querySelector('.milestone-notification');
102
103 if (overlay) overlay.classList.add('milestone-overlay--visible');
104 if (notification) notification.classList.add('milestone-notification--visible');
105 }, 100);
106 }
107
108 function hideNotificationXMilestone(event) {
109 if (event) event.preventDefault();
110
111 var container = document.getElementById('notificationx-milestone-container');
112 if (!container) return;
113
114 var overlay = container.querySelector('.milestone-overlay');
115 var notification = container.querySelector('.milestone-notification');
116
117 if (overlay) overlay.classList.remove('milestone-overlay--visible');
118 if (notification) notification.classList.remove('milestone-notification--visible');
119
120 // Remove from DOM after animation
121 setTimeout(function() {
122 container.style.display = 'none';
123 }, 400);
124
125 // Mark milestone as seen via AJAX
126 jQuery.post(ajaxurl, {
127 action: 'notificationx_mark_milestone_seen',
128 nonce: '" . wp_create_nonce('notificationx_milestone_nonce') . "'
129 });
130 }
131
132 // Close on Escape key
133 document.addEventListener('keydown', function(e) {
134 if (e.key === 'Escape') {
135 hideNotificationXMilestone();
136 }
137 });
138
139 // Close on overlay click
140 document.addEventListener('click', function(e) {
141 if (e.target && e.target.classList.contains('milestone-overlay')) {
142 hideNotificationXMilestone();
143 }
144 });
145 ";
146 }
147
148 /**
149 * Render the milestone notification HTML
150 */
151 public function render_milestone_notification()
152 {
153 // Only show on main dashboard
154 $screen = get_current_screen();
155 if (!$screen || $screen->id !== 'dashboard') {
156 return;
157 }
158
159 // Check if milestone should be shown
160 if (!$this->should_show_milestone()) {
161 return;
162 }
163
164 // Get milestone data
165 $data = $this->get_milestone_data();
166 $black_friday_notice = esc_url( NOTIFICATIONX_PUBLIC_URL . 'image/reports/black-friday-small.webp' );
167 $nx_icon = esc_url( NOTIFICATIONX_ADMIN_URL . 'images/nx-icon.svg' );
168
169 ?>
170 <div id="notificationx-milestone-container" style="display: none;">
171 <div class="milestone-overlay">
172 <div class="milestone-notification" onclick="event.stopPropagation()">
173 <!-- Header -->
174 <div class="milestone-header">
175 <h2 class="milestone-title">
176 <img width="24" src="<?php echo esc_url( $nx_icon ) ?>" alt="">
177 <?php echo esc_html__('NotificationX Milestones', 'notificationx'); ?>
178 </h2>
179 <button class="milestone-close" onclick="hideNotificationXMilestone(event)" aria-label="Close">
180 <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
181 <path d="M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z" fill="currentColor" />
182 </svg>
183 </button>
184 </div>
185
186 <!-- Content -->
187 <div class="milestone-content">
188 <!-- Achievement Banner -->
189 <div class="milestone-achievement">
190 <h3 class="milestone-achievement-title">
191 <?php echo esc_html( $data['emoji'] ); ?> <?php echo wp_kses_post($data['title']); ?>
192 </h3>
193 <p class="milestone-achievement-subtitle">
194 <?php echo wp_kses_post($data['subtitle']); ?>
195 </p>
196 <a href="<?php echo esc_url(admin_url('admin.php?page=nx-analytics')); ?>" class="milestone-link <?php echo NotificationX::is_pro() ? 'pro-activated' : 'pro-deactivated' ?>">
197 <?php echo ! NotificationX::is_pro() ? esc_html__('View Analytics', 'notificationx') : esc_html__('View Detail Insights', 'notificationx'); ?>
198 </a>
199 </div>
200
201 <!-- Stats Grid -->
202 <div class="milestone-stats">
203 <div class="milestone-stats-inner-wrapper">
204 <div class="milestone-stats-inner">
205 <?php foreach ($data['stats'] as $stat) : ?>
206 <div class="milestone-stat-card">
207 <div class="milestone-stat-label"><?php echo esc_html($stat['label']); ?></div>
208 <div class="milestone-stat-value"><?php echo esc_html($stat['value']); ?></div>
209 </div>
210 <?php endforeach; ?>
211 </div>
212
213 <!-- CTA Button -->
214 <a href="<?php echo esc_url('https://notificationx.com/pricing/'); ?>" target="_blank" class="milestone-cta">
215 <?php echo esc_html__('Unlock Advanced Analytics Data', 'notificationx'); ?>
216 </a>
217 </div>
218 </div>
219 </div>
220 </div>
221 </div>
222 </div>
223 <?php
224 }
225
226 /**
227 * Get milestone data
228 * Fetches real analytics data from the database to show user's notification performance
229 */
230 private function get_milestone_data()
231 {
232 // Get Analytics instance
233 $analytics = Analytics::get_instance();
234
235 // Get real analytics data
236 $total_notifications = 0;
237 $total_views = 0;
238 $total_clicks = 0;
239 $total_ctr = 0;
240
241 try {
242 // Get total count data
243 $analytics_data = $analytics->get_total_count();
244
245 if (is_array($analytics_data)) {
246 $total_views = isset($analytics_data['totalViews']) ? $this->parse_number($analytics_data['totalViews']) : 0;
247 $total_clicks = isset($analytics_data['totalClicks']) ? $this->parse_number($analytics_data['totalClicks']) : 0;
248 $total_ctr = isset($analytics_data['totalCtr']) ? $analytics_data['totalCtr'] : 0;
249 }
250
251 // Get total notifications count
252 global $wpdb;
253 $table_name = $wpdb->prefix . 'nx_posts';
254 $total_notifications = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name} WHERE enabled = 1");
255 $total_notifications = $total_notifications ? intval($total_notifications) : 0;
256
257 } catch (\Exception $e) {
258 // Fallback to default values if there's an error
259 error_log('NotificationX Milestone: Error fetching analytics data - ' . $e->getMessage());
260 }
261
262 // Format numbers for display
263 $notifications_formatted = $this->format_number($total_notifications);
264 $views_formatted = $this->format_number($total_views);
265 $clicks_formatted = $this->format_number($total_clicks);
266 $ctr_formatted = number_format($total_ctr, 2) . '%';
267
268 // Calculate total interactions (sum of all metrics)
269 $total_interactions = $total_notifications + $total_views + $total_clicks;
270
271 // Get milestone configuration based on total interactions
272 $milestone_config = $this->get_milestone_config($total_interactions);
273
274 return array_merge($milestone_config, [
275 'stats' => [
276 [
277 'label' => esc_html__('Total Views', 'notificationx'),
278 'value' => $views_formatted
279 ],
280 [
281 'label' => esc_html__('Total Clicks', 'notificationx'),
282 'value' => $clicks_formatted
283 ],
284 [
285 'label' => esc_html__('Click Rate', 'notificationx'),
286 'value' => $ctr_formatted
287 ]
288 ]
289 ]);
290 }
291
292 /**
293 * Parse number from formatted string (e.g., "1.2K" -> 1200)
294 */
295 private function parse_number($formatted_number)
296 {
297 if (is_numeric($formatted_number)) {
298 return intval($formatted_number);
299 }
300
301 $formatted_number = strtoupper(trim($formatted_number));
302 $multiplier = 1;
303
304 if (strpos($formatted_number, 'K') !== false) {
305 $multiplier = 1000;
306 $formatted_number = str_replace('K', '', $formatted_number);
307 } elseif (strpos($formatted_number, 'M') !== false) {
308 $multiplier = 1000000;
309 $formatted_number = str_replace('M', '', $formatted_number);
310 }
311
312 return intval(floatval($formatted_number) * $multiplier);
313 }
314
315 /**
316 * Get milestone configuration based on total interactions
317 * Returns unique title, subtitle, and emoji for each milestone level
318 */
319 private function get_milestone_config($total_interactions)
320 {
321 // Define milestone levels with unique messages
322 $milestones = [
323 2000000 => [
324 'emoji' => '',
325 'title' => wp_kses_post( __('<strong>Mega Milestone Unlocked!</strong> 🚀', 'notificationx') ),
326 'subtitle' => esc_html__( 'Your website notifications are on fire! Over 2M+ interactions have taken place across the globe.', 'notificationx' ),
327 'level' => '2m'
328 ],
329
330 1000000 => [
331 'emoji' => '',
332 'title' => wp_kses_post( __('<strong>Huge milestone achieved!</strong> 🎉', 'notificationx') ),
333 'subtitle' => esc_html__( 'You have achieved something unbelievable. 1M+ interactions have already happened on your website globally.', 'notificationx' ),
334 'level' => '1m'
335 ],
336
337 700000 => [
338 'emoji' => '',
339 'title' => wp_kses_post( __('700,000 <strong>interaction milestone reached!</strong> 🎉', 'notificationx') ),
340 'subtitle' => esc_html__( 'New interactions milestone achieved! Create more amazing notifications to reach out to a wider audience globally.', 'notificationx' ),
341 'level' => '700k'
342 ],
343
344 500000 => [
345 'emoji' => '',
346 'title' => wp_kses_post( __('<strong>You are doing amazing!</strong> 🎉', 'notificationx') ),
347 'subtitle' => esc_html__( 'Your notification is doing great and getting global clicks and impressions. See the detailed analytics below.', 'notificationx' ),
348 'level' => '500k'
349 ],
350
351 300000 => [
352 'emoji' => '',
353 'title' => wp_kses_post( __('<strong>Legendary achievement!</strong> 🎉', 'notificationx') ),
354 'subtitle' => esc_html__( 'New interactions milestone achieved! Create more amazing notifications to reach out to a wider audience globally.', 'notificationx' ),
355 'level' => '300k'
356 ],
357
358 250000 => [
359 'emoji' => '',
360 'title' => wp_kses_post( __('<strong>Diamond Status!!</strong> 🎉', 'notificationx') ),
361 'subtitle' => esc_html__( 'Your notification is grabbing attention globally. Check the detailed analytics to learn more about the performance.', 'notificationx' ),
362 'level' => '250k'
363 ],
364
365 200000 => [
366 'emoji' => '',
367 'title' => wp_kses_post( __('200,000 <strong>interaction milestone reached!</strong> 🎉', 'notificationx') ),
368 'subtitle' => esc_html__( 'Globally, 200,000 interactions are happening on your website. Check the detailed analytics to grow your audience further.', 'notificationx' ),
369 'level' => '200k'
370 ],
371
372 150000 => [
373 'emoji' => '',
374 'title' => wp_kses_post( __('Congratulations! <strong>Another milestone</strong> 🎉', 'notificationx') ),
375 'subtitle' => esc_html__( 'Your notifications are performing incredibly well worldwide. Check out the detailed analytics below!', 'notificationx' ),
376 'level' => '150k'
377 ],
378
379 100000 => [
380 'emoji' => '',
381 'title' => wp_kses_post( __('100,000 <strong>interaction milestone reached!</strong> 🎉', 'notificationx') ),
382 'subtitle' => esc_html__( 'New interactions milestone achieved! Create more amazing notifications to reach out to a wider audience globally.', 'notificationx' ),
383 'level' => '100k'
384 ],
385
386 75000 => [
387 'emoji' => '',
388 'title' => wp_kses_post( __('75,000+ <strong>interactions achieved today!</strong> 🎉', 'notificationx') ),
389 'subtitle' => esc_html__( 'Your notification is doing great and getting global clicks and impressions. See the detailed analytics below.', 'notificationx' ),
390 'level' => '75k'
391 ],
392
393 50000 => [
394 'emoji' => '',
395 'title' => wp_kses_post( __('Incredible, <strong>50,000 interactions unlocked!</strong> 🎉', 'notificationx') ),
396 'subtitle' => esc_html__( 'You are going great with your notification. Do not forget to check the detailed analytics to learn more.', 'notificationx' ),
397 'level' => '50k'
398 ],
399
400 25000 => [
401 'emoji' => '',
402 'title' => wp_kses_post( __('25,000 <strong>interaction milestone reached!</strong> 🎉', 'notificationx') ),
403 'subtitle' => esc_html__( 'Globally, 25,000 interactions are happening on your website. Check the detailed analytics to grow your audience further.', 'notificationx' ),
404 'level' => '25k'
405 ],
406
407 10000 => [
408 'emoji' => '',
409 'title' => wp_kses_post( __('Fantastic! <strong>10,000 interactions reached!</strong> 🎉', 'notificationx') ),
410 'subtitle' => esc_html__( 'New interactions milestone achieved! Create more amazing notifications to reach out to a wider audience globally.', 'notificationx' ),
411 'level' => '10k'
412 ],
413
414 5000 => [
415 'emoji' => '',
416 'title' => wp_kses_post( __('Awesome - <strong>you got 5,000 interactions!</strong> 🎉', 'notificationx') ),
417 'subtitle' => esc_html__( 'Your amazing website reached 5,000 interactions from your notification. Check the detailed analytics and achieve more.', 'notificationx' ),
418 'level' => '5k'
419 ],
420 2000 => [
421 'emoji' => '',
422 'title' => wp_kses_post( __('2,000 <strong>interaction milestone achieved!</strong> 🎉', 'notificationx') ),
423 'subtitle' => esc_html__( 'Your website has more than 2,000 interactions from your notification. Do not forget to check the detailed analytics and achieve more.', 'notificationx' ),
424 'level' => '2000'
425 ],
426
427 1000 => [
428 'emoji' => '',
429 'title' => wp_kses_post( __('Great - <strong>1,000 interactions achieved!</strong> 👏', 'notificationx') ),
430 'subtitle' => esc_html__( 'Your notifications are performing incredibly well worldwide. Check out the detailed analytics below!', 'notificationx' ),
431 'level' => '1000'
432 ],
433
434 100 => [
435 'emoji' => '',
436 'title' => wp_kses_post( __('You\'ve got <strong>100 interactions overall!</strong> 🎉', 'notificationx') ),
437 'subtitle' => esc_html__( 'Your notification is doing great and getting global clicks and impressions. See the detailed analytics below.', 'notificationx' ),
438 'level' => '100'
439 ],
440 ];
441
442
443 // Find the appropriate milestone level
444 foreach ($milestones as $threshold => $config) {
445 if ($total_interactions >= $threshold) {
446 return $config;
447 }
448 }
449
450 // Default for users below 1K interactions
451 return [];
452 }
453
454 /**
455 * Format number for display (e.g., 1000 -> 1K, 1000000 -> 1M)
456 *
457 * @param int $number
458 * @return string
459 */
460 private function format_number($number)
461 {
462 $number = (int) $number;
463
464 if ($number === 0) {
465 return '0';
466 }
467
468 if ($number >= 1000000) {
469 return round($number / 1000000, 1) . 'M';
470 }
471
472 if ($number >= 1000) {
473 return round($number / 1000, 1) . 'K';
474 }
475
476 return (string) $number;
477 }
478
479 /**
480 * Check if milestone should be shown
481 * Shows milestone only when site reaches a new level (site-wide, not per-user)
482 */
483 private function should_show_milestone()
484 {
485 // Get Analytics instance
486 $analytics = Analytics::get_instance();
487
488 // Get real analytics data
489 $total_notifications = 0;
490 $total_views = 0;
491 $total_clicks = 0;
492
493 try {
494 // Get total count data
495 $analytics_data = $analytics->get_total_count();
496
497 if (is_array($analytics_data)) {
498 $total_views = isset($analytics_data['totalViews']) ? $this->parse_number($analytics_data['totalViews']) : 0;
499 $total_clicks = isset($analytics_data['totalClicks']) ? $this->parse_number($analytics_data['totalClicks']) : 0;
500 }
501
502 // Get total notifications count
503 global $wpdb;
504 $table_name = $wpdb->prefix . 'nx_posts';
505 $total_notifications = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name} WHERE enabled = 1");
506 $total_notifications = $total_notifications ? intval($total_notifications) : 0;
507
508 } catch (\Exception $e) {
509 error_log('NotificationX Milestone: Error fetching analytics data - ' . $e->getMessage());
510 return false;
511 }
512
513 // Calculate total interactions
514 $total_interactions = $total_notifications + $total_views + $total_clicks;
515
516 // Determine current milestone level
517 $current_level = 'starter';
518 if ($total_interactions >= 2000000) {
519 $current_level = '2m';
520 } elseif ($total_interactions >= 1000000) {
521 $current_level = '1m';
522 } elseif ($total_interactions >= 700000) {
523 $current_level = '700k';
524 } elseif ($total_interactions >= 500000) {
525 $current_level = '500k';
526 } elseif ($total_interactions >= 300000) {
527 $current_level = '300k';
528 } elseif ($total_interactions >= 250000) {
529 $current_level = '250k';
530 } elseif ($total_interactions >= 200000) {
531 $current_level = '200k';
532 } elseif ($total_interactions >= 150000) {
533 $current_level = '150k';
534 } elseif ($total_interactions >= 100000) {
535 $current_level = '100k';
536 } elseif ($total_interactions >= 75000) {
537 $current_level = '75k';
538 } elseif ($total_interactions >= 50000) {
539 $current_level = '50k';
540 } elseif ($total_interactions >= 25000) {
541 $current_level = '25k';
542 } elseif ($total_interactions >= 10000) {
543 $current_level = '10k';
544 } elseif ($total_interactions >= 5000) {
545 $current_level = '5k';
546 } elseif ($total_interactions >= 2000) {
547 $current_level = '2k';
548 } elseif ($total_interactions >= 1000) {
549 $current_level = '1k';
550 } elseif ($total_interactions >= 100) {
551 $current_level = '100';
552 } elseif( $total_interactions < 100 ) {
553 return false;
554 }
555
556
557 // Get the last seen milestone level (site-wide option)
558 $last_seen_level = get_option('notificationx_milestone_level', '');
559
560 // Show milestone if:
561 // 1. Site has never seen any milestone, OR
562 // 2. Site has reached a new milestone level
563 if (empty($last_seen_level) || $last_seen_level !== $current_level) {
564 // Don't update here - only update when user closes the notification
565 // Store current level temporarily so we can update it later
566 update_option('notificationx_milestone_current_level', $current_level);
567 return true;
568 }
569
570 return false;
571 }
572
573 /**
574 * AJAX handler to mark milestone as seen
575 */
576 public function ajax_mark_milestone_seen()
577 {
578 // Verify nonce
579 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'notificationx_milestone_nonce')) {
580 wp_send_json_error('Invalid nonce');
581 return;
582 }
583
584 // Get the current milestone level that was shown
585 $current_level = get_option('notificationx_milestone_current_level', '');
586
587 if (!empty($current_level)) {
588 // Mark this milestone level as seen (site-wide)
589 update_option('notificationx_milestone_level', $current_level);
590 update_option('notificationx_force_milestone', '1');
591 // Clean up the temporary option
592 delete_option('notificationx_milestone_current_level');
593 }
594
595 wp_send_json_success();
596 }
597 }