Completed
Push — add/e2e-mailchimp-block-test ( e217db...6066d0 )
by Yaroslav
98:30 queued 85:55
created

class.jetpack-display-posts-widget.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * Display a list of recent posts from a WordPress.com or Jetpack-enabled blog.
5
 */
6
7
class Jetpack_Display_Posts_Widget extends Jetpack_Display_Posts_Widget__Base {
8
	/**
9
	 * @var string Widget options key prefix.
10
	 */
11
	public $widget_options_key_prefix = 'display_posts_site_data_';
12
13
	/**
14
	 * @var string The name of the cron that will update widget data.
15
	 */
16
	public static $cron_name = 'jetpack_display_posts_widget_cron_update';
17
18
19
	// DATA STORE
20
21
	/**
22
	 * Gets blog data from the cache.
23
	 *
24
	 * @param string $site
25
	 *
26
	 * @return array|WP_Error
27
	 */
28
	public function get_blog_data( $site ) {
29
		// load from cache, if nothing return an error
30
		$site_hash = $this->get_site_hash( $site );
31
32
		$cached_data = $this->wp_get_option( $this->widget_options_key_prefix . $site_hash );
33
34
		/**
35
		 * If the cache is empty, return an empty_cache error.
36
		 */
37
		if ( false === $cached_data ) {
38
			return new WP_Error(
39
				'empty_cache',
0 ignored issues
show
The call to WP_Error::__construct() has too many arguments starting with 'empty_cache'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
40
				__( 'Information about this blog is currently being retrieved.', 'jetpack' )
41
			);
42
		}
43
44
		return $cached_data;
45
46
	}
47
48
	/**
49
	 * Update a widget instance.
50
	 *
51
	 * @param string $site The site to fetch the latest data for.
52
	 *
53
	 * @return array - the new data
54
	 */
55
	public function update_instance( $site ) {
56
57
		/**
58
		 * Fetch current information for a site.
59
		 */
60
		$site_hash = $this->get_site_hash( $site );
61
62
		$option_key = $this->widget_options_key_prefix . $site_hash;
63
64
		$instance_data = $this->wp_get_option( $option_key );
65
66
		/**
67
		 * Fetch blog data and save it in $instance_data.
68
		 */
69
		$new_data = $this->fetch_blog_data( $site, $instance_data );
70
71
		/**
72
		 * If the option doesn't exist yet - create a new option
73
		 */
74
		if ( false === $instance_data ) {
75
			$this->wp_add_option( $option_key, $new_data );
76
		}
77
		else {
78
			$this->wp_update_option( $option_key, $new_data );
79
		}
80
81
		return $new_data;
82
	}
83
84
85
	// WIDGET API
86
87
	public function update( $new_instance, $old_instance ) {
88
		$instance = parent::update( $new_instance, $old_instance );
89
90
		/**
91
		 * Forcefully activate the update cron when saving widget instance.
92
		 *
93
		 * So we can be sure that it will be running later.
94
		 */
95
		$this->activate_cron();
96
97
		return $instance;
98
	}
99
100
101
	// CRON
102
103
	/**
104
	 * Activates widget update cron task.
105
	 */
106
	public static function activate_cron() {
107
		if ( ! wp_next_scheduled( self::$cron_name ) ) {
108
			wp_schedule_event( time(), 'minutes_10', self::$cron_name );
109
		}
110
	}
111
112
	/**
113
	 * Deactivates widget update cron task.
114
	 *
115
	 * This is a wrapper over the static method as it provides some syntactic sugar.
116
	 */
117
	public function deactivate_cron() {
118
		self::deactivate_cron_static();
119
	}
120
121
	/**
122
	 * Deactivates widget update cron task.
123
	 */
124
	public static function deactivate_cron_static() {
125
		$next_scheduled_time = wp_next_scheduled( self::$cron_name );
126
		wp_unschedule_event( $next_scheduled_time, self::$cron_name );
127
	}
128
129
	/**
130
	 * Checks if the update cron should be running and returns appropriate result.
131
	 *
132
	 * @return bool If the cron should be running or not.
133
	 */
134
	public function should_cron_be_running() {
135
		/**
136
		 * The cron doesn't need to run empty loops.
137
		 */
138
		$widget_instances = $this->get_instances_sites();
139
140
		if ( empty( $widget_instances ) || ! is_array( $widget_instances ) ) {
141
			return false;
142
		}
143
144
		if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) {
145
			/**
146
			 * If Jetpack is not active or in development mode, we don't want to update widget data.
147
			 */
148
			if ( ! Jetpack::is_active() && ! Jetpack::is_development_mode() ) {
149
				return false;
150
			}
151
152
			/**
153
			 * If Extra Sidebar Widgets module is not active, we don't need to update widget data.
154
			 */
155
			if ( ! Jetpack::is_module_active( 'widgets' ) ) {
156
				return false;
157
			}
158
		}
159
160
		/**
161
		 * If none of the above checks failed, then we definitely want to update widget data.
162
		 */
163
		return true;
164
	}
165
166
	/**
167
	 * Main cron code. Updates all instances of the widget.
168
	 *
169
	 * @return bool
170
	 */
171
	public function cron_task() {
172
173
		/**
174
		 * If the cron should not be running, disable it.
175
		 */
176
		if ( false === $this->should_cron_be_running() ) {
177
			return true;
178
		}
179
180
		$instances_to_update = $this->get_instances_sites();
181
182
		/**
183
		 * If no instances are found to be updated - stop.
184
		 */
185
		if ( empty( $instances_to_update ) || ! is_array( $instances_to_update ) ) {
186
			return true;
187
		}
188
189
		foreach ( $instances_to_update as $site_url ) {
190
			$this->update_instance( $site_url );
191
		}
192
193
		return true;
194
	}
195
196
	/**
197
	 * Get a list of unique sites from all instances of the widget.
198
	 *
199
	 * @return array|bool
200
	 */
201
	public function get_instances_sites() {
202
203
		$widget_settings = $this->wp_get_option( 'widget_jetpack_display_posts_widget' );
204
205
		/**
206
		 * If the widget still hasn't been added anywhere, the config will not be present.
207
		 *
208
		 * In such case we don't want to continue execution.
209
		 */
210
		if ( false === $widget_settings || ! is_array( $widget_settings ) ) {
211
			return false;
212
		}
213
214
		$urls = array();
215
216
		foreach ( $widget_settings as $widget_instance_data ) {
217
			if ( isset( $widget_instance_data['url'] ) && ! empty( $widget_instance_data['url'] ) ) {
218
				$urls[] = $widget_instance_data['url'];
219
			}
220
		}
221
222
		/**
223
		 * Make sure only unique URLs are returned.
224
		 */
225
		$urls = array_unique( $urls );
226
227
		return $urls;
228
229
	}
230
231
232
	// MOCKABLES
233
234
	/**
235
	 * This is just to make method mocks in the unit tests easier.
236
	 *
237
	 * @param string $param Option key to get
238
	 *
239
	 * @return mixed
240
	 *
241
	 * @codeCoverageIgnore
242
	 */
243
	public function wp_get_option( $param ) {
244
		return get_option( $param );
245
	}
246
247
	/**
248
	 * This is just to make method mocks in the unit tests easier.
249
	 *
250
	 * @param string $option_name  Option name to be added
251
	 * @param mixed  $option_value Option value
252
	 *
253
	 * @return mixed
254
	 *
255
	 * @codeCoverageIgnore
256
	 */
257
	public function wp_add_option( $option_name, $option_value ) {
258
		return add_option( $option_name, $option_value );
259
	}
260
261
	/**
262
	 * This is just to make method mocks in the unit tests easier.
263
	 *
264
	 * @param string $option_name  Option name to be updated
265
	 * @param mixed  $option_value Option value
266
	 *
267
	 * @return mixed
268
	 *
269
	 * @codeCoverageIgnore
270
	 */
271
	public function wp_update_option( $option_name, $option_value ) {
272
		return update_option( $option_name, $option_value );
273
	}
274
}
275