PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 15.9-a.7
Jetpack – WP Security, Backup, Speed, & Growth v15.9-a.7
15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / class.jetpack-autoupdate.php
jetpack Last commit date
3rd-party 1 week ago _inc 2 days ago css 2 weeks ago extensions 2 days ago images 1 month ago jetpack_vendor 2 days ago json-endpoints 1 week ago modules 2 days ago sal 1 week ago src 2 days ago vendor 2 days ago views 1 month ago CHANGELOG.md 2 days ago LICENSE.txt 5 months ago SECURITY.md 2 days ago class-jetpack-connection-status.php 2 years ago class-jetpack-gallery-settings.php 6 months ago class-jetpack-newsletter-dashboard-widget.php 6 months ago class-jetpack-pre-connection-jitms.php 2 years ago class-jetpack-stats-dashboard-widget.php 3 months ago class-jetpack-xmlrpc-methods.php 1 week ago class.frame-nonce-preview.php 6 months ago class.jetpack-admin.php 2 days ago class.jetpack-autoupdate.php 6 months ago class.jetpack-cli.php 2 days ago class.jetpack-client-server.php 2 years ago class.jetpack-gutenberg.php 1 week ago class.jetpack-heartbeat.php 3 months ago class.jetpack-modules-list-table.php 6 months ago class.jetpack-network-sites-list-table.php 6 months ago class.jetpack-network.php 1 month ago class.jetpack-plan.php 2 years ago class.jetpack-post-images.php 2 months ago class.jetpack-twitter-cards.php 3 months ago class.jetpack-user-agent.php 2 years ago class.jetpack.php 2 days ago class.json-api-endpoints.php 1 week ago class.json-api.php 2 weeks ago class.photon.php 3 years ago composer.json 2 days ago enhanced-open-graph.php 1 week ago functions.compat.php 3 months ago functions.cookies.php 2 years ago functions.global.php 2 days ago functions.is-mobile.php 2 years ago functions.opengraph.php 2 months ago functions.photon.php 2 years ago jetpack.php 2 days ago json-api-config.php 3 years ago json-endpoints.php 2 years ago load-jetpack.php 1 week ago locales.php 6 months ago readme.txt 2 days ago unauth-file-upload.php 6 months ago uninstall.php 6 months ago wpml-config.xml 3 years ago
class.jetpack-autoupdate.php
380 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Handles items that have been selected for automatic updates.
4 * Hooks into WP_Automatic_Updater
5 *
6 * @package automattic/jetpack
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit( 0 );
11 }
12
13 /**
14 * Handles items that have been selected for automatic updates.
15 * Hooks into WP_Automatic_Updater
16 */
17 class Jetpack_Autoupdate {
18
19 /**
20 * Results.
21 *
22 * @var array
23 */
24 private $results = array();
25
26 /**
27 * Expected updates.
28 *
29 * @var array
30 */
31 private $expected = array();
32
33 /**
34 * Successful updates.
35 *
36 * @var array
37 */
38 private $success = array(
39 'plugin' => array(),
40 'theme' => array(),
41 );
42
43 /**
44 * Failed updates.
45 *
46 * @var array
47 */
48 private $failed = array(
49 'plugin' => array(),
50 'theme' => array(),
51 );
52
53 /**
54 * Static instance.
55 *
56 * @var self
57 */
58 private static $instance = null;
59
60 /**
61 * Initialize and fetch the static instance.
62 *
63 * @return self
64 */
65 public static function init() {
66 if ( self::$instance === null ) {
67 self::$instance = new Jetpack_Autoupdate();
68 }
69
70 return self::$instance;
71 }
72
73 /** Constructor. */
74 private function __construct() {
75 if (
76 /** This filter is documented in class.jetpack-json-api-endpoint.php */
77 apply_filters( 'jetpack_json_manage_api_enabled', true )
78 ) {
79 add_filter( 'auto_update_theme', array( $this, 'autoupdate_theme' ), 10, 2 );
80 add_filter( 'auto_update_core', array( $this, 'autoupdate_core' ), 10, 2 );
81 add_filter( 'auto_update_translation', array( $this, 'autoupdate_translation' ), 10, 2 );
82 add_action( 'automatic_updates_complete', array( $this, 'automatic_updates_complete' ), 999, 1 );
83 }
84 }
85
86 /**
87 * Filter function for `auto_update_translation`.
88 *
89 * @param bool|null $update Whether to update.
90 * @param object $item The update offer.
91 * @return bool|null Whether to update.
92 */
93 public function autoupdate_translation( $update, $item ) {
94 // Autoupdate all translations.
95 if ( Jetpack_Options::get_option( 'autoupdate_translations', false ) ) {
96 return true;
97 }
98
99 if ( ! isset( $item->slug ) || ! isset( $item->type ) ) {
100 return $update;
101 }
102
103 // Themes.
104 $autoupdate_themes_translations = Jetpack_Options::get_option( 'autoupdate_themes_translations', array() );
105 $autoupdate_theme_list = Jetpack_Options::get_option( 'autoupdate_themes', array() );
106
107 if ( ( in_array( $item->slug, $autoupdate_themes_translations, true ) || in_array( $item->slug, $autoupdate_theme_list, true ) )
108 && 'theme' === $item->type
109 ) {
110 $this->expect( $item->type . ':' . $item->slug, 'translation' );
111
112 return true;
113 }
114
115 // Plugins.
116 $autoupdate_plugin_translations = Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() );
117 $autoupdate_plugin_list = (array) get_site_option( 'auto_update_plugins', array() );
118 $plugin_files = array_unique( array_merge( $autoupdate_plugin_list, $autoupdate_plugin_translations ) );
119 $plugin_slugs = array_map( array( __CLASS__, 'get_plugin_slug' ), $plugin_files );
120
121 if ( in_array( $item->slug, $plugin_slugs, true )
122 && 'plugin' === $item->type
123 ) {
124 $this->expect( $item->type . ':' . $item->slug, 'translation' );
125 return true;
126 }
127
128 return $update;
129 }
130
131 /**
132 * Filter function for `auto_update_theme`.
133 *
134 * @param bool|null $update Whether to update.
135 * @param object $item The update offer.
136 * @return bool|null Whether to update.
137 */
138 public function autoupdate_theme( $update, $item ) {
139 if ( ! isset( $item->theme ) ) {
140 return $update;
141 }
142 $autoupdate_theme_list = Jetpack_Options::get_option( 'autoupdate_themes', array() );
143 if ( in_array( $item->theme, $autoupdate_theme_list, true ) ) {
144 $this->expect( $item->theme, 'theme' );
145 return true;
146 }
147
148 return $update;
149 }
150
151 /**
152 * Filter function for `auto_update_core`.
153 *
154 * @param bool|null $update Whether to update.
155 * @return bool|null Whether to update.
156 */
157 public function autoupdate_core( $update ) {
158 $autoupdate_core = Jetpack_Options::get_option( 'autoupdate_core', false );
159 if ( $autoupdate_core ) {
160 return $autoupdate_core;
161 }
162
163 return $update;
164 }
165
166 /**
167 * Stores the an item identifier to the expected array.
168 *
169 * @param string $item Example: 'jetpack/jetpack.php' for type 'plugin' or 'twentyfifteen' for type 'theme'.
170 * @param string $type 'plugin' or 'theme'.
171 */
172 private function expect( $item, $type ) {
173 if ( ! isset( $this->expected[ $type ] ) ) {
174 $this->expected[ $type ] = array();
175 }
176 $this->expected[ $type ][] = $item;
177 }
178
179 /**
180 * On completion of an automatic update, let's store the results.
181 *
182 * @param mixed $results - Sent by WP_Automatic_Updater after it completes an autoupdate action. Results may be empty.
183 */
184 public function automatic_updates_complete( $results ) {
185 if ( empty( $this->expected ) ) {
186 return;
187 }
188 $this->results = empty( $results ) ? self::get_possible_failures() : $results;
189
190 add_action( 'shutdown', array( $this, 'bump_stats' ) );
191
192 Jetpack::init();
193
194 $items_to_log = array( 'plugin', 'theme', 'translation' );
195 foreach ( $items_to_log as $items ) {
196 $this->log_items( $items );
197 }
198
199 Jetpack::log( 'autoupdates', $this->get_log() );
200 }
201
202 /**
203 * Get log data.
204 *
205 * @return array Data.
206 */
207 public function get_log() {
208 return array(
209 'results' => $this->results,
210 'failed' => $this->failed,
211 'success' => $this->success,
212 );
213 }
214
215 /**
216 * Iterates through expected items ( plugins or themes ) and compares them to actual results.
217 *
218 * @param string $items 'plugin' or 'theme'.
219 */
220 private function log_items( $items ) {
221 if ( ! isset( $this->expected[ $items ] ) ) {
222 return;
223 }
224
225 $item_results = $this->get_successful_updates( $items );
226
227 if ( is_array( $this->expected[ $items ] ) ) {
228 foreach ( $this->expected[ $items ] as $item ) {
229 if ( in_array( $item, $item_results, true ) ) {
230 $this->success[ $items ][] = $item;
231 } else {
232 $this->failed[ $items ][] = $item;
233 }
234 }
235 }
236 }
237
238 /**
239 * Bump stats.
240 */
241 public function bump_stats() {
242 $instance = Jetpack::init();
243 $log = array();
244 // Bump numbers.
245
246 if ( ! empty( $this->success['theme'] ) ) {
247 $instance->stat( 'autoupdates/theme-success', is_countable( $this->success['theme'] ) ? count( $this->success['theme'] ) : 0 );
248 $log['themes_success'] = $this->success['theme'];
249 }
250
251 if ( ! empty( $this->failed['theme'] ) ) {
252 $instance->stat( 'autoupdates/theme-fail', is_countable( $this->failed['theme'] ) ? count( $this->failed['theme'] ) : 0 );
253 $log['themes_failed'] = $this->failed['theme'];
254 }
255
256 $instance->do_stats( 'server_side' );
257
258 // Send a more detailed log to logstash.
259 if ( ! empty( $log ) ) {
260 $xml = new Jetpack_IXR_Client(
261 array(
262 'user_id' => get_current_user_id(),
263 )
264 );
265 $log['blog_id'] = Jetpack_Options::get_option( 'id' );
266 $xml->query( 'jetpack.debug_autoupdate', $log );
267 }
268 }
269
270 /**
271 * Parses the autoupdate results generated by WP_Automatic_Updater and returns a simple array of successful items.
272 *
273 * @param string $type 'plugin' or 'theme'.
274 * @return array
275 */
276 private function get_successful_updates( $type ) {
277 $successful_updates = array();
278
279 if ( ! isset( $this->results[ $type ] ) ) {
280 return $successful_updates;
281 }
282
283 foreach ( $this->results[ $type ] as $result ) {
284 if ( $result->result ) {
285 switch ( $type ) {
286 case 'theme':
287 $successful_updates[] = $result->item->theme;
288 break;
289 case 'translation':
290 $successful_updates[] = $result->item->type . ':' . $result->item->slug;
291 break;
292 }
293 }
294 }
295
296 return $successful_updates;
297 }
298
299 /**
300 * Get possible failure codes.
301 *
302 * @return string[] Failure codes.
303 */
304 public static function get_possible_failures() {
305 $result = array();
306 // Lets check some reasons why it might not be working as expected.
307 include_once ABSPATH . '/wp-admin/includes/admin.php';
308 include_once ABSPATH . '/wp-admin/includes/class-wp-upgrader.php';
309 $upgrader = new WP_Automatic_Updater();
310
311 if ( $upgrader->is_disabled() ) {
312 $result[] = 'autoupdates-disabled';
313 }
314 if ( ! is_main_site() ) {
315 $result[] = 'is-not-main-site';
316 }
317 if ( ! is_main_network() ) {
318 $result[] = 'is-not-main-network';
319 }
320 if ( $upgrader->is_vcs_checkout( ABSPATH ) ) {
321 $result[] = 'site-on-vcs';
322 }
323 if ( $upgrader->is_vcs_checkout( WP_PLUGIN_DIR ) ) {
324 $result[] = 'plugin-directory-on-vcs';
325 }
326 if ( $upgrader->is_vcs_checkout( WP_CONTENT_DIR ) ) {
327 $result[] = 'content-directory-on-vcs';
328 }
329 $lock = get_option( 'auto_updater.lock' );
330 if ( $lock > ( time() - HOUR_IN_SECONDS ) ) {
331 $result[] = 'lock-is-set';
332 }
333 $skin = new Automatic_Upgrader_Skin();
334 include_once ABSPATH . 'wp-admin/includes/file.php';
335 include_once ABSPATH . 'wp-admin/includes/template.php';
336 if ( ! $skin->request_filesystem_credentials( false, ABSPATH, false ) ) {
337 $result[] = 'no-system-write-access';
338 }
339 if ( ! $skin->request_filesystem_credentials( false, WP_PLUGIN_DIR, false ) ) {
340 $result[] = 'no-plugin-directory-write-access';
341 }
342 if ( ! $skin->request_filesystem_credentials( false, WP_CONTENT_DIR, false ) ) {
343 $result[] = 'no-wp-content-directory-write-access';
344 }
345
346 return $result;
347 }
348
349 /**
350 * Get the plugin slug.
351 *
352 * @param string $plugin_file Plugin file.
353 * @return string Slug.
354 */
355 public static function get_plugin_slug( $plugin_file ) {
356 $update_plugins = get_site_transient( 'update_plugins' );
357 if ( isset( $update_plugins->no_update ) ) {
358 if ( isset( $update_plugins->no_update[ $plugin_file ]->slug ) ) {
359 $slug = $update_plugins->no_update[ $plugin_file ]->slug;
360 }
361 }
362 if ( empty( $slug ) && isset( $update_plugins->response ) ) {
363 if ( isset( $update_plugins->response[ $plugin_file ]->slug ) ) {
364 $slug = $update_plugins->response[ $plugin_file ]->slug;
365 }
366 }
367
368 // Try to infer from the plugin file if not cached.
369 if ( empty( $slug ) ) {
370 $slug = dirname( $plugin_file );
371 if ( '.' === $slug ) {
372 $slug = preg_replace( '/(.+)\.php$/', '$1', $plugin_file );
373 }
374 }
375 return $slug;
376 }
377 }
378
379 Jetpack_Autoupdate::init();
380