暫無描述

class.jetpack-display-posts-widget.php 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <?php
  2. use Automattic\Jetpack\Status;
  3. /*
  4. * Display a list of recent posts from a WordPress.com or Jetpack-enabled blog.
  5. */
  6. class Jetpack_Display_Posts_Widget extends Jetpack_Display_Posts_Widget__Base {
  7. /**
  8. * @var string Widget options key prefix.
  9. */
  10. public $widget_options_key_prefix = 'display_posts_site_data_';
  11. /**
  12. * @var string The name of the cron that will update widget data.
  13. */
  14. public static $cron_name = 'jetpack_display_posts_widget_cron_update';
  15. // DATA STORE
  16. /**
  17. * Gets blog data from the cache.
  18. *
  19. * @param string $site
  20. *
  21. * @return array|WP_Error
  22. */
  23. public function get_blog_data( $site ) {
  24. // load from cache, if nothing return an error
  25. $site_hash = $this->get_site_hash( $site );
  26. $cached_data = $this->wp_get_option( $this->widget_options_key_prefix . $site_hash );
  27. /**
  28. * If the cache is empty, return an empty_cache error.
  29. */
  30. if ( false === $cached_data ) {
  31. return new WP_Error(
  32. 'empty_cache',
  33. __( 'Information about this blog is currently being retrieved.', 'jetpack' )
  34. );
  35. }
  36. return $cached_data;
  37. }
  38. /**
  39. * Update a widget instance.
  40. *
  41. * @param string $site The site to fetch the latest data for.
  42. *
  43. * @return array - the new data
  44. */
  45. public function update_instance( $site ) {
  46. /**
  47. * Fetch current information for a site.
  48. */
  49. $site_hash = $this->get_site_hash( $site );
  50. $option_key = $this->widget_options_key_prefix . $site_hash;
  51. $instance_data = $this->wp_get_option( $option_key );
  52. /**
  53. * Fetch blog data and save it in $instance_data.
  54. */
  55. $new_data = $this->fetch_blog_data( $site, $instance_data );
  56. /**
  57. * If the option doesn't exist yet - create a new option
  58. */
  59. if ( false === $instance_data ) {
  60. $this->wp_add_option( $option_key, $new_data );
  61. }
  62. else {
  63. $this->wp_update_option( $option_key, $new_data );
  64. }
  65. return $new_data;
  66. }
  67. // WIDGET API
  68. public function update( $new_instance, $old_instance ) {
  69. $instance = parent::update( $new_instance, $old_instance );
  70. /**
  71. * Forcefully activate the update cron when saving widget instance.
  72. *
  73. * So we can be sure that it will be running later.
  74. */
  75. $this->activate_cron();
  76. return $instance;
  77. }
  78. // CRON
  79. /**
  80. * Activates widget update cron task.
  81. */
  82. public static function activate_cron() {
  83. if ( ! wp_next_scheduled( self::$cron_name ) ) {
  84. wp_schedule_event( time(), 'minutes_10', self::$cron_name );
  85. }
  86. }
  87. /**
  88. * Deactivates widget update cron task.
  89. *
  90. * This is a wrapper over the static method as it provides some syntactic sugar.
  91. */
  92. public function deactivate_cron() {
  93. self::deactivate_cron_static();
  94. }
  95. /**
  96. * Deactivates widget update cron task.
  97. */
  98. public static function deactivate_cron_static() {
  99. $next_scheduled_time = wp_next_scheduled( self::$cron_name );
  100. wp_unschedule_event( $next_scheduled_time, self::$cron_name );
  101. }
  102. /**
  103. * Checks if the update cron should be running and returns appropriate result.
  104. *
  105. * @return bool If the cron should be running or not.
  106. */
  107. public function should_cron_be_running() {
  108. /**
  109. * The cron doesn't need to run empty loops.
  110. */
  111. $widget_instances = $this->get_instances_sites();
  112. if ( empty( $widget_instances ) || ! is_array( $widget_instances ) ) {
  113. return false;
  114. }
  115. if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) {
  116. /**
  117. * If Jetpack is not active or in offline mode, we don't want to update widget data.
  118. */
  119. if ( ! Jetpack::is_connection_ready() && ! ( new Status() )->is_offline_mode() ) {
  120. return false;
  121. }
  122. /**
  123. * If Extra Sidebar Widgets module is not active, we don't need to update widget data.
  124. */
  125. if ( ! Jetpack::is_module_active( 'widgets' ) ) {
  126. return false;
  127. }
  128. }
  129. /**
  130. * If none of the above checks failed, then we definitely want to update widget data.
  131. */
  132. return true;
  133. }
  134. /**
  135. * Main cron code. Updates all instances of the widget.
  136. *
  137. * @return bool
  138. */
  139. public function cron_task() {
  140. /**
  141. * If the cron should not be running, disable it.
  142. */
  143. if ( false === $this->should_cron_be_running() ) {
  144. return true;
  145. }
  146. $instances_to_update = $this->get_instances_sites();
  147. /**
  148. * If no instances are found to be updated - stop.
  149. */
  150. if ( empty( $instances_to_update ) || ! is_array( $instances_to_update ) ) {
  151. return true;
  152. }
  153. foreach ( $instances_to_update as $site_url ) {
  154. $this->update_instance( $site_url );
  155. }
  156. return true;
  157. }
  158. /**
  159. * Get a list of unique sites from all instances of the widget.
  160. *
  161. * @return array|bool
  162. */
  163. public function get_instances_sites() {
  164. $widget_settings = $this->wp_get_option( 'widget_jetpack_display_posts_widget' );
  165. /**
  166. * If the widget still hasn't been added anywhere, the config will not be present.
  167. *
  168. * In such case we don't want to continue execution.
  169. */
  170. if ( false === $widget_settings || ! is_array( $widget_settings ) ) {
  171. return false;
  172. }
  173. $urls = array();
  174. foreach ( $widget_settings as $widget_instance_data ) {
  175. if ( isset( $widget_instance_data['url'] ) && ! empty( $widget_instance_data['url'] ) ) {
  176. $urls[] = $widget_instance_data['url'];
  177. }
  178. }
  179. /**
  180. * Make sure only unique URLs are returned.
  181. */
  182. $urls = array_unique( $urls );
  183. return $urls;
  184. }
  185. // MOCKABLES
  186. /**
  187. * This is just to make method mocks in the unit tests easier.
  188. *
  189. * @param string $param Option key to get
  190. *
  191. * @return mixed
  192. *
  193. * @codeCoverageIgnore
  194. */
  195. public function wp_get_option( $param ) {
  196. return get_option( $param );
  197. }
  198. /**
  199. * This is just to make method mocks in the unit tests easier.
  200. *
  201. * @param string $option_name Option name to be added
  202. * @param mixed $option_value Option value
  203. *
  204. * @return mixed
  205. *
  206. * @codeCoverageIgnore
  207. */
  208. public function wp_add_option( $option_name, $option_value ) {
  209. return add_option( $option_name, $option_value );
  210. }
  211. /**
  212. * This is just to make method mocks in the unit tests easier.
  213. *
  214. * @param string $option_name Option name to be updated
  215. * @param mixed $option_value Option value
  216. *
  217. * @return mixed
  218. *
  219. * @codeCoverageIgnore
  220. */
  221. public function wp_update_option( $option_name, $option_value ) {
  222. return update_option( $option_name, $option_value );
  223. }
  224. }