PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.0.1
Jetpack – WP Security, Backup, Speed, & Growth v16.0.1
16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 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 / json-endpoints / jetpack / class.jetpack-json-api-plugins-modify-endpoint.php
jetpack / json-endpoints / jetpack Last commit date
class-jetpack-json-api-attachment-ownership-trait.php 2 months ago class-jetpack-json-api-delete-backup-helper-script-endpoint.php 7 months ago class-jetpack-json-api-install-backup-helper-script-endpoint.php 7 months ago class-jetpack-json-api-modules-list-v1-2-endpoint.php 7 months ago class.jetpack-json-api-check-capabilities-endpoint.php 7 months ago class.jetpack-json-api-core-endpoint.php 7 months ago class.jetpack-json-api-core-modify-endpoint.php 1 month ago class.jetpack-json-api-cron-endpoint.php 7 months ago class.jetpack-json-api-endpoint.php 1 month ago class.jetpack-json-api-get-comment-backup-endpoint.php 7 months ago class.jetpack-json-api-get-database-object-backup-endpoint.php 7 months ago class.jetpack-json-api-get-option-backup-endpoint.php 7 months ago class.jetpack-json-api-get-post-backup-endpoint.php 7 months ago class.jetpack-json-api-get-term-backup-endpoint.php 7 months ago class.jetpack-json-api-get-user-backup-endpoint.php 7 months ago class.jetpack-json-api-jps-woocommerce-connect-endpoint.php 7 months ago class.jetpack-json-api-log-endpoint.php 7 months ago class.jetpack-json-api-maybe-auto-update-endpoint.php 7 months ago class.jetpack-json-api-modules-endpoint.php 7 months ago class.jetpack-json-api-modules-get-endpoint.php 7 months ago class.jetpack-json-api-modules-list-endpoint.php 7 months ago class.jetpack-json-api-modules-modify-endpoint.php 7 months ago class.jetpack-json-api-plugins-delete-endpoint.php 7 months ago class.jetpack-json-api-plugins-endpoint.php 1 month ago class.jetpack-json-api-plugins-get-endpoint.php 7 months ago class.jetpack-json-api-plugins-install-endpoint.php 7 months ago class.jetpack-json-api-plugins-list-endpoint.php 3 weeks ago class.jetpack-json-api-plugins-modify-endpoint.php 7 months ago class.jetpack-json-api-plugins-modify-v1-2-endpoint.php 7 months ago class.jetpack-json-api-plugins-new-endpoint.php 7 months ago class.jetpack-json-api-plugins-replace-endpoint.php 2 months ago class.jetpack-json-api-sync-endpoint.php 1 month ago class.jetpack-json-api-themes-active-endpoint.php 7 months ago class.jetpack-json-api-themes-delete-endpoint.php 7 months ago class.jetpack-json-api-themes-endpoint.php 1 month ago class.jetpack-json-api-themes-get-endpoint.php 7 months ago class.jetpack-json-api-themes-install-endpoint.php 7 months ago class.jetpack-json-api-themes-list-endpoint.php 7 months ago class.jetpack-json-api-themes-modify-endpoint.php 7 months ago class.jetpack-json-api-themes-new-endpoint.php 7 months ago class.jetpack-json-api-themes-replace-endpoint.php 2 months ago class.jetpack-json-api-translations-endpoint.php 7 months ago class.jetpack-json-api-translations-modify-endpoint.php 7 months ago class.jetpack-json-api-updates-status-endpoint.php 1 month ago class.jetpack-json-api-user-connect-endpoint.php 7 months ago class.jetpack-json-api-user-create-endpoint.php 1 month ago class.wpcom-json-api-get-option-endpoint.php 1 month ago class.wpcom-json-api-update-option-endpoint.php 7 months ago json-api-jetpack-endpoints.php 2 months ago
class.jetpack-json-api-plugins-modify-endpoint.php
566 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3 use Automattic\Jetpack\Constants;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit( 0 );
7 }
8
9 new Jetpack_JSON_API_Plugins_Modify_Endpoint(
10 array(
11 'description' => 'Activate/Deactivate a Plugin on your Jetpack Site, or set automatic updates',
12 'min_version' => '1',
13 'max_version' => '1.1',
14 'method' => 'POST',
15 'path' => '/sites/%s/plugins/%s',
16 'stat' => 'plugins:1:modify',
17 'path_labels' => array(
18 '$site' => '(int|string) The site ID, The site domain',
19 '$plugin' => '(string) The plugin ID',
20 ),
21 'allow_jetpack_site_auth' => true,
22 'request_format' => array(
23 'action' => '(string) Possible values are \'update\'',
24 'autoupdate' => '(bool) Whether or not to automatically update the plugin',
25 'active' => '(bool) Activate or deactivate the plugin',
26 'network_wide' => '(bool) Do action network wide (default value: false)',
27 'scheduled_update' => '(bool) If the update is happening as a result of a scheduled update event',
28 ),
29 'query_parameters' => array(
30 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event',
31 ),
32 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format,
33 'example_request_data' => array(
34 'headers' => array(
35 'authorization' => 'Bearer YOUR_API_TOKEN',
36 ),
37 'body' => array(
38 'action' => 'update',
39 ),
40 ),
41 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello',
42 )
43 );
44
45 new Jetpack_JSON_API_Plugins_Modify_Endpoint(
46 array(
47 'description' => 'Activate/Deactivate a list of plugins on your Jetpack Site, or set automatic updates',
48 'min_version' => '1',
49 'max_version' => '1.1',
50 'method' => 'POST',
51 'path' => '/sites/%s/plugins',
52 'stat' => 'plugins:modify',
53 'path_labels' => array(
54 '$site' => '(int|string) The site ID, The site domain',
55 ),
56 'request_format' => array(
57 'action' => '(string) Possible values are \'update\'',
58 'autoupdate' => '(bool) Whether or not to automatically update the plugin',
59 'active' => '(bool) Activate or deactivate the plugin',
60 'network_wide' => '(bool) Do action network wide (default value: false)',
61 'plugins' => '(array) A list of plugin ids to modify',
62 ),
63 'allow_jetpack_site_auth' => true,
64 'query_parameters' => array(
65 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event',
66 ),
67 'response_format' => array(
68 'plugins' => '(array:plugin) An array of plugin objects.',
69 'updated' => '(array) A list of plugin ids that were updated. Only present if action is update.',
70 'not_updated' => '(array) A list of plugin ids that were not updated. Only present if action is update.',
71 'log' => '(array) Update log. Only present if action is update.',
72 ),
73 'example_request_data' => array(
74 'headers' => array(
75 'authorization' => 'Bearer YOUR_API_TOKEN',
76 ),
77 'body' => array(
78 'active' => true,
79 'plugins' => array(
80 'jetpack/jetpack',
81 'akismet/akismet',
82 ),
83 ),
84 ),
85 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins',
86 )
87 );
88
89 new Jetpack_JSON_API_Plugins_Modify_Endpoint(
90 array(
91 'description' => 'Update a Plugin on your Jetpack Site',
92 'min_version' => '1',
93 'max_version' => '1.1',
94 'method' => 'POST',
95 'path' => '/sites/%s/plugins/%s/update/',
96 'stat' => 'plugins:1:update',
97 'path_labels' => array(
98 '$site' => '(int|string) The site ID, The site domain',
99 '$plugin' => '(string) The plugin ID',
100 ),
101 'allow_jetpack_site_auth' => true,
102 'query_parameters' => array(
103 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event',
104 ),
105 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format,
106 'example_request_data' => array(
107 'headers' => array(
108 'authorization' => 'Bearer YOUR_API_TOKEN',
109 ),
110 ),
111 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello/update',
112 )
113 );
114
115 /**
116 * Plugins modify endpoint class.
117 *
118 * POST /sites/%s/plugins/%s
119 * POST /sites/%s/plugins
120 *
121 * @phan-constructor-used-for-side-effects
122 */
123 class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_Endpoint {
124
125 /**
126 * The slug.
127 *
128 * @var string
129 */
130 protected $slug = null;
131
132 /**
133 * Needed capabilities.
134 *
135 * @var string
136 */
137 protected $needed_capabilities = 'activate_plugins';
138
139 /**
140 * Action.
141 *
142 * @var string
143 */
144 protected $action = 'default_action';
145
146 /**
147 * Expected actions.
148 *
149 * @var array
150 */
151 protected $expected_actions = array( 'update', 'install', 'delete', 'update_translations' );
152
153 /**
154 * Callback.
155 *
156 * @param string $path - the path.
157 * @param int $blog_id - the blog ID.
158 * @param object $object - the object.
159 *
160 * @return bool|WP_Error
161 */
162 public function callback( $path = '', $blog_id = 0, $object = null ) {
163
164 Jetpack_JSON_API_Endpoint::validate_input( $object );
165 switch ( $this->action ) {
166 case 'delete':
167 $this->needed_capabilities = 'delete_plugins';
168 break;
169 case 'update_translations':
170 case 'update':
171 $this->needed_capabilities = 'update_plugins';
172 break;
173 case 'install':
174 $this->needed_capabilities = 'install_plugins';
175 break;
176 }
177
178 $args = $this->input();
179
180 if ( is_array( $args ) && ( isset( $args['autoupdate'] ) || isset( $args['autoupdate_translations'] ) ) ) {
181 $this->needed_capabilities = 'update_plugins';
182 }
183
184 return parent::callback( $path, $blog_id, $object );
185 }
186
187 /**
188 * The default action.
189 *
190 * @return bool|WP_Error
191 */
192 public function default_action() {
193 $args = $this->input();
194
195 if ( isset( $args['autoupdate'] ) && is_bool( $args['autoupdate'] ) ) {
196 if ( $args['autoupdate'] ) {
197 $this->autoupdate_on();
198 } else {
199 $this->autoupdate_off();
200 }
201 }
202
203 if ( isset( $args['active'] ) && is_bool( $args['active'] ) ) {
204 if ( $args['active'] ) {
205 // We don't have to check for activate_plugins permissions since we assume that the user has those
206 // Since we set them via $needed_capabilities.
207 return $this->activate();
208 } elseif ( $this->current_user_can( 'deactivate_plugins' ) ) {
209 return $this->deactivate();
210 } else {
211 return new WP_Error( 'unauthorized_error', __( 'Plugin deactivation is not allowed', 'jetpack' ), '403' );
212 }
213 }
214
215 if ( isset( $args['autoupdate_translations'] ) && is_bool( $args['autoupdate_translations'] ) ) {
216 if ( $args['autoupdate_translations'] ) {
217 $this->autoupdate_translations_on();
218 } else {
219 $this->autoupdate_translations_off();
220 }
221 }
222
223 return true;
224 }
225
226 /**
227 * Turn on autoupdate.
228 */
229 protected function autoupdate_on() {
230 $autoupdate_plugins = (array) get_site_option( 'auto_update_plugins', array() );
231 $autoupdate_plugins = array_unique( array_merge( $autoupdate_plugins, $this->plugins ) );
232 update_site_option( 'auto_update_plugins', $autoupdate_plugins );
233 }
234
235 /**
236 * Turn off autoupdate.
237 */
238 protected function autoupdate_off() {
239 $autoupdate_plugins = (array) get_site_option( 'auto_update_plugins', array() );
240 $autoupdate_plugins = array_diff( $autoupdate_plugins, $this->plugins );
241 update_site_option( 'auto_update_plugins', $autoupdate_plugins );
242 }
243
244 /**
245 * Turn autoupdate translations on.
246 */
247 protected function autoupdate_translations_on() {
248 $autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() );
249 $autoupdate_plugins = array_unique( array_merge( $autoupdate_plugins, $this->plugins ) );
250 Jetpack_Options::update_option( 'autoupdate_plugins_translations', $autoupdate_plugins );
251 }
252
253 /**
254 * Turn autoupdate translations off.
255 */
256 protected function autoupdate_translations_off() {
257 $autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() );
258 $autoupdate_plugins = array_diff( $autoupdate_plugins, $this->plugins );
259 Jetpack_Options::update_option( 'autoupdate_plugins_translations', $autoupdate_plugins );
260 }
261
262 /**
263 * Activate the plugin.
264 *
265 * @return null|WP_Error null if the activation was successful.
266 */
267 protected function activate() {
268 $permission_error = false;
269 foreach ( $this->plugins as $plugin ) {
270
271 if ( ! $this->current_user_can( 'activate_plugin', $plugin ) ) {
272 $this->log[ $plugin ]['error'] = __( 'Sorry, you are not allowed to activate this plugin.', 'jetpack' );
273 $has_errors = true;
274 $permission_error = true;
275 continue;
276 }
277
278 if ( ( ! $this->network_wide && Jetpack::is_plugin_active( $plugin ) ) || is_plugin_active_for_network( $plugin ) ) {
279 $this->log[ $plugin ]['error'] = __( 'The Plugin is already active.', 'jetpack' );
280 $has_errors = true;
281 continue;
282 }
283
284 if ( ! $this->network_wide && is_network_only_plugin( $plugin ) && is_multisite() ) {
285 $this->log[ $plugin ]['error'] = __( 'Plugin can only be Network Activated', 'jetpack' );
286 $has_errors = true;
287 continue;
288 }
289
290 $result = activate_plugin( $plugin, '', $this->network_wide );
291
292 if ( is_wp_error( $result ) ) {
293 $this->log[ $plugin ]['error'] = $result->get_error_messages();
294 $has_errors = true;
295 continue;
296 }
297
298 $success = Jetpack::is_plugin_active( $plugin );
299 if ( $success && $this->network_wide ) {
300 $success &= is_plugin_active_for_network( $plugin );
301 }
302
303 if ( ! $success ) {
304 $this->log[ $plugin ]['error'] = $result->get_error_messages;
305 $has_errors = true;
306 continue;
307 }
308 $this->log[ $plugin ][] = __( 'Plugin activated.', 'jetpack' );
309 }
310
311 if ( ! $this->bulk && isset( $has_errors ) ) {
312 $plugin = $this->plugins[0];
313 if ( $permission_error ) {
314 return new WP_Error( 'unauthorized_error', $this->log[ $plugin ]['error'], 403 );
315 }
316
317 return new WP_Error( 'activation_error', $this->log[ $plugin ]['error'] );
318 }
319 }
320
321 /**
322 * Check if the current user has capabilities.
323 *
324 * @param string $capability - the capability we're checking.
325 * @param string $plugin - the plugin we're checking.
326 *
327 * @return bool
328 */
329 protected function current_user_can( $capability, $plugin = null ) {
330 // If this endpoint accepts site based authentication and a blog token is used, skip capabilities check.
331 if ( $this->accepts_site_based_authentication() ) {
332 return true;
333 }
334 if ( $plugin ) {
335 return current_user_can( $capability, $plugin );
336 }
337
338 return current_user_can( $capability );
339 }
340
341 /**
342 * Deactivate the plugin.
343 *
344 * @return null|WP_Error null if the deactivation was successful
345 */
346 protected function deactivate() {
347 $permission_error = false;
348 foreach ( $this->plugins as $plugin ) {
349 if ( ! $this->current_user_can( 'deactivate_plugin', $plugin ) ) {
350 $error = __( 'Sorry, you are not allowed to deactivate this plugin.', 'jetpack' );
351 $this->log[ $plugin ]['error'] = $error;
352 $permission_error = true;
353 continue;
354 }
355
356 if ( ! Jetpack::is_plugin_active( $plugin ) ) {
357 $error = __( 'The Plugin is already deactivated.', 'jetpack' );
358 $this->log[ $plugin ]['error'] = $error;
359 continue;
360 }
361
362 deactivate_plugins( $plugin, false, $this->network_wide );
363
364 $success = ! Jetpack::is_plugin_active( $plugin );
365 if ( $success && $this->network_wide ) {
366 $success &= ! is_plugin_active_for_network( $plugin );
367 }
368
369 if ( ! $success ) {
370 $error = __( 'There was an error deactivating your plugin', 'jetpack' );
371 $this->log[ $plugin ]['error'] = $error;
372 continue;
373 }
374 $this->log[ $plugin ][] = __( 'Plugin deactivated.', 'jetpack' );
375 }
376 if ( ! $this->bulk && isset( $error ) ) {
377 if ( $permission_error ) {
378 return new WP_Error( 'unauthorized_error', $error, 403 );
379 }
380
381 return new WP_Error( 'deactivation_error', $error );
382 }
383 }
384
385 /**
386 * Update the plugin.
387 *
388 * @return bool|WP_Error
389 */
390 protected function update() {
391 $query_args = $this->query_args();
392
393 $is_automatic_update = false;
394 if ( isset( $query_args['autoupdate'] ) && $query_args['autoupdate'] || $this->scheduled_update ) {
395 $is_automatic_update = true;
396 }
397
398 if ( $this->scheduled_update ) {
399 Constants::set_constant( 'SCHEDULED_AUTOUPDATE', true );
400 }
401 wp_clean_plugins_cache( false );
402 ob_start();
403 wp_update_plugins(); // Check for Plugin updates
404 ob_end_clean();
405
406 $update_plugins = get_site_transient( 'update_plugins' );
407
408 if ( isset( $update_plugins->response ) ) {
409 $plugin_updates_needed = array_keys( $update_plugins->response );
410 } else {
411 $plugin_updates_needed = array();
412 }
413
414 $update_attempted = false;
415
416 include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
417
418 // unhook this functions that output things before we send our response header.
419 remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
420 remove_action( 'upgrader_process_complete', 'wp_version_check' );
421 remove_action( 'upgrader_process_complete', 'wp_update_themes' );
422
423 // Set the lock timeout to 15 minutes if it's scheduled update, otherwise default to one hour.
424 $lock_release_timeout = $this->scheduled_update ? 15 * MINUTE_IN_SECONDS : null;
425
426 // Early return if unable to obtain auto_updater lock.
427 // @see https://github.com/WordPress/wordpress-develop/blob/66469efa99e7978c8824e287834135aa9842e84f/src/wp-admin/includes/class-wp-automatic-updater.php#L453.
428 if ( $is_automatic_update && ! WP_Upgrader::create_lock( 'auto_updater', $lock_release_timeout ) ) {
429 return new WP_Error( 'update_fail', __( 'Updates are already in progress.', 'jetpack' ), 400 );
430 }
431
432 $result = false;
433
434 foreach ( $this->plugins as $plugin ) {
435
436 if ( ! in_array( $plugin, $plugin_updates_needed, true ) ) {
437 $this->log[ $plugin ][] = __( 'No update needed', 'jetpack' );
438 continue;
439 }
440
441 // Rely on WP_Automatic_Updater class to check if a plugin item should be updated if it is a Jetpack autoupdate request.
442 if ( $is_automatic_update && ! ( new WP_Automatic_Updater() )->should_update( 'plugin', $update_plugins->response[ $plugin ], WP_PLUGIN_DIR ) ) {
443 continue;
444 }
445
446 // Establish per plugin lock.
447 $plugin_slug = Jetpack_Autoupdate::get_plugin_slug( $plugin );
448 if ( ! WP_Upgrader::create_lock( 'jetpack_' . $plugin_slug, $lock_release_timeout ) ) {
449 continue;
450 }
451
452 /**
453 * Pre-upgrade action
454 *
455 * @since 3.9.3
456 *
457 * @param array $plugin Plugin data
458 * @param array $plugin Array of plugin objects
459 * @param bool $updated_attempted false for the first update, true subsequently
460 */
461 do_action( 'jetpack_pre_plugin_upgrade', $plugin, $this->plugins, $update_attempted );
462
463 $update_attempted = true;
464
465 // Object created inside the for loop to clean the messages for each plugin
466 $skin = new WP_Ajax_Upgrader_Skin();
467 // The Automatic_Upgrader_Skin skin shouldn't output anything.
468 $upgrader = new Plugin_Upgrader( $skin );
469 $upgrader->init();
470 // This avoids the plugin to be deactivated.
471 // Using bulk upgrade puts the site into maintenance mode during the upgrades
472 $result = $upgrader->bulk_upgrade( array( $plugin ) );
473 $errors = $skin->get_errors();
474 $this->log[ $plugin ] = $skin->get_upgrade_messages();
475
476 // release individual plugin lock.
477 WP_Upgrader::release_lock( 'jetpack_' . $plugin_slug );
478
479 if ( is_wp_error( $errors ) && $errors->get_error_code() ) {
480 return $errors;
481 }
482 }
483
484 // release auto_udpate lock.
485 if ( $is_automatic_update ) {
486 WP_Upgrader::release_lock( 'auto_updater' );
487 }
488
489 if ( ! $this->bulk && ! $result && $update_attempted ) {
490 return new WP_Error( 'update_fail', __( 'There was an error updating your plugin', 'jetpack' ), 400 );
491 }
492
493 return $this->default_action();
494 }
495
496 /**
497 * Update translations.
498 *
499 * @return bool|WP_Error
500 */
501 public function update_translations() {
502 include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
503
504 // Clear the cache.
505 wp_clean_plugins_cache( false );
506 ob_start();
507 wp_update_plugins(); // Check for Plugin updates
508 ob_end_clean();
509
510 $available_updates = get_site_transient( 'update_plugins' );
511 if ( ! isset( $available_updates->translations ) || empty( $available_updates->translations ) ) {
512 return new WP_Error( 'nothing_to_translate' );
513 }
514
515 $update_attempted = false;
516 $result = false;
517 foreach ( $this->plugins as $plugin ) {
518 $this->slug = Jetpack_Autoupdate::get_plugin_slug( $plugin );
519 $translation = array_filter( $available_updates->translations, array( $this, 'get_translation' ) );
520
521 if ( empty( $translation ) ) {
522 $this->log[ $plugin ][] = __( 'No update needed', 'jetpack' );
523 continue;
524 }
525
526 /**
527 * Pre-upgrade action
528 *
529 * @since 4.4.0
530 *
531 * @param array $plugin Plugin data
532 * @param array $plugin Array of plugin objects
533 * @param bool $update_attempted false for the first update, true subsequently
534 */
535 do_action( 'jetpack_pre_plugin_upgrade_translations', $plugin, $this->plugins, $update_attempted );
536
537 $update_attempted = true;
538
539 $skin = new Automatic_Upgrader_Skin();
540 $upgrader = new Language_Pack_Upgrader( $skin );
541 $upgrader->init();
542
543 $result = $upgrader->upgrade( (object) $translation[0] );
544
545 $this->log[ $plugin ] = $upgrader->skin->get_upgrade_messages();
546 }
547
548 if ( ! $this->bulk && ! $result ) {
549 return new WP_Error( 'update_fail', __( 'There was an error updating your plugin', 'jetpack' ), 400 );
550 }
551
552 return true;
553 }
554
555 /**
556 * Test whether the translation matches `$this->slug`.
557 *
558 * @param array $translation - the translation.
559 *
560 * @return bool
561 */
562 protected function get_translation( $translation ) {
563 return ( $translation['slug'] === $this->slug );
564 }
565 }
566