changeset 5 | 5e2f62d02dcd |
parent 0 | d970ebf37754 |
child 7 | cf61fcea0001 |
4:346c88efed21 | 5:5e2f62d02dcd |
---|---|
2 /** |
2 /** |
3 * A File upgrader class for WordPress. |
3 * A File upgrader class for WordPress. |
4 * |
4 * |
5 * This set of classes are designed to be used to upgrade/install a local set of files on the filesystem via the Filesystem Abstraction classes. |
5 * This set of classes are designed to be used to upgrade/install a local set of files on the filesystem via the Filesystem Abstraction classes. |
6 * |
6 * |
7 * @link http://trac.wordpress.org/ticket/7875 consolidate plugin/theme/core upgrade/install functions |
7 * @link https://core.trac.wordpress.org/ticket/7875 consolidate plugin/theme/core upgrade/install functions |
8 * |
8 * |
9 * @package WordPress |
9 * @package WordPress |
10 * @subpackage Upgrader |
10 * @subpackage Upgrader |
11 * @since 2.8.0 |
11 * @since 2.8.0 |
12 */ |
12 */ |
19 * @package WordPress |
19 * @package WordPress |
20 * @subpackage Upgrader |
20 * @subpackage Upgrader |
21 * @since 2.8.0 |
21 * @since 2.8.0 |
22 */ |
22 */ |
23 class WP_Upgrader { |
23 class WP_Upgrader { |
24 var $strings = array(); |
24 |
25 var $skin = null; |
25 /** |
26 var $result = array(); |
26 * The error/notification strings used to update the user on the progress. |
27 |
27 * |
28 function __construct($skin = null) { |
28 * @since 2.8.0 |
29 * @var string $strings |
|
30 */ |
|
31 public $strings = array(); |
|
32 |
|
33 /** |
|
34 * The upgrader skin being used. |
|
35 * |
|
36 * @since 2.8.0 |
|
37 * @var WP_Upgrader_Skin $skin |
|
38 */ |
|
39 public $skin = null; |
|
40 |
|
41 /** |
|
42 * The result of the installation. |
|
43 * |
|
44 * This is set by {@see WP_Upgrader::install_package()}, only when the package is installed |
|
45 * successfully. It will then be an array, unless a {@see WP_Error} is returned by the |
|
46 * {@see 'upgrader_post_install'} filter. In that case, the `WP_Error` will be assigned to |
|
47 * it. |
|
48 * |
|
49 * @since 2.8.0 |
|
50 * @var WP_Error|array $result { |
|
51 * @type string $source The full path to the source the files were installed from. |
|
52 * @type string $source_files List of all the files in the source directory. |
|
53 * @type string $destination The full path to the install destination folder. |
|
54 * @type string $destination_name The name of the destination folder, or empty if `$destination` |
|
55 * and `$local_destination` are the same. |
|
56 * @type string $local_destination The full local path to the destination folder. This is usually |
|
57 * the same as `$destination`. |
|
58 * @type string $remote_destination The full remote path to the destination folder |
|
59 * (i.e., from `$wp_filesystem`). |
|
60 * @type bool $clear_destination Whether the destination folder was cleared. |
|
61 * } |
|
62 */ |
|
63 public $result = array(); |
|
64 |
|
65 /** |
|
66 * The total number of updates being performed. |
|
67 * |
|
68 * Set by the bulk update methods. |
|
69 * |
|
70 * @since 3.0.0 |
|
71 * @var int $update_count |
|
72 */ |
|
73 public $update_count = 0; |
|
74 |
|
75 /** |
|
76 * The current update if multiple updates are being performed. |
|
77 * |
|
78 * Used by the bulk update methods, and incremented for each update. |
|
79 * |
|
80 * @since 3.0.0 |
|
81 * @var int |
|
82 */ |
|
83 public $update_current = 0; |
|
84 |
|
85 /** |
|
86 * Construct the upgrader with a skin. |
|
87 * |
|
88 * @since 2.8.0 |
|
89 * |
|
90 * @param WP_Upgrader_Skin $skin The upgrader skin to use. Default is a {@see WP_Upgrader_Skin} |
|
91 * instance. |
|
92 */ |
|
93 public function __construct( $skin = null ) { |
|
29 if ( null == $skin ) |
94 if ( null == $skin ) |
30 $this->skin = new WP_Upgrader_Skin(); |
95 $this->skin = new WP_Upgrader_Skin(); |
31 else |
96 else |
32 $this->skin = $skin; |
97 $this->skin = $skin; |
33 } |
98 } |
34 |
99 |
35 function init() { |
100 /** |
101 * Initialize the upgrader. |
|
102 * |
|
103 * This will set the relationship between the skin being used and this upgrader, |
|
104 * and also add the generic strings to `WP_Upgrader::$strings`. |
|
105 * |
|
106 * @since 2.8.0 |
|
107 */ |
|
108 public function init() { |
|
36 $this->skin->set_upgrader($this); |
109 $this->skin->set_upgrader($this); |
37 $this->generic_strings(); |
110 $this->generic_strings(); |
38 } |
111 } |
39 |
112 |
40 function generic_strings() { |
113 /** |
114 * Add the generic strings to WP_Upgrader::$strings. |
|
115 * |
|
116 * @since 2.8.0 |
|
117 */ |
|
118 public function generic_strings() { |
|
41 $this->strings['bad_request'] = __('Invalid Data provided.'); |
119 $this->strings['bad_request'] = __('Invalid Data provided.'); |
42 $this->strings['fs_unavailable'] = __('Could not access filesystem.'); |
120 $this->strings['fs_unavailable'] = __('Could not access filesystem.'); |
43 $this->strings['fs_error'] = __('Filesystem error.'); |
121 $this->strings['fs_error'] = __('Filesystem error.'); |
44 $this->strings['fs_no_root_dir'] = __('Unable to locate WordPress Root directory.'); |
122 $this->strings['fs_no_root_dir'] = __('Unable to locate WordPress Root directory.'); |
45 $this->strings['fs_no_content_dir'] = __('Unable to locate WordPress Content directory (wp-content).'); |
123 $this->strings['fs_no_content_dir'] = __('Unable to locate WordPress Content directory (wp-content).'); |
57 |
135 |
58 $this->strings['maintenance_start'] = __('Enabling Maintenance mode…'); |
136 $this->strings['maintenance_start'] = __('Enabling Maintenance mode…'); |
59 $this->strings['maintenance_end'] = __('Disabling Maintenance mode…'); |
137 $this->strings['maintenance_end'] = __('Disabling Maintenance mode…'); |
60 } |
138 } |
61 |
139 |
62 function fs_connect( $directories = array() ) { |
140 /** |
141 * Connect to the filesystem. |
|
142 * |
|
143 * @since 2.8.0 |
|
144 * |
|
145 * @param array $directories Optional. A list of directories. If any of these do |
|
146 * not exist, a {@see WP_Error} object will be returned. |
|
147 * Default empty array. |
|
148 * @param bool $allow_relaxed_file_ownership Whether to allow relaxed file ownership. |
|
149 * Default false. |
|
150 * @return bool|WP_Error True if able to connect, false or a {@see WP_Error} otherwise. |
|
151 */ |
|
152 public function fs_connect( $directories = array(), $allow_relaxed_file_ownership = false ) { |
|
63 global $wp_filesystem; |
153 global $wp_filesystem; |
64 |
154 |
65 if ( false === ($credentials = $this->skin->request_filesystem_credentials()) ) |
155 if ( false === ( $credentials = $this->skin->request_filesystem_credentials( false, $directories[0], $allow_relaxed_file_ownership ) ) ) { |
66 return false; |
156 return false; |
67 |
157 } |
68 if ( ! WP_Filesystem($credentials) ) { |
158 |
159 if ( ! WP_Filesystem( $credentials, $directories[0], $allow_relaxed_file_ownership ) ) { |
|
69 $error = true; |
160 $error = true; |
70 if ( is_object($wp_filesystem) && $wp_filesystem->errors->get_error_code() ) |
161 if ( is_object($wp_filesystem) && $wp_filesystem->errors->get_error_code() ) |
71 $error = $wp_filesystem->errors; |
162 $error = $wp_filesystem->errors; |
72 $this->skin->request_filesystem_credentials($error); //Failed to connect, Error and request again |
163 // Failed to connect, Error and request again |
164 $this->skin->request_filesystem_credentials( $error, $directories[0], $allow_relaxed_file_ownership ); |
|
73 return false; |
165 return false; |
74 } |
166 } |
75 |
167 |
76 if ( ! is_object($wp_filesystem) ) |
168 if ( ! is_object($wp_filesystem) ) |
77 return new WP_Error('fs_unavailable', $this->strings['fs_unavailable'] ); |
169 return new WP_Error('fs_unavailable', $this->strings['fs_unavailable'] ); |
104 } |
196 } |
105 } |
197 } |
106 return true; |
198 return true; |
107 } //end fs_connect(); |
199 } //end fs_connect(); |
108 |
200 |
109 function download_package($package) { |
201 /** |
202 * Download a package. |
|
203 * |
|
204 * @since 2.8.0 |
|
205 * |
|
206 * @param string $package The URI of the package. If this is the full path to an |
|
207 * existing local file, it will be returned untouched. |
|
208 * @return string|WP_Error The full path to the downloaded package file, or a {@see WP_Error} object. |
|
209 */ |
|
210 public function download_package( $package ) { |
|
110 |
211 |
111 /** |
212 /** |
112 * Filter whether to return the package. |
213 * Filter whether to return the package. |
113 * |
214 * |
114 * @since 3.7.0 |
215 * @since 3.7.0 |
115 * |
216 * |
116 * @param bool $reply Whether to bail without returning the package. Default is false. |
217 * @param bool $reply Whether to bail without returning the package. |
117 * @param string $package The package file name. |
218 * Default false. |
118 * @param object $this The WP_Upgrader instance. |
219 * @param string $package The package file name. |
220 * @param WP_Upgrader $this The WP_Upgrader instance. |
|
119 */ |
221 */ |
120 $reply = apply_filters( 'upgrader_pre_download', false, $package, $this ); |
222 $reply = apply_filters( 'upgrader_pre_download', false, $package, $this ); |
121 if ( false !== $reply ) |
223 if ( false !== $reply ) |
122 return $reply; |
224 return $reply; |
123 |
225 |
135 return new WP_Error('download_failed', $this->strings['download_failed'], $download_file->get_error_message()); |
237 return new WP_Error('download_failed', $this->strings['download_failed'], $download_file->get_error_message()); |
136 |
238 |
137 return $download_file; |
239 return $download_file; |
138 } |
240 } |
139 |
241 |
140 function unpack_package($package, $delete_package = true) { |
242 /** |
243 * Unpack a compressed package file. |
|
244 * |
|
245 * @since 2.8.0 |
|
246 * |
|
247 * @param string $package Full path to the package file. |
|
248 * @param bool $delete_package Optional. Whether to delete the package file after attempting |
|
249 * to unpack it. Default true. |
|
250 * @return string|WP_Error The path to the unpacked contents, or a {@see WP_Error} on failure. |
|
251 */ |
|
252 public function unpack_package( $package, $delete_package = true ) { |
|
141 global $wp_filesystem; |
253 global $wp_filesystem; |
142 |
254 |
143 $this->skin->feedback('unpack_package'); |
255 $this->skin->feedback('unpack_package'); |
144 |
256 |
145 $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/'; |
257 $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/'; |
149 if ( !empty($upgrade_files) ) { |
261 if ( !empty($upgrade_files) ) { |
150 foreach ( $upgrade_files as $file ) |
262 foreach ( $upgrade_files as $file ) |
151 $wp_filesystem->delete($upgrade_folder . $file['name'], true); |
263 $wp_filesystem->delete($upgrade_folder . $file['name'], true); |
152 } |
264 } |
153 |
265 |
154 //We need a working directory |
266 // We need a working directory - Strip off any .tmp or .zip suffixes |
155 $working_dir = $upgrade_folder . basename($package, '.zip'); |
267 $working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' ); |
156 |
268 |
157 // Clean up working directory |
269 // Clean up working directory |
158 if ( $wp_filesystem->is_dir($working_dir) ) |
270 if ( $wp_filesystem->is_dir($working_dir) ) |
159 $wp_filesystem->delete($working_dir, true); |
271 $wp_filesystem->delete($working_dir, true); |
160 |
272 |
174 } |
286 } |
175 |
287 |
176 return $working_dir; |
288 return $working_dir; |
177 } |
289 } |
178 |
290 |
179 function install_package( $args = array() ) { |
291 /** |
292 * Install a package. |
|
293 * |
|
294 * Copies the contents of a package form a source directory, and installs them in |
|
295 * a destination directory. Optionally removes the source. It can also optionally |
|
296 * clear out the destination folder if it already exists. |
|
297 * |
|
298 * @since 2.8.0 |
|
299 * |
|
300 * @param array|string $args { |
|
301 * Optional. Array or string of arguments for installing a package. Default empty array. |
|
302 * |
|
303 * @type string $source Required path to the package source. Default empty. |
|
304 * @type string $destination Required path to a folder to install the package in. |
|
305 * Default empty. |
|
306 * @type bool $clear_destination Whether to delete any files already in the destination |
|
307 * folder. Default false. |
|
308 * @type bool $clear_working Whether to delete the files form the working directory |
|
309 * after copying to the destination. Default false. |
|
310 * @type bool $abort_if_destination_exists Whether to abort the installation if |
|
311 * the destination folder already exists. Default true. |
|
312 * @type array $hook_extra Extra arguments to pass to the filter hooks called by |
|
313 * {@see WP_Upgrader::install_package()}. Default empty array. |
|
314 * } |
|
315 * |
|
316 * @return array|WP_Error The result (also stored in `WP_Upgrader:$result`), or a {@see WP_Error} on failure. |
|
317 */ |
|
318 public function install_package( $args = array() ) { |
|
180 global $wp_filesystem, $wp_theme_directories; |
319 global $wp_filesystem, $wp_theme_directories; |
181 |
320 |
182 $defaults = array( |
321 $defaults = array( |
183 'source' => '', // Please always pass this |
322 'source' => '', // Please always pass this |
184 'destination' => '', // and this |
323 'destination' => '', // and this |
187 'abort_if_destination_exists' => true, |
326 'abort_if_destination_exists' => true, |
188 'hook_extra' => array() |
327 'hook_extra' => array() |
189 ); |
328 ); |
190 |
329 |
191 $args = wp_parse_args($args, $defaults); |
330 $args = wp_parse_args($args, $defaults); |
192 extract($args); |
331 |
332 // These were previously extract()'d. |
|
333 $source = $args['source']; |
|
334 $destination = $args['destination']; |
|
335 $clear_destination = $args['clear_destination']; |
|
193 |
336 |
194 @set_time_limit( 300 ); |
337 @set_time_limit( 300 ); |
195 |
338 |
196 if ( empty($source) || empty($destination) ) |
339 if ( empty( $source ) || empty( $destination ) ) { |
197 return new WP_Error('bad_request', $this->strings['bad_request']); |
340 return new WP_Error( 'bad_request', $this->strings['bad_request'] ); |
198 |
341 } |
199 $this->skin->feedback('installing_package'); |
342 $this->skin->feedback( 'installing_package' ); |
200 |
343 |
201 $res = apply_filters('upgrader_pre_install', true, $hook_extra); |
344 /** |
202 if ( is_wp_error($res) ) |
345 * Filter the install response before the installation has started. |
346 * |
|
347 * Returning a truthy value, or one that could be evaluated as a WP_Error |
|
348 * will effectively short-circuit the installation, returning that value |
|
349 * instead. |
|
350 * |
|
351 * @since 2.8.0 |
|
352 * |
|
353 * @param bool|WP_Error $response Response. |
|
354 * @param array $hook_extra Extra arguments passed to hooked filters. |
|
355 */ |
|
356 $res = apply_filters( 'upgrader_pre_install', true, $args['hook_extra'] ); |
|
357 if ( is_wp_error( $res ) ) { |
|
203 return $res; |
358 return $res; |
359 } |
|
204 |
360 |
205 //Retain the Original source and destinations |
361 //Retain the Original source and destinations |
206 $remote_source = $source; |
362 $remote_source = $args['source']; |
207 $local_destination = $destination; |
363 $local_destination = $destination; |
208 |
364 |
209 $source_files = array_keys( $wp_filesystem->dirlist($remote_source) ); |
365 $source_files = array_keys( $wp_filesystem->dirlist( $remote_source ) ); |
210 $remote_destination = $wp_filesystem->find_folder($local_destination); |
366 $remote_destination = $wp_filesystem->find_folder( $local_destination ); |
211 |
367 |
212 //Locate which directory to copy to the new folder, This is based on the actual folder holding the files. |
368 //Locate which directory to copy to the new folder, This is based on the actual folder holding the files. |
213 if ( 1 == count($source_files) && $wp_filesystem->is_dir( trailingslashit($source) . $source_files[0] . '/') ) //Only one folder? Then we want its contents. |
369 if ( 1 == count( $source_files ) && $wp_filesystem->is_dir( trailingslashit( $args['source'] ) . $source_files[0] . '/' ) ) { //Only one folder? Then we want its contents. |
214 $source = trailingslashit($source) . trailingslashit($source_files[0]); |
370 $source = trailingslashit( $args['source'] ) . trailingslashit( $source_files[0] ); |
215 elseif ( count($source_files) == 0 ) |
371 } elseif ( count( $source_files ) == 0 ) { |
216 return new WP_Error( 'incompatible_archive_empty', $this->strings['incompatible_archive'], $this->strings['no_files'] ); // There are no files? |
372 return new WP_Error( 'incompatible_archive_empty', $this->strings['incompatible_archive'], $this->strings['no_files'] ); // There are no files? |
217 else //It's only a single file, the upgrader will use the foldername of this file as the destination folder. foldername is based on zip filename. |
373 } else { //It's only a single file, the upgrader will use the foldername of this file as the destination folder. foldername is based on zip filename. |
218 $source = trailingslashit($source); |
374 $source = trailingslashit( $args['source'] ); |
219 |
375 } |
220 //Hook ability to change the source file location.. |
376 |
221 $source = apply_filters('upgrader_source_selection', $source, $remote_source, $this); |
377 /** |
222 if ( is_wp_error($source) ) |
378 * Filter the source file location for the upgrade package. |
379 * |
|
380 * @since 2.8.0 |
|
381 * |
|
382 * @param string $source File source location. |
|
383 * @param string $remote_source Remove file source location. |
|
384 * @param WP_Upgrader $this WP_Upgrader instance. |
|
385 */ |
|
386 $source = apply_filters( 'upgrader_source_selection', $source, $remote_source, $this ); |
|
387 if ( is_wp_error( $source ) ) { |
|
223 return $source; |
388 return $source; |
224 |
389 } |
225 //Has the source location changed? If so, we need a new source_files list. |
390 |
226 if ( $source !== $remote_source ) |
391 // Has the source location changed? If so, we need a new source_files list. |
227 $source_files = array_keys( $wp_filesystem->dirlist($source) ); |
392 if ( $source !== $remote_source ) { |
228 |
393 $source_files = array_keys( $wp_filesystem->dirlist( $source ) ); |
229 // Protection against deleting files in any important base directories. |
394 } |
230 // Theme_Upgrader & Plugin_Upgrader also trigger this, as they pass the destination directory (WP_PLUGIN_DIR / wp-content/themes) |
395 /* |
231 // intending to copy the directory into the directory, whilst they pass the source as the actual files to copy. |
396 * Protection against deleting files in any important base directories. |
397 * Theme_Upgrader & Plugin_Upgrader also trigger this, as they pass the |
|
398 * destination directory (WP_PLUGIN_DIR / wp-content/themes) intending |
|
399 * to copy the directory into the directory, whilst they pass the source |
|
400 * as the actual files to copy. |
|
401 */ |
|
232 $protected_directories = array( ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, WP_CONTENT_DIR . '/themes' ); |
402 $protected_directories = array( ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, WP_CONTENT_DIR . '/themes' ); |
233 if ( is_array( $wp_theme_directories ) ) |
403 |
404 if ( is_array( $wp_theme_directories ) ) { |
|
234 $protected_directories = array_merge( $protected_directories, $wp_theme_directories ); |
405 $protected_directories = array_merge( $protected_directories, $wp_theme_directories ); |
406 } |
|
235 if ( in_array( $destination, $protected_directories ) ) { |
407 if ( in_array( $destination, $protected_directories ) ) { |
236 $remote_destination = trailingslashit($remote_destination) . trailingslashit(basename($source)); |
408 $remote_destination = trailingslashit( $remote_destination ) . trailingslashit( basename( $source ) ); |
237 $destination = trailingslashit($destination) . trailingslashit(basename($source)); |
409 $destination = trailingslashit( $destination ) . trailingslashit( basename( $source ) ); |
238 } |
410 } |
239 |
411 |
240 if ( $clear_destination ) { |
412 if ( $clear_destination ) { |
241 //We're going to clear the destination if there's something there |
413 //We're going to clear the destination if there's something there |
242 $this->skin->feedback('remove_old'); |
414 $this->skin->feedback('remove_old'); |
243 $removed = true; |
415 $removed = true; |
244 if ( $wp_filesystem->exists($remote_destination) ) |
416 if ( $wp_filesystem->exists( $remote_destination ) ) { |
245 $removed = $wp_filesystem->delete($remote_destination, true); |
417 $removed = $wp_filesystem->delete( $remote_destination, true ); |
246 $removed = apply_filters('upgrader_clear_destination', $removed, $local_destination, $remote_destination, $hook_extra); |
418 } |
247 |
419 |
248 if ( is_wp_error($removed) ) |
420 /** |
421 * Filter whether the upgrader cleared the destination. |
|
422 * |
|
423 * @since 2.8.0 |
|
424 * |
|
425 * @param bool $removed Whether the destination was cleared. |
|
426 * @param string $local_destination The local package destination. |
|
427 * @param string $remote_destination The remote package destination. |
|
428 * @param array $hook_extra Extra arguments passed to hooked filters. |
|
429 */ |
|
430 $removed = apply_filters( 'upgrader_clear_destination', $removed, $local_destination, $remote_destination, $args['hook_extra'] ); |
|
431 |
|
432 if ( is_wp_error($removed) ) { |
|
249 return $removed; |
433 return $removed; |
250 else if ( ! $removed ) |
434 } elseif ( ! $removed ) { |
251 return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']); |
435 return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']); |
252 } elseif ( $abort_if_destination_exists && $wp_filesystem->exists($remote_destination) ) { |
436 } |
437 } elseif ( $args['abort_if_destination_exists'] && $wp_filesystem->exists($remote_destination) ) { |
|
253 //If we're not clearing the destination folder and something exists there already, Bail. |
438 //If we're not clearing the destination folder and something exists there already, Bail. |
254 //But first check to see if there are actually any files in the folder. |
439 //But first check to see if there are actually any files in the folder. |
255 $_files = $wp_filesystem->dirlist($remote_destination); |
440 $_files = $wp_filesystem->dirlist($remote_destination); |
256 if ( ! empty($_files) ) { |
441 if ( ! empty($_files) ) { |
257 $wp_filesystem->delete($remote_source, true); //Clear out the source files. |
442 $wp_filesystem->delete($remote_source, true); //Clear out the source files. |
258 return new WP_Error('folder_exists', $this->strings['folder_exists'], $remote_destination ); |
443 return new WP_Error('folder_exists', $this->strings['folder_exists'], $remote_destination ); |
259 } |
444 } |
260 } |
445 } |
261 |
446 |
262 //Create destination if needed |
447 //Create destination if needed |
263 if ( !$wp_filesystem->exists($remote_destination) ) |
448 if ( ! $wp_filesystem->exists( $remote_destination ) ) { |
264 if ( !$wp_filesystem->mkdir($remote_destination, FS_CHMOD_DIR) ) |
449 if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) ) { |
265 return new WP_Error( 'mkdir_failed_destination', $this->strings['mkdir_failed'], $remote_destination ); |
450 return new WP_Error( 'mkdir_failed_destination', $this->strings['mkdir_failed'], $remote_destination ); |
266 |
451 } |
452 } |
|
267 // Copy new version of item into place. |
453 // Copy new version of item into place. |
268 $result = copy_dir($source, $remote_destination); |
454 $result = copy_dir($source, $remote_destination); |
269 if ( is_wp_error($result) ) { |
455 if ( is_wp_error($result) ) { |
270 if ( $clear_working ) |
456 if ( $args['clear_working'] ) { |
271 $wp_filesystem->delete($remote_source, true); |
457 $wp_filesystem->delete( $remote_source, true ); |
458 } |
|
272 return $result; |
459 return $result; |
273 } |
460 } |
274 |
461 |
275 //Clear the Working folder? |
462 //Clear the Working folder? |
276 if ( $clear_working ) |
463 if ( $args['clear_working'] ) { |
277 $wp_filesystem->delete($remote_source, true); |
464 $wp_filesystem->delete( $remote_source, true ); |
465 } |
|
278 |
466 |
279 $destination_name = basename( str_replace($local_destination, '', $destination) ); |
467 $destination_name = basename( str_replace($local_destination, '', $destination) ); |
280 if ( '.' == $destination_name ) |
468 if ( '.' == $destination_name ) { |
281 $destination_name = ''; |
469 $destination_name = ''; |
282 |
470 } |
283 $this->result = compact('local_source', 'source', 'source_name', 'source_files', 'destination', 'destination_name', 'local_destination', 'remote_destination', 'clear_destination', 'delete_source_dir'); |
471 |
284 |
472 $this->result = compact( 'source', 'source_files', 'destination', 'destination_name', 'local_destination', 'remote_destination', 'clear_destination' ); |
285 $res = apply_filters('upgrader_post_install', true, $hook_extra, $this->result); |
473 |
474 /** |
|
475 * Filter the install response after the installation has finished. |
|
476 * |
|
477 * @since 2.8.0 |
|
478 * |
|
479 * @param bool $response Install response. |
|
480 * @param array $hook_extra Extra arguments passed to hooked filters. |
|
481 * @param array $result Installation result data. |
|
482 */ |
|
483 $res = apply_filters( 'upgrader_post_install', true, $args['hook_extra'], $this->result ); |
|
484 |
|
286 if ( is_wp_error($res) ) { |
485 if ( is_wp_error($res) ) { |
287 $this->result = $res; |
486 $this->result = $res; |
288 return $res; |
487 return $res; |
289 } |
488 } |
290 |
489 |
291 //Bombard the calling function will all the info which we've just used. |
490 //Bombard the calling function will all the info which we've just used. |
292 return $this->result; |
491 return $this->result; |
293 } |
492 } |
294 |
493 |
295 function run($options) { |
494 /** |
495 * Run an upgrade/install. |
|
496 * |
|
497 * Attempts to download the package (if it is not a local file), unpack it, and |
|
498 * install it in the destination folder. |
|
499 * |
|
500 * @since 2.8.0 |
|
501 * |
|
502 * @param array $options { |
|
503 * Array or string of arguments for upgrading/installing a package. |
|
504 * |
|
505 * @type string $package The full path or URI of the package to install. |
|
506 * Default empty. |
|
507 * @type string $destination The full path to the destination folder. |
|
508 * Default empty. |
|
509 * @type bool $clear_destination Whether to delete any files already in the |
|
510 * destination folder. Default false. |
|
511 * @type bool $clear_working Whether to delete the files form the working |
|
512 * directory after copying to the destination. |
|
513 * Default false. |
|
514 * @type bool $abort_if_destination_exists Whether to abort the installation if the destination |
|
515 * folder already exists. When true, `$clear_destination` |
|
516 * should be false. Default true. |
|
517 * @type bool $is_multi Whether this run is one of multiple upgrade/install |
|
518 * actions being performed in bulk. When true, the skin |
|
519 * {@see WP_Upgrader::header()} and {@see WP_Upgrader::footer()} |
|
520 * aren't called. Default false. |
|
521 * @type array $hook_extra Extra arguments to pass to the filter hooks called by |
|
522 * {@see WP_Upgrader::run()}. |
|
523 * } |
|
524 * |
|
525 * @return array|false|WP_error The result from self::install_package() on success, otherwise a WP_Error, |
|
526 * or false if unable to connect to the filesystem. |
|
527 */ |
|
528 public function run( $options ) { |
|
296 |
529 |
297 $defaults = array( |
530 $defaults = array( |
298 'package' => '', // Please always pass this. |
531 'package' => '', // Please always pass this. |
299 'destination' => '', // And this |
532 'destination' => '', // And this |
300 'clear_destination' => false, |
533 'clear_destination' => false, |
302 'clear_working' => true, |
535 'clear_working' => true, |
303 'is_multi' => false, |
536 'is_multi' => false, |
304 'hook_extra' => array() // Pass any extra $hook_extra args here, this will be passed to any hooked filters. |
537 'hook_extra' => array() // Pass any extra $hook_extra args here, this will be passed to any hooked filters. |
305 ); |
538 ); |
306 |
539 |
307 $options = wp_parse_args($options, $defaults); |
540 $options = wp_parse_args( $options, $defaults ); |
308 extract($options); |
541 |
309 |
542 if ( ! $options['is_multi'] ) { // call $this->header separately if running multiple times |
310 if ( ! $is_multi ) // call $this->header separately if running multiple times |
|
311 $this->skin->header(); |
543 $this->skin->header(); |
544 } |
|
312 |
545 |
313 // Connect to the Filesystem first. |
546 // Connect to the Filesystem first. |
314 $res = $this->fs_connect( array(WP_CONTENT_DIR, $destination) ); |
547 $res = $this->fs_connect( array( WP_CONTENT_DIR, $options['destination'] ) ); |
315 // Mainly for non-connected filesystem. |
548 // Mainly for non-connected filesystem. |
316 if ( ! $res ) { |
549 if ( ! $res ) { |
317 if ( ! $is_multi ) |
550 if ( ! $options['is_multi'] ) { |
318 $this->skin->footer(); |
551 $this->skin->footer(); |
552 } |
|
319 return false; |
553 return false; |
320 } |
554 } |
321 |
555 |
322 $this->skin->before(); |
556 $this->skin->before(); |
323 |
557 |
324 if ( is_wp_error($res) ) { |
558 if ( is_wp_error($res) ) { |
325 $this->skin->error($res); |
559 $this->skin->error($res); |
326 $this->skin->after(); |
560 $this->skin->after(); |
327 if ( ! $is_multi ) |
561 if ( ! $options['is_multi'] ) { |
328 $this->skin->footer(); |
562 $this->skin->footer(); |
563 } |
|
329 return $res; |
564 return $res; |
330 } |
565 } |
331 |
566 |
332 //Download the package (Note, This just returns the filename of the file if the package is a local file) |
567 //Download the package (Note, This just returns the filename of the file if the package is a local file) |
333 $download = $this->download_package( $package ); |
568 $download = $this->download_package( $options['package'] ); |
334 if ( is_wp_error($download) ) { |
569 if ( is_wp_error($download) ) { |
335 $this->skin->error($download); |
570 $this->skin->error($download); |
336 $this->skin->after(); |
571 $this->skin->after(); |
337 if ( ! $is_multi ) |
572 if ( ! $options['is_multi'] ) { |
338 $this->skin->footer(); |
573 $this->skin->footer(); |
574 } |
|
339 return $download; |
575 return $download; |
340 } |
576 } |
341 |
577 |
342 $delete_package = ($download != $package); // Do not delete a "local" file |
578 $delete_package = ( $download != $options['package'] ); // Do not delete a "local" file |
343 |
579 |
344 //Unzips the file into a temporary directory |
580 //Unzips the file into a temporary directory |
345 $working_dir = $this->unpack_package( $download, $delete_package ); |
581 $working_dir = $this->unpack_package( $download, $delete_package ); |
346 if ( is_wp_error($working_dir) ) { |
582 if ( is_wp_error($working_dir) ) { |
347 $this->skin->error($working_dir); |
583 $this->skin->error($working_dir); |
348 $this->skin->after(); |
584 $this->skin->after(); |
349 if ( ! $is_multi ) |
585 if ( ! $options['is_multi'] ) { |
350 $this->skin->footer(); |
586 $this->skin->footer(); |
587 } |
|
351 return $working_dir; |
588 return $working_dir; |
352 } |
589 } |
353 |
590 |
354 //With the given options, this installs it to the destination directory. |
591 //With the given options, this installs it to the destination directory. |
355 $result = $this->install_package( array( |
592 $result = $this->install_package( array( |
356 'source' => $working_dir, |
593 'source' => $working_dir, |
357 'destination' => $destination, |
594 'destination' => $options['destination'], |
358 'clear_destination' => $clear_destination, |
595 'clear_destination' => $options['clear_destination'], |
359 'abort_if_destination_exists' => $abort_if_destination_exists, |
596 'abort_if_destination_exists' => $options['abort_if_destination_exists'], |
360 'clear_working' => $clear_working, |
597 'clear_working' => $options['clear_working'], |
361 'hook_extra' => $hook_extra |
598 'hook_extra' => $options['hook_extra'] |
362 ) ); |
599 ) ); |
363 |
600 |
364 $this->skin->set_result($result); |
601 $this->skin->set_result($result); |
365 if ( is_wp_error($result) ) { |
602 if ( is_wp_error($result) ) { |
366 $this->skin->error($result); |
603 $this->skin->error($result); |
370 $this->skin->feedback('process_success'); |
607 $this->skin->feedback('process_success'); |
371 } |
608 } |
372 |
609 |
373 $this->skin->after(); |
610 $this->skin->after(); |
374 |
611 |
375 if ( ! $is_multi ) { |
612 if ( ! $options['is_multi'] ) { |
376 do_action( 'upgrader_process_complete', $this, $hook_extra ); |
613 |
614 /** This action is documented in wp-admin/includes/class-wp-upgrader.php */ |
|
615 do_action( 'upgrader_process_complete', $this, $options['hook_extra'] ); |
|
377 $this->skin->footer(); |
616 $this->skin->footer(); |
378 } |
617 } |
379 |
618 |
380 return $result; |
619 return $result; |
381 } |
620 } |
382 |
621 |
383 function maintenance_mode($enable = false) { |
622 /** |
623 * Toggle maintenance mode for the site. |
|
624 * |
|
625 * Creates/deletes the maintenance file to enable/disable maintenance mode. |
|
626 * |
|
627 * @since 2.8.0 |
|
628 * |
|
629 * @param bool $enable True to enable maintenance mode, false to disable. |
|
630 */ |
|
631 public function maintenance_mode( $enable = false ) { |
|
384 global $wp_filesystem; |
632 global $wp_filesystem; |
385 $file = $wp_filesystem->abspath() . '.maintenance'; |
633 $file = $wp_filesystem->abspath() . '.maintenance'; |
386 if ( $enable ) { |
634 if ( $enable ) { |
387 $this->skin->feedback('maintenance_start'); |
635 $this->skin->feedback('maintenance_start'); |
388 // Create maintenance file to signal that we are upgrading |
636 // Create maintenance file to signal that we are upgrading |
389 $maintenance_string = '<?php $upgrading = ' . time() . '; ?>'; |
637 $maintenance_string = '<?php $upgrading = ' . time() . '; ?>'; |
390 $wp_filesystem->delete($file); |
638 $wp_filesystem->delete($file); |
391 $wp_filesystem->put_contents($file, $maintenance_string, FS_CHMOD_FILE); |
639 $wp_filesystem->put_contents($file, $maintenance_string, FS_CHMOD_FILE); |
392 } else if ( !$enable && $wp_filesystem->exists($file) ) { |
640 } elseif ( ! $enable && $wp_filesystem->exists( $file ) ) { |
393 $this->skin->feedback('maintenance_end'); |
641 $this->skin->feedback('maintenance_end'); |
394 $wp_filesystem->delete($file); |
642 $wp_filesystem->delete($file); |
395 } |
643 } |
396 } |
644 } |
397 |
645 |
404 * @subpackage Upgrader |
652 * @subpackage Upgrader |
405 * @since 2.8.0 |
653 * @since 2.8.0 |
406 */ |
654 */ |
407 class Plugin_Upgrader extends WP_Upgrader { |
655 class Plugin_Upgrader extends WP_Upgrader { |
408 |
656 |
409 var $result; |
657 /** |
410 var $bulk = false; |
658 * Plugin upgrade result. |
411 var $show_before = ''; |
659 * |
412 |
660 * @since 2.8.0 |
413 function upgrade_strings() { |
661 * @var array|WP_Error $result |
662 * @see WP_Upgrader::$result |
|
663 */ |
|
664 public $result; |
|
665 |
|
666 /** |
|
667 * Whether a bulk upgrade/install is being performed. |
|
668 * |
|
669 * @since 2.9.0 |
|
670 * @var bool $bulk |
|
671 */ |
|
672 public $bulk = false; |
|
673 |
|
674 /** |
|
675 * Initialize the upgrade strings. |
|
676 * |
|
677 * @since 2.8.0 |
|
678 */ |
|
679 public function upgrade_strings() { |
|
414 $this->strings['up_to_date'] = __('The plugin is at the latest version.'); |
680 $this->strings['up_to_date'] = __('The plugin is at the latest version.'); |
415 $this->strings['no_package'] = __('Update package not available.'); |
681 $this->strings['no_package'] = __('Update package not available.'); |
416 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>…'); |
682 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>…'); |
417 $this->strings['unpack_package'] = __('Unpacking the update…'); |
683 $this->strings['unpack_package'] = __('Unpacking the update…'); |
418 $this->strings['remove_old'] = __('Removing the old version of the plugin…'); |
684 $this->strings['remove_old'] = __('Removing the old version of the plugin…'); |
419 $this->strings['remove_old_failed'] = __('Could not remove the old plugin.'); |
685 $this->strings['remove_old_failed'] = __('Could not remove the old plugin.'); |
420 $this->strings['process_failed'] = __('Plugin update failed.'); |
686 $this->strings['process_failed'] = __('Plugin update failed.'); |
421 $this->strings['process_success'] = __('Plugin updated successfully.'); |
687 $this->strings['process_success'] = __('Plugin updated successfully.'); |
422 } |
688 $this->strings['process_bulk_success'] = __('Plugins updated successfully.'); |
423 |
689 } |
424 function install_strings() { |
690 |
691 /** |
|
692 * Initialize the install strings. |
|
693 * |
|
694 * @since 2.8.0 |
|
695 */ |
|
696 public function install_strings() { |
|
425 $this->strings['no_package'] = __('Install package not available.'); |
697 $this->strings['no_package'] = __('Install package not available.'); |
426 $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>…'); |
698 $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>…'); |
427 $this->strings['unpack_package'] = __('Unpacking the package…'); |
699 $this->strings['unpack_package'] = __('Unpacking the package…'); |
428 $this->strings['installing_package'] = __('Installing the plugin…'); |
700 $this->strings['installing_package'] = __('Installing the plugin…'); |
429 $this->strings['no_files'] = __('The plugin contains no files.'); |
701 $this->strings['no_files'] = __('The plugin contains no files.'); |
430 $this->strings['process_failed'] = __('Plugin install failed.'); |
702 $this->strings['process_failed'] = __('Plugin install failed.'); |
431 $this->strings['process_success'] = __('Plugin installed successfully.'); |
703 $this->strings['process_success'] = __('Plugin installed successfully.'); |
432 } |
704 } |
433 |
705 |
434 function install( $package, $args = array() ) { |
706 /** |
707 * Install a plugin package. |
|
708 * |
|
709 * @since 2.8.0 |
|
710 * @since 3.7.0 The `$args` parameter was added, making clearing the plugin update cache optional. |
|
711 * |
|
712 * @param string $package The full local path or URI of the package. |
|
713 * @param array $args { |
|
714 * Optional. Other arguments for installing a plugin package. Default empty array. |
|
715 * |
|
716 * @type bool $clear_update_cache Whether to clear the plugin updates cache if successful. |
|
717 * Default true. |
|
718 * } |
|
719 * |
|
720 * @return bool|WP_Error True if the install was successful, false or a WP_Error otherwise. |
|
721 */ |
|
722 public function install( $package, $args = array() ) { |
|
435 |
723 |
436 $defaults = array( |
724 $defaults = array( |
437 'clear_update_cache' => true, |
725 'clear_update_cache' => true, |
438 ); |
726 ); |
439 $parsed_args = wp_parse_args( $args, $defaults ); |
727 $parsed_args = wp_parse_args( $args, $defaults ); |
463 wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); |
751 wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); |
464 |
752 |
465 return true; |
753 return true; |
466 } |
754 } |
467 |
755 |
468 function upgrade( $plugin, $args = array() ) { |
756 /** |
757 * Upgrade a plugin. |
|
758 * |
|
759 * @since 2.8.0 |
|
760 * @since 3.7.0 The `$args` parameter was added, making clearing the plugin update cache optional. |
|
761 * |
|
762 * @param string $plugin The basename path to the main plugin file. |
|
763 * @param array $args { |
|
764 * Optional. Other arguments for upgrading a plugin package. Defualt empty array. |
|
765 * |
|
766 * @type bool $clear_update_cache Whether to clear the plugin updates cache if successful. |
|
767 * Default true. |
|
768 * } |
|
769 * @return bool|WP_Error True if the upgrade was successful, false or a {@see WP_Error} object otherwise. |
|
770 */ |
|
771 public function upgrade( $plugin, $args = array() ) { |
|
469 |
772 |
470 $defaults = array( |
773 $defaults = array( |
471 'clear_update_cache' => true, |
774 'clear_update_cache' => true, |
472 ); |
775 ); |
473 $parsed_args = wp_parse_args( $args, $defaults ); |
776 $parsed_args = wp_parse_args( $args, $defaults ); |
514 wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); |
817 wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); |
515 |
818 |
516 return true; |
819 return true; |
517 } |
820 } |
518 |
821 |
519 function bulk_upgrade( $plugins, $args = array() ) { |
822 /** |
823 * Bulk upgrade several plugins at once. |
|
824 * |
|
825 * @since 2.8.0 |
|
826 * @since 3.7.0 The `$args` parameter was added, making clearing the plugin update cache optional. |
|
827 * |
|
828 * @param array $plugins Array of the basename paths of the plugins' main files. |
|
829 * @param array $args { |
|
830 * Optional. Other arguments for upgrading several plugins at once. Default empty array. |
|
831 * |
|
832 * @type bool $clear_update_cache Whether to clear the plugin updates cache if successful. |
|
833 * Default true. |
|
834 * } |
|
835 * |
|
836 * @return array|false An array of results indexed by plugin file, or false if unable to connect to the filesystem. |
|
837 */ |
|
838 public function bulk_upgrade( $plugins, $args = array() ) { |
|
520 |
839 |
521 $defaults = array( |
840 $defaults = array( |
522 'clear_update_cache' => true, |
841 'clear_update_cache' => true, |
523 ); |
842 ); |
524 $parsed_args = wp_parse_args( $args, $defaults ); |
843 $parsed_args = wp_parse_args( $args, $defaults ); |
559 foreach ( $plugins as $plugin ) { |
878 foreach ( $plugins as $plugin ) { |
560 $this->update_current++; |
879 $this->update_current++; |
561 $this->skin->plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true); |
880 $this->skin->plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true); |
562 |
881 |
563 if ( !isset( $current->response[ $plugin ] ) ) { |
882 if ( !isset( $current->response[ $plugin ] ) ) { |
564 $this->skin->set_result(true); |
883 $this->skin->set_result('up_to_date'); |
565 $this->skin->before(); |
884 $this->skin->before(); |
566 $this->skin->feedback('up_to_date'); |
885 $this->skin->feedback('up_to_date'); |
567 $this->skin->after(); |
886 $this->skin->after(); |
568 $results[$plugin] = true; |
887 $results[$plugin] = true; |
569 continue; |
888 continue; |
592 break; |
911 break; |
593 } //end foreach $plugins |
912 } //end foreach $plugins |
594 |
913 |
595 $this->maintenance_mode(false); |
914 $this->maintenance_mode(false); |
596 |
915 |
916 /** |
|
917 * Fires when the bulk upgrader process is complete. |
|
918 * |
|
919 * @since 3.6.0 |
|
920 * |
|
921 * @param Plugin_Upgrader $this Plugin_Upgrader instance. In other contexts, $this, might |
|
922 * be a Theme_Upgrader or Core_Upgrade instance. |
|
923 * @param array $data { |
|
924 * Array of bulk item update data. |
|
925 * |
|
926 * @type string $action Type of action. Default 'update'. |
|
927 * @type string $type Type of update process. Accepts 'plugin', 'theme', or 'core'. |
|
928 * @type bool $bulk Whether the update process is a bulk update. Default true. |
|
929 * @type array $packages Array of plugin, theme, or core packages to update. |
|
930 * } |
|
931 */ |
|
597 do_action( 'upgrader_process_complete', $this, array( |
932 do_action( 'upgrader_process_complete', $this, array( |
598 'action' => 'update', |
933 'action' => 'update', |
599 'type' => 'plugin', |
934 'type' => 'plugin', |
600 'bulk' => true, |
935 'bulk' => true, |
601 'plugins' => $plugins, |
936 'plugins' => $plugins, |
612 wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); |
947 wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); |
613 |
948 |
614 return $results; |
949 return $results; |
615 } |
950 } |
616 |
951 |
617 function check_package($source) { |
952 /** |
953 * Check a source package to be sure it contains a plugin. |
|
954 * |
|
955 * This function is added to the {@see 'upgrader_source_selection'} filter by |
|
956 * {@see Plugin_Upgrader::install()}. |
|
957 * |
|
958 * @since 3.3.0 |
|
959 * |
|
960 * @param string $source The path to the downloaded package source. |
|
961 * @return string|WP_Error The source as passed, or a {@see WP_Error} object if no plugins were found. |
|
962 */ |
|
963 public function check_package($source) { |
|
618 global $wp_filesystem; |
964 global $wp_filesystem; |
619 |
965 |
620 if ( is_wp_error($source) ) |
966 if ( is_wp_error($source) ) |
621 return $source; |
967 return $source; |
622 |
968 |
623 $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source); |
969 $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source); |
624 if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, lets not prevent installation. |
970 if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, let's not prevent installation. |
625 return $source; |
971 return $source; |
626 |
972 |
627 // Check the folder contains at least 1 valid plugin. |
973 // Check the folder contains at least 1 valid plugin. |
628 $plugins_found = false; |
974 $plugins_found = false; |
629 foreach ( glob( $working_directory . '*.php' ) as $file ) { |
975 foreach ( glob( $working_directory . '*.php' ) as $file ) { |
638 return new WP_Error( 'incompatible_archive_no_plugins', $this->strings['incompatible_archive'], __( 'No valid plugins were found.' ) ); |
984 return new WP_Error( 'incompatible_archive_no_plugins', $this->strings['incompatible_archive'], __( 'No valid plugins were found.' ) ); |
639 |
985 |
640 return $source; |
986 return $source; |
641 } |
987 } |
642 |
988 |
643 //return plugin info. |
989 /** |
644 function plugin_info() { |
990 * Retrieve the path to the file that contains the plugin info. |
991 * |
|
992 * This isn't used internally in the class, but is called by the skins. |
|
993 * |
|
994 * @since 2.8.0 |
|
995 * |
|
996 * @return string|false The full path to the main plugin file, or false. |
|
997 */ |
|
998 public function plugin_info() { |
|
645 if ( ! is_array($this->result) ) |
999 if ( ! is_array($this->result) ) |
646 return false; |
1000 return false; |
647 if ( empty($this->result['destination_name']) ) |
1001 if ( empty($this->result['destination_name']) ) |
648 return false; |
1002 return false; |
649 |
1003 |
654 $pluginfiles = array_keys($plugin); //Assume the requested plugin is the first in the list |
1008 $pluginfiles = array_keys($plugin); //Assume the requested plugin is the first in the list |
655 |
1009 |
656 return $this->result['destination_name'] . '/' . $pluginfiles[0]; |
1010 return $this->result['destination_name'] . '/' . $pluginfiles[0]; |
657 } |
1011 } |
658 |
1012 |
659 //Hooked to pre_install |
1013 /** |
660 function deactivate_plugin_before_upgrade($return, $plugin) { |
1014 * Deactivates a plugin before it is upgraded. |
1015 * |
|
1016 * Hooked to the {@see 'upgrader_pre_install'} filter by {@see Plugin_Upgrader::upgrade()}. |
|
1017 * |
|
1018 * @since 2.8.0 |
|
1019 * @since 4.1.0 Added a return value. |
|
1020 * |
|
1021 * @param bool|WP_Error $return Upgrade offer return. |
|
1022 * @param array $plugin Plugin package arguments. |
|
1023 * @return bool|WP_Error The passed in $return param or {@see WP_Error}. |
|
1024 */ |
|
1025 public function deactivate_plugin_before_upgrade($return, $plugin) { |
|
661 |
1026 |
662 if ( is_wp_error($return) ) //Bypass. |
1027 if ( is_wp_error($return) ) //Bypass. |
663 return $return; |
1028 return $return; |
664 |
1029 |
665 // When in cron (background updates) don't deactivate the plugin, as we require a browser to reactivate it |
1030 // When in cron (background updates) don't deactivate the plugin, as we require a browser to reactivate it |
672 |
1037 |
673 if ( is_plugin_active($plugin) ) { |
1038 if ( is_plugin_active($plugin) ) { |
674 //Deactivate the plugin silently, Prevent deactivation hooks from running. |
1039 //Deactivate the plugin silently, Prevent deactivation hooks from running. |
675 deactivate_plugins($plugin, true); |
1040 deactivate_plugins($plugin, true); |
676 } |
1041 } |
677 } |
1042 |
678 |
1043 return $return; |
679 //Hooked to upgrade_clear_destination |
1044 } |
680 function delete_old_plugin($removed, $local_destination, $remote_destination, $plugin) { |
1045 |
1046 /** |
|
1047 * Delete the old plugin during an upgrade. |
|
1048 * |
|
1049 * Hooked to the {@see 'upgrader_clear_destination'} filter by |
|
1050 * {@see Plugin_Upgrader::upgrade()} and {@see Plugin_Upgrader::bulk_upgrade()}. |
|
1051 * |
|
1052 * @since 2.8.0 |
|
1053 */ |
|
1054 public function delete_old_plugin($removed, $local_destination, $remote_destination, $plugin) { |
|
681 global $wp_filesystem; |
1055 global $wp_filesystem; |
682 |
1056 |
683 if ( is_wp_error($removed) ) |
1057 if ( is_wp_error($removed) ) |
684 return $removed; //Pass errors through. |
1058 return $removed; //Pass errors through. |
685 |
1059 |
713 * @subpackage Upgrader |
1087 * @subpackage Upgrader |
714 * @since 2.8.0 |
1088 * @since 2.8.0 |
715 */ |
1089 */ |
716 class Theme_Upgrader extends WP_Upgrader { |
1090 class Theme_Upgrader extends WP_Upgrader { |
717 |
1091 |
718 var $result; |
1092 /** |
719 var $bulk = false; |
1093 * Result of the theme upgrade offer. |
720 |
1094 * |
721 function upgrade_strings() { |
1095 * @since 2.8.0 |
1096 * @var array|WP_Erorr $result |
|
1097 * @see WP_Upgrader::$result |
|
1098 */ |
|
1099 public $result; |
|
1100 |
|
1101 /** |
|
1102 * Whether multiple plugins are being upgraded/installed in bulk. |
|
1103 * |
|
1104 * @since 2.9.0 |
|
1105 * @var bool $bulk |
|
1106 */ |
|
1107 public $bulk = false; |
|
1108 |
|
1109 /** |
|
1110 * Initialize the upgrade strings. |
|
1111 * |
|
1112 * @since 2.8.0 |
|
1113 */ |
|
1114 public function upgrade_strings() { |
|
722 $this->strings['up_to_date'] = __('The theme is at the latest version.'); |
1115 $this->strings['up_to_date'] = __('The theme is at the latest version.'); |
723 $this->strings['no_package'] = __('Update package not available.'); |
1116 $this->strings['no_package'] = __('Update package not available.'); |
724 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>…'); |
1117 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>…'); |
725 $this->strings['unpack_package'] = __('Unpacking the update…'); |
1118 $this->strings['unpack_package'] = __('Unpacking the update…'); |
726 $this->strings['remove_old'] = __('Removing the old version of the theme…'); |
1119 $this->strings['remove_old'] = __('Removing the old version of the theme…'); |
727 $this->strings['remove_old_failed'] = __('Could not remove the old theme.'); |
1120 $this->strings['remove_old_failed'] = __('Could not remove the old theme.'); |
728 $this->strings['process_failed'] = __('Theme update failed.'); |
1121 $this->strings['process_failed'] = __('Theme update failed.'); |
729 $this->strings['process_success'] = __('Theme updated successfully.'); |
1122 $this->strings['process_success'] = __('Theme updated successfully.'); |
730 } |
1123 } |
731 |
1124 |
732 function install_strings() { |
1125 /** |
1126 * Initialize the install strings. |
|
1127 * |
|
1128 * @since 2.8.0 |
|
1129 */ |
|
1130 public function install_strings() { |
|
733 $this->strings['no_package'] = __('Install package not available.'); |
1131 $this->strings['no_package'] = __('Install package not available.'); |
734 $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>…'); |
1132 $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>…'); |
735 $this->strings['unpack_package'] = __('Unpacking the package…'); |
1133 $this->strings['unpack_package'] = __('Unpacking the package…'); |
736 $this->strings['installing_package'] = __('Installing the theme…'); |
1134 $this->strings['installing_package'] = __('Installing the theme…'); |
737 $this->strings['no_files'] = __('The theme contains no files.'); |
1135 $this->strings['no_files'] = __('The theme contains no files.'); |
747 /* translators: 1: theme name, 2: version */ |
1145 /* translators: 1: theme name, 2: version */ |
748 $this->strings['parent_theme_install_success'] = __('Successfully installed the parent theme, <strong>%1$s %2$s</strong>.'); |
1146 $this->strings['parent_theme_install_success'] = __('Successfully installed the parent theme, <strong>%1$s %2$s</strong>.'); |
749 $this->strings['parent_theme_not_found'] = __('<strong>The parent theme could not be found.</strong> You will need to install the parent theme, <strong>%s</strong>, before you can use this child theme.'); |
1147 $this->strings['parent_theme_not_found'] = __('<strong>The parent theme could not be found.</strong> You will need to install the parent theme, <strong>%s</strong>, before you can use this child theme.'); |
750 } |
1148 } |
751 |
1149 |
752 function check_parent_theme_filter($install_result, $hook_extra, $child_result) { |
1150 /** |
1151 * Check if a child theme is being installed and we need to install its parent. |
|
1152 * |
|
1153 * Hooked to the {@see 'upgrader_post_install'} filter by {@see Theme_Upgrader::install()}. |
|
1154 * |
|
1155 * @since 3.4.0 |
|
1156 */ |
|
1157 public function check_parent_theme_filter( $install_result, $hook_extra, $child_result ) { |
|
753 // Check to see if we need to install a parent theme |
1158 // Check to see if we need to install a parent theme |
754 $theme_info = $this->theme_info(); |
1159 $theme_info = $this->theme_info(); |
755 |
1160 |
756 if ( ! $theme_info->parent() ) |
1161 if ( ! $theme_info->parent() ) |
757 return $install_result; |
1162 return $install_result; |
762 $this->skin->feedback( 'parent_theme_currently_installed', $theme_info->parent()->display('Name'), $theme_info->parent()->display('Version') ); |
1167 $this->skin->feedback( 'parent_theme_currently_installed', $theme_info->parent()->display('Name'), $theme_info->parent()->display('Version') ); |
763 // We already have the theme, fall through. |
1168 // We already have the theme, fall through. |
764 return $install_result; |
1169 return $install_result; |
765 } |
1170 } |
766 |
1171 |
767 // We don't have the parent theme, lets install it |
1172 // We don't have the parent theme, let's install it. |
768 $api = themes_api('theme_information', array('slug' => $theme_info->get('Template'), 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth. |
1173 $api = themes_api('theme_information', array('slug' => $theme_info->get('Template'), 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth. |
769 |
1174 |
770 if ( ! $api || is_wp_error($api) ) { |
1175 if ( ! $api || is_wp_error($api) ) { |
771 $this->skin->feedback( 'parent_theme_not_found', $theme_info->get('Template') ); |
1176 $this->skin->feedback( 'parent_theme_not_found', $theme_info->get('Template') ); |
772 // Don't show activate or preview actions after install |
1177 // Don't show activate or preview actions after install |
806 $this->strings['process_success'] = $child_success_message; |
1211 $this->strings['process_success'] = $child_success_message; |
807 |
1212 |
808 return $install_result; |
1213 return $install_result; |
809 } |
1214 } |
810 |
1215 |
811 function hide_activate_preview_actions($actions) { |
1216 /** |
1217 * Don't display the activate and preview actions to the user. |
|
1218 * |
|
1219 * Hooked to the {@see 'install_theme_complete_actions'} filter by |
|
1220 * {@see Theme_Upgrader::check_parent_theme_filter()} when installing |
|
1221 * a child theme and installing the parent theme fails. |
|
1222 * |
|
1223 * @since 3.4.0 |
|
1224 * |
|
1225 * @param array $actions Preview actions. |
|
1226 */ |
|
1227 public function hide_activate_preview_actions( $actions ) { |
|
812 unset($actions['activate'], $actions['preview']); |
1228 unset($actions['activate'], $actions['preview']); |
813 return $actions; |
1229 return $actions; |
814 } |
1230 } |
815 |
1231 |
816 function install( $package, $args = array() ) { |
1232 /** |
1233 * Install a theme package. |
|
1234 * |
|
1235 * @since 2.8.0 |
|
1236 * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional. |
|
1237 * |
|
1238 * @param string $package The full local path or URI of the package. |
|
1239 * @param array $args { |
|
1240 * Optional. Other arguments for installing a theme package. Default empty array. |
|
1241 * |
|
1242 * @type bool $clear_update_cache Whether to clear the updates cache if successful. |
|
1243 * Default true. |
|
1244 * } |
|
1245 * |
|
1246 * @return bool|WP_Error True if the install was successful, false or a {@see WP_Error} object otherwise. |
|
1247 */ |
|
1248 public function install( $package, $args = array() ) { |
|
817 |
1249 |
818 $defaults = array( |
1250 $defaults = array( |
819 'clear_update_cache' => true, |
1251 'clear_update_cache' => true, |
820 ); |
1252 ); |
821 $parsed_args = wp_parse_args( $args, $defaults ); |
1253 $parsed_args = wp_parse_args( $args, $defaults ); |
847 wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); |
1279 wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); |
848 |
1280 |
849 return true; |
1281 return true; |
850 } |
1282 } |
851 |
1283 |
852 function upgrade( $theme, $args = array() ) { |
1284 /** |
1285 * Upgrade a theme. |
|
1286 * |
|
1287 * @since 2.8.0 |
|
1288 * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional. |
|
1289 * |
|
1290 * @param string $theme The theme slug. |
|
1291 * @param array $args { |
|
1292 * Optional. Other arguments for upgrading a theme. Default empty array. |
|
1293 * |
|
1294 * @type bool $clear_update_cache Whether to clear the update cache if successful. |
|
1295 * Default true. |
|
1296 * } |
|
1297 * @return bool|WP_Error True if the upgrade was successful, false or a {@see WP_Error} object otherwise. |
|
1298 */ |
|
1299 public function upgrade( $theme, $args = array() ) { |
|
853 |
1300 |
854 $defaults = array( |
1301 $defaults = array( |
855 'clear_update_cache' => true, |
1302 'clear_update_cache' => true, |
856 ); |
1303 ); |
857 $parsed_args = wp_parse_args( $args, $defaults ); |
1304 $parsed_args = wp_parse_args( $args, $defaults ); |
862 // Is an update available? |
1309 // Is an update available? |
863 $current = get_site_transient( 'update_themes' ); |
1310 $current = get_site_transient( 'update_themes' ); |
864 if ( !isset( $current->response[ $theme ] ) ) { |
1311 if ( !isset( $current->response[ $theme ] ) ) { |
865 $this->skin->before(); |
1312 $this->skin->before(); |
866 $this->skin->set_result(false); |
1313 $this->skin->set_result(false); |
867 $this->skin->error('up_to_date'); |
1314 $this->skin->error( 'up_to_date' ); |
868 $this->skin->after(); |
1315 $this->skin->after(); |
869 return false; |
1316 return false; |
870 } |
1317 } |
871 |
1318 |
872 $r = $current->response[ $theme ]; |
1319 $r = $current->response[ $theme ]; |
897 wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); |
1344 wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); |
898 |
1345 |
899 return true; |
1346 return true; |
900 } |
1347 } |
901 |
1348 |
902 function bulk_upgrade( $themes, $args = array() ) { |
1349 /** |
1350 * Upgrade several themes at once. |
|
1351 * |
|
1352 * @since 3.0.0 |
|
1353 * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional. |
|
1354 * |
|
1355 * @param array $themes The theme slugs. |
|
1356 * @param array $args { |
|
1357 * Optional. Other arguments for upgrading several themes at once. Default empty array. |
|
1358 * |
|
1359 * @type bool $clear_update_cache Whether to clear the update cache if successful. |
|
1360 * Default true. |
|
1361 * } |
|
1362 * @return array[]|false An array of results, or false if unable to connect to the filesystem. |
|
1363 */ |
|
1364 public function bulk_upgrade( $themes, $args = array() ) { |
|
903 |
1365 |
904 $defaults = array( |
1366 $defaults = array( |
905 'clear_update_cache' => true, |
1367 'clear_update_cache' => true, |
906 ); |
1368 ); |
907 $parsed_args = wp_parse_args( $args, $defaults ); |
1369 $parsed_args = wp_parse_args( $args, $defaults ); |
947 $this->skin->theme_info = $this->theme_info($theme); |
1409 $this->skin->theme_info = $this->theme_info($theme); |
948 |
1410 |
949 if ( !isset( $current->response[ $theme ] ) ) { |
1411 if ( !isset( $current->response[ $theme ] ) ) { |
950 $this->skin->set_result(true); |
1412 $this->skin->set_result(true); |
951 $this->skin->before(); |
1413 $this->skin->before(); |
952 $this->skin->feedback('up_to_date'); |
1414 $this->skin->feedback( 'up_to_date' ); |
953 $this->skin->after(); |
1415 $this->skin->after(); |
954 $results[$theme] = true; |
1416 $results[$theme] = true; |
955 continue; |
1417 continue; |
956 } |
1418 } |
957 |
1419 |
961 $result = $this->run( array( |
1423 $result = $this->run( array( |
962 'package' => $r['package'], |
1424 'package' => $r['package'], |
963 'destination' => get_theme_root( $theme ), |
1425 'destination' => get_theme_root( $theme ), |
964 'clear_destination' => true, |
1426 'clear_destination' => true, |
965 'clear_working' => true, |
1427 'clear_working' => true, |
1428 'is_multi' => true, |
|
966 'hook_extra' => array( |
1429 'hook_extra' => array( |
967 'theme' => $theme |
1430 'theme' => $theme |
968 ), |
1431 ), |
969 ) ); |
1432 ) ); |
970 |
1433 |
975 break; |
1438 break; |
976 } //end foreach $plugins |
1439 } //end foreach $plugins |
977 |
1440 |
978 $this->maintenance_mode(false); |
1441 $this->maintenance_mode(false); |
979 |
1442 |
1443 /** This action is documented in wp-admin/includes/class-wp-upgrader.php */ |
|
980 do_action( 'upgrader_process_complete', $this, array( |
1444 do_action( 'upgrader_process_complete', $this, array( |
981 'action' => 'update', |
1445 'action' => 'update', |
982 'type' => 'plugin', |
1446 'type' => 'theme', |
983 'bulk' => true, |
1447 'bulk' => true, |
984 'themes' => $themes, |
1448 'themes' => $themes, |
985 ) ); |
1449 ) ); |
986 |
1450 |
987 $this->skin->bulk_footer(); |
1451 $this->skin->bulk_footer(); |
997 wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); |
1461 wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); |
998 |
1462 |
999 return $results; |
1463 return $results; |
1000 } |
1464 } |
1001 |
1465 |
1002 function check_package($source) { |
1466 /** |
1467 * Check that the package source contains a valid theme. |
|
1468 * |
|
1469 * Hooked to the {@see 'upgrader_source_selection'} filter by {@see Theme_Upgrader::install()}. |
|
1470 * It will return an error if the theme doesn't have style.css or index.php |
|
1471 * files. |
|
1472 * |
|
1473 * @since 3.3.0 |
|
1474 * |
|
1475 * @param string $source The full path to the package source. |
|
1476 * @return string|WP_Error The source or a WP_Error. |
|
1477 */ |
|
1478 public function check_package( $source ) { |
|
1003 global $wp_filesystem; |
1479 global $wp_filesystem; |
1004 |
1480 |
1005 if ( is_wp_error($source) ) |
1481 if ( is_wp_error($source) ) |
1006 return $source; |
1482 return $source; |
1007 |
1483 |
1008 // Check the folder contains a valid theme |
1484 // Check the folder contains a valid theme |
1009 $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source); |
1485 $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source); |
1010 if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, lets not prevent installation. |
1486 if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, let's not prevent installation. |
1011 return $source; |
1487 return $source; |
1012 |
1488 |
1013 // A proper archive should have a style.css file in the single subdirectory |
1489 // A proper archive should have a style.css file in the single subdirectory |
1014 if ( ! file_exists( $working_directory . 'style.css' ) ) |
1490 if ( ! file_exists( $working_directory . 'style.css' ) ) |
1015 return new WP_Error( 'incompatible_archive_theme_no_style', $this->strings['incompatible_archive'], __( 'The theme is missing the <code>style.css</code> stylesheet.' ) ); |
1491 return new WP_Error( 'incompatible_archive_theme_no_style', $this->strings['incompatible_archive'], __( 'The theme is missing the <code>style.css</code> stylesheet.' ) ); |
1024 return new WP_Error( 'incompatible_archive_theme_no_index', $this->strings['incompatible_archive'], __( 'The theme is missing the <code>index.php</code> file.' ) ); |
1500 return new WP_Error( 'incompatible_archive_theme_no_index', $this->strings['incompatible_archive'], __( 'The theme is missing the <code>index.php</code> file.' ) ); |
1025 |
1501 |
1026 return $source; |
1502 return $source; |
1027 } |
1503 } |
1028 |
1504 |
1029 function current_before($return, $theme) { |
1505 /** |
1506 * Turn on maintenance mode before attempting to upgrade the current theme. |
|
1507 * |
|
1508 * Hooked to the {@see 'upgrader_pre_install'} filter by {@see Theme_Upgrader::upgrade()} and |
|
1509 * {@see Theme_Upgrader::bulk_upgrade()}. |
|
1510 * |
|
1511 * @since 2.8.0 |
|
1512 */ |
|
1513 public function current_before($return, $theme) { |
|
1030 |
1514 |
1031 if ( is_wp_error($return) ) |
1515 if ( is_wp_error($return) ) |
1032 return $return; |
1516 return $return; |
1033 |
1517 |
1034 $theme = isset($theme['theme']) ? $theme['theme'] : ''; |
1518 $theme = isset($theme['theme']) ? $theme['theme'] : ''; |
1040 $this->maintenance_mode(true); |
1524 $this->maintenance_mode(true); |
1041 |
1525 |
1042 return $return; |
1526 return $return; |
1043 } |
1527 } |
1044 |
1528 |
1045 function current_after($return, $theme) { |
1529 /** |
1530 * Turn off maintenance mode after upgrading the current theme. |
|
1531 * |
|
1532 * Hooked to the {@see 'upgrader_post_install'} filter by {@see Theme_Upgrader::upgrade()} |
|
1533 * and {@see Theme_Upgrader::bulk_upgrade()}. |
|
1534 * |
|
1535 * @since 2.8.0 |
|
1536 */ |
|
1537 public function current_after($return, $theme) { |
|
1046 if ( is_wp_error($return) ) |
1538 if ( is_wp_error($return) ) |
1047 return $return; |
1539 return $return; |
1048 |
1540 |
1049 $theme = isset($theme['theme']) ? $theme['theme'] : ''; |
1541 $theme = isset($theme['theme']) ? $theme['theme'] : ''; |
1050 |
1542 |
1062 if ( ! $this->bulk ) |
1554 if ( ! $this->bulk ) |
1063 $this->maintenance_mode(false); |
1555 $this->maintenance_mode(false); |
1064 return $return; |
1556 return $return; |
1065 } |
1557 } |
1066 |
1558 |
1067 function delete_old_theme( $removed, $local_destination, $remote_destination, $theme ) { |
1559 /** |
1560 * Delete the old theme during an upgrade. |
|
1561 * |
|
1562 * Hooked to the {@see 'upgrader_clear_destination'} filter by {@see Theme_Upgrader::upgrade()} |
|
1563 * and {@see Theme_Upgrader::bulk_upgrade()}. |
|
1564 * |
|
1565 * @since 2.8.0 |
|
1566 */ |
|
1567 public function delete_old_theme( $removed, $local_destination, $remote_destination, $theme ) { |
|
1068 global $wp_filesystem; |
1568 global $wp_filesystem; |
1069 |
1569 |
1070 if ( is_wp_error( $removed ) ) |
1570 if ( is_wp_error( $removed ) ) |
1071 return $removed; // Pass errors through. |
1571 return $removed; // Pass errors through. |
1072 |
1572 |
1081 } |
1581 } |
1082 |
1582 |
1083 return true; |
1583 return true; |
1084 } |
1584 } |
1085 |
1585 |
1086 function theme_info($theme = null) { |
1586 /** |
1587 * Get the WP_Theme object for a theme. |
|
1588 * |
|
1589 * @since 2.8.0 |
|
1590 * @since 3.0.0 The `$theme` argument was added. |
|
1591 * |
|
1592 * @param string $theme The directory name of the theme. This is optional, and if not supplied, |
|
1593 * the directory name from the last result will be used. |
|
1594 * @return WP_Theme|false The theme's info object, or false `$theme` is not supplied |
|
1595 * and the last result isn't set. |
|
1596 */ |
|
1597 public function theme_info($theme = null) { |
|
1087 |
1598 |
1088 if ( empty($theme) ) { |
1599 if ( empty($theme) ) { |
1089 if ( !empty($this->result['destination_name']) ) |
1600 if ( !empty($this->result['destination_name']) ) |
1090 $theme = $this->result['destination_name']; |
1601 $theme = $this->result['destination_name']; |
1091 else |
1602 else |
1105 * @subpackage Upgrader |
1616 * @subpackage Upgrader |
1106 * @since 3.7.0 |
1617 * @since 3.7.0 |
1107 */ |
1618 */ |
1108 class Language_Pack_Upgrader extends WP_Upgrader { |
1619 class Language_Pack_Upgrader extends WP_Upgrader { |
1109 |
1620 |
1110 var $result; |
1621 /** |
1111 var $bulk = true; |
1622 * Result of the language pack upgrade. |
1112 |
1623 * |
1113 static function async_upgrade( $upgrader = false ) { |
1624 * @since 3.7.0 |
1625 * @var array|WP_Error $result |
|
1626 * @see WP_Upgrader::$result |
|
1627 */ |
|
1628 public $result; |
|
1629 |
|
1630 /** |
|
1631 * Whether a bulk upgrade/install is being performed. |
|
1632 * |
|
1633 * @since 3.7.0 |
|
1634 * @var bool $bulk |
|
1635 */ |
|
1636 public $bulk = true; |
|
1637 |
|
1638 /** |
|
1639 * Asynchronously upgrade language packs after other upgrades have been made. |
|
1640 * |
|
1641 * Hooked to the {@see 'upgrader_process_complete'} action by default. |
|
1642 * |
|
1643 * @since 3.7.0 |
|
1644 */ |
|
1645 public static function async_upgrade( $upgrader = false ) { |
|
1114 // Avoid recursion. |
1646 // Avoid recursion. |
1115 if ( $upgrader && $upgrader instanceof Language_Pack_Upgrader ) |
1647 if ( $upgrader && $upgrader instanceof Language_Pack_Upgrader ) { |
1116 return; |
1648 return; |
1649 } |
|
1117 |
1650 |
1118 // Nothing to do? |
1651 // Nothing to do? |
1119 $language_updates = wp_get_translation_updates(); |
1652 $language_updates = wp_get_translation_updates(); |
1120 if ( ! $language_updates ) |
1653 if ( ! $language_updates ) { |
1121 return; |
1654 return; |
1655 } |
|
1656 |
|
1657 // Avoid messing with VCS installs, at least for now. |
|
1658 // Noted: this is not the ideal way to accomplish this. |
|
1659 $check_vcs = new WP_Automatic_Updater; |
|
1660 if ( $check_vcs->is_vcs_checkout( WP_CONTENT_DIR ) ) { |
|
1661 return; |
|
1662 } |
|
1663 |
|
1664 foreach ( $language_updates as $key => $language_update ) { |
|
1665 $update = ! empty( $language_update->autoupdate ); |
|
1666 |
|
1667 /** |
|
1668 * Filter whether to asynchronously update translation for core, a plugin, or a theme. |
|
1669 * |
|
1670 * @since 4.0.0 |
|
1671 * |
|
1672 * @param bool $update Whether to update. |
|
1673 * @param object $language_update The update offer. |
|
1674 */ |
|
1675 $update = apply_filters( 'async_update_translation', $update, $language_update ); |
|
1676 |
|
1677 if ( ! $update ) { |
|
1678 unset( $language_updates[ $key ] ); |
|
1679 } |
|
1680 } |
|
1681 |
|
1682 if ( empty( $language_updates ) ) { |
|
1683 return; |
|
1684 } |
|
1122 |
1685 |
1123 $skin = new Language_Pack_Upgrader_Skin( array( |
1686 $skin = new Language_Pack_Upgrader_Skin( array( |
1124 'skip_header_footer' => true, |
1687 'skip_header_footer' => true, |
1125 ) ); |
1688 ) ); |
1126 |
1689 |
1127 $lp_upgrader = new Language_Pack_Upgrader( $skin ); |
1690 $lp_upgrader = new Language_Pack_Upgrader( $skin ); |
1128 $lp_upgrader->upgrade(); |
1691 $lp_upgrader->bulk_upgrade( $language_updates ); |
1129 } |
1692 } |
1130 |
1693 |
1131 function upgrade_strings() { |
1694 /** |
1695 * Initialize the upgrade strings. |
|
1696 * |
|
1697 * @since 3.7.0 |
|
1698 */ |
|
1699 public function upgrade_strings() { |
|
1132 $this->strings['starting_upgrade'] = __( 'Some of your translations need updating. Sit tight for a few more seconds while we update them as well.' ); |
1700 $this->strings['starting_upgrade'] = __( 'Some of your translations need updating. Sit tight for a few more seconds while we update them as well.' ); |
1133 $this->strings['up_to_date'] = __( 'The translation is up to date.' ); // We need to silently skip this case |
1701 $this->strings['up_to_date'] = __( 'The translation is up to date.' ); // We need to silently skip this case |
1134 $this->strings['no_package'] = __( 'Update package not available.' ); |
1702 $this->strings['no_package'] = __( 'Update package not available.' ); |
1135 $this->strings['downloading_package'] = __( 'Downloading translation from <span class="code">%s</span>…' ); |
1703 $this->strings['downloading_package'] = __( 'Downloading translation from <span class="code">%s</span>…' ); |
1136 $this->strings['unpack_package'] = __( 'Unpacking the update…' ); |
1704 $this->strings['unpack_package'] = __( 'Unpacking the update…' ); |
1137 $this->strings['process_failed'] = __( 'Translation update failed.' ); |
1705 $this->strings['process_failed'] = __( 'Translation update failed.' ); |
1138 $this->strings['process_success'] = __( 'Translation updated successfully.' ); |
1706 $this->strings['process_success'] = __( 'Translation updated successfully.' ); |
1139 } |
1707 } |
1140 |
1708 |
1141 function upgrade( $update = false, $args = array() ) { |
1709 /** |
1142 if ( $update ) |
1710 * Upgrade a language pack. |
1711 * |
|
1712 * @since 3.7.0 |
|
1713 * |
|
1714 * @param string|false $update Optional. Whether an update offer is available. Default false. |
|
1715 * @param array $args Optional. Other optional arguments, see |
|
1716 * {@see Language_Pack_Upgrader::bulk_upgrade()}. Default empty array. |
|
1717 * @return array|WP_Error The result of the upgrade, or a {@see wP_Error} object instead. |
|
1718 */ |
|
1719 public function upgrade( $update = false, $args = array() ) { |
|
1720 if ( $update ) { |
|
1143 $update = array( $update ); |
1721 $update = array( $update ); |
1722 } |
|
1723 |
|
1144 $results = $this->bulk_upgrade( $update, $args ); |
1724 $results = $this->bulk_upgrade( $update, $args ); |
1725 |
|
1726 if ( ! is_array( $results ) ) { |
|
1727 return $results; |
|
1728 } |
|
1729 |
|
1145 return $results[0]; |
1730 return $results[0]; |
1146 } |
1731 } |
1147 |
1732 |
1148 function bulk_upgrade( $language_updates = array(), $args = array() ) { |
1733 /** |
1734 * Bulk upgrade language packs. |
|
1735 * |
|
1736 * @since 3.7.0 |
|
1737 * |
|
1738 * @param array $language_updates Optional. Language pack updates. Default empty array. |
|
1739 * @param array $args { |
|
1740 * Optional. Other arguments for upgrading multiple language packs. Default empty array |
|
1741 * |
|
1742 * @type bool $clear_update_cache Whether to clear the update cache when done. |
|
1743 * Default true. |
|
1744 * } |
|
1745 * @return array|true|false|WP_Error Will return an array of results, or true if there are no updates, |
|
1746 * false or WP_Error for initial errors. |
|
1747 */ |
|
1748 public function bulk_upgrade( $language_updates = array(), $args = array() ) { |
|
1149 global $wp_filesystem; |
1749 global $wp_filesystem; |
1150 |
1750 |
1151 $defaults = array( |
1751 $defaults = array( |
1152 'clear_update_cache' => true, |
1752 'clear_update_cache' => true, |
1153 ); |
1753 ); |
1171 } |
1771 } |
1172 |
1772 |
1173 if ( 'upgrader_process_complete' == current_filter() ) |
1773 if ( 'upgrader_process_complete' == current_filter() ) |
1174 $this->skin->feedback( 'starting_upgrade' ); |
1774 $this->skin->feedback( 'starting_upgrade' ); |
1175 |
1775 |
1176 add_filter( 'upgrader_source_selection', array( &$this, 'check_package' ), 10, 3 ); |
1776 // Remove any existing upgrade filters from the plugin/theme upgraders #WP29425 & #WP29230 |
1777 remove_all_filters( 'upgrader_pre_install' ); |
|
1778 remove_all_filters( 'upgrader_clear_destination' ); |
|
1779 remove_all_filterS( 'upgrader_post_install' ); |
|
1780 remove_all_filters( 'upgrader_source_selection' ); |
|
1781 |
|
1782 add_filter( 'upgrader_source_selection', array( $this, 'check_package' ), 10, 2 ); |
|
1177 |
1783 |
1178 $this->skin->header(); |
1784 $this->skin->header(); |
1179 |
1785 |
1180 // Connect to the Filesystem first. |
1786 // Connect to the Filesystem first. |
1181 $res = $this->fs_connect( array( WP_CONTENT_DIR, WP_LANG_DIR ) ); |
1787 $res = $this->fs_connect( array( WP_CONTENT_DIR, WP_LANG_DIR ) ); |
1187 $results = array(); |
1793 $results = array(); |
1188 |
1794 |
1189 $this->update_count = count( $language_updates ); |
1795 $this->update_count = count( $language_updates ); |
1190 $this->update_current = 0; |
1796 $this->update_current = 0; |
1191 |
1797 |
1192 // The filesystem's mkdir() is not recursive. Make sure WP_LANG_DIR exists, |
1798 /* |
1193 // as we then may need to create a /plugins or /themes directory inside of it. |
1799 * The filesystem's mkdir() is not recursive. Make sure WP_LANG_DIR exists, |
1800 * as we then may need to create a /plugins or /themes directory inside of it. |
|
1801 */ |
|
1194 $remote_destination = $wp_filesystem->find_folder( WP_LANG_DIR ); |
1802 $remote_destination = $wp_filesystem->find_folder( WP_LANG_DIR ); |
1195 if ( ! $wp_filesystem->exists( $remote_destination ) ) |
1803 if ( ! $wp_filesystem->exists( $remote_destination ) ) |
1196 if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) ) |
1804 if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) ) |
1197 return new WP_Error( 'mkdir_failed_lang_dir', $this->strings['mkdir_failed'], $remote_destination ); |
1805 return new WP_Error( 'mkdir_failed_lang_dir', $this->strings['mkdir_failed'], $remote_destination ); |
1198 |
1806 |
1233 $this->skin->bulk_footer(); |
1841 $this->skin->bulk_footer(); |
1234 |
1842 |
1235 $this->skin->footer(); |
1843 $this->skin->footer(); |
1236 |
1844 |
1237 // Clean up our hooks, in case something else does an upgrade on this connection. |
1845 // Clean up our hooks, in case something else does an upgrade on this connection. |
1238 remove_filter( 'upgrader_source_selection', array( &$this, 'check_package' ), 10, 2 ); |
1846 remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); |
1239 |
1847 |
1240 if ( $parsed_args['clear_update_cache'] ) { |
1848 if ( $parsed_args['clear_update_cache'] ) { |
1241 wp_clean_themes_cache( true ); |
1849 wp_clean_update_cache(); |
1242 wp_clean_plugins_cache( true ); |
|
1243 delete_site_transient( 'update_core' ); |
|
1244 } |
1850 } |
1245 |
1851 |
1246 return $results; |
1852 return $results; |
1247 } |
1853 } |
1248 |
1854 |
1249 function check_package( $source, $remote_source ) { |
1855 /** |
1856 * Check the package source to make sure there are .mo and .po files. |
|
1857 * |
|
1858 * Hooked to the {@see 'upgrader_source_selection'} filter by |
|
1859 * {@see Language_Pack_Upgrader::bulk_upgrade()}. |
|
1860 * |
|
1861 * @since 3.7.0 |
|
1862 */ |
|
1863 public function check_package( $source, $remote_source ) { |
|
1250 global $wp_filesystem; |
1864 global $wp_filesystem; |
1251 |
1865 |
1252 if ( is_wp_error( $source ) ) |
1866 if ( is_wp_error( $source ) ) |
1253 return $source; |
1867 return $source; |
1254 |
1868 |
1269 __( 'The language pack is missing either the <code>.po</code> or <code>.mo</code> files.' ) ); |
1883 __( 'The language pack is missing either the <code>.po</code> or <code>.mo</code> files.' ) ); |
1270 |
1884 |
1271 return $source; |
1885 return $source; |
1272 } |
1886 } |
1273 |
1887 |
1274 function get_name_for_update( $update ) { |
1888 /** |
1889 * Get the name of an item being updated. |
|
1890 * |
|
1891 * @since 3.7.0 |
|
1892 * |
|
1893 * @param object The data for an update. |
|
1894 * @return string The name of the item being updated. |
|
1895 */ |
|
1896 public function get_name_for_update( $update ) { |
|
1275 switch ( $update->type ) { |
1897 switch ( $update->type ) { |
1276 case 'core': |
1898 case 'core': |
1277 return 'WordPress'; // Not translated |
1899 return 'WordPress'; // Not translated |
1278 break; |
1900 |
1279 case 'theme': |
1901 case 'theme': |
1280 $theme = wp_get_theme( $update->slug ); |
1902 $theme = wp_get_theme( $update->slug ); |
1281 if ( $theme->exists() ) |
1903 if ( $theme->exists() ) |
1282 return $theme->Get( 'Name' ); |
1904 return $theme->Get( 'Name' ); |
1283 break; |
1905 break; |
1284 case 'plugin': |
1906 case 'plugin': |
1285 $plugin_data = get_plugins( '/' . $update->slug ); |
1907 $plugin_data = get_plugins( '/' . $update->slug ); |
1286 $plugin_data = array_shift( $plugin_data ); |
1908 $plugin_data = reset( $plugin_data ); |
1287 if ( $plugin_data ) |
1909 if ( $plugin_data ) |
1288 return $plugin_data['Name']; |
1910 return $plugin_data['Name']; |
1289 break; |
1911 break; |
1290 } |
1912 } |
1291 return ''; |
1913 return ''; |
1300 * @subpackage Upgrader |
1922 * @subpackage Upgrader |
1301 * @since 2.8.0 |
1923 * @since 2.8.0 |
1302 */ |
1924 */ |
1303 class Core_Upgrader extends WP_Upgrader { |
1925 class Core_Upgrader extends WP_Upgrader { |
1304 |
1926 |
1305 function upgrade_strings() { |
1927 /** |
1928 * Initialize the upgrade strings. |
|
1929 * |
|
1930 * @since 2.8.0 |
|
1931 */ |
|
1932 public function upgrade_strings() { |
|
1306 $this->strings['up_to_date'] = __('WordPress is at the latest version.'); |
1933 $this->strings['up_to_date'] = __('WordPress is at the latest version.'); |
1307 $this->strings['no_package'] = __('Update package not available.'); |
1934 $this->strings['no_package'] = __('Update package not available.'); |
1308 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>…'); |
1935 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>…'); |
1309 $this->strings['unpack_package'] = __('Unpacking the update…'); |
1936 $this->strings['unpack_package'] = __('Unpacking the update…'); |
1310 $this->strings['copy_failed'] = __('Could not copy files.'); |
1937 $this->strings['copy_failed'] = __('Could not copy files.'); |
1311 $this->strings['copy_failed_space'] = __('Could not copy files. You may have run out of disk space.' ); |
1938 $this->strings['copy_failed_space'] = __('Could not copy files. You may have run out of disk space.' ); |
1312 $this->strings['start_rollback'] = __( 'Attempting to roll back to previous version.' ); |
1939 $this->strings['start_rollback'] = __( 'Attempting to roll back to previous version.' ); |
1313 $this->strings['rollback_was_required'] = __( 'Due to an error during updating, WordPress has rolled back to your previous version.' ); |
1940 $this->strings['rollback_was_required'] = __( 'Due to an error during updating, WordPress has rolled back to your previous version.' ); |
1314 } |
1941 } |
1315 |
1942 |
1316 function upgrade( $current, $args = array() ) { |
1943 /** |
1317 global $wp_filesystem, $wp_version; |
1944 * Upgrade WordPress core. |
1945 * |
|
1946 * @since 2.8.0 |
|
1947 * |
|
1948 * @param object $current Response object for whether WordPress is current. |
|
1949 * @param array $args { |
|
1950 * Optional. Arguments for upgrading WordPress core. Default empty array. |
|
1951 * |
|
1952 * @type bool $pre_check_md5 Whether to check the file checksums before |
|
1953 * attempting the upgrade. Default true. |
|
1954 * @type bool $attempt_rollback Whether to attempt to rollback the chances if |
|
1955 * there is a problem. Default false. |
|
1956 * @type bool $do_rollback Whether to perform this "upgrade" as a rollback. |
|
1957 * Default false. |
|
1958 * } |
|
1959 * @return null|false|WP_Error False or WP_Error on failure, null on success. |
|
1960 */ |
|
1961 public function upgrade( $current, $args = array() ) { |
|
1962 global $wp_filesystem; |
|
1963 |
|
1964 include( ABSPATH . WPINC . '/version.php' ); // $wp_version; |
|
1318 |
1965 |
1319 $start_time = time(); |
1966 $start_time = time(); |
1320 |
1967 |
1321 $defaults = array( |
1968 $defaults = array( |
1322 'pre_check_md5' => true, |
1969 'pre_check_md5' => true, |
1323 'attempt_rollback' => false, |
1970 'attempt_rollback' => false, |
1324 'do_rollback' => false, |
1971 'do_rollback' => false, |
1972 'allow_relaxed_file_ownership' => false, |
|
1325 ); |
1973 ); |
1326 $parsed_args = wp_parse_args( $args, $defaults ); |
1974 $parsed_args = wp_parse_args( $args, $defaults ); |
1327 |
1975 |
1328 $this->init(); |
1976 $this->init(); |
1329 $this->upgrade_strings(); |
1977 $this->upgrade_strings(); |
1330 |
1978 |
1331 // Is an update available? |
1979 // Is an update available? |
1332 if ( !isset( $current->response ) || $current->response == 'latest' ) |
1980 if ( !isset( $current->response ) || $current->response == 'latest' ) |
1333 return new WP_Error('up_to_date', $this->strings['up_to_date']); |
1981 return new WP_Error('up_to_date', $this->strings['up_to_date']); |
1334 |
1982 |
1335 $res = $this->fs_connect( array(ABSPATH, WP_CONTENT_DIR) ); |
1983 $res = $this->fs_connect( array( ABSPATH, WP_CONTENT_DIR ), $parsed_args['allow_relaxed_file_ownership'] ); |
1336 if ( is_wp_error($res) ) |
1984 if ( ! $res || is_wp_error( $res ) ) { |
1337 return $res; |
1985 return $res; |
1986 } |
|
1338 |
1987 |
1339 $wp_dir = trailingslashit($wp_filesystem->abspath()); |
1988 $wp_dir = trailingslashit($wp_filesystem->abspath()); |
1340 |
1989 |
1341 $partial = true; |
1990 $partial = true; |
1342 if ( $parsed_args['do_rollback'] ) |
1991 if ( $parsed_args['do_rollback'] ) |
1343 $partial = false; |
1992 $partial = false; |
1344 elseif ( $parsed_args['pre_check_md5'] && ! $this->check_files() ) |
1993 elseif ( $parsed_args['pre_check_md5'] && ! $this->check_files() ) |
1345 $partial = false; |
1994 $partial = false; |
1346 |
1995 |
1347 // If partial update is returned from the API, use that, unless we're doing a reinstall. |
1996 /* |
1348 // If we cross the new_bundled version number, then use the new_bundled zip. |
1997 * If partial update is returned from the API, use that, unless we're doing |
1349 // Don't though if the constant is set to skip bundled items. |
1998 * a reinstall. If we cross the new_bundled version number, then use |
1350 // If the API returns a no_content zip, go with it. Finally, default to the full zip. |
1999 * the new_bundled zip. Don't though if the constant is set to skip bundled items. |
2000 * If the API returns a no_content zip, go with it. Finally, default to the full zip. |
|
2001 */ |
|
1351 if ( $parsed_args['do_rollback'] && $current->packages->rollback ) |
2002 if ( $parsed_args['do_rollback'] && $current->packages->rollback ) |
1352 $to_download = 'rollback'; |
2003 $to_download = 'rollback'; |
1353 elseif ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version && $partial ) |
2004 elseif ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version && $partial ) |
1354 $to_download = 'partial'; |
2005 $to_download = 'partial'; |
1355 elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '<' ) |
2006 elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '<' ) |
1385 // In the event of an issue, we may be able to roll back. |
2036 // In the event of an issue, we may be able to roll back. |
1386 if ( $parsed_args['attempt_rollback'] && $current->packages->rollback && ! $parsed_args['do_rollback'] ) { |
2037 if ( $parsed_args['attempt_rollback'] && $current->packages->rollback && ! $parsed_args['do_rollback'] ) { |
1387 $try_rollback = false; |
2038 $try_rollback = false; |
1388 if ( is_wp_error( $result ) ) { |
2039 if ( is_wp_error( $result ) ) { |
1389 $error_code = $result->get_error_code(); |
2040 $error_code = $result->get_error_code(); |
1390 // Not all errors are equal. These codes are critical: copy_failed__copy_dir, |
2041 /* |
1391 // mkdir_failed__copy_dir, copy_failed__copy_dir_retry, and disk_full. |
2042 * Not all errors are equal. These codes are critical: copy_failed__copy_dir, |
1392 // do_rollback allows for update_core() to trigger a rollback if needed. |
2043 * mkdir_failed__copy_dir, copy_failed__copy_dir_retry, and disk_full. |
2044 * do_rollback allows for update_core() to trigger a rollback if needed. |
|
2045 */ |
|
1393 if ( false !== strpos( $error_code, 'do_rollback' ) ) |
2046 if ( false !== strpos( $error_code, 'do_rollback' ) ) |
1394 $try_rollback = true; |
2047 $try_rollback = true; |
1395 elseif ( false !== strpos( $error_code, '__copy_dir' ) ) |
2048 elseif ( false !== strpos( $error_code, '__copy_dir' ) ) |
1396 $try_rollback = true; |
2049 $try_rollback = true; |
1397 elseif ( 'disk_full' === $error_code ) |
2050 elseif ( 'disk_full' === $error_code ) |
1398 $try_rollback = true; |
2051 $try_rollback = true; |
1399 } |
2052 } |
1400 |
2053 |
1401 if ( $try_rollback ) { |
2054 if ( $try_rollback ) { |
2055 /** This filter is documented in wp-admin/includes/update-core.php */ |
|
1402 apply_filters( 'update_feedback', $result ); |
2056 apply_filters( 'update_feedback', $result ); |
2057 |
|
2058 /** This filter is documented in wp-admin/includes/update-core.php */ |
|
1403 apply_filters( 'update_feedback', $this->strings['start_rollback'] ); |
2059 apply_filters( 'update_feedback', $this->strings['start_rollback'] ); |
1404 |
2060 |
1405 $rollback_result = $this->upgrade( $current, array_merge( $parsed_args, array( 'do_rollback' => true ) ) ); |
2061 $rollback_result = $this->upgrade( $current, array_merge( $parsed_args, array( 'do_rollback' => true ) ) ); |
1406 |
2062 |
1407 $original_result = $result; |
2063 $original_result = $result; |
1408 $result = new WP_Error( 'rollback_was_required', $this->strings['rollback_was_required'], (object) array( 'update' => $original_result, 'rollback' => $rollback_result ) ); |
2064 $result = new WP_Error( 'rollback_was_required', $this->strings['rollback_was_required'], (object) array( 'update' => $original_result, 'rollback' => $rollback_result ) ); |
1409 } |
2065 } |
1410 } |
2066 } |
1411 |
2067 |
2068 /** This action is documented in wp-admin/includes/class-wp-upgrader.php */ |
|
1412 do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'core' ) ); |
2069 do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'core' ) ); |
1413 |
2070 |
1414 // Clear the current updates |
2071 // Clear the current updates |
1415 delete_site_transient( 'update_core' ); |
2072 delete_site_transient( 'update_core' ); |
1416 |
2073 |
1418 $stats = array( |
2075 $stats = array( |
1419 'update_type' => $current->response, |
2076 'update_type' => $current->response, |
1420 'success' => true, |
2077 'success' => true, |
1421 'fs_method' => $wp_filesystem->method, |
2078 'fs_method' => $wp_filesystem->method, |
1422 'fs_method_forced' => defined( 'FS_METHOD' ) || has_filter( 'filesystem_method' ), |
2079 'fs_method_forced' => defined( 'FS_METHOD' ) || has_filter( 'filesystem_method' ), |
2080 'fs_method_direct' => !empty( $GLOBALS['_wp_filesystem_direct_method'] ) ? $GLOBALS['_wp_filesystem_direct_method'] : '', |
|
1423 'time_taken' => time() - $start_time, |
2081 'time_taken' => time() - $start_time, |
2082 'reported' => $wp_version, |
|
1424 'attempted' => $current->version, |
2083 'attempted' => $current->version, |
1425 ); |
2084 ); |
1426 |
2085 |
1427 if ( is_wp_error( $result ) ) { |
2086 if ( is_wp_error( $result ) ) { |
1428 $stats['success'] = false; |
2087 $stats['success'] = false; |
1446 } |
2105 } |
1447 |
2106 |
1448 return $result; |
2107 return $result; |
1449 } |
2108 } |
1450 |
2109 |
1451 // Determines if this WordPress Core version should update to $offered_ver or not |
2110 /** |
1452 static function should_update_to_version( $offered_ver /* x.y.z */ ) { |
2111 * Determines if this WordPress Core version should update to an offered version or not. |
1453 include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z |
2112 * |
2113 * @since 3.7.0 |
|
2114 * |
|
2115 * @param string $offered_ver The offered version, of the format x.y.z. |
|
2116 * @return bool True if we should update to the offered version, otherwise false. |
|
2117 */ |
|
2118 public static function should_update_to_version( $offered_ver ) { |
|
2119 include( ABSPATH . WPINC . '/version.php' ); // $wp_version; // x.y.z |
|
1454 |
2120 |
1455 $current_branch = implode( '.', array_slice( preg_split( '/[.-]/', $wp_version ), 0, 2 ) ); // x.y |
2121 $current_branch = implode( '.', array_slice( preg_split( '/[.-]/', $wp_version ), 0, 2 ) ); // x.y |
1456 $new_branch = implode( '.', array_slice( preg_split( '/[.-]/', $offered_ver ), 0, 2 ) ); // x.y |
2122 $new_branch = implode( '.', array_slice( preg_split( '/[.-]/', $offered_ver ), 0, 2 ) ); // x.y |
1457 $current_is_development_version = (bool) strpos( $wp_version, '-' ); |
2123 $current_is_development_version = (bool) strpos( $wp_version, '-' ); |
1458 |
2124 |
1501 return false; |
2167 return false; |
1502 } |
2168 } |
1503 |
2169 |
1504 // 3: 3.7-alpha-25000 -> 3.7-alpha-25678 -> 3.7-beta1 -> 3.7-beta2 |
2170 // 3: 3.7-alpha-25000 -> 3.7-alpha-25678 -> 3.7-beta1 -> 3.7-beta2 |
1505 if ( $current_is_development_version ) { |
2171 if ( $current_is_development_version ) { |
2172 |
|
2173 /** |
|
2174 * Filter whether to enable automatic core updates for development versions. |
|
2175 * |
|
2176 * @since 3.7.0 |
|
2177 * |
|
2178 * @param bool $upgrade_dev Whether to enable automatic updates for |
|
2179 * development versions. |
|
2180 */ |
|
1506 if ( ! apply_filters( 'allow_dev_auto_core_updates', $upgrade_dev ) ) |
2181 if ( ! apply_filters( 'allow_dev_auto_core_updates', $upgrade_dev ) ) |
1507 return false; |
2182 return false; |
1508 // else fall through to minor + major branches below |
2183 // Else fall through to minor + major branches below. |
1509 } |
2184 } |
1510 |
2185 |
1511 // 4: Minor In-branch updates (3.7.0 -> 3.7.1 -> 3.7.2 -> 3.7.4) |
2186 // 4: Minor In-branch updates (3.7.0 -> 3.7.1 -> 3.7.2 -> 3.7.4) |
1512 if ( $current_branch == $new_branch ) |
2187 if ( $current_branch == $new_branch ) { |
2188 |
|
2189 /** |
|
2190 * Filter whether to enable minor automatic core updates. |
|
2191 * |
|
2192 * @since 3.7.0 |
|
2193 * |
|
2194 * @param bool $upgrade_minor Whether to enable minor automatic core updates. |
|
2195 */ |
|
1513 return apply_filters( 'allow_minor_auto_core_updates', $upgrade_minor ); |
2196 return apply_filters( 'allow_minor_auto_core_updates', $upgrade_minor ); |
2197 } |
|
1514 |
2198 |
1515 // 5: Major version updates (3.7.0 -> 3.8.0 -> 3.9.1) |
2199 // 5: Major version updates (3.7.0 -> 3.8.0 -> 3.9.1) |
1516 if ( version_compare( $new_branch, $current_branch, '>' ) ) |
2200 if ( version_compare( $new_branch, $current_branch, '>' ) ) { |
2201 |
|
2202 /** |
|
2203 * Filter whether to enable major automatic core updates. |
|
2204 * |
|
2205 * @since 3.7.0 |
|
2206 * |
|
2207 * @param bool $upgrade_major Whether to enable major automatic core updates. |
|
2208 */ |
|
1517 return apply_filters( 'allow_major_auto_core_updates', $upgrade_major ); |
2209 return apply_filters( 'allow_major_auto_core_updates', $upgrade_major ); |
2210 } |
|
1518 |
2211 |
1519 // If we're not sure, we don't want it |
2212 // If we're not sure, we don't want it |
1520 return false; |
2213 return false; |
1521 } |
2214 } |
1522 |
2215 |
1523 function check_files() { |
2216 /** |
2217 * Compare the disk file checksums agains the expected checksums. |
|
2218 * |
|
2219 * @since 3.7.0 |
|
2220 * |
|
2221 * @return bool True if the checksums match, otherwise false. |
|
2222 */ |
|
2223 public function check_files() { |
|
1524 global $wp_version, $wp_local_package; |
2224 global $wp_version, $wp_local_package; |
1525 |
2225 |
1526 $checksums = get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); |
2226 $checksums = get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); |
1527 |
2227 |
1528 if ( ! is_array( $checksums ) ) |
2228 if ( ! is_array( $checksums ) ) |
1546 * @package WordPress |
2246 * @package WordPress |
1547 * @subpackage Upgrader |
2247 * @subpackage Upgrader |
1548 * @since 2.8.0 |
2248 * @since 2.8.0 |
1549 */ |
2249 */ |
1550 class File_Upload_Upgrader { |
2250 class File_Upload_Upgrader { |
1551 var $package; |
2251 |
1552 var $filename; |
2252 /** |
1553 var $id = 0; |
2253 * The full path to the file package. |
1554 |
2254 * |
1555 function __construct($form, $urlholder) { |
2255 * @since 2.8.0 |
2256 * @var string $package |
|
2257 */ |
|
2258 public $package; |
|
2259 |
|
2260 /** |
|
2261 * The name of the file. |
|
2262 * |
|
2263 * @since 2.8.0 |
|
2264 * @var string $filename |
|
2265 */ |
|
2266 public $filename; |
|
2267 |
|
2268 /** |
|
2269 * The ID of the attachment post for this file. |
|
2270 * |
|
2271 * @since 3.3.0 |
|
2272 * @var int $id |
|
2273 */ |
|
2274 public $id = 0; |
|
2275 |
|
2276 /** |
|
2277 * Construct the upgrader for a form. |
|
2278 * |
|
2279 * @since 2.8.0 |
|
2280 * |
|
2281 * @param string $form The name of the form the file was uploaded from. |
|
2282 * @param string $urlholder The name of the `GET` parameter that holds the filename. |
|
2283 */ |
|
2284 public function __construct( $form, $urlholder ) { |
|
1556 |
2285 |
1557 if ( empty($_FILES[$form]['name']) && empty($_GET[$urlholder]) ) |
2286 if ( empty($_FILES[$form]['name']) && empty($_GET[$urlholder]) ) |
1558 wp_die(__('Please select a file')); |
2287 wp_die(__('Please select a file')); |
1559 |
2288 |
1560 //Handle a newly uploaded file, Else assume it's already been uploaded |
2289 //Handle a newly uploaded file, Else assume it's already been uploaded |
1576 'guid' => $file['url'], |
2305 'guid' => $file['url'], |
1577 'context' => 'upgrader', |
2306 'context' => 'upgrader', |
1578 'post_status' => 'private' |
2307 'post_status' => 'private' |
1579 ); |
2308 ); |
1580 |
2309 |
1581 // Save the data |
2310 // Save the data. |
1582 $this->id = wp_insert_attachment( $object, $file['file'] ); |
2311 $this->id = wp_insert_attachment( $object, $file['file'] ); |
1583 |
2312 |
1584 // schedule a cleanup for 2 hours from now in case of failed install |
2313 // Schedule a cleanup for 2 hours from now in case of failed install. |
1585 wp_schedule_single_event( time() + 7200, 'upgrader_scheduled_cleanup', array( $this->id ) ); |
2314 wp_schedule_single_event( time() + 2 * HOUR_IN_SECONDS, 'upgrader_scheduled_cleanup', array( $this->id ) ); |
1586 |
2315 |
1587 } elseif ( is_numeric( $_GET[$urlholder] ) ) { |
2316 } elseif ( is_numeric( $_GET[$urlholder] ) ) { |
1588 // Numeric Package = previously uploaded file, see above. |
2317 // Numeric Package = previously uploaded file, see above. |
1589 $this->id = (int) $_GET[$urlholder]; |
2318 $this->id = (int) $_GET[$urlholder]; |
1590 $attachment = get_post( $this->id ); |
2319 $attachment = get_post( $this->id ); |
1601 $this->filename = $_GET[$urlholder]; |
2330 $this->filename = $_GET[$urlholder]; |
1602 $this->package = $uploads['basedir'] . '/' . $this->filename; |
2331 $this->package = $uploads['basedir'] . '/' . $this->filename; |
1603 } |
2332 } |
1604 } |
2333 } |
1605 |
2334 |
1606 function cleanup() { |
2335 /** |
2336 * Delete the attachment/uploaded file. |
|
2337 * |
|
2338 * @since 3.2.2 |
|
2339 * |
|
2340 * @return bool Whether the cleanup was successful. |
|
2341 */ |
|
2342 public function cleanup() { |
|
1607 if ( $this->id ) |
2343 if ( $this->id ) |
1608 wp_delete_attachment( $this->id ); |
2344 wp_delete_attachment( $this->id ); |
1609 |
2345 |
1610 elseif ( file_exists( $this->package ) ) |
2346 elseif ( file_exists( $this->package ) ) |
1611 return @unlink( $this->package ); |
2347 return @unlink( $this->package ); |
1653 * This filter parallels the AUTOMATIC_UPDATER_DISABLED constant in name. |
2389 * This filter parallels the AUTOMATIC_UPDATER_DISABLED constant in name. |
1654 * |
2390 * |
1655 * This also disables update notification emails. That may change in the future. |
2391 * This also disables update notification emails. That may change in the future. |
1656 * |
2392 * |
1657 * @since 3.7.0 |
2393 * @since 3.7.0 |
2394 * |
|
1658 * @param bool $disabled Whether the updater should be disabled. |
2395 * @param bool $disabled Whether the updater should be disabled. |
1659 */ |
2396 */ |
1660 return apply_filters( 'automatic_updater_disabled', $disabled ); |
2397 return apply_filters( 'automatic_updater_disabled', $disabled ); |
1661 } |
2398 } |
1662 |
2399 |
1706 break 2; |
2443 break 2; |
1707 } |
2444 } |
1708 } |
2445 } |
1709 |
2446 |
1710 /** |
2447 /** |
1711 * Filter whether the automatic updater should consider a filesystem location to be potentially |
2448 * Filter whether the automatic updater should consider a filesystem |
1712 * managed by a version control system. |
2449 * location to be potentially managed by a version control system. |
1713 * |
2450 * |
1714 * @since 3.7.0 |
2451 * @since 3.7.0 |
1715 * |
2452 * |
1716 * @param bool $checkout Whether a VCS checkout was discovered at $context or ABSPATH, or anywhere higher. |
2453 * @param bool $checkout Whether a VCS checkout was discovered at $context |
1717 * @param string $context The filesystem context (a path) against which filesystem status should be checked. |
2454 * or ABSPATH, or anywhere higher. |
2455 * @param string $context The filesystem context (a path) against which |
|
2456 * filesystem status should be checked. |
|
1718 */ |
2457 */ |
1719 return apply_filters( 'automatic_updates_is_vcs_checkout', $checkout, $context ); |
2458 return apply_filters( 'automatic_updates_is_vcs_checkout', $checkout, $context ); |
1720 } |
2459 } |
1721 |
2460 |
1722 /** |
2461 /** |
1723 * Tests to see if we can and should update a specific item. |
2462 * Tests to see if we can and should update a specific item. |
1724 * |
2463 * |
1725 * @since 3.7.0 |
2464 * @since 3.7.0 |
1726 * |
2465 * |
1727 * @param string $type The type of update being checked: 'core', 'theme', 'plugin', 'translation'. |
2466 * @param string $type The type of update being checked: 'core', 'theme', |
2467 * 'plugin', 'translation'. |
|
1728 * @param object $item The update offer. |
2468 * @param object $item The update offer. |
1729 * @param string $context The filesystem context (a path) against which filesystem access and status |
2469 * @param string $context The filesystem context (a path) against which filesystem |
1730 * should be checked. |
2470 * access and status should be checked. |
1731 */ |
2471 */ |
1732 public function should_update( $type, $item, $context ) { |
2472 public function should_update( $type, $item, $context ) { |
1733 // Used to see if WP_Filesystem is set up to allow unattended updates. |
2473 // Used to see if WP_Filesystem is set up to allow unattended updates. |
1734 $skin = new Automatic_Upgrader_Skin; |
2474 $skin = new Automatic_Upgrader_Skin; |
1735 |
2475 |
1736 if ( $this->is_disabled() ) |
2476 if ( $this->is_disabled() ) |
1737 return false; |
2477 return false; |
1738 |
2478 |
2479 // Only relax the filesystem checks when the update doesn't include new files |
|
2480 $allow_relaxed_file_ownership = false; |
|
2481 if ( 'core' == $type && isset( $item->new_files ) && ! $item->new_files ) { |
|
2482 $allow_relaxed_file_ownership = true; |
|
2483 } |
|
2484 |
|
1739 // If we can't do an auto core update, we may still be able to email the user. |
2485 // If we can't do an auto core update, we may still be able to email the user. |
1740 if ( ! $skin->request_filesystem_credentials( false, $context ) || $this->is_vcs_checkout( $context ) ) { |
2486 if ( ! $skin->request_filesystem_credentials( false, $context, $allow_relaxed_file_ownership ) || $this->is_vcs_checkout( $context ) ) { |
1741 if ( 'core' == $type ) |
2487 if ( 'core' == $type ) |
1742 $this->send_core_update_notification_email( $item ); |
2488 $this->send_core_update_notification_email( $item ); |
1743 return false; |
2489 return false; |
1744 } |
2490 } |
1745 |
2491 |
1750 $update = ! empty( $item->autoupdate ); |
2496 $update = ! empty( $item->autoupdate ); |
1751 |
2497 |
1752 /** |
2498 /** |
1753 * Filter whether to automatically update core, a plugin, a theme, or a language. |
2499 * Filter whether to automatically update core, a plugin, a theme, or a language. |
1754 * |
2500 * |
1755 * The dynamic portion of the hook name, $type, refers to the type of update |
2501 * The dynamic portion of the hook name, `$type`, refers to the type of update |
1756 * being checked. Can be 'core', 'theme', 'plugin', or 'translation'. |
2502 * being checked. Can be 'core', 'theme', 'plugin', or 'translation'. |
1757 * |
2503 * |
1758 * Generally speaking, plugins, themes, and major core versions are not updated by default, |
2504 * Generally speaking, plugins, themes, and major core versions are not updated |
1759 * while translations and minor and development versions for core are updated by default. |
2505 * by default, while translations and minor and development versions for core |
1760 * |
2506 * are updated by default. |
1761 * See the filters allow_dev_auto_core_updates, allow_minor_auto_core_updates, and |
2507 * |
1762 * allow_major_auto_core_updates more straightforward filters to adjust core updates. |
2508 * See the {@see 'allow_dev_auto_core_updates', {@see 'allow_minor_auto_core_updates'}, |
2509 * and {@see 'allow_major_auto_core_updates'} filters for a more straightforward way to |
|
2510 * adjust core updates. |
|
1763 * |
2511 * |
1764 * @since 3.7.0 |
2512 * @since 3.7.0 |
1765 * |
2513 * |
1766 * @param bool $update Whether to update. |
2514 * @param bool $update Whether to update. |
1767 * @param object $item The update offer. |
2515 * @param object $item The update offer. |
1797 * @since 3.7.0 |
2545 * @since 3.7.0 |
1798 * |
2546 * |
1799 * @param object $item The update offer. |
2547 * @param object $item The update offer. |
1800 */ |
2548 */ |
1801 protected function send_core_update_notification_email( $item ) { |
2549 protected function send_core_update_notification_email( $item ) { |
1802 $notify = true; |
|
1803 $notified = get_site_option( 'auto_core_update_notified' ); |
2550 $notified = get_site_option( 'auto_core_update_notified' ); |
1804 |
2551 |
1805 // Don't notify if we've already notified the same email address of the same version. |
2552 // Don't notify if we've already notified the same email address of the same version. |
1806 if ( $notified && $notified['email'] == get_site_option( 'admin_email' ) && $notified['version'] == $item->current ) |
2553 if ( $notified && $notified['email'] == get_site_option( 'admin_email' ) && $notified['version'] == $item->current ) |
1807 return false; |
2554 return false; |
1808 |
2555 |
1809 // See if we need to notify users of a core update. |
2556 // See if we need to notify users of a core update. |
1810 $notify = ! empty( $item->notify_email ); |
2557 $notify = ! empty( $item->notify_email ); |
1811 |
2558 |
1812 /** |
2559 /** |
1813 * Whether to notify the site administrator of a new core update. |
2560 * Filter whether to notify the site administrator of a new core update. |
1814 * |
2561 * |
1815 * By default, administrators are notified when the update offer received from WordPress.org |
2562 * By default, administrators are notified when the update offer received |
1816 * sets a particular flag. This allows for discretion in if and when to notify. |
2563 * from WordPress.org sets a particular flag. This allows some discretion |
1817 * |
2564 * in if and when to notify. |
1818 * This filter only fires once per release -- if the same email address was already |
2565 * |
1819 * notified of the same new version, we won't repeatedly email the administrator. |
2566 * This filter is only evaluated once per release. If the same email address |
1820 * |
2567 * was already notified of the same new version, WordPress won't repeatedly |
1821 * This filter is also used on about.php to check if a plugin has disabled these notifications. |
2568 * email the administrator. |
2569 * |
|
2570 * This filter is also used on about.php to check if a plugin has disabled |
|
2571 * these notifications. |
|
1822 * |
2572 * |
1823 * @since 3.7.0 |
2573 * @since 3.7.0 |
1824 * |
2574 * |
1825 * @param bool $notify Whether the site administrator is notified. |
2575 * @param bool $notify Whether the site administrator is notified. |
1826 * @param object $item The update offer. |
2576 * @param object $item The update offer. |
1827 */ |
2577 */ |
1828 if ( ! apply_filters( 'send_core_update_notification_email', $notify, $item ) ) |
2578 if ( ! apply_filters( 'send_core_update_notification_email', $notify, $item ) ) |
1829 return false; |
2579 return false; |
1830 |
2580 |
1831 $this->send_email( 'manual', $item ); |
2581 $this->send_email( 'manual', $item ); |
1854 $upgrader = new Plugin_Upgrader( $skin ); |
2604 $upgrader = new Plugin_Upgrader( $skin ); |
1855 $context = WP_PLUGIN_DIR; // We don't support custom Plugin directories, or updates for WPMU_PLUGIN_DIR |
2605 $context = WP_PLUGIN_DIR; // We don't support custom Plugin directories, or updates for WPMU_PLUGIN_DIR |
1856 break; |
2606 break; |
1857 case 'theme': |
2607 case 'theme': |
1858 $upgrader = new Theme_Upgrader( $skin ); |
2608 $upgrader = new Theme_Upgrader( $skin ); |
1859 $context = get_theme_root( $item ); |
2609 $context = get_theme_root( $item->theme ); |
1860 break; |
2610 break; |
1861 case 'translation': |
2611 case 'translation': |
1862 $upgrader = new Language_Pack_Upgrader( $skin ); |
2612 $upgrader = new Language_Pack_Upgrader( $skin ); |
1863 $context = WP_CONTENT_DIR; // WP_LANG_DIR; |
2613 $context = WP_CONTENT_DIR; // WP_LANG_DIR; |
1864 break; |
2614 break; |
1866 |
2616 |
1867 // Determine whether we can and should perform this update. |
2617 // Determine whether we can and should perform this update. |
1868 if ( ! $this->should_update( $type, $item, $context ) ) |
2618 if ( ! $this->should_update( $type, $item, $context ) ) |
1869 return false; |
2619 return false; |
1870 |
2620 |
2621 $upgrader_item = $item; |
|
1871 switch ( $type ) { |
2622 switch ( $type ) { |
1872 case 'core': |
2623 case 'core': |
1873 $skin->feedback( __( 'Updating to WordPress %s' ), $item->version ); |
2624 $skin->feedback( __( 'Updating to WordPress %s' ), $item->version ); |
1874 $item_name = sprintf( __( 'WordPress %s' ), $item->version ); |
2625 $item_name = sprintf( __( 'WordPress %s' ), $item->version ); |
1875 break; |
2626 break; |
1876 case 'theme': |
2627 case 'theme': |
1877 $theme = wp_get_theme( $item ); |
2628 $upgrader_item = $item->theme; |
2629 $theme = wp_get_theme( $upgrader_item ); |
|
1878 $item_name = $theme->Get( 'Name' ); |
2630 $item_name = $theme->Get( 'Name' ); |
1879 $skin->feedback( __( 'Updating theme: %s' ), $item_name ); |
2631 $skin->feedback( __( 'Updating theme: %s' ), $item_name ); |
1880 break; |
2632 break; |
1881 case 'plugin': |
2633 case 'plugin': |
1882 $plugin_data = get_plugin_data( $context . '/' . $item ); |
2634 $upgrader_item = $item->plugin; |
2635 $plugin_data = get_plugin_data( $context . '/' . $upgrader_item ); |
|
1883 $item_name = $plugin_data['Name']; |
2636 $item_name = $plugin_data['Name']; |
1884 $skin->feedback( __( 'Updating plugin: %s' ), $item_name ); |
2637 $skin->feedback( __( 'Updating plugin: %s' ), $item_name ); |
1885 break; |
2638 break; |
1886 case 'translation': |
2639 case 'translation': |
1887 $language_item_name = $upgrader->get_name_for_update( $item ); |
2640 $language_item_name = $upgrader->get_name_for_update( $item ); |
1888 $item_name = sprintf( __( 'Translations for %s' ), $language_item_name ); |
2641 $item_name = sprintf( __( 'Translations for %s' ), $language_item_name ); |
1889 $skin->feedback( sprintf( __( 'Updating translations for %1$s (%2$s)…' ), $language_item_name, $item->language ) ); |
2642 $skin->feedback( sprintf( __( 'Updating translations for %1$s (%2$s)…' ), $language_item_name, $item->language ) ); |
1890 break; |
2643 break; |
1891 } |
2644 } |
1892 |
2645 |
2646 $allow_relaxed_file_ownership = false; |
|
2647 if ( 'core' == $type && isset( $item->new_files ) && ! $item->new_files ) { |
|
2648 $allow_relaxed_file_ownership = true; |
|
2649 } |
|
2650 |
|
1893 // Boom, This sites about to get a whole new splash of paint! |
2651 // Boom, This sites about to get a whole new splash of paint! |
1894 $upgrade_result = $upgrader->upgrade( $item, array( |
2652 $upgrade_result = $upgrader->upgrade( $upgrader_item, array( |
1895 'clear_update_cache' => false, |
2653 'clear_update_cache' => false, |
1896 'pre_check_md5' => false, /* always use partial builds if possible for core updates */ |
2654 // Always use partial builds if possible for core updates. |
1897 'attempt_rollback' => true, /* only available for core updates */ |
2655 'pre_check_md5' => false, |
2656 // Only available for core updates. |
|
2657 'attempt_rollback' => true, |
|
2658 // Allow relaxed file ownership in some scenarios |
|
2659 'allow_relaxed_file_ownership' => $allow_relaxed_file_ownership, |
|
1898 ) ); |
2660 ) ); |
1899 |
2661 |
1900 // Core doesn't output this, so lets append it so we don't get confused |
2662 // If the filesystem is unavailable, false is returned. |
2663 if ( false === $upgrade_result ) { |
|
2664 $upgrade_result = new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) ); |
|
2665 } |
|
2666 |
|
2667 // Core doesn't output this, so let's append it so we don't get confused. |
|
1901 if ( 'core' == $type ) { |
2668 if ( 'core' == $type ) { |
1902 if ( is_wp_error( $upgrade_result ) ) { |
2669 if ( is_wp_error( $upgrade_result ) ) { |
1903 $skin->error( __( 'Installation Failed' ), $upgrade_result ); |
2670 $skin->error( __( 'Installation Failed' ), $upgrade_result ); |
1904 } else { |
2671 } else { |
1905 $skin->feedback( __( 'WordPress updated successfully' ) ); |
2672 $skin->feedback( __( 'WordPress updated successfully' ) ); |
1945 // Check to see if the lock is still valid |
2712 // Check to see if the lock is still valid |
1946 if ( $lock_result > ( time() - HOUR_IN_SECONDS ) ) |
2713 if ( $lock_result > ( time() - HOUR_IN_SECONDS ) ) |
1947 return; |
2714 return; |
1948 } |
2715 } |
1949 |
2716 |
1950 // Update the lock, as by this point we've definately got a lock, just need to fire the actions |
2717 // Update the lock, as by this point we've definitely got a lock, just need to fire the actions |
1951 update_option( $lock_name, time() ); |
2718 update_option( $lock_name, time() ); |
1952 |
2719 |
1953 // Don't automatically run these thins, as we'll handle it ourselves |
2720 // Don't automatically run these thins, as we'll handle it ourselves |
1954 remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); |
2721 remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); |
1955 remove_action( 'upgrader_process_complete', 'wp_version_check' ); |
2722 remove_action( 'upgrader_process_complete', 'wp_version_check' ); |
1958 |
2725 |
1959 // Next, Plugins |
2726 // Next, Plugins |
1960 wp_update_plugins(); // Check for Plugin updates |
2727 wp_update_plugins(); // Check for Plugin updates |
1961 $plugin_updates = get_site_transient( 'update_plugins' ); |
2728 $plugin_updates = get_site_transient( 'update_plugins' ); |
1962 if ( $plugin_updates && !empty( $plugin_updates->response ) ) { |
2729 if ( $plugin_updates && !empty( $plugin_updates->response ) ) { |
1963 foreach ( array_keys( $plugin_updates->response ) as $plugin ) { |
2730 foreach ( $plugin_updates->response as $plugin ) { |
1964 $this->update( 'plugin', $plugin ); |
2731 $this->update( 'plugin', $plugin ); |
1965 } |
2732 } |
1966 // Force refresh of plugin update information |
2733 // Force refresh of plugin update information |
1967 wp_clean_plugins_cache(); |
2734 wp_clean_plugins_cache(); |
1968 } |
2735 } |
1969 |
2736 |
1970 // Next, those themes we all love |
2737 // Next, those themes we all love |
1971 wp_update_themes(); // Check for Theme updates |
2738 wp_update_themes(); // Check for Theme updates |
1972 $theme_updates = get_site_transient( 'update_themes' ); |
2739 $theme_updates = get_site_transient( 'update_themes' ); |
1973 if ( $theme_updates && !empty( $theme_updates->response ) ) { |
2740 if ( $theme_updates && !empty( $theme_updates->response ) ) { |
1974 foreach ( array_keys( $theme_updates->response ) as $theme ) { |
2741 foreach ( $theme_updates->response as $theme ) { |
1975 $this->update( 'theme', $theme ); |
2742 $this->update( 'theme', (object) $theme ); |
1976 } |
2743 } |
1977 // Force refresh of theme update information |
2744 // Force refresh of theme update information |
1978 wp_clean_themes_cache(); |
2745 wp_clean_themes_cache(); |
1979 } |
2746 } |
1980 |
2747 |
1985 if ( $core_update ) |
2752 if ( $core_update ) |
1986 $this->update( 'core', $core_update ); |
2753 $this->update( 'core', $core_update ); |
1987 |
2754 |
1988 // Clean up, and check for any pending translations |
2755 // Clean up, and check for any pending translations |
1989 // (Core_Upgrader checks for core updates) |
2756 // (Core_Upgrader checks for core updates) |
1990 wp_update_themes(); // Check for Theme updates |
2757 $theme_stats = array(); |
1991 wp_update_plugins(); // Check for Plugin updates |
2758 if ( isset( $this->update_results['theme'] ) ) { |
2759 foreach ( $this->update_results['theme'] as $upgrade ) { |
|
2760 $theme_stats[ $upgrade->item->theme ] = ( true === $upgrade->result ); |
|
2761 } |
|
2762 } |
|
2763 wp_update_themes( $theme_stats ); // Check for Theme updates |
|
2764 |
|
2765 $plugin_stats = array(); |
|
2766 if ( isset( $this->update_results['plugin'] ) ) { |
|
2767 foreach ( $this->update_results['plugin'] as $upgrade ) { |
|
2768 $plugin_stats[ $upgrade->item->plugin ] = ( true === $upgrade->result ); |
|
2769 } |
|
2770 } |
|
2771 wp_update_plugins( $plugin_stats ); // Check for Plugin updates |
|
1992 |
2772 |
1993 // Finally, Process any new translations |
2773 // Finally, Process any new translations |
1994 $language_updates = wp_get_translation_updates(); |
2774 $language_updates = wp_get_translation_updates(); |
1995 if ( $language_updates ) { |
2775 if ( $language_updates ) { |
1996 foreach ( $language_updates as $update ) { |
2776 foreach ( $language_updates as $update ) { |
1997 $this->update( 'translation', $update ); |
2777 $this->update( 'translation', $update ); |
1998 } |
2778 } |
1999 |
2779 |
2000 // Clear existing caches |
2780 // Clear existing caches |
2001 wp_clean_plugins_cache(); |
2781 wp_clean_update_cache(); |
2002 wp_clean_themes_cache(); |
|
2003 delete_site_transient( 'update_core' ); |
|
2004 |
2782 |
2005 wp_version_check(); // check for Core updates |
2783 wp_version_check(); // check for Core updates |
2006 wp_update_themes(); // Check for Theme updates |
2784 wp_update_themes(); // Check for Theme updates |
2007 wp_update_plugins(); // Check for Plugin updates |
2785 wp_update_plugins(); // Check for Plugin updates |
2008 } |
2786 } |
2009 |
2787 |
2010 // Send debugging email to all development installs. |
2788 // Send debugging email to all development installs. |
2011 if ( ! empty( $this->update_results ) ) { |
2789 if ( ! empty( $this->update_results ) ) { |
2012 $development_version = false !== strpos( $wp_version, '-' ); |
2790 $development_version = false !== strpos( $wp_version, '-' ); |
2791 |
|
2013 /** |
2792 /** |
2014 * Filter whether to send a debugging email for each automatic background update. |
2793 * Filter whether to send a debugging email for each automatic background update. |
2015 * |
2794 * |
2016 * @since 3.7.0 |
2795 * @since 3.7.0 |
2017 * @param bool $development_version By default, emails are sent if the install is a development version. |
2796 * |
2797 * @param bool $development_version By default, emails are sent if the |
|
2798 * install is a development version. |
|
2018 * Return false to avoid the email. |
2799 * Return false to avoid the email. |
2019 */ |
2800 */ |
2020 if ( apply_filters( 'automatic_updates_send_debug_email', $development_version ) ) |
2801 if ( apply_filters( 'automatic_updates_send_debug_email', $development_version ) ) |
2021 $this->send_debug_email(); |
2802 $this->send_debug_email(); |
2022 |
2803 |
2023 if ( ! empty( $this->update_results['core'] ) ) |
2804 if ( ! empty( $this->update_results['core'] ) ) |
2024 $this->after_core_update( $this->update_results['core'][0] ); |
2805 $this->after_core_update( $this->update_results['core'][0] ); |
2806 |
|
2807 /** |
|
2808 * Fires after all automatic updates have run. |
|
2809 * |
|
2810 * @since 3.8.0 |
|
2811 * |
|
2812 * @param array $update_results The results of all attempted updates. |
|
2813 */ |
|
2814 do_action( 'automatic_updates_complete', $this->update_results ); |
|
2025 } |
2815 } |
2026 |
2816 |
2027 // Clear the lock |
2817 // Clear the lock |
2028 delete_option( $lock_name ); |
2818 delete_option( $lock_name ); |
2029 } |
2819 } |
2141 * Filter whether to send an email following an automatic background core update. |
2931 * Filter whether to send an email following an automatic background core update. |
2142 * |
2932 * |
2143 * @since 3.7.0 |
2933 * @since 3.7.0 |
2144 * |
2934 * |
2145 * @param bool $send Whether to send the email. Default true. |
2935 * @param bool $send Whether to send the email. Default true. |
2146 * @param string $type The type of email to send. Can be one of 'success', 'fail', 'critical'. |
2936 * @param string $type The type of email to send. Can be one of |
2937 * 'success', 'fail', 'critical'. |
|
2147 * @param object $core_update The update offer that was attempted. |
2938 * @param object $core_update The update offer that was attempted. |
2148 * @param mixed $result The result for the core update. Can be WP_Error. |
2939 * @param mixed $result The result for the core update. Can be WP_Error. |
2149 */ |
2940 */ |
2150 if ( 'manual' !== $type && ! apply_filters( 'auto_core_update_send_email', true, $type, $core_update, $result ) ) |
2941 if ( 'manual' !== $type && ! apply_filters( 'auto_core_update_send_email', true, $type, $core_update, $result ) ) |
2151 return; |
2942 return; |
2223 $body .= "\n\n" . __( "Please check out your site now. It's possible that everything is working. If it says you need to update, you should do so:" ); |
3014 $body .= "\n\n" . __( "Please check out your site now. It's possible that everything is working. If it says you need to update, you should do so:" ); |
2224 $body .= "\n" . network_admin_url( 'update-core.php' ); |
3015 $body .= "\n" . network_admin_url( 'update-core.php' ); |
2225 break; |
3016 break; |
2226 } |
3017 } |
2227 |
3018 |
3019 $critical_support = 'critical' === $type && ! empty( $core_update->support_email ); |
|
3020 if ( $critical_support ) { |
|
3021 // Support offer if available. |
|
3022 $body .= "\n\n" . sprintf( __( "The WordPress team is willing to help you. Forward this email to %s and the team will work with you to make sure your site is working." ), $core_update->support_email ); |
|
3023 } else { |
|
3024 // Add a note about the support forums. |
|
3025 $body .= "\n\n" . __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' ); |
|
3026 $body .= "\n" . __( 'https://wordpress.org/support/' ); |
|
3027 } |
|
3028 |
|
2228 // Updates are important! |
3029 // Updates are important! |
2229 if ( $type != 'success' || $newer_version_available ) |
3030 if ( $type != 'success' || $newer_version_available ) { |
2230 $body .= "\n\n" . __( 'Keeping your site updated is important for security. It also makes the internet a safer place for you and your readers.' ); |
3031 $body .= "\n\n" . __( 'Keeping your site updated is important for security. It also makes the internet a safer place for you and your readers.' ); |
2231 |
3032 } |
2232 // Add a note about the support forums to all emails. |
3033 |
2233 $body .= "\n\n" . __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' ); |
3034 if ( $critical_support ) { |
2234 $body .= "\n" . __( 'http://wordpress.org/support/' ); |
3035 $body .= " " . __( "If you reach out to us, we'll also ensure you'll never have this problem again." ); |
3036 } |
|
2235 |
3037 |
2236 // If things are successful and we're now on the latest, mention plugins and themes if any are out of date. |
3038 // If things are successful and we're now on the latest, mention plugins and themes if any are out of date. |
2237 if ( $type == 'success' && ! $newer_version_available && ( get_plugin_updates() || get_theme_updates() ) ) { |
3039 if ( $type == 'success' && ! $newer_version_available && ( get_plugin_updates() || get_theme_updates() ) ) { |
2238 $body .= "\n\n" . __( 'You also have some plugins or themes with updates available. Update them now:' ); |
3040 $body .= "\n\n" . __( 'You also have some plugins or themes with updates available. Update them now:' ); |
2239 $body .= "\n" . network_admin_url(); |
3041 $body .= "\n" . network_admin_url(); |
2272 |
3074 |
2273 $to = get_site_option( 'admin_email' ); |
3075 $to = get_site_option( 'admin_email' ); |
2274 $headers = ''; |
3076 $headers = ''; |
2275 |
3077 |
2276 $email = compact( 'to', 'subject', 'body', 'headers' ); |
3078 $email = compact( 'to', 'subject', 'body', 'headers' ); |
3079 |
|
2277 /** |
3080 /** |
2278 * Filter the email sent following an automatic background core update. |
3081 * Filter the email sent following an automatic background core update. |
2279 * |
3082 * |
2280 * @since 3.7.0 |
3083 * @since 3.7.0 |
2281 * |
3084 * |
2282 * @param array $email { |
3085 * @param array $email { |
2283 * Array of email arguments that will be passed to wp_mail(). |
3086 * Array of email arguments that will be passed to wp_mail(). |
2284 * |
3087 * |
2285 * @type string $to The email recipient. An array of emails can be returned, as handled by wp_mail(). |
3088 * @type string $to The email recipient. An array of emails |
3089 * can be returned, as handled by wp_mail(). |
|
2286 * @type string $subject The email's subject. |
3090 * @type string $subject The email's subject. |
2287 * @type string $body The email message body. |
3091 * @type string $body The email message body. |
2288 * @type string $headers Any email headers, defaults to no headers. |
3092 * @type string $headers Any email headers, defaults to no headers. |
2289 * } |
3093 * } |
2290 * @param string $type The type of email being sent. Can be one of 'success', 'fail', 'manual', 'critical'. |
3094 * @param string $type The type of email being sent. Can be one of |
3095 * 'success', 'fail', 'manual', 'critical'. |
|
2291 * @param object $core_update The update offer that was attempted. |
3096 * @param object $core_update The update offer that was attempted. |
2292 * @param mixed $result The result for the core update. Can be WP_Error. |
3097 * @param mixed $result The result for the core update. Can be WP_Error. |
2293 */ |
3098 */ |
2294 $email = apply_filters( 'auto_core_update_email', $email, $type, $core_update, $result ); |
3099 $email = apply_filters( 'auto_core_update_email', $email, $type, $core_update, $result ); |
2295 |
3100 |
2296 wp_mail( $email['to'], $email['subject'], $email['body'], $email['headers'] ); |
3101 wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] ); |
2297 } |
3102 } |
2298 |
3103 |
2299 /** |
3104 /** |
2300 * Prepares and sends an email of a full log of background update results, useful for debugging and geekery. |
3105 * Prepares and sends an email of a full log of background update results, useful for debugging and geekery. |
2301 * |
3106 * |
2307 $update_count += count( $updates ); |
3112 $update_count += count( $updates ); |
2308 |
3113 |
2309 $body = array(); |
3114 $body = array(); |
2310 $failures = 0; |
3115 $failures = 0; |
2311 |
3116 |
2312 $body[] = 'WordPress site: ' . network_home_url( '/' ); |
3117 $body[] = sprintf( __( 'WordPress site: %s' ), network_home_url( '/' ) ); |
2313 |
3118 |
2314 // Core |
3119 // Core |
2315 if ( isset( $this->update_results['core'] ) ) { |
3120 if ( isset( $this->update_results['core'] ) ) { |
2316 $result = $this->update_results['core'][0]; |
3121 $result = $this->update_results['core'][0]; |
2317 if ( $result->result && ! is_wp_error( $result->result ) ) { |
3122 if ( $result->result && ! is_wp_error( $result->result ) ) { |
2318 $body[] = sprintf( 'SUCCESS: WordPress was successfully updated to %s', $result->name ); |
3123 $body[] = sprintf( __( 'SUCCESS: WordPress was successfully updated to %s' ), $result->name ); |
2319 } else { |
3124 } else { |
2320 $body[] = sprintf( 'FAILED: WordPress failed to update to %s', $result->name ); |
3125 $body[] = sprintf( __( 'FAILED: WordPress failed to update to %s' ), $result->name ); |
2321 $failures++; |
3126 $failures++; |
2322 } |
3127 } |
2323 $body[] = ''; |
3128 $body[] = ''; |
2324 } |
3129 } |
2325 |
3130 |
2327 foreach ( array( 'plugin', 'theme', 'translation' ) as $type ) { |
3132 foreach ( array( 'plugin', 'theme', 'translation' ) as $type ) { |
2328 if ( ! isset( $this->update_results[ $type ] ) ) |
3133 if ( ! isset( $this->update_results[ $type ] ) ) |
2329 continue; |
3134 continue; |
2330 $success_items = wp_list_filter( $this->update_results[ $type ], array( 'result' => true ) ); |
3135 $success_items = wp_list_filter( $this->update_results[ $type ], array( 'result' => true ) ); |
2331 if ( $success_items ) { |
3136 if ( $success_items ) { |
2332 $body[] = "The following {$type}s were successfully updated:"; |
3137 $messages = array( |
2333 foreach ( wp_list_pluck( $success_items, 'name' ) as $name ) |
3138 'plugin' => __( 'The following plugins were successfully updated:' ), |
2334 $body[] = ' * SUCCESS: ' . $name; |
3139 'theme' => __( 'The following themes were successfully updated:' ), |
3140 'translation' => __( 'The following translations were successfully updated:' ), |
|
3141 ); |
|
3142 |
|
3143 $body[] = $messages[ $type ]; |
|
3144 foreach ( wp_list_pluck( $success_items, 'name' ) as $name ) { |
|
3145 $body[] = ' * ' . sprintf( __( 'SUCCESS: %s' ), $name ); |
|
3146 } |
|
2335 } |
3147 } |
2336 if ( $success_items != $this->update_results[ $type ] ) { |
3148 if ( $success_items != $this->update_results[ $type ] ) { |
2337 // Failed updates |
3149 // Failed updates |
2338 $body[] = "The following {$type}s failed to update:"; |
3150 $messages = array( |
3151 'plugin' => __( 'The following plugins failed to update:' ), |
|
3152 'theme' => __( 'The following themes failed to update:' ), |
|
3153 'translation' => __( 'The following translations failed to update:' ), |
|
3154 ); |
|
3155 |
|
3156 $body[] = $messages[ $type ]; |
|
2339 foreach ( $this->update_results[ $type ] as $item ) { |
3157 foreach ( $this->update_results[ $type ] as $item ) { |
2340 if ( ! $item->result || is_wp_error( $item->result ) ) { |
3158 if ( ! $item->result || is_wp_error( $item->result ) ) { |
2341 $body[] = ' * FAILED: ' . $item->name; |
3159 $body[] = ' * ' . sprintf( __( 'FAILED: %s' ), $item->name ); |
2342 $failures++; |
3160 $failures++; |
2343 } |
3161 } |
2344 } |
3162 } |
2345 } |
3163 } |
2346 $body[] = ''; |
3164 $body[] = ''; |
2347 } |
3165 } |
2348 |
3166 |
3167 $site_title = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); |
|
2349 if ( $failures ) { |
3168 if ( $failures ) { |
3169 $body[] = trim( __( |
|
3170 "BETA TESTING? |
|
3171 ============= |
|
3172 |
|
3173 This debugging email is sent when you are using a development version of WordPress. |
|
3174 |
|
3175 If you think these failures might be due to a bug in WordPress, could you report it? |
|
3176 * Open a thread in the support forums: https://wordpress.org/support/forum/alphabeta |
|
3177 * Or, if you're comfortable writing a bug report: https://core.trac.wordpress.org/ |
|
3178 |
|
3179 Thanks! -- The WordPress Team" ) ); |
|
2350 $body[] = ''; |
3180 $body[] = ''; |
2351 $body[] = 'BETA TESTING?'; |
3181 |
2352 $body[] = '============='; |
3182 $subject = sprintf( __( '[%s] There were failures during background updates' ), $site_title ); |
2353 $body[] = ''; |
|
2354 $body[] = 'This debugging email is sent when you are using a development version of WordPress.'; |
|
2355 $body[] = ''; |
|
2356 $body[] = 'If you think these failures might be due to a bug in WordPress, could you report it?'; |
|
2357 $body[] = ' * Open a thread in the support forums: http://wordpress.org/support/forum/alphabeta'; |
|
2358 $body[] = " * Or, if you're comfortable writing a bug report: http://core.trac.wordpress.org/"; |
|
2359 $body[] = ''; |
|
2360 $body[] = 'Thanks! -- The WordPress Team'; |
|
2361 $body[] = ''; |
|
2362 $subject = sprintf( '[%s] There were failures during background updates', get_bloginfo( 'name' ) ); |
|
2363 } else { |
3183 } else { |
2364 $subject = sprintf( '[%s] Background updates have finished', get_bloginfo( 'name' ) ); |
3184 $subject = sprintf( __( '[%s] Background updates have finished' ), $site_title ); |
2365 } |
3185 } |
2366 |
3186 |
2367 $body[] = 'UPDATE LOG'; |
3187 $body[] = trim( __( |
2368 $body[] = '=========='; |
3188 'UPDATE LOG |
3189 ==========' ) ); |
|
2369 $body[] = ''; |
3190 $body[] = ''; |
2370 |
3191 |
2371 foreach ( array( 'core', 'plugin', 'theme', 'translation' ) as $type ) { |
3192 foreach ( array( 'core', 'plugin', 'theme', 'translation' ) as $type ) { |
2372 if ( ! isset( $this->update_results[ $type ] ) ) |
3193 if ( ! isset( $this->update_results[ $type ] ) ) |
2373 continue; |
3194 continue; |
2382 if ( 'rollback_was_required' === $update->result->get_error_code() ) |
3203 if ( 'rollback_was_required' === $update->result->get_error_code() ) |
2383 $results = (array) $update->result->get_error_data(); |
3204 $results = (array) $update->result->get_error_data(); |
2384 foreach ( $results as $result_type => $result ) { |
3205 foreach ( $results as $result_type => $result ) { |
2385 if ( ! is_wp_error( $result ) ) |
3206 if ( ! is_wp_error( $result ) ) |
2386 continue; |
3207 continue; |
2387 $body[] = ' ' . ( 'rollback' === $result_type ? 'Rollback ' : '' ) . 'Error: [' . $result->get_error_code() . '] ' . $result->get_error_message(); |
3208 |
3209 if ( 'rollback' === $result_type ) { |
|
3210 /* translators: 1: Error code, 2: Error message. */ |
|
3211 $body[] = ' ' . sprintf( __( 'Rollback Error: [%1$s] %2$s' ), $result->get_error_code(), $result->get_error_message() ); |
|
3212 } else { |
|
3213 /* translators: 1: Error code, 2: Error message. */ |
|
3214 $body[] = ' ' . sprintf( __( 'Error: [%1$s] %2$s' ), $result->get_error_code(), $result->get_error_message() ); |
|
3215 } |
|
3216 |
|
2388 if ( $result->get_error_data() ) |
3217 if ( $result->get_error_data() ) |
2389 $body[] = ' ' . implode( ', ', (array) $result->get_error_data() ); |
3218 $body[] = ' ' . implode( ', ', (array) $result->get_error_data() ); |
2390 } |
3219 } |
2391 } |
3220 } |
2392 $body[] = ''; |
3221 $body[] = ''; |
2393 } |
3222 } |
2394 } |
3223 } |
2395 |
3224 |
2396 //echo "<h1>\n$subject\n</h1>\n"; |
3225 $email = array( |
2397 //echo "<pre>\n" . implode( "\n", $body ) . "\n</pre>"; |
3226 'to' => get_site_option( 'admin_email' ), |
2398 |
3227 'subject' => $subject, |
2399 wp_mail( get_site_option( 'admin_email' ), $subject, implode( "\n", $body ) ); |
3228 'body' => implode( "\n", $body ), |
3229 'headers' => '' |
|
3230 ); |
|
3231 |
|
3232 /** |
|
3233 * Filter the debug email that can be sent following an automatic |
|
3234 * background core update. |
|
3235 * |
|
3236 * @since 3.8.0 |
|
3237 * |
|
3238 * @param array $email { |
|
3239 * Array of email arguments that will be passed to wp_mail(). |
|
3240 * |
|
3241 * @type string $to The email recipient. An array of emails |
|
3242 * can be returned, as handled by wp_mail(). |
|
3243 * @type string $subject Email subject. |
|
3244 * @type string $body Email message body. |
|
3245 * @type string $headers Any email headers. Default empty. |
|
3246 * } |
|
3247 * @param int $failures The number of failures encountered while upgrading. |
|
3248 * @param mixed $results The results of all attempted updates. |
|
3249 */ |
|
3250 $email = apply_filters( 'automatic_updates_debug_email', $email, $failures, $this->update_results ); |
|
3251 |
|
3252 wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] ); |
|
2400 } |
3253 } |
2401 } |
3254 } |