class-fl-builder-notifications.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <?php
  2. /**
  3. * Notifications
  4. * @since 2.1
  5. */
  6. final class FLBuilderNotifications {
  7. static $url = 'https://www.wpbeaverbuilder.com/wp-json/wp/v2/fl_notification';
  8. static $option = 'fl_notifications';
  9. public static function init() {
  10. if ( FLBuilderModel::is_white_labeled() || true == apply_filters( 'fl_disable_notifications', false ) ) {
  11. return false;
  12. }
  13. add_action( 'pre_set_site_transient_update_plugins', array( 'FLBuilderNotifications', 'fetch_notifications_trigger' ) );
  14. add_action( 'fl_fetch_notifications', array( 'FLBuilderNotifications', 'fetch_notifications' ) );
  15. FLBuilderAJAX::add_action( 'fl_builder_notifications', array( 'FLBuilderNotifications', 'notications_ajax' ), array( 'read' ) );
  16. }
  17. /**
  18. * Transient is passed by reference here, lets not mess with it and just trigger our fetch.
  19. */
  20. public static function fetch_notifications_trigger( $transient ) {
  21. if ( ! did_action( 'fl_fetch_notifications' ) ) {
  22. do_action( 'fl_fetch_notifications' );
  23. }
  24. return $transient;
  25. }
  26. /**
  27. * Notification AJAX callback.
  28. *
  29. * @since 2.1
  30. */
  31. public static function notications_ajax( $read ) {
  32. if ( $read ) {
  33. self::update_state( true );
  34. } else {
  35. self::update_state( false );
  36. }
  37. wp_send_json_success();
  38. }
  39. /**
  40. * Fetch notifications from remote.
  41. *
  42. * @since 2.1
  43. */
  44. public static function fetch_notifications() {
  45. $defaults = array(
  46. 'read' => false,
  47. 'checksum' => '',
  48. 'data' => '{}',
  49. );
  50. $url = ( isset( $_GET['force-check'] ) ) ? self::$url . '/?a=' . rand() : self::$url;
  51. $stored_data = get_option( self::$option, $defaults );
  52. $response = wp_remote_get( $url );
  53. $response_code = wp_remote_retrieve_response_code( $response );
  54. $body = wp_remote_retrieve_body( $response );
  55. if ( 200 === $response_code ) {
  56. $body = json_decode( $body );
  57. // No post 0
  58. if ( ! isset( $body[0] ) || ! isset( $body[0]->date ) ) {
  59. return $stored_data;
  60. }
  61. // Generate checksum data
  62. $latest_checksum = self::get_checksum( $body );
  63. $stored_checksum = $stored_data['checksum'];
  64. // check if we have any unread posts by comparing checksums
  65. $unread = self::compare_checksums( $stored_checksum, $latest_checksum );
  66. $stored_data = array(
  67. 'read' => true,
  68. 'checksum' => $latest_checksum,
  69. 'data' => wp_json_encode( $body ),
  70. );
  71. if ( $unread ) {
  72. $stored_data['read'] = false;
  73. }
  74. update_option( self::$option, $stored_data );
  75. } else {
  76. error_log( 'response was not a 200' );
  77. }
  78. return $stored_data;
  79. }
  80. /**
  81. * Compare locally stored checksums against new data.
  82. * @since 2.1
  83. * @return bool true if new posts detected
  84. */
  85. public static function compare_checksums( $stored_checksum, $latest_checksum ) {
  86. if ( ! is_array( $stored_checksum ) ) {
  87. return true;
  88. }
  89. foreach ( $stored_checksum as $id => $date ) {
  90. // if a post has been deleted, then remove it from local checksum
  91. if ( ! isset( $latest_checksum[ $id ] ) ) {
  92. unset( $stored_checksum[ $id ] );
  93. }
  94. }
  95. $diff = array_diff_assoc( $latest_checksum, $stored_checksum );
  96. return ( ! empty( $diff ) ) ? true : false;
  97. }
  98. /**
  99. * Prepare checksum array from rest data.
  100. *
  101. * @since 2.1
  102. */
  103. public static function get_checksum( $body ) {
  104. $checksum = array();
  105. foreach ( $body as $post ) {
  106. $checksum[ $post->id ] = crc32( $post->content->rendered );
  107. }
  108. return (array) $checksum;
  109. }
  110. /**
  111. * Return notications from the db or fetch from remote
  112. *
  113. * @since 2.1
  114. */
  115. public static function get_notifications() {
  116. $defaults = array(
  117. 'read' => false,
  118. 'checksum' => '',
  119. 'data' => '{}',
  120. );
  121. $notifications = get_option( self::$option, $defaults );
  122. if ( '{}' == $notifications['data'] ) {
  123. return self::fetch_notifications();
  124. }
  125. return $notifications;
  126. }
  127. /**
  128. * Mark notifications read/unread
  129. *
  130. * @since 2.1
  131. */
  132. public static function update_state( $state ) {
  133. $defaults = array(
  134. 'read' => false,
  135. 'checksum' => '',
  136. 'data' => '{}',
  137. );
  138. $notifications = get_option( self::$option, $defaults );
  139. $notifications['read'] = $state;
  140. update_option( self::$option, $notifications );
  141. }
  142. }
  143. FLBuilderNotifications::init();