|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Remote Dashboard Notifications. |
|
4
|
|
|
* |
|
5
|
|
|
* This class is part of the Remote Dashboard Notifications plugin. |
|
6
|
|
|
* This plugin allows you to send notifications to your client's |
|
7
|
|
|
* WordPress dashboard easily. |
|
8
|
|
|
* |
|
9
|
|
|
* Notification you send will be displayed as admin notifications |
|
10
|
|
|
* using the standard WordPress hooks. A "dismiss" option is added |
|
11
|
|
|
* in order to let the user hide the notification. |
|
12
|
|
|
* |
|
13
|
|
|
* @package Remote Dashboard Notifications |
|
14
|
|
|
* @author ThemeAvenue <[email protected]> |
|
15
|
|
|
* @license GPL-2.0+ |
|
16
|
|
|
* @link http://themeavenue.net |
|
17
|
|
|
* @link http://wordpress.org/plugins/remote-dashboard-notifications/ |
|
18
|
|
|
* @link https://github.com/ThemeAvenue/Remote-Dashboard-Notifications |
|
19
|
|
|
* @copyright 2016 ThemeAvenue |
|
20
|
|
|
*/ |
|
21
|
|
|
|
|
22
|
|
|
// If this file is called directly, abort. |
|
23
|
|
|
if ( ! defined( 'WPINC' ) ) { |
|
24
|
|
|
die; |
|
25
|
|
|
} |
|
26
|
|
|
|
|
27
|
|
|
if ( ! class_exists( 'Remote_Dashboard_Notifications_Client' ) ) { |
|
28
|
|
|
|
|
29
|
|
|
final class Remote_Dashboard_Notifications_Client { |
|
30
|
|
|
|
|
31
|
|
|
/** |
|
32
|
|
|
* @var Remote_Dashboard_Notifications_Client Holds the unique instance |
|
33
|
|
|
* @since 1.3.0 |
|
34
|
|
|
*/ |
|
35
|
|
|
private static $instance; |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* Minimum version of WordPress required ot run the plugin |
|
39
|
|
|
* |
|
40
|
|
|
* @since 1.3.0 |
|
41
|
|
|
* @var string |
|
42
|
|
|
*/ |
|
43
|
|
|
public $wordpress_version_required = '3.8'; |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* Required version of PHP. |
|
47
|
|
|
* |
|
48
|
|
|
* Follow WordPress latest requirements and require |
|
49
|
|
|
* PHP version 5.2 at least. |
|
50
|
|
|
* |
|
51
|
|
|
* @since 1.3.0 |
|
52
|
|
|
* @var string |
|
53
|
|
|
*/ |
|
54
|
|
|
public $php_version_required = '5.2'; |
|
55
|
|
|
|
|
56
|
|
|
/** |
|
57
|
|
|
* Holds all the registered notifications |
|
58
|
|
|
* |
|
59
|
|
|
* @since 1.3.0 |
|
60
|
|
|
* @var array |
|
61
|
|
|
*/ |
|
62
|
|
|
public $notifications = array(); |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* Instantiate and return the unique object |
|
66
|
|
|
* |
|
67
|
|
|
* @since 1.2.0 |
|
68
|
|
|
* @return object Remote_Dashboard_Notifications_Client Unique instance |
|
69
|
|
|
*/ |
|
70
|
|
|
public static function instance() { |
|
71
|
|
|
|
|
72
|
|
|
if ( ! isset( self::$instance ) && ! ( self::$instance instanceof Awesome_Support ) ) { |
|
|
|
|
|
|
73
|
|
|
self::$instance = new Remote_Dashboard_Notifications_Client; |
|
74
|
|
|
self::$instance->init(); |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
return self::$instance; |
|
78
|
|
|
|
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
/** |
|
82
|
|
|
* Instantiate the plugin |
|
83
|
|
|
* |
|
84
|
|
|
* @since 1.3.0 |
|
85
|
|
|
* @return void |
|
86
|
|
|
*/ |
|
87
|
|
|
private function init() { |
|
88
|
|
|
|
|
89
|
|
|
// Make sure the WordPress version is recent enough |
|
90
|
|
|
if ( ! self::$instance->is_version_compatible() ) { |
|
91
|
|
|
return; |
|
92
|
|
|
} |
|
93
|
|
|
|
|
94
|
|
|
// Make sure we have a version of PHP that's not too old |
|
95
|
|
|
if ( ! self::$instance->is_php_version_enough() ) { |
|
96
|
|
|
return; |
|
97
|
|
|
} |
|
98
|
|
|
|
|
99
|
|
|
// Call the dismiss method before testing for Ajax |
|
100
|
|
|
if ( isset( $_GET['rn'] ) && isset( $_GET['notification'] ) ) { |
|
101
|
|
|
add_action( 'plugins_loaded', array( self::$instance, 'dismiss' ) ); |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { |
|
105
|
|
|
add_action( 'admin_print_styles', array( self::$instance, 'style' ), 100 ); |
|
106
|
|
|
add_action( 'admin_notices', array( self::$instance, 'show_notices' ) ); |
|
107
|
|
|
add_action( 'admin_footer', array( self::$instance, 'script' ) ); |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
add_action( 'wp_ajax_rdn_fetch_notifications', array( $this, 'remote_get_notice_ajax' ) ); |
|
111
|
|
|
add_filter( 'heartbeat_received', array( self::$instance, 'heartbeat' ), 10, 2 ); |
|
112
|
|
|
|
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
/** |
|
116
|
|
|
* Throw error on object clone |
|
117
|
|
|
* |
|
118
|
|
|
* The whole idea of the singleton design pattern is that there is a single |
|
119
|
|
|
* object therefore, we don't want the object to be cloned. |
|
120
|
|
|
* |
|
121
|
|
|
* @since 3.2.5 |
|
122
|
|
|
* @return void |
|
123
|
|
|
*/ |
|
124
|
|
|
public function __clone() { |
|
125
|
|
|
// Cloning instances of the class is forbidden |
|
126
|
|
|
_doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'awesome-support' ), '3.2.5' ); |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
/** |
|
130
|
|
|
* Disable unserializing of the class |
|
131
|
|
|
* |
|
132
|
|
|
* @since 3.2.5 |
|
133
|
|
|
* @return void |
|
134
|
|
|
*/ |
|
135
|
|
|
public function __wakeup() { |
|
136
|
|
|
// Unserializing instances of the class is forbidden |
|
137
|
|
|
_doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'awesome-support' ), '3.2.5' ); |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
|
|
/** |
|
141
|
|
|
* Check if the core version is compatible with this addon. |
|
142
|
|
|
* |
|
143
|
|
|
* @since 1.3.0 |
|
144
|
|
|
* @return boolean |
|
145
|
|
|
*/ |
|
146
|
|
View Code Duplication |
private function is_version_compatible() { |
|
|
|
|
|
|
147
|
|
|
|
|
148
|
|
|
if ( empty( self::$instance->wordpress_version_required ) ) { |
|
149
|
|
|
return true; |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
if ( version_compare( get_bloginfo( 'version' ), self::$instance->wordpress_version_required, '<' ) ) { |
|
153
|
|
|
return false; |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
return true; |
|
157
|
|
|
|
|
158
|
|
|
} |
|
159
|
|
|
|
|
160
|
|
|
/** |
|
161
|
|
|
* Check if the version of PHP is compatible with this addon. |
|
162
|
|
|
* |
|
163
|
|
|
* @since 1.3.0 |
|
164
|
|
|
* @return boolean |
|
165
|
|
|
*/ |
|
166
|
|
View Code Duplication |
private function is_php_version_enough() { |
|
|
|
|
|
|
167
|
|
|
|
|
168
|
|
|
/** |
|
169
|
|
|
* No version set, we assume everything is fine. |
|
170
|
|
|
*/ |
|
171
|
|
|
if ( empty( self::$instance->php_version_required ) ) { |
|
172
|
|
|
return true; |
|
173
|
|
|
} |
|
174
|
|
|
|
|
175
|
|
|
if ( version_compare( phpversion(), self::$instance->php_version_required, '<' ) ) { |
|
176
|
|
|
return false; |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
return true; |
|
180
|
|
|
|
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* Register a new remote notification |
|
185
|
|
|
* |
|
186
|
|
|
* @since 1.3.0 |
|
187
|
|
|
* |
|
188
|
|
|
* @param int $channel_id Channel ID on the remote server |
|
189
|
|
|
* @param string $channel_key Channel key for authentication with the server |
|
190
|
|
|
* @param string $server Notification server URL |
|
191
|
|
|
* @param int $cache Cache lifetime (in hours) |
|
192
|
|
|
* |
|
193
|
|
|
* @return bool|string |
|
194
|
|
|
*/ |
|
195
|
|
|
public function add_notification( $channel_id, $channel_key, $server, $cache = 6 ) { |
|
196
|
|
|
|
|
197
|
|
|
$notification = array( |
|
198
|
|
|
'channel_id' => (int) $channel_id, |
|
199
|
|
|
'channel_key' => $channel_key, |
|
200
|
|
|
'server_url' => esc_url( $server ), |
|
201
|
|
|
'cache_lifetime' => apply_filters( 'rn_notice_caching_time', $cache ), |
|
202
|
|
|
); |
|
203
|
|
|
|
|
204
|
|
|
// Generate the notice unique ID |
|
205
|
|
|
$notification['notice_id'] = $notification['channel_id'] . substr( $channel_key, 0, 5 ); |
|
206
|
|
|
|
|
207
|
|
|
// Double check that the required info is here |
|
208
|
|
|
if ( '' === ( $notification['channel_id'] || $notification['channel_key'] || $notification['server_url'] ) ) { |
|
209
|
|
|
return false; |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
|
|
// Check that there is no notification with the same ID |
|
213
|
|
|
if ( array_key_exists( $notification['notice_id'], $this->notifications ) ) { |
|
214
|
|
|
return false; |
|
215
|
|
|
} |
|
216
|
|
|
|
|
217
|
|
|
$this->notifications[ $notification['notice_id'] ] = $notification; |
|
218
|
|
|
|
|
219
|
|
|
return $notification['notice_id']; |
|
220
|
|
|
|
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
/** |
|
224
|
|
|
* Remove a registered notification |
|
225
|
|
|
* |
|
226
|
|
|
* @since 1.3.0 |
|
227
|
|
|
* |
|
228
|
|
|
* @param string $notice_id ID of the notice to remove |
|
229
|
|
|
* |
|
230
|
|
|
* @return void |
|
231
|
|
|
*/ |
|
232
|
|
|
public function remove_notification( $notice_id ) { |
|
233
|
|
|
if ( array_key_exists( $notice_id, $this->notifications ) ) { |
|
234
|
|
|
unset( $this->notifications[ $notice_id ] ); |
|
235
|
|
|
} |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
/** |
|
239
|
|
|
* Get all registered notifications |
|
240
|
|
|
* |
|
241
|
|
|
* @since 1.3.0 |
|
242
|
|
|
* @return array |
|
243
|
|
|
*/ |
|
244
|
|
|
public function get_notifications() { |
|
245
|
|
|
return $this->notifications; |
|
246
|
|
|
} |
|
247
|
|
|
|
|
248
|
|
|
/** |
|
249
|
|
|
* Get a specific notification |
|
250
|
|
|
* |
|
251
|
|
|
* @since 1.3.0 |
|
252
|
|
|
* |
|
253
|
|
|
* @param string $notice_id ID of the notice to retrieve |
|
254
|
|
|
* |
|
255
|
|
|
* @return bool|array |
|
256
|
|
|
*/ |
|
257
|
|
|
public function get_notification( $notice_id ) { |
|
258
|
|
|
|
|
259
|
|
|
if ( ! array_key_exists( $notice_id, $this->notifications ) ) { |
|
260
|
|
|
return false; |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
return $this->notifications[ $notice_id ]; |
|
264
|
|
|
} |
|
265
|
|
|
|
|
266
|
|
|
/** |
|
267
|
|
|
* Adds inline style for non standard notices |
|
268
|
|
|
* |
|
269
|
|
|
* This function will only be called if the notice style is not standard. |
|
270
|
|
|
* |
|
271
|
|
|
* @since 0.1.0 |
|
272
|
|
|
*/ |
|
273
|
|
|
public function style() { ?> |
|
274
|
|
|
<style type="text/css">div.rn-alert{padding:15px 35px 15px 15px;margin-bottom:20px;border:1px solid transparent;-webkit-box-shadow:none;box-shadow:none}div.rn-alert p:empty{display:none}div.rn-alert ol,div.rn-alert ol li,div.rn-alert ul,div.rn-alert ul li{list-style:inherit!important}div.rn-alert ol,div.rn-alert ul{padding-left:30px}div.rn-alert hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}div.rn-alert h1,h2,h3,h4,h5,h6{margin-top:0;color:inherit}div.rn-alert a{font-weight:700}div.rn-alert a:hover{text-decoration:underline}div.rn-alert>p{margin:0;padding:0;line-height:1}div.rn-alert>p,div.rn-alert>ul{margin-bottom:0}div.rn-alert>p+p{margin-top:5px}div.rn-alert .rn-dismiss-btn{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;position:relative;top:-2px;right:-21px;padding:0;cursor:pointer;background:0;border:0;-webkit-appearance:none;float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20);text-decoration:none}div.rn-alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}div.rn-alert-success hr{border-top-color:#c9e2b3}div.rn-alert-success a{color:#2b542c}div.rn-alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}div.rn-alert-info hr{border-top-color:#a6e1ec}div.rn-alert-info a{color:#245269}div.rn-alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}div.rn-alert-warning hr{border-top-color:#f7e1b5}div.rn-alert-warning a{color:#66512c}div.rn-alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}div.rn-alert-danger hr{border-top-color:#e4b9c0}div.rn-alert-danger a{color:#843534}</style> |
|
275
|
|
|
<?php } |
|
276
|
|
|
|
|
277
|
|
|
/** |
|
278
|
|
|
* Display all the registered and available notifications |
|
279
|
|
|
* |
|
280
|
|
|
* @since 1.3.0 |
|
281
|
|
|
* @return void |
|
282
|
|
|
*/ |
|
283
|
|
|
public function show_notices() { |
|
284
|
|
|
|
|
285
|
|
|
foreach ( $this->notifications as $id => $notification ) { |
|
286
|
|
|
|
|
287
|
|
|
$rn = $this->get_remote_notification( $notification ); |
|
288
|
|
|
|
|
289
|
|
|
if ( empty( $rn ) || is_wp_error( $rn ) ) { |
|
290
|
|
|
continue; |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
|
|
if ( $this->is_notification_error( $rn ) ) { |
|
294
|
|
|
continue; |
|
295
|
|
|
} |
|
296
|
|
|
|
|
297
|
|
|
if ( $this->is_notice_dismissed( $rn->slug ) ) { |
|
298
|
|
|
continue; |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
|
|
if ( $this->is_post_type_restricted( $rn ) ) { |
|
302
|
|
|
continue; |
|
303
|
|
|
} |
|
304
|
|
|
|
|
305
|
|
|
if ( ! $this->is_notification_started( $rn ) ) { |
|
306
|
|
|
continue; |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
if ( $this->has_notification_ended( $rn ) ) { |
|
310
|
|
|
continue; |
|
311
|
|
|
} |
|
312
|
|
|
|
|
313
|
|
|
// Output the admin notice |
|
314
|
|
|
$this->create_admin_notice( $rn->message, $this->get_notice_class( isset( $rn->style ) ? $rn->style : 'updated' ), $this->get_notice_dismissal_url( $rn->slug ) ); |
|
315
|
|
|
|
|
316
|
|
|
} |
|
317
|
|
|
|
|
318
|
|
|
} |
|
319
|
|
|
|
|
320
|
|
|
/** |
|
321
|
|
|
* Check if the notification has been dismissed |
|
322
|
|
|
* |
|
323
|
|
|
* @since 1.2.0 |
|
324
|
|
|
* |
|
325
|
|
|
* @param string $slug Slug of the notice to check |
|
326
|
|
|
* |
|
327
|
|
|
* @return bool |
|
328
|
|
|
*/ |
|
329
|
|
|
protected function is_notice_dismissed( $slug ) { |
|
330
|
|
|
|
|
331
|
|
|
global $current_user; |
|
332
|
|
|
|
|
333
|
|
|
$dismissed = array_filter( (array) get_user_meta( $current_user->ID, '_rn_dismissed', true ) ); |
|
334
|
|
|
|
|
335
|
|
|
if ( is_array( $dismissed ) && in_array( $slug, $dismissed ) ) { |
|
336
|
|
|
return true; |
|
337
|
|
|
} |
|
338
|
|
|
|
|
339
|
|
|
return false; |
|
340
|
|
|
|
|
341
|
|
|
} |
|
342
|
|
|
|
|
343
|
|
|
/** |
|
344
|
|
|
* Check if the notification can be displayed for the current post type |
|
345
|
|
|
* |
|
346
|
|
|
* @since 1.2.0 |
|
347
|
|
|
* |
|
348
|
|
|
* @param stdClass $notification The notification object |
|
349
|
|
|
* |
|
350
|
|
|
* @return bool |
|
351
|
|
|
*/ |
|
352
|
|
|
protected function is_post_type_restricted( $notification ) { |
|
353
|
|
|
|
|
354
|
|
|
/* If the type array isn't empty we have a limitation */ |
|
355
|
|
|
if ( isset( $notification->type ) && is_array( $notification->type ) && ! empty( $notification->type ) ) { |
|
356
|
|
|
|
|
357
|
|
|
/* Get current post type */ |
|
358
|
|
|
$pt = get_post_type(); |
|
359
|
|
|
|
|
360
|
|
|
/** |
|
361
|
|
|
* If the current post type can't be retrieved |
|
362
|
|
|
* or if it's not in the allowed post types, |
|
363
|
|
|
* then we don't display the admin notice. |
|
364
|
|
|
*/ |
|
365
|
|
|
if ( false === $pt || ! in_array( $pt, $notification->type ) ) { |
|
366
|
|
|
return true; |
|
367
|
|
|
} |
|
368
|
|
|
|
|
369
|
|
|
} |
|
370
|
|
|
|
|
371
|
|
|
return false; |
|
372
|
|
|
|
|
373
|
|
|
} |
|
374
|
|
|
|
|
375
|
|
|
/** |
|
376
|
|
|
* Check if the notification has started yet |
|
377
|
|
|
* |
|
378
|
|
|
* @since 1.2.0 |
|
379
|
|
|
* |
|
380
|
|
|
* @param stdClass $notification The notification object |
|
381
|
|
|
* |
|
382
|
|
|
* @return bool |
|
383
|
|
|
*/ |
|
384
|
|
View Code Duplication |
protected function is_notification_started( $notification ) { |
|
|
|
|
|
|
385
|
|
|
|
|
386
|
|
|
if ( ! isset( $notification->date_start ) ) { |
|
387
|
|
|
return true; |
|
388
|
|
|
} |
|
389
|
|
|
|
|
390
|
|
|
if ( empty( $notification->date_start ) || strtotime( $notification->date_start ) < time() ) { |
|
391
|
|
|
return true; |
|
392
|
|
|
} |
|
393
|
|
|
|
|
394
|
|
|
return false; |
|
395
|
|
|
|
|
396
|
|
|
} |
|
397
|
|
|
|
|
398
|
|
|
/** |
|
399
|
|
|
* Check if the notification has expired |
|
400
|
|
|
* |
|
401
|
|
|
* @since 1.2.0 |
|
402
|
|
|
* |
|
403
|
|
|
* @param stdClass $notification The notification object |
|
404
|
|
|
* |
|
405
|
|
|
* @return bool |
|
406
|
|
|
*/ |
|
407
|
|
View Code Duplication |
protected function has_notification_ended( $notification ) { |
|
|
|
|
|
|
408
|
|
|
|
|
409
|
|
|
if ( ! isset( $notification->date_end ) ) { |
|
410
|
|
|
return false; |
|
411
|
|
|
} |
|
412
|
|
|
|
|
413
|
|
|
if ( empty( $notification->date_end ) || strtotime( $notification->date_end ) > time() ) { |
|
414
|
|
|
return false; |
|
415
|
|
|
} |
|
416
|
|
|
|
|
417
|
|
|
return true; |
|
418
|
|
|
|
|
419
|
|
|
} |
|
420
|
|
|
|
|
421
|
|
|
/** |
|
422
|
|
|
* Get the remote notification object |
|
423
|
|
|
* |
|
424
|
|
|
* @since 1.3.0 |
|
425
|
|
|
* |
|
426
|
|
|
* @param array $notification The notification data array |
|
427
|
|
|
* |
|
428
|
|
|
* @return object|false |
|
429
|
|
|
*/ |
|
430
|
|
|
protected function get_remote_notification( $notification ) { |
|
431
|
|
|
|
|
432
|
|
|
$content = get_transient( 'rn_last_notification_' . $notification['notice_id'] ); |
|
433
|
|
|
|
|
434
|
|
|
if ( false === $content ) { |
|
435
|
|
|
add_option( 'rdn_fetch_' . $notification['notice_id'], 'fetch' ); |
|
436
|
|
|
} |
|
437
|
|
|
|
|
438
|
|
|
return $content; |
|
439
|
|
|
|
|
440
|
|
|
} |
|
441
|
|
|
|
|
442
|
|
|
/** |
|
443
|
|
|
* Get the admin notice class attribute |
|
444
|
|
|
* |
|
445
|
|
|
* @since 1.3.0 |
|
446
|
|
|
* |
|
447
|
|
|
* @param string $style Notification style |
|
448
|
|
|
* |
|
449
|
|
|
* @return string |
|
450
|
|
|
*/ |
|
451
|
|
|
protected function get_notice_class( $style ) { |
|
452
|
|
|
|
|
453
|
|
|
switch ( $style ) { |
|
454
|
|
|
case 'updated': |
|
455
|
|
|
$class = $style; |
|
456
|
|
|
break; |
|
457
|
|
|
|
|
458
|
|
|
case 'error': |
|
459
|
|
|
$class = 'updated error'; |
|
460
|
|
|
break; |
|
461
|
|
|
|
|
462
|
|
|
default: |
|
463
|
|
|
$class = "updated rn-alert rn-alert-$style"; |
|
464
|
|
|
} |
|
465
|
|
|
|
|
466
|
|
|
return $class; |
|
467
|
|
|
|
|
468
|
|
|
} |
|
469
|
|
|
|
|
470
|
|
|
/** |
|
471
|
|
|
* Prepare the dismissal URL for the notice |
|
472
|
|
|
* |
|
473
|
|
|
* @since 1.3.0 |
|
474
|
|
|
* |
|
475
|
|
|
* @param string $slug Notice slug |
|
476
|
|
|
* |
|
477
|
|
|
* @return string |
|
478
|
|
|
*/ |
|
479
|
|
|
protected function get_notice_dismissal_url( $slug ) { |
|
480
|
|
|
|
|
481
|
|
|
$args = $_GET; |
|
482
|
|
|
$args['rn'] = wp_create_nonce( 'rn-dismiss' ); |
|
483
|
|
|
$args['notification'] = trim( $slug ); |
|
484
|
|
|
|
|
485
|
|
|
return esc_url( add_query_arg( $args, '' ) ); |
|
486
|
|
|
|
|
487
|
|
|
} |
|
488
|
|
|
|
|
489
|
|
|
/** |
|
490
|
|
|
* Create the actual admin notice |
|
491
|
|
|
* |
|
492
|
|
|
* @since 1.3.0 |
|
493
|
|
|
* |
|
494
|
|
|
* @param string $contents Notice contents |
|
495
|
|
|
* @param string $class Wrapper class |
|
496
|
|
|
* @param string $dismiss Dismissal link |
|
497
|
|
|
* |
|
498
|
|
|
* @return void |
|
499
|
|
|
*/ |
|
500
|
|
|
protected function create_admin_notice( $contents, $class, $dismiss ) { ?> |
|
501
|
|
|
<div class="<?php echo $class; ?>"> |
|
502
|
|
|
<a href="<?php echo $dismiss; ?>" id="rn-dismiss" class="rn-dismiss-btn" title="<?php _e( 'Dismiss notification', 'remote-notifications' ); ?>">×</a> |
|
503
|
|
|
<p><?php echo html_entity_decode( $contents ); ?></p> |
|
504
|
|
|
</div> |
|
505
|
|
|
<?php } |
|
506
|
|
|
|
|
507
|
|
|
/** |
|
508
|
|
|
* Dismiss notice |
|
509
|
|
|
* |
|
510
|
|
|
* When the user dismisses a notice, its slug |
|
511
|
|
|
* is added to the _rn_dismissed entry in the DB options table. |
|
512
|
|
|
* This entry is then used to check if a notie has been dismissed |
|
513
|
|
|
* before displaying it on the dashboard. |
|
514
|
|
|
* |
|
515
|
|
|
* @since 0.1.0 |
|
516
|
|
|
*/ |
|
517
|
|
|
public function dismiss() { |
|
518
|
|
|
|
|
519
|
|
|
global $current_user; |
|
520
|
|
|
|
|
521
|
|
|
/* Check if we have all the vars */ |
|
522
|
|
|
if ( ! isset( $_GET['rn'] ) || ! isset( $_GET['notification'] ) ) { |
|
523
|
|
|
return; |
|
524
|
|
|
} |
|
525
|
|
|
|
|
526
|
|
|
/* Validate nonce */ |
|
527
|
|
|
if ( ! wp_verify_nonce( sanitize_key( $_GET['rn'] ), 'rn-dismiss' ) ) { |
|
528
|
|
|
return; |
|
529
|
|
|
} |
|
530
|
|
|
|
|
531
|
|
|
/* Get dismissed list */ |
|
532
|
|
|
$dismissed = array_filter( (array) get_user_meta( $current_user->ID, '_rn_dismissed', true ) ); |
|
533
|
|
|
|
|
534
|
|
|
/* Add the current notice to the list if needed */ |
|
535
|
|
|
if ( is_array( $dismissed ) && ! in_array( $_GET['notification'], $dismissed ) ) { |
|
536
|
|
|
array_push( $dismissed, $_GET['notification'] ); |
|
537
|
|
|
} |
|
538
|
|
|
|
|
539
|
|
|
/* Update option */ |
|
540
|
|
|
update_user_meta( $current_user->ID, '_rn_dismissed', $dismissed ); |
|
541
|
|
|
|
|
542
|
|
|
} |
|
543
|
|
|
|
|
544
|
|
|
/** |
|
545
|
|
|
* Adds the script that hooks into the Heartbeat API |
|
546
|
|
|
* |
|
547
|
|
|
* @since 1.3.0 |
|
548
|
|
|
* @return void |
|
549
|
|
|
*/ |
|
550
|
|
|
public function script() { |
|
551
|
|
|
|
|
552
|
|
|
$maybe_fetch = array(); |
|
553
|
|
|
|
|
554
|
|
|
foreach ( $this->get_notifications() as $id => $n ) { |
|
555
|
|
|
$maybe_fetch[] = (string) $id; |
|
556
|
|
|
} ?> |
|
557
|
|
|
|
|
558
|
|
|
<script type="text/javascript"> |
|
559
|
|
|
jQuery(document).ready(function ($) { |
|
560
|
|
|
|
|
561
|
|
|
// Hook into the heartbeat-send |
|
562
|
|
|
$(document).on('heartbeat-send', function (e, data) { |
|
563
|
|
|
data['rdn_maybe_fetch'] = <?php echo json_encode( $maybe_fetch ); ?>; |
|
564
|
|
|
}); |
|
565
|
|
|
|
|
566
|
|
|
// Listen for the custom event "heartbeat-tick" on $(document). |
|
567
|
|
|
$(document).on('heartbeat-tick', function (e, data) { |
|
568
|
|
|
|
|
569
|
|
|
if (data.rdn_fetch !== '') { |
|
570
|
|
|
|
|
571
|
|
|
ajax_data = { |
|
572
|
|
|
'action': 'rdn_fetch_notifications', |
|
573
|
|
|
'notices': data.rdn_fetch |
|
574
|
|
|
}; |
|
575
|
|
|
|
|
576
|
|
|
$.post(ajaxurl, ajax_data); |
|
577
|
|
|
|
|
578
|
|
|
} |
|
579
|
|
|
|
|
580
|
|
|
}); |
|
581
|
|
|
}); |
|
582
|
|
|
</script> |
|
583
|
|
|
|
|
584
|
|
|
<?php } |
|
585
|
|
|
|
|
586
|
|
|
/** |
|
587
|
|
|
* Hook into the Heartbeat API. |
|
588
|
|
|
* |
|
589
|
|
|
* @since 1.3.0 |
|
590
|
|
|
* |
|
591
|
|
|
* @param array $response Heartbeat tick response |
|
592
|
|
|
* @param array $data Heartbeat tick data |
|
593
|
|
|
* |
|
594
|
|
|
* @return array Updated Heartbeat tick response |
|
595
|
|
|
*/ |
|
596
|
|
|
function heartbeat( $response, $data ) { |
|
|
|
|
|
|
597
|
|
|
|
|
598
|
|
|
if ( isset( $data['rdn_maybe_fetch'] ) ) { |
|
599
|
|
|
|
|
600
|
|
|
$notices = $data['rdn_maybe_fetch']; |
|
601
|
|
|
|
|
602
|
|
|
if ( ! is_array( $notices ) ) { |
|
603
|
|
|
$notices = array( $notices ); |
|
604
|
|
|
} |
|
605
|
|
|
|
|
606
|
|
|
foreach ( $notices as $notice_id ) { |
|
607
|
|
|
|
|
608
|
|
|
$fetch = get_option( "rdn_fetch_$notice_id", false ); |
|
609
|
|
|
|
|
610
|
|
|
if ( 'fetch' === $fetch ) { |
|
611
|
|
|
|
|
612
|
|
|
if ( ! isset( $response['rdn_fetch'] ) ) { |
|
613
|
|
|
$response['rdn_fetch'] = array(); |
|
614
|
|
|
} |
|
615
|
|
|
|
|
616
|
|
|
$response['rdn_fetch'][] = $notice_id; |
|
617
|
|
|
|
|
618
|
|
|
} |
|
619
|
|
|
|
|
620
|
|
|
} |
|
621
|
|
|
|
|
622
|
|
|
} |
|
623
|
|
|
|
|
624
|
|
|
return $response; |
|
625
|
|
|
|
|
626
|
|
|
} |
|
627
|
|
|
|
|
628
|
|
|
/** |
|
629
|
|
|
* Triggers the remote requests that fetches notices for this particular instance |
|
630
|
|
|
* |
|
631
|
|
|
* @since 1.3.0 |
|
632
|
|
|
* @return void |
|
633
|
|
|
*/ |
|
634
|
|
|
public function remote_get_notice_ajax() { |
|
635
|
|
|
|
|
636
|
|
|
if ( isset( $_POST['notices'] ) ) { |
|
637
|
|
|
$notices = $_POST['notices']; |
|
638
|
|
|
} else { |
|
639
|
|
|
echo 'No notice ID'; |
|
640
|
|
|
die(); |
|
641
|
|
|
} |
|
642
|
|
|
|
|
643
|
|
|
if ( ! is_array( $notices ) ) { |
|
644
|
|
|
$notices = array( $notices ); |
|
645
|
|
|
} |
|
646
|
|
|
|
|
647
|
|
|
foreach ( $notices as $notice_id ) { |
|
648
|
|
|
|
|
649
|
|
|
$notification = $this->get_notification( $notice_id ); |
|
650
|
|
|
$rn = $this->remote_get_notification( $notification ); |
|
|
|
|
|
|
651
|
|
|
|
|
652
|
|
|
if ( is_wp_error( $rn ) ) { |
|
653
|
|
|
echo $rn->get_error_message(); |
|
654
|
|
|
} else { |
|
655
|
|
|
echo json_encode( $rn ); |
|
656
|
|
|
} |
|
657
|
|
|
|
|
658
|
|
|
} |
|
659
|
|
|
|
|
660
|
|
|
die(); |
|
661
|
|
|
|
|
662
|
|
|
} |
|
663
|
|
|
|
|
664
|
|
|
/** |
|
665
|
|
|
* Get the remote server URL |
|
666
|
|
|
* |
|
667
|
|
|
* @since 1.2.0 |
|
668
|
|
|
* |
|
669
|
|
|
* @param string $url THe server URL to sanitize |
|
670
|
|
|
* |
|
671
|
|
|
* @return string |
|
672
|
|
|
*/ |
|
673
|
|
|
protected function get_remote_url( $url ) { |
|
674
|
|
|
|
|
675
|
|
|
$url = explode( '?', $url ); |
|
676
|
|
|
|
|
677
|
|
|
return esc_url( $url[0] ); |
|
678
|
|
|
|
|
679
|
|
|
} |
|
680
|
|
|
|
|
681
|
|
|
/** |
|
682
|
|
|
* Maybe get a notification from the remote server |
|
683
|
|
|
* |
|
684
|
|
|
* @since 1.2.0 |
|
685
|
|
|
* |
|
686
|
|
|
* @param array $notification The notification data array |
|
687
|
|
|
* |
|
688
|
|
|
* @return string|WP_Error |
|
689
|
|
|
*/ |
|
690
|
|
|
protected function remote_get_notification( $notification ) { |
|
691
|
|
|
|
|
692
|
|
|
/* Query the server */ |
|
693
|
|
|
$response = wp_remote_get( $this->build_query_url( $notification['server_url'], $this->get_payload( $notification ) ), array( 'timeout' => apply_filters( 'rn_http_request_timeout', 5 ) ) ); |
|
694
|
|
|
|
|
695
|
|
|
/* If we have a WP_Error object we abort */ |
|
696
|
|
|
if ( is_wp_error( $response ) ) { |
|
697
|
|
|
return $response; |
|
698
|
|
|
} |
|
699
|
|
|
|
|
700
|
|
|
if ( 200 !== (int) wp_remote_retrieve_response_code( $response ) ) { |
|
701
|
|
|
return new WP_Error( 'invalid_response', sprintf( __( 'The server response was invalid (code %s)', 'remote-notifications' ), wp_remote_retrieve_response_code( $response ) ) ); |
|
702
|
|
|
} |
|
703
|
|
|
|
|
704
|
|
|
$body = wp_remote_retrieve_body( $response ); |
|
705
|
|
|
|
|
706
|
|
|
if ( empty( $body ) ) { |
|
707
|
|
|
return new WP_Error( 'empty_response', __( 'The server response is empty', 'remote-notifications' ) ); |
|
708
|
|
|
} |
|
709
|
|
|
|
|
710
|
|
|
$body = json_decode( $body ); |
|
711
|
|
|
|
|
712
|
|
|
if ( is_null( $body ) ) { |
|
713
|
|
|
return new WP_Error( 'json_decode_error', __( 'Cannot decode the response content', 'remote-notifications' ) ); |
|
714
|
|
|
} |
|
715
|
|
|
|
|
716
|
|
|
set_transient( 'rn_last_notification_' . $notification['notice_id'], $body, $notification['cache_lifetime'] * 60 * 60 ); |
|
717
|
|
|
delete_option( 'rdn_fetch_' . $notification['notice_id'] ); |
|
718
|
|
|
|
|
719
|
|
|
if ( $this->is_notification_error( $body ) ) { |
|
720
|
|
|
return new WP_Error( 'notification_error', $this->get_notification_error_message( $body ) ); |
|
721
|
|
|
} |
|
722
|
|
|
|
|
723
|
|
|
return $body; |
|
|
|
|
|
|
724
|
|
|
|
|
725
|
|
|
} |
|
726
|
|
|
|
|
727
|
|
|
/** |
|
728
|
|
|
* Check if the notification returned by the server is an error |
|
729
|
|
|
* |
|
730
|
|
|
* @since 1.2.0 |
|
731
|
|
|
* |
|
732
|
|
|
* @param object $notification Notification returned |
|
733
|
|
|
* |
|
734
|
|
|
* @return bool |
|
735
|
|
|
*/ |
|
736
|
|
|
protected function is_notification_error( $notification ) { |
|
737
|
|
|
|
|
738
|
|
|
if ( false === $this->get_notification_error_message( $notification ) ) { |
|
739
|
|
|
return false; |
|
740
|
|
|
} |
|
741
|
|
|
|
|
742
|
|
|
return true; |
|
743
|
|
|
|
|
744
|
|
|
} |
|
745
|
|
|
|
|
746
|
|
|
/** |
|
747
|
|
|
* Get the error message returned by the remote server |
|
748
|
|
|
* |
|
749
|
|
|
* @since 1.2.0 |
|
750
|
|
|
* |
|
751
|
|
|
* @param object $notification Notification returned |
|
752
|
|
|
* |
|
753
|
|
|
* @return bool|string |
|
754
|
|
|
*/ |
|
755
|
|
|
protected function get_notification_error_message( $notification ) { |
|
756
|
|
|
|
|
757
|
|
|
if ( ! is_object( $notification ) ) { |
|
758
|
|
|
return false; |
|
759
|
|
|
} |
|
760
|
|
|
|
|
761
|
|
|
if ( ! isset( $notification->error ) ) { |
|
762
|
|
|
return false; |
|
763
|
|
|
} |
|
764
|
|
|
|
|
765
|
|
|
return sanitize_text_field( $notification->error ); |
|
766
|
|
|
|
|
767
|
|
|
} |
|
768
|
|
|
|
|
769
|
|
|
/** |
|
770
|
|
|
* Get the payload required for querying the remote server |
|
771
|
|
|
* |
|
772
|
|
|
* @since 1.2.0 |
|
773
|
|
|
* |
|
774
|
|
|
* @param array $notification The notification data array |
|
775
|
|
|
* |
|
776
|
|
|
* @return string |
|
777
|
|
|
*/ |
|
778
|
|
|
protected function get_payload( $notification ) { |
|
779
|
|
|
return base64_encode( json_encode( array( |
|
780
|
|
|
'channel' => $notification['channel_id'], |
|
781
|
|
|
'key' => $notification['channel_key'] |
|
782
|
|
|
) ) ); |
|
783
|
|
|
} |
|
784
|
|
|
|
|
785
|
|
|
/** |
|
786
|
|
|
* Get the full URL used for the remote get |
|
787
|
|
|
* |
|
788
|
|
|
* @since 1.2.0 |
|
789
|
|
|
* |
|
790
|
|
|
* @param string $url The remote server URL |
|
791
|
|
|
* @param string $payload The encoded payload |
|
792
|
|
|
* |
|
793
|
|
|
* @return string |
|
794
|
|
|
*/ |
|
795
|
|
|
protected function build_query_url( $url, $payload ) { |
|
796
|
|
|
return add_query_arg( array( |
|
797
|
|
|
'post_type' => 'notification', |
|
798
|
|
|
'payload' => $payload |
|
799
|
|
|
), $this->get_remote_url( $url ) ); |
|
800
|
|
|
} |
|
801
|
|
|
|
|
802
|
|
|
} |
|
803
|
|
|
|
|
804
|
|
|
} |
|
805
|
|
|
|
|
806
|
|
|
/** |
|
807
|
|
|
* The main function responsible for returning the unique RDN client |
|
808
|
|
|
* |
|
809
|
|
|
* Use this function like you would a global variable, except without needing |
|
810
|
|
|
* to declare the global. |
|
811
|
|
|
* |
|
812
|
|
|
* @since 1.3.0 |
|
813
|
|
|
* @return object Remote_Dashboard_Notifications_Client |
|
814
|
|
|
*/ |
|
815
|
|
|
function RDNC() { |
|
816
|
|
|
return Remote_Dashboard_Notifications_Client::instance(); |
|
817
|
|
|
} |
|
818
|
|
|
|
|
819
|
|
|
// Get Awesome Support Running |
|
820
|
|
|
RDNC(); |
|
821
|
|
|
|
|
822
|
|
|
/** |
|
823
|
|
|
* Register a new remote notification |
|
824
|
|
|
* |
|
825
|
|
|
* Helper function for registering new notifications through the Remote_Dashboard_Notifications_Client class |
|
826
|
|
|
* |
|
827
|
|
|
* @since 1.3.0 |
|
828
|
|
|
* |
|
829
|
|
|
* @param int $channel_id Channel ID on the remote server |
|
830
|
|
|
* @param string $channel_key Channel key for authentication with the server |
|
831
|
|
|
* @param string $server Notification server URL |
|
832
|
|
|
* @param int $cache Cache lifetime (in hours) |
|
833
|
|
|
* |
|
834
|
|
|
* @return bool|string |
|
835
|
|
|
*/ |
|
836
|
|
|
function rdnc_add_notification( $channel_id, $channel_key, $server, $cache = 6 ) { |
|
837
|
|
|
return RDNC()->add_notification( $channel_id, $channel_key, $server, $cache ); |
|
838
|
|
|
} |
|
839
|
|
|
|
|
840
|
|
|
if ( ! class_exists( 'TAV_Remote_Notification_Client' ) ) { |
|
841
|
|
|
|
|
842
|
|
|
/** |
|
843
|
|
|
* Class TAV_Remote_Notification_Client |
|
844
|
|
|
* |
|
845
|
|
|
* This class, even though deprecated, is kept here for backwards compatibility. It is now just a wrapper for the new notification registration method. |
|
846
|
|
|
* |
|
847
|
|
|
* @deprecated @1.3.0 |
|
848
|
|
|
*/ |
|
849
|
|
|
class TAV_Remote_Notification_Client { |
|
850
|
|
|
|
|
851
|
|
|
public function __construct( $channel_id = false, $channel_key = false, $server = false ) { |
|
852
|
|
|
rdnc_add_notification( $channel_id, $channel_key, $server ); |
|
|
|
|
|
|
853
|
|
|
} |
|
854
|
|
|
} |
|
855
|
|
|
|
|
856
|
|
|
} |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.jsonfile (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.jsonto be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
requireorrequire-devsection?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceofchecks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.