PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 4.4.9
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v4.4.9
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 7 months ago Database 5 months ago Elementor_Enhancer.php 6 months ago EmbedPress_Core_Installer.php 6 years ago EmbedPress_Notice.php 2 years ago EmbedPress_Plugin_Usage_Tracker.php 1 year ago Extend_CustomPlayer_Controls.php 1 year ago Extend_Elementor_Controls.php 1 year ago FeatureNoticeManager.php 8 months ago FeatureNotices.php 8 months ago Feature_Enhancer.php 6 months ago Helper.php 5 months ago PermalinkHelper.php 10 months ago README_FEATURE_NOTICES.md 8 months ago
FeatureNoticeManager.php
336 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 // Get the highest priority notice
180 $notice_to_display = null;
181 $notice_id = null;
182
183 foreach ($this->notices as $id => $notice) {
184 if ($this->should_display_notice($id)) {
185 if ($notice_to_display === null || $notice['priority'] < $notice_to_display['priority']) {
186 $notice_to_display = $notice;
187 $notice_id = $id;
188 }
189 }
190 }
191
192 if (!$notice_to_display) {
193 return;
194 }
195
196 // Render tooltip HTML to be injected via JavaScript
197 ?>
198 <script type="text/html" id="embedpress-feature-tooltip-template">
199 <?php $this->render_tooltip($notice_id, $notice_to_display); ?>
200 </script>
201 <script type="text/javascript">
202 jQuery(document).ready(function($) {
203 // Inject tooltip into menu item
204 var $menuItem = $('#toplevel_page_embedpress');
205 if ($menuItem.length) {
206 var tooltipHtml = $('#embedpress-feature-tooltip-template').html();
207 $menuItem.append(tooltipHtml);
208 }
209 });
210 </script>
211 <?php
212 }
213
214 /**
215 * Render tooltip/popover
216 *
217 * @param string $id Notice ID
218 * @param array $notice Notice configuration
219 */
220 private function render_tooltip($id, $notice) {
221
222 error_log(print_r($notice, true));
223
224 $icon = !empty($notice['icon']) ? $notice['icon'] : '';
225 $title = esc_html($notice['title']);
226 $message = wp_kses_post($notice['message']);
227 $button_text = esc_html($notice['button_text']);
228 $button_url = esc_url($notice['button_url']);
229 $button_target = esc_attr($notice['button_target']);
230 $skip_text = esc_html($notice['skip_text']);
231 $notice_id = esc_attr($id);
232 $type = esc_attr($notice['type']);
233
234 ?>
235 <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;">
236 <div class="embedpress-feature-tooltip__arrow"></div>
237 <button type="button" class="embedpress-feature-tooltip__close" aria-label="Close">
238 <span class="dashicons dashicons-no-alt"></span>
239 </button>
240 <div class="embedpress-feature-tooltip__header">
241 <span class="embedpress-feature-tooltip__icon"><?php echo $icon; ?></span>
242 <h3 class="embedpress-feature-tooltip__title"><?php echo $title; ?></h3>
243 </div>
244 <div class="embedpress-feature-tooltip__content">
245 <div class="embedpress-feature-tooltip__message">
246 <?php echo $message; ?>
247 </div>
248 <div class="embedpress-feature-tooltip__actions">
249 <?php if ($notice['skip_text']): ?>
250 <button type="button" class="embedpress-feature-tooltip__skip" data-action="skip">
251 <?php echo $skip_text; ?>
252 </button>
253 <?php endif; ?>
254
255 <?php if ($notice['button_text'] && $notice['button_url']): ?>
256 <a href="<?php echo $button_url; ?>"
257 target="<?php echo $button_target; ?>"
258 class="embedpress-feature-tooltip__button">
259 <?php echo $button_text; ?>
260 </a>
261 <?php endif; ?>
262 </div>
263 </div>
264 </div>
265 <?php
266 }
267
268 /**
269 * AJAX handler for dismissing a notice
270 */
271 public function ajax_dismiss_notice() {
272 check_ajax_referer('embedpress_feature_notice', 'nonce');
273
274 $notice_id = isset($_POST['notice_id']) ? sanitize_text_field($_POST['notice_id']) : '';
275
276 if (empty($notice_id)) {
277 wp_send_json_error(['message' => 'Invalid notice ID']);
278 }
279
280 $dismissed = get_option(self::DISMISSED_NOTICES_OPTION, []);
281 if (!in_array($notice_id, $dismissed)) {
282 $dismissed[] = $notice_id;
283 update_option(self::DISMISSED_NOTICES_OPTION, $dismissed);
284 }
285
286 wp_send_json_success(['message' => 'Notice dismissed']);
287 }
288
289 /**
290 * AJAX handler for skipping a notice
291 * Skip = Permanent dismiss (same as close button)
292 */
293 public function ajax_skip_notice() {
294 check_ajax_referer('embedpress_feature_notice', 'nonce');
295
296 $notice_id = isset($_POST['notice_id']) ? sanitize_text_field($_POST['notice_id']) : '';
297
298 if (empty($notice_id)) {
299 wp_send_json_error(['message' => 'Invalid notice ID']);
300 }
301
302 // Permanently dismiss (same as close button)
303 $dismissed = get_option(self::DISMISSED_NOTICES_OPTION, []);
304 if (!in_array($notice_id, $dismissed)) {
305 $dismissed[] = $notice_id;
306 update_option(self::DISMISSED_NOTICES_OPTION, $dismissed);
307 }
308
309 wp_send_json_success(['message' => 'Notice dismissed']);
310 }
311
312 /**
313 * AJAX handler for viewing a notice (clicking primary button)
314 * View = Permanent dismiss (user engaged with the notice)
315 */
316 public function ajax_view_notice() {
317 check_ajax_referer('embedpress_feature_notice', 'nonce');
318
319 $notice_id = isset($_POST['notice_id']) ? sanitize_text_field($_POST['notice_id']) : '';
320
321 if (empty($notice_id)) {
322 wp_send_json_error(['message' => 'Invalid notice ID']);
323 }
324
325 // Permanently dismiss (user clicked the button)
326 $dismissed = get_option(self::DISMISSED_NOTICES_OPTION, []);
327 if (!in_array($notice_id, $dismissed)) {
328 $dismissed[] = $notice_id;
329 update_option(self::DISMISSED_NOTICES_OPTION, $dismissed);
330 }
331
332 wp_send_json_success(['message' => 'Notice dismissed']);
333 }
334 }
335
336