PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 4.6.0
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v4.6.0
4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / EmbedPress / Includes / Classes / FeatureNoticeManager.php
embedpress / EmbedPress / Includes / Classes Last commit date
Analytics 2 weeks ago Database 2 months ago DynamicFieldResolver.php 1 month ago Elementor_Enhancer.php 6 months ago EmbedPress_Core_Installer.php 6 years ago EmbedPress_Notice.php 3 months ago EmbedPress_Plugin_Usage_Tracker.php 1 month ago Extend_CustomPlayer_Controls.php 2 months ago Extend_Elementor_Controls.php 1 year ago FeatureNoticeManager.php 4 days ago FeatureNotices.php 4 days ago FeaturePreviewModal.php 4 days ago Feature_Enhancer.php 1 month ago GoogleReviewsAdminPage.php 4 days ago GoogleReviewsApify.php 4 days ago GoogleReviewsManaged.php 4 days ago GoogleReviewsRenderer.php 4 days ago GoogleReviewsRestController.php 4 days ago GoogleReviewsStore.php 4 days ago Helper.php 4 days ago Pdf_Thumbnail_Handler.php 2 months ago PermalinkHelper.php 10 months ago View_Count_Display.php 2 weeks ago
FeatureNoticeManager.php
341 lines
1 <?php
2 namespace EmbedPress\Includes\Classes;
3
4 /**
5 * Feature Notice Manager
6 *
7 * A modern, reusable notice system for announcing new features and important updates.
8 * Displays beautiful notices in the WordPress admin with customizable content, buttons, and actions.
9 *
10 * @package EmbedPress
11 * @since 4.1.0
12 */
13
14 (defined('ABSPATH') && defined('EMBEDPRESS_IS_LOADED')) or die("No direct script access allowed.");
15
16 class FeatureNoticeManager {
17
18 /**
19 * Option name for storing dismissed notices
20 */
21 const DISMISSED_NOTICES_OPTION = 'embedpress_dismissed_feature_notices';
22
23 /**
24 * Option name for storing skipped notices
25 */
26 const SKIPPED_NOTICES_OPTION = 'embedpress_skipped_feature_notices';
27
28 /**
29 * Registered notices
30 * @var array
31 */
32 private $notices = [];
33
34 /**
35 * Singleton instance
36 * @var FeatureNoticeManager
37 */
38 private static $instance = null;
39
40 /**
41 * Get singleton instance
42 *
43 * @return FeatureNoticeManager
44 */
45 public static function get_instance() {
46 if (self::$instance === null) {
47 self::$instance = new self();
48 }
49 return self::$instance;
50 }
51
52 /**
53 * Constructor
54 */
55 private function __construct() {
56 // Render tooltip in admin footer instead of admin_notices
57 add_action('admin_footer', [$this, 'display_menu_tooltip']);
58 add_action('wp_ajax_embedpress_dismiss_feature_notice', [$this, 'ajax_dismiss_notice']);
59 add_action('wp_ajax_embedpress_skip_feature_notice', [$this, 'ajax_skip_notice']);
60 add_action('wp_ajax_embedpress_view_feature_notice', [$this, 'ajax_view_notice']);
61
62 // Add menu badge indicator
63 add_action('admin_menu', [$this, 'add_menu_badge'], 999);
64 }
65
66 /**
67 * Register a new feature notice
68 *
69 * @param string $id Unique notice ID
70 * @param array $args Notice configuration
71 *
72 * Example usage:
73 * FeatureNoticeManager::get_instance()->register_notice('analytics_dashboard', [
74 * 'title' => 'New Features',
75 * 'icon' => '🎉',
76 * 'message' => 'New In EmbedPress: Introducing Analytics dashboard...',
77 * 'button_text' => 'View Analytics',
78 * 'button_url' => admin_url('admin.php?page=embedpress&page_type=analytics'),
79 * 'skip_text' => 'Skip',
80 * 'screens' => ['toplevel_page_embedpress'], // Show only on specific screens
81 * 'capability' => 'manage_options',
82 * 'start_date' => '2024-01-01', // Optional: when to start showing
83 * 'end_date' => '2024-12-31', // Optional: when to stop showing
84 * 'priority' => 10,
85 * ]);
86 */
87 public function register_notice($id, $args = []) {
88 $defaults = [
89 'title' => 'New Features',
90 'icon' => '<svg width="11" height="13" viewBox="0 0 11 13" fill="none" xmlns="http://www.w3.org/2000/svg">
91 <path d="M0 1.61956C1.26645e-05 1.53091 0.0177073 1.44315 0.0520487 1.36142C0.0863901 1.27968 0.136689 1.20562 0.2 1.14356C0.926563 0.431321 1.89723 0.0227172 2.91444 0.000919081C3.93164 -0.0208791 4.91893 0.345767 5.67533 1.02623L5.90933 1.2449C6.39562 1.67096 7.02013 1.90585 7.66667 1.90585C8.3132 1.90585 8.93771 1.67096 9.424 1.2449L9.59 1.09356C9.99667 0.771563 10.608 1.0289 10.6633 1.54423L10.6667 1.61956V7.61956C10.6667 7.70822 10.649 7.79598 10.6146 7.87771C10.5803 7.95944 10.53 8.03351 10.4667 8.09556C9.7401 8.8078 8.76943 9.21641 7.75223 9.23821C6.73502 9.26 5.74774 8.89336 4.99133 8.2129L4.75733 7.99423C4.28636 7.58157 3.68518 7.3478 3.05915 7.33391C2.43311 7.32001 1.82216 7.52687 1.33333 7.91823V12.2862C1.33314 12.4561 1.26808 12.6196 1.15143 12.7431C1.03479 12.8667 0.875365 12.9411 0.705737 12.951C0.536109 12.961 0.36908 12.9058 0.238778 12.7967C0.108476 12.6877 0.0247357 12.533 0.00466665 12.3642L0 12.2862V1.61956Z" fill="#25396F"/>
92 </svg>',
93 'message' => '',
94 'button_text' => 'Learn More',
95 'button_url' => '',
96 'button_target' => '_self',
97 'skip_text' => 'Skip',
98 'screens' => [], // Empty means show on all admin pages
99 'capability' => 'manage_options',
100 'start_date' => null,
101 'end_date' => null,
102 'priority' => 10,
103 'dismissible' => true,
104 'type' => 'info', // info, success, warning, error
105 ];
106
107 $this->notices[$id] = wp_parse_args($args, $defaults);
108 $this->notices[$id]['id'] = $id;
109 }
110
111 /**
112 * Check if a notice should be displayed
113 *
114 * @param string $id Notice ID
115 * @return bool
116 */
117 private function should_display_notice($id) {
118 if (!isset($this->notices[$id])) {
119 return false;
120 }
121
122 $notice = $this->notices[$id];
123
124 // Only show on dashboard page
125 $screen = get_current_screen();
126 if (!$screen || $screen->id !== 'dashboard') {
127 return false;
128 }
129
130 // Check capability
131 if (!current_user_can($notice['capability'])) {
132 return false;
133 }
134
135 // Check if dismissed (any action = permanent dismiss)
136 $dismissed = get_option(self::DISMISSED_NOTICES_OPTION, []);
137 if (in_array($id, $dismissed)) {
138 return false;
139 }
140
141 // Check date range
142 if ($notice['start_date'] && strtotime($notice['start_date']) > time()) {
143 return false;
144 }
145
146 if ($notice['end_date'] && strtotime($notice['end_date']) < time()) {
147 return false;
148 }
149
150 return true;
151 }
152
153 /**
154 * Add badge indicator to EmbedPress menu
155 */
156 public function add_menu_badge() {
157 global $menu;
158
159 // Check if there's any active notice
160 $has_active_notice = false;
161 foreach ($this->notices as $id => $notice) {
162 if ($this->should_display_notice($id)) {
163 $has_active_notice = true;
164 break;
165 }
166 }
167
168 if (!$has_active_notice) {
169 return;
170 }
171 }
172
173 /**
174 * Display menu tooltip
175 *
176 * Renders tooltip/popover next to EmbedPress menu item
177 */
178 public function display_menu_tooltip() {
179 // Suppress the small menu tooltip when the bigger "What's New" modal is
180 // queued for this release — never announce the same release twice.
181 if (class_exists('\\EmbedPress\\Includes\\Classes\\FeaturePreviewModal')
182 && FeaturePreviewModal::get_instance()->has_active_modal()) {
183 return;
184 }
185
186 // Get the highest priority notice
187 $notice_to_display = null;
188 $notice_id = null;
189
190 foreach ($this->notices as $id => $notice) {
191 if ($this->should_display_notice($id)) {
192 if ($notice_to_display === null || $notice['priority'] < $notice_to_display['priority']) {
193 $notice_to_display = $notice;
194 $notice_id = $id;
195 }
196 }
197 }
198
199 if (!$notice_to_display) {
200 return;
201 }
202
203 // Render tooltip HTML to be injected via JavaScript
204 ?>
205 <script type="text/html" id="embedpress-feature-tooltip-template">
206 <?php $this->render_tooltip($notice_id, $notice_to_display); ?>
207 </script>
208 <script type="text/javascript">
209 jQuery(document).ready(function($) {
210 // Inject tooltip into menu item
211 var $menuItem = $('#toplevel_page_embedpress');
212 if ($menuItem.length) {
213 var tooltipHtml = $('#embedpress-feature-tooltip-template').html();
214 $menuItem.append(tooltipHtml);
215 }
216 });
217 </script>
218 <?php
219 }
220
221 /**
222 * Render tooltip/popover
223 *
224 * @param string $id Notice ID
225 * @param array $notice Notice configuration
226 */
227 private function render_tooltip($id, $notice) {
228
229 $icon = !empty($notice['icon']) ? $notice['icon'] : '';
230 $title = esc_html($notice['title']);
231 $message = wp_kses_post($notice['message']);
232 $button_text = esc_html($notice['button_text']);
233 $button_url = esc_url($notice['button_url']);
234 $button_target = esc_attr($notice['button_target']);
235 $skip_text = esc_html($notice['skip_text']);
236 $notice_id = esc_attr($id);
237 $type = esc_attr($notice['type']);
238
239 ?>
240 <div id="embedpress-feature-tooltip" class="embedpress-feature-tooltip embedpress-feature-tooltip--<?php echo $type; ?>" data-notice-id="<?php echo $notice_id; ?>" style="visibility: hidden; opacity: 0;">
241 <div class="embedpress-feature-tooltip__arrow"></div>
242 <button type="button" class="embedpress-feature-tooltip__close" aria-label="Close">
243 <span class="dashicons dashicons-no-alt"></span>
244 </button>
245 <div class="embedpress-feature-tooltip__header">
246 <span class="embedpress-feature-tooltip__icon"><?php echo $icon; ?></span>
247 <h3 class="embedpress-feature-tooltip__title"><?php echo $title; ?></h3>
248 </div>
249 <div class="embedpress-feature-tooltip__content">
250 <div class="embedpress-feature-tooltip__message">
251 <?php echo $message; ?>
252 </div>
253 <div class="embedpress-feature-tooltip__actions">
254 <?php if ($notice['skip_text']): ?>
255 <button type="button" class="embedpress-feature-tooltip__skip" data-action="skip">
256 <?php echo $skip_text; ?>
257 </button>
258 <?php endif; ?>
259
260 <?php if ($notice['button_text'] && $notice['button_url']): ?>
261 <a href="<?php echo $button_url; ?>"
262 target="<?php echo $button_target; ?>"
263 class="embedpress-feature-tooltip__button">
264 <?php echo $button_text; ?>
265 </a>
266 <?php endif; ?>
267 </div>
268 </div>
269 </div>
270 <?php
271 }
272
273 /**
274 * AJAX handler for dismissing a notice
275 */
276 public function ajax_dismiss_notice() {
277 check_ajax_referer('embedpress_feature_notice', 'nonce');
278
279 $notice_id = isset($_POST['notice_id']) ? sanitize_text_field($_POST['notice_id']) : '';
280
281 if (empty($notice_id)) {
282 wp_send_json_error(['message' => 'Invalid notice ID']);
283 }
284
285 $dismissed = get_option(self::DISMISSED_NOTICES_OPTION, []);
286 if (!in_array($notice_id, $dismissed)) {
287 $dismissed[] = $notice_id;
288 update_option(self::DISMISSED_NOTICES_OPTION, $dismissed);
289 }
290
291 wp_send_json_success(['message' => 'Notice dismissed']);
292 }
293
294 /**
295 * AJAX handler for skipping a notice
296 * Skip = Permanent dismiss (same as close button)
297 */
298 public function ajax_skip_notice() {
299 check_ajax_referer('embedpress_feature_notice', 'nonce');
300
301 $notice_id = isset($_POST['notice_id']) ? sanitize_text_field($_POST['notice_id']) : '';
302
303 if (empty($notice_id)) {
304 wp_send_json_error(['message' => 'Invalid notice ID']);
305 }
306
307 // Permanently dismiss (same as close button)
308 $dismissed = get_option(self::DISMISSED_NOTICES_OPTION, []);
309 if (!in_array($notice_id, $dismissed)) {
310 $dismissed[] = $notice_id;
311 update_option(self::DISMISSED_NOTICES_OPTION, $dismissed);
312 }
313
314 wp_send_json_success(['message' => 'Notice dismissed']);
315 }
316
317 /**
318 * AJAX handler for viewing a notice (clicking primary button)
319 * View = Permanent dismiss (user engaged with the notice)
320 */
321 public function ajax_view_notice() {
322 check_ajax_referer('embedpress_feature_notice', 'nonce');
323
324 $notice_id = isset($_POST['notice_id']) ? sanitize_text_field($_POST['notice_id']) : '';
325
326 if (empty($notice_id)) {
327 wp_send_json_error(['message' => 'Invalid notice ID']);
328 }
329
330 // Permanently dismiss (user clicked the button)
331 $dismissed = get_option(self::DISMISSED_NOTICES_OPTION, []);
332 if (!in_array($notice_id, $dismissed)) {
333 $dismissed[] = $notice_id;
334 update_option(self::DISMISSED_NOTICES_OPTION, $dismissed);
335 }
336
337 wp_send_json_success(['message' => 'Notice dismissed']);
338 }
339 }
340
341