1
|
|
|
<?php
|
|
|
|
|
2
|
|
|
/**
|
3
|
|
|
* @package Freemius
|
4
|
|
|
* @copyright Copyright (c) 2015, Freemius, Inc.
|
5
|
|
|
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
|
6
|
|
|
* @since 1.0.7
|
7
|
|
|
*/
|
8
|
|
|
|
9
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
10
|
|
|
exit;
|
11
|
|
|
}
|
12
|
|
|
|
13
|
|
|
class FS_Admin_Notice_Manager {
|
|
|
|
|
14
|
|
|
/**
|
15
|
|
|
* @since 1.2.2
|
16
|
|
|
*
|
17
|
|
|
* @var string
|
18
|
|
|
*/
|
19
|
|
|
protected $_module_unique_affix;
|
20
|
|
|
/**
|
21
|
|
|
* @var string
|
22
|
|
|
*/
|
23
|
|
|
protected $_id;
|
24
|
|
|
/**
|
25
|
|
|
* @var string
|
26
|
|
|
*/
|
27
|
|
|
protected $_title;
|
28
|
|
|
/**
|
29
|
|
|
* @var array[string]array
|
30
|
|
|
*/
|
31
|
|
|
private $_notices = array();
|
32
|
|
|
/**
|
33
|
|
|
* @var FS_Key_Value_Storage
|
34
|
|
|
*/
|
35
|
|
|
private $_sticky_storage;
|
36
|
|
|
/**
|
37
|
|
|
* @var FS_Logger
|
38
|
|
|
*/
|
39
|
|
|
protected $_logger;
|
40
|
|
|
/**
|
41
|
|
|
* @since 2.0.0
|
42
|
|
|
* @var int The ID of the blog that is associated with the current site level admin notices.
|
43
|
|
|
*/
|
44
|
|
|
private $_blog_id = 0;
|
45
|
|
|
/**
|
46
|
|
|
* @since 2.0.0
|
47
|
|
|
* @var bool
|
48
|
|
|
*/
|
49
|
|
|
private $_is_network_notices;
|
50
|
|
|
|
51
|
|
|
/**
|
52
|
|
|
* @var FS_Admin_Notice_Manager[]
|
53
|
|
|
*/
|
54
|
|
|
private static $_instances = array();
|
55
|
|
|
|
56
|
|
|
/**
|
57
|
|
|
* @param string $id
|
58
|
|
|
* @param string $title
|
59
|
|
|
* @param string $module_unique_affix
|
60
|
|
|
* @param bool $is_network_and_blog_admins Whether or not the message should be shown both on
|
61
|
|
|
* network and blog admin pages.
|
62
|
|
|
* @param bool $network_level_or_blog_id Since 2.0.0
|
63
|
|
|
*
|
64
|
|
|
* @return \FS_Admin_Notice_Manager
|
65
|
|
|
*/
|
66
|
|
|
static function instance(
|
|
|
|
|
67
|
|
|
$id,
|
68
|
|
|
$title = '',
|
69
|
|
|
$module_unique_affix = '',
|
70
|
|
|
$is_network_and_blog_admins = false,
|
71
|
|
|
$network_level_or_blog_id = false
|
72
|
|
|
) {
|
73
|
|
|
if ( $is_network_and_blog_admins ) {
|
74
|
|
|
$network_level_or_blog_id = true;
|
75
|
|
|
}
|
76
|
|
|
|
77
|
|
|
$key = strtolower( $id );
|
78
|
|
|
|
79
|
|
|
if ( is_multisite() ) {
|
80
|
|
|
if ( true === $network_level_or_blog_id ) {
|
81
|
|
|
$key .= ':ms';
|
82
|
|
|
} else if ( is_numeric( $network_level_or_blog_id ) && $network_level_or_blog_id > 0 ) {
|
83
|
|
|
$key .= ":{$network_level_or_blog_id}";
|
84
|
|
|
} else {
|
85
|
|
|
$network_level_or_blog_id = get_current_blog_id();
|
86
|
|
|
|
87
|
|
|
$key .= ":{$network_level_or_blog_id}";
|
88
|
|
|
}
|
89
|
|
|
}
|
90
|
|
|
|
91
|
|
|
if ( ! isset( self::$_instances[ $key ] ) ) {
|
92
|
|
|
self::$_instances[ $key ] = new FS_Admin_Notice_Manager(
|
93
|
|
|
$id,
|
94
|
|
|
$title,
|
95
|
|
|
$module_unique_affix,
|
96
|
|
|
$is_network_and_blog_admins,
|
97
|
|
|
$network_level_or_blog_id
|
98
|
|
|
);
|
99
|
|
|
}
|
100
|
|
|
|
101
|
|
|
return self::$_instances[ $key ];
|
102
|
|
|
}
|
103
|
|
|
|
104
|
|
|
/**
|
105
|
|
|
* @param string $id
|
106
|
|
|
* @param string $title
|
107
|
|
|
* @param string $module_unique_affix
|
108
|
|
|
* @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network and
|
109
|
|
|
* blog admin pages.
|
110
|
|
|
* @param bool|int $network_level_or_blog_id
|
111
|
|
|
*/
|
112
|
|
|
protected function __construct(
|
113
|
|
|
$id,
|
114
|
|
|
$title = '',
|
115
|
|
|
$module_unique_affix = '',
|
116
|
|
|
$is_network_and_blog_admins = false,
|
117
|
|
|
$network_level_or_blog_id = false
|
118
|
|
|
) {
|
119
|
|
|
$this->_id = $id;
|
120
|
|
|
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $this->_id . '_data', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
121
|
|
|
$this->_title = ! empty( $title ) ? $title : '';
|
122
|
|
|
$this->_module_unique_affix = $module_unique_affix;
|
123
|
|
|
$this->_sticky_storage = FS_Key_Value_Storage::instance( 'admin_notices', $this->_id, $network_level_or_blog_id );
|
|
|
|
|
124
|
|
|
|
125
|
|
|
if ( is_multisite() ) {
|
126
|
|
|
$this->_is_network_notices = ( true === $network_level_or_blog_id );
|
127
|
|
|
|
128
|
|
|
if ( is_numeric( $network_level_or_blog_id ) ) {
|
129
|
|
|
$this->_blog_id = $network_level_or_blog_id;
|
|
|
|
|
130
|
|
|
}
|
131
|
|
|
} else {
|
132
|
|
|
$this->_is_network_notices = false;
|
133
|
|
|
}
|
134
|
|
|
|
135
|
|
|
$is_network_admin = fs_is_network_admin();
|
136
|
|
|
$is_blog_admin = fs_is_blog_admin();
|
137
|
|
|
|
138
|
|
|
if ( ( $this->_is_network_notices && $is_network_admin ) ||
|
139
|
|
|
( ! $this->_is_network_notices && $is_blog_admin ) ||
|
140
|
|
|
( $is_network_and_blog_admins && ( $is_network_admin || $is_blog_admin ) )
|
141
|
|
|
) {
|
142
|
|
|
if ( 0 < count( $this->_sticky_storage ) ) {
|
143
|
|
|
$ajax_action_suffix = str_replace( ':', '-', $this->_id );
|
144
|
|
|
|
145
|
|
|
// If there are sticky notices for the current slug, add a callback
|
146
|
|
|
// to the AJAX action that handles message dismiss.
|
147
|
|
|
add_action( "wp_ajax_fs_dismiss_notice_action_{$ajax_action_suffix}", array(
|
148
|
|
|
&$this,
|
149
|
|
|
'dismiss_notice_ajax_callback'
|
150
|
|
|
) );
|
151
|
|
|
|
152
|
|
|
foreach ( $this->_sticky_storage as $msg ) {
|
153
|
|
|
// Add admin notice.
|
154
|
|
|
$this->add(
|
155
|
|
|
$msg['message'],
|
156
|
|
|
$msg['title'],
|
157
|
|
|
$msg['type'],
|
158
|
|
|
true,
|
159
|
|
|
$msg['id'],
|
160
|
|
|
false,
|
161
|
|
|
isset( $msg['wp_user_id'] ) ? $msg['wp_user_id'] : null,
|
162
|
|
|
! empty( $msg['plugin'] ) ? $msg['plugin'] : null,
|
163
|
|
|
$is_network_and_blog_admins
|
164
|
|
|
);
|
165
|
|
|
}
|
166
|
|
|
}
|
167
|
|
|
}
|
168
|
|
|
}
|
169
|
|
|
|
170
|
|
|
/**
|
171
|
|
|
* Remove sticky message by ID.
|
172
|
|
|
*
|
173
|
|
|
* @author Vova Feldman (@svovaf)
|
174
|
|
|
* @since 1.0.7
|
175
|
|
|
*
|
176
|
|
|
*/
|
177
|
|
|
function dismiss_notice_ajax_callback() {
|
|
|
|
|
178
|
|
|
$this->_sticky_storage->remove( $_POST['message_id'] );
|
179
|
|
|
wp_die();
|
180
|
|
|
}
|
181
|
|
|
|
182
|
|
|
/**
|
183
|
|
|
* Rendered sticky message dismiss JavaScript.
|
184
|
|
|
*
|
185
|
|
|
* @author Vova Feldman (@svovaf)
|
186
|
|
|
* @since 1.0.7
|
187
|
|
|
*/
|
188
|
|
|
static function _add_sticky_dismiss_javascript() {
|
|
|
|
|
189
|
|
|
$params = array();
|
190
|
|
|
fs_require_once_template( 'sticky-admin-notice-js.php', $params );
|
191
|
|
|
}
|
192
|
|
|
|
193
|
|
|
private static $_added_sticky_javascript = false;
|
194
|
|
|
|
195
|
|
|
/**
|
196
|
|
|
* Hook to the admin_footer to add sticky message dismiss JavaScript handler.
|
197
|
|
|
*
|
198
|
|
|
* @author Vova Feldman (@svovaf)
|
199
|
|
|
* @since 1.0.7
|
200
|
|
|
*/
|
201
|
|
|
private static function has_sticky_messages() {
|
202
|
|
|
if ( ! self::$_added_sticky_javascript ) {
|
203
|
|
|
add_action( 'admin_footer', array( 'FS_Admin_Notice_Manager', '_add_sticky_dismiss_javascript' ) );
|
204
|
|
|
}
|
205
|
|
|
}
|
206
|
|
|
|
207
|
|
|
/**
|
208
|
|
|
* Handle admin_notices by printing the admin messages stacked in the queue.
|
209
|
|
|
*
|
210
|
|
|
* @author Vova Feldman (@svovaf)
|
211
|
|
|
* @since 1.0.4
|
212
|
|
|
*
|
213
|
|
|
*/
|
214
|
|
|
function _admin_notices_hook() {
|
|
|
|
|
215
|
|
|
if ( function_exists( 'current_user_can' ) &&
|
216
|
|
|
! current_user_can( 'manage_options' )
|
217
|
|
|
) {
|
218
|
|
|
// Only show messages to admins.
|
219
|
|
|
return;
|
220
|
|
|
}
|
221
|
|
|
|
222
|
|
|
|
223
|
|
|
$show_admin_notices = ( ! $this->is_gutenberg_page() );
|
224
|
|
|
|
225
|
|
|
foreach ( $this->_notices as $id => $msg ) {
|
226
|
|
|
if ( isset( $msg['wp_user_id'] ) && is_numeric( $msg['wp_user_id'] ) ) {
|
227
|
|
|
if ( get_current_user_id() != $msg['wp_user_id'] ) {
|
228
|
|
|
continue;
|
229
|
|
|
}
|
230
|
|
|
}
|
231
|
|
|
|
232
|
|
|
/**
|
233
|
|
|
* Added a filter to control the visibility of admin notices.
|
234
|
|
|
*
|
235
|
|
|
* Usage example:
|
236
|
|
|
*
|
237
|
|
|
* /**
|
238
|
|
|
* * @param bool $show
|
239
|
|
|
* * @param array $msg {
|
240
|
|
|
* * @var string $message The actual message.
|
241
|
|
|
* * @var string $title An optional message title.
|
242
|
|
|
* * @var string $type The type of the message ('success', 'update', 'warning', 'promotion').
|
243
|
|
|
* * @var string $id The unique identifier of the message.
|
244
|
|
|
* * @var string $manager_id The unique identifier of the notices manager. For plugins it would be the plugin's slug, for themes - `<slug>-theme`.
|
245
|
|
|
* * @var string $plugin The product's title.
|
246
|
|
|
* * @var string $wp_user_id An optional WP user ID that this admin notice is for.
|
247
|
|
|
* * }
|
248
|
|
|
* *
|
249
|
|
|
* * @return bool
|
250
|
|
|
* *\/
|
251
|
|
|
* function my_custom_show_admin_notice( $show, $msg ) {
|
252
|
|
|
* if ('trial_promotion' != $msg['id']) {
|
253
|
|
|
* return false;
|
254
|
|
|
* }
|
255
|
|
|
*
|
256
|
|
|
* return $show;
|
257
|
|
|
* }
|
258
|
|
|
*
|
259
|
|
|
* my_fs()->add_filter( 'show_admin_notice', 'my_custom_show_admin_notice', 10, 2 );
|
260
|
|
|
*
|
261
|
|
|
* @author Vova Feldman
|
262
|
|
|
* @since 2.2.0
|
263
|
|
|
*/
|
264
|
|
|
$show_notice = call_user_func_array( 'fs_apply_filter', array(
|
265
|
|
|
$this->_module_unique_affix,
|
266
|
|
|
'show_admin_notice',
|
267
|
|
|
$show_admin_notices,
|
268
|
|
|
$msg
|
269
|
|
|
) );
|
270
|
|
|
|
271
|
|
|
if ( true !== $show_notice ) {
|
272
|
|
|
continue;
|
273
|
|
|
}
|
274
|
|
|
|
275
|
|
|
fs_require_template( 'admin-notice.php', $msg );
|
276
|
|
|
|
277
|
|
|
if ( $msg['sticky'] ) {
|
278
|
|
|
self::has_sticky_messages();
|
279
|
|
|
}
|
280
|
|
|
}
|
281
|
|
|
}
|
282
|
|
|
|
283
|
|
|
/**
|
284
|
|
|
* Enqueue common stylesheet to style admin notice.
|
285
|
|
|
*
|
286
|
|
|
* @author Vova Feldman (@svovaf)
|
287
|
|
|
* @since 1.0.7
|
288
|
|
|
*/
|
289
|
|
|
function _enqueue_styles() {
|
|
|
|
|
290
|
|
|
fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
|
291
|
|
|
}
|
292
|
|
|
|
293
|
|
|
/**
|
294
|
|
|
* Check if the current page is the Gutenberg block editor.
|
295
|
|
|
*
|
296
|
|
|
* @author Vova Feldman (@svovaf)
|
297
|
|
|
* @since 2.2.3
|
298
|
|
|
*
|
299
|
|
|
* @return bool
|
300
|
|
|
*/
|
301
|
|
|
function is_gutenberg_page() {
|
|
|
|
|
302
|
|
|
if ( function_exists( 'is_gutenberg_page' ) &&
|
303
|
|
|
is_gutenberg_page()
|
304
|
|
|
) {
|
305
|
|
|
// The Gutenberg plugin is on.
|
306
|
|
|
return true;
|
307
|
|
|
}
|
308
|
|
|
|
309
|
|
|
$current_screen = get_current_screen();
|
310
|
|
|
|
311
|
|
|
if ( method_exists( $current_screen, 'is_block_editor' ) &&
|
312
|
|
|
$current_screen->is_block_editor()
|
313
|
|
|
) {
|
314
|
|
|
// Gutenberg page on 5+.
|
315
|
|
|
return true;
|
316
|
|
|
}
|
317
|
|
|
|
318
|
|
|
return false;
|
319
|
|
|
}
|
320
|
|
|
|
321
|
|
|
/**
|
322
|
|
|
* Add admin message to admin messages queue, and hook to admin_notices / all_admin_notices if not yet hooked.
|
323
|
|
|
*
|
324
|
|
|
* @author Vova Feldman (@svovaf)
|
325
|
|
|
* @since 1.0.4
|
326
|
|
|
*
|
327
|
|
|
* @param string $message
|
328
|
|
|
* @param string $title
|
329
|
|
|
* @param string $type
|
330
|
|
|
* @param bool $is_sticky
|
331
|
|
|
* @param string $id Message ID
|
332
|
|
|
* @param bool $store_if_sticky
|
333
|
|
|
* @param number|null $wp_user_id
|
334
|
|
|
* @param string|null $plugin_title
|
335
|
|
|
* @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network
|
336
|
|
|
* and blog admin pages.
|
337
|
|
|
*
|
338
|
|
|
* @uses add_action()
|
339
|
|
|
*/
|
340
|
|
|
function add(
|
|
|
|
|
341
|
|
|
$message,
|
342
|
|
|
$title = '',
|
343
|
|
|
$type = 'success',
|
344
|
|
|
$is_sticky = false,
|
345
|
|
|
$id = '',
|
346
|
|
|
$store_if_sticky = true,
|
347
|
|
|
$wp_user_id = null,
|
348
|
|
|
$plugin_title = null,
|
349
|
|
|
$is_network_and_blog_admins = false
|
350
|
|
|
) {
|
351
|
|
|
$notices_type = $this->get_notices_type();
|
352
|
|
|
|
353
|
|
|
if ( empty( $this->_notices ) ) {
|
354
|
|
|
if ( ! $is_network_and_blog_admins ) {
|
355
|
|
|
add_action( $notices_type, array( &$this, "_admin_notices_hook" ) );
|
356
|
|
|
} else {
|
357
|
|
|
add_action( 'network_admin_notices', array( &$this, "_admin_notices_hook" ) );
|
358
|
|
|
add_action( 'admin_notices', array( &$this, "_admin_notices_hook" ) );
|
359
|
|
|
}
|
360
|
|
|
|
361
|
|
|
add_action( 'admin_enqueue_scripts', array( &$this, '_enqueue_styles' ) );
|
362
|
|
|
}
|
363
|
|
|
|
364
|
|
|
if ( '' === $id ) {
|
365
|
|
|
$id = md5( $title . ' ' . $message . ' ' . $type );
|
366
|
|
|
}
|
367
|
|
|
|
368
|
|
|
$message_object = array(
|
369
|
|
|
'message' => $message,
|
370
|
|
|
'title' => $title,
|
371
|
|
|
'type' => $type,
|
372
|
|
|
'sticky' => $is_sticky,
|
373
|
|
|
'id' => $id,
|
374
|
|
|
'manager_id' => $this->_id,
|
375
|
|
|
'plugin' => ( ! is_null( $plugin_title ) ? $plugin_title : $this->_title ),
|
376
|
|
|
'wp_user_id' => $wp_user_id,
|
377
|
|
|
);
|
378
|
|
|
|
379
|
|
|
if ( $is_sticky && $store_if_sticky ) {
|
380
|
|
|
$this->_sticky_storage->{$id} = $message_object;
|
381
|
|
|
}
|
382
|
|
|
|
383
|
|
|
$this->_notices[ $id ] = $message_object;
|
384
|
|
|
}
|
385
|
|
|
|
386
|
|
|
/**
|
387
|
|
|
* @author Vova Feldman (@svovaf)
|
388
|
|
|
* @since 1.0.7
|
389
|
|
|
*
|
390
|
|
|
* @param string|string[] $ids
|
391
|
|
|
*/
|
392
|
|
|
function remove_sticky( $ids ) {
|
|
|
|
|
393
|
|
|
if ( ! is_array( $ids ) ) {
|
394
|
|
|
$ids = array( $ids );
|
395
|
|
|
}
|
396
|
|
|
|
397
|
|
|
foreach ( $ids as $id ) {
|
398
|
|
|
// Remove from sticky storage.
|
399
|
|
|
$this->_sticky_storage->remove( $id );
|
400
|
|
|
|
401
|
|
|
if ( isset( $this->_notices[ $id ] ) ) {
|
402
|
|
|
unset( $this->_notices[ $id ] );
|
403
|
|
|
}
|
404
|
|
|
}
|
405
|
|
|
}
|
406
|
|
|
|
407
|
|
|
/**
|
408
|
|
|
* Check if sticky message exists by id.
|
409
|
|
|
*
|
410
|
|
|
* @author Vova Feldman (@svovaf)
|
411
|
|
|
* @since 1.0.9
|
412
|
|
|
*
|
413
|
|
|
* @param $id
|
414
|
|
|
*
|
415
|
|
|
* @return bool
|
416
|
|
|
*/
|
417
|
|
|
function has_sticky( $id ) {
|
|
|
|
|
418
|
|
|
return isset( $this->_sticky_storage[ $id ] );
|
419
|
|
|
}
|
420
|
|
|
|
421
|
|
|
/**
|
422
|
|
|
* Adds sticky admin notification.
|
423
|
|
|
*
|
424
|
|
|
* @author Vova Feldman (@svovaf)
|
425
|
|
|
* @since 1.0.7
|
426
|
|
|
*
|
427
|
|
|
* @param string $message
|
428
|
|
|
* @param string $id Message ID
|
429
|
|
|
* @param string $title
|
430
|
|
|
* @param string $type
|
431
|
|
|
* @param number|null $wp_user_id
|
432
|
|
|
* @param string|null $plugin_title
|
433
|
|
|
* @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network
|
434
|
|
|
* and blog admin pages.
|
435
|
|
|
*/
|
436
|
|
|
function add_sticky( $message, $id, $title = '', $type = 'success', $wp_user_id = null, $plugin_title = null, $is_network_and_blog_admins = false ) {
|
|
|
|
|
437
|
|
|
if ( ! empty( $this->_module_unique_affix ) ) {
|
438
|
|
|
$message = fs_apply_filter( $this->_module_unique_affix, "sticky_message_{$id}", $message );
|
439
|
|
|
$title = fs_apply_filter( $this->_module_unique_affix, "sticky_title_{$id}", $title );
|
440
|
|
|
}
|
441
|
|
|
|
442
|
|
|
$this->add( $message, $title, $type, true, $id, true, $wp_user_id, $plugin_title, $is_network_and_blog_admins );
|
443
|
|
|
}
|
444
|
|
|
|
445
|
|
|
/**
|
446
|
|
|
* Clear all sticky messages.
|
447
|
|
|
*
|
448
|
|
|
* @author Vova Feldman (@svovaf)
|
449
|
|
|
* @since 1.0.8
|
450
|
|
|
*/
|
451
|
|
|
function clear_all_sticky() {
|
|
|
|
|
452
|
|
|
$this->_sticky_storage->clear_all();
|
453
|
|
|
}
|
454
|
|
|
|
455
|
|
|
#--------------------------------------------------------------------------------
|
456
|
|
|
#region Helper Method
|
457
|
|
|
#--------------------------------------------------------------------------------
|
458
|
|
|
|
459
|
|
|
/**
|
460
|
|
|
* @author Vova Feldman (@svovaf)
|
461
|
|
|
* @since 2.0.0
|
462
|
|
|
*
|
463
|
|
|
* @return string
|
464
|
|
|
*/
|
465
|
|
|
private function get_notices_type() {
|
466
|
|
|
return $this->_is_network_notices ?
|
467
|
|
|
'network_admin_notices' :
|
468
|
|
|
'admin_notices';
|
469
|
|
|
}
|
470
|
|
|
|
471
|
|
|
#endregion
|
472
|
|
|
} |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.