ThemeAvenue /
Remote-Dashboard-Notifications
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 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 ) { |
||
|
0 ignored issues
–
show
|
|||
| 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 ); |
||
|
0 ignored issues
–
show
It seems like
$notification defined by $this->get_notification($notice_id) on line 649 can also be of type boolean; however, Remote_Dashboard_Notific...mote_get_notification() does only seem to accept array, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 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 ); |
||
|
0 ignored issues
–
show
$channel_id is of type boolean, but the function expects a integer.
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
$channel_key is of type boolean, but the function expects a string.
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
$server is of type boolean, but the function expects a string.
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
| 853 | } |
||
| 854 | } |
||
| 855 | |||
| 856 | } |
Adding explicit visibility (
private,protected, orpublic) is generally recommend to communicate to other developers how, and from where this method is intended to be used.