24 * Initialize the upgrade strings. |
24 * Initialize the upgrade strings. |
25 * |
25 * |
26 * @since 2.8.0 |
26 * @since 2.8.0 |
27 */ |
27 */ |
28 public function upgrade_strings() { |
28 public function upgrade_strings() { |
29 $this->strings['up_to_date'] = __('WordPress is at the latest version.'); |
29 $this->strings['up_to_date'] = __( 'WordPress is at the latest version.' ); |
30 $this->strings['locked'] = __('Another update is currently in progress.'); |
30 $this->strings['locked'] = __( 'Another update is currently in progress.' ); |
31 $this->strings['no_package'] = __('Update package not available.'); |
31 $this->strings['no_package'] = __( 'Update package not available.' ); |
32 /* translators: %s: package URL */ |
32 /* translators: %s: package URL */ |
33 $this->strings['downloading_package'] = sprintf( __( 'Downloading update from %s…' ), '<span class="code">%s</span>' ); |
33 $this->strings['downloading_package'] = sprintf( __( 'Downloading update from %s…' ), '<span class="code">%s</span>' ); |
34 $this->strings['unpack_package'] = __('Unpacking the update…'); |
34 $this->strings['unpack_package'] = __( 'Unpacking the update…' ); |
35 $this->strings['copy_failed'] = __('Could not copy files.'); |
35 $this->strings['copy_failed'] = __( 'Could not copy files.' ); |
36 $this->strings['copy_failed_space'] = __('Could not copy files. You may have run out of disk space.' ); |
36 $this->strings['copy_failed_space'] = __( 'Could not copy files. You may have run out of disk space.' ); |
37 $this->strings['start_rollback'] = __( 'Attempting to roll back to previous version.' ); |
37 $this->strings['start_rollback'] = __( 'Attempting to roll back to previous version.' ); |
38 $this->strings['rollback_was_required'] = __( 'Due to an error during updating, WordPress has rolled back to your previous version.' ); |
38 $this->strings['rollback_was_required'] = __( 'Due to an error during updating, WordPress has rolled back to your previous version.' ); |
39 } |
39 } |
40 |
40 |
41 /** |
41 /** |
42 * Upgrade WordPress core. |
42 * Upgrade WordPress core. |
43 * |
43 * |
44 * @since 2.8.0 |
44 * @since 2.8.0 |
45 * |
45 * |
46 * @global WP_Filesystem_Base $wp_filesystem Subclass |
46 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. |
47 * @global callable $_wp_filesystem_direct_method |
47 * @global callable $_wp_filesystem_direct_method |
48 * |
48 * |
49 * @param object $current Response object for whether WordPress is current. |
49 * @param object $current Response object for whether WordPress is current. |
50 * @param array $args { |
50 * @param array $args { |
51 * Optional. Arguments for upgrading WordPress core. Default empty array. |
51 * Optional. Arguments for upgrading WordPress core. Default empty array. |
64 |
64 |
65 include( ABSPATH . WPINC . '/version.php' ); // $wp_version; |
65 include( ABSPATH . WPINC . '/version.php' ); // $wp_version; |
66 |
66 |
67 $start_time = time(); |
67 $start_time = time(); |
68 |
68 |
69 $defaults = array( |
69 $defaults = array( |
70 'pre_check_md5' => true, |
70 'pre_check_md5' => true, |
71 'attempt_rollback' => false, |
71 'attempt_rollback' => false, |
72 'do_rollback' => false, |
72 'do_rollback' => false, |
73 'allow_relaxed_file_ownership' => false, |
73 'allow_relaxed_file_ownership' => false, |
74 ); |
74 ); |
75 $parsed_args = wp_parse_args( $args, $defaults ); |
75 $parsed_args = wp_parse_args( $args, $defaults ); |
76 |
76 |
77 $this->init(); |
77 $this->init(); |
78 $this->upgrade_strings(); |
78 $this->upgrade_strings(); |
79 |
79 |
80 // Is an update available? |
80 // Is an update available? |
81 if ( !isset( $current->response ) || $current->response == 'latest' ) |
81 if ( ! isset( $current->response ) || $current->response == 'latest' ) { |
82 return new WP_Error('up_to_date', $this->strings['up_to_date']); |
82 return new WP_Error( 'up_to_date', $this->strings['up_to_date'] ); |
|
83 } |
83 |
84 |
84 $res = $this->fs_connect( array( ABSPATH, WP_CONTENT_DIR ), $parsed_args['allow_relaxed_file_ownership'] ); |
85 $res = $this->fs_connect( array( ABSPATH, WP_CONTENT_DIR ), $parsed_args['allow_relaxed_file_ownership'] ); |
85 if ( ! $res || is_wp_error( $res ) ) { |
86 if ( ! $res || is_wp_error( $res ) ) { |
86 return $res; |
87 return $res; |
87 } |
88 } |
88 |
89 |
89 $wp_dir = trailingslashit($wp_filesystem->abspath()); |
90 $wp_dir = trailingslashit( $wp_filesystem->abspath() ); |
90 |
91 |
91 $partial = true; |
92 $partial = true; |
92 if ( $parsed_args['do_rollback'] ) |
93 if ( $parsed_args['do_rollback'] ) { |
93 $partial = false; |
94 $partial = false; |
94 elseif ( $parsed_args['pre_check_md5'] && ! $this->check_files() ) |
95 } elseif ( $parsed_args['pre_check_md5'] && ! $this->check_files() ) { |
95 $partial = false; |
96 $partial = false; |
|
97 } |
96 |
98 |
97 /* |
99 /* |
98 * If partial update is returned from the API, use that, unless we're doing |
100 * If partial update is returned from the API, use that, unless we're doing |
99 * a reinstallation. If we cross the new_bundled version number, then use |
101 * a reinstallation. If we cross the new_bundled version number, then use |
100 * the new_bundled zip. Don't though if the constant is set to skip bundled items. |
102 * the new_bundled zip. Don't though if the constant is set to skip bundled items. |
101 * If the API returns a no_content zip, go with it. Finally, default to the full zip. |
103 * If the API returns a no_content zip, go with it. Finally, default to the full zip. |
102 */ |
104 */ |
103 if ( $parsed_args['do_rollback'] && $current->packages->rollback ) |
105 if ( $parsed_args['do_rollback'] && $current->packages->rollback ) { |
104 $to_download = 'rollback'; |
106 $to_download = 'rollback'; |
105 elseif ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version && $partial ) |
107 } elseif ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version && $partial ) { |
106 $to_download = 'partial'; |
108 $to_download = 'partial'; |
107 elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '<' ) |
109 } elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '<' ) |
108 && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) ) |
110 && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) ) { |
109 $to_download = 'new_bundled'; |
111 $to_download = 'new_bundled'; |
110 elseif ( $current->packages->no_content ) |
112 } elseif ( $current->packages->no_content ) { |
111 $to_download = 'no_content'; |
113 $to_download = 'no_content'; |
112 else |
114 } else { |
113 $to_download = 'full'; |
115 $to_download = 'full'; |
|
116 } |
114 |
117 |
115 // Lock to prevent multiple Core Updates occurring |
118 // Lock to prevent multiple Core Updates occurring |
116 $lock = WP_Upgrader::create_lock( 'core_updater', 15 * MINUTE_IN_SECONDS ); |
119 $lock = WP_Upgrader::create_lock( 'core_updater', 15 * MINUTE_IN_SECONDS ); |
117 if ( ! $lock ) { |
120 if ( ! $lock ) { |
118 return new WP_Error( 'locked', $this->strings['locked'] ); |
121 return new WP_Error( 'locked', $this->strings['locked'] ); |
119 } |
122 } |
120 |
123 |
121 $download = $this->download_package( $current->packages->$to_download ); |
124 $download = $this->download_package( $current->packages->$to_download, true ); |
|
125 |
|
126 // Allow for signature soft-fail. |
|
127 // WARNING: This may be removed in the future. |
|
128 if ( is_wp_error( $download ) && $download->get_error_data( 'softfail-filename' ) ) { |
|
129 // Outout the failure error as a normal feedback, and not as an error: |
|
130 apply_filters( 'update_feedback', $download->get_error_message() ); |
|
131 |
|
132 // Report this failure back to WordPress.org for debugging purposes. |
|
133 wp_version_check( |
|
134 array( |
|
135 'signature_failure_code' => $download->get_error_code(), |
|
136 'signature_failure_data' => $download->get_error_data(), |
|
137 ) |
|
138 ); |
|
139 |
|
140 // Pretend this error didn't happen. |
|
141 $download = $download->get_error_data( 'softfail-filename' ); |
|
142 } |
|
143 |
122 if ( is_wp_error( $download ) ) { |
144 if ( is_wp_error( $download ) ) { |
123 WP_Upgrader::release_lock( 'core_updater' ); |
145 WP_Upgrader::release_lock( 'core_updater' ); |
124 return $download; |
146 return $download; |
125 } |
147 } |
126 |
148 |
129 WP_Upgrader::release_lock( 'core_updater' ); |
151 WP_Upgrader::release_lock( 'core_updater' ); |
130 return $working_dir; |
152 return $working_dir; |
131 } |
153 } |
132 |
154 |
133 // Copy update-core.php from the new version into place. |
155 // Copy update-core.php from the new version into place. |
134 if ( !$wp_filesystem->copy($working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true) ) { |
156 if ( ! $wp_filesystem->copy( $working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true ) ) { |
135 $wp_filesystem->delete($working_dir, true); |
157 $wp_filesystem->delete( $working_dir, true ); |
136 WP_Upgrader::release_lock( 'core_updater' ); |
158 WP_Upgrader::release_lock( 'core_updater' ); |
137 return new WP_Error( 'copy_failed_for_update_core_file', __( 'The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.' ), 'wp-admin/includes/update-core.php' ); |
159 return new WP_Error( 'copy_failed_for_update_core_file', __( 'The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.' ), 'wp-admin/includes/update-core.php' ); |
138 } |
160 } |
139 $wp_filesystem->chmod($wp_dir . 'wp-admin/includes/update-core.php', FS_CHMOD_FILE); |
161 $wp_filesystem->chmod( $wp_dir . 'wp-admin/includes/update-core.php', FS_CHMOD_FILE ); |
140 |
162 |
141 require_once( ABSPATH . 'wp-admin/includes/update-core.php' ); |
163 require_once( ABSPATH . 'wp-admin/includes/update-core.php' ); |
142 |
164 |
143 if ( ! function_exists( 'update_core' ) ) { |
165 if ( ! function_exists( 'update_core' ) ) { |
144 WP_Upgrader::release_lock( 'core_updater' ); |
166 WP_Upgrader::release_lock( 'core_updater' ); |
155 /* |
177 /* |
156 * Not all errors are equal. These codes are critical: copy_failed__copy_dir, |
178 * Not all errors are equal. These codes are critical: copy_failed__copy_dir, |
157 * mkdir_failed__copy_dir, copy_failed__copy_dir_retry, and disk_full. |
179 * mkdir_failed__copy_dir, copy_failed__copy_dir_retry, and disk_full. |
158 * do_rollback allows for update_core() to trigger a rollback if needed. |
180 * do_rollback allows for update_core() to trigger a rollback if needed. |
159 */ |
181 */ |
160 if ( false !== strpos( $error_code, 'do_rollback' ) ) |
182 if ( false !== strpos( $error_code, 'do_rollback' ) ) { |
161 $try_rollback = true; |
183 $try_rollback = true; |
162 elseif ( false !== strpos( $error_code, '__copy_dir' ) ) |
184 } elseif ( false !== strpos( $error_code, '__copy_dir' ) ) { |
163 $try_rollback = true; |
185 $try_rollback = true; |
164 elseif ( 'disk_full' === $error_code ) |
186 } elseif ( 'disk_full' === $error_code ) { |
165 $try_rollback = true; |
187 $try_rollback = true; |
|
188 } |
166 } |
189 } |
167 |
190 |
168 if ( $try_rollback ) { |
191 if ( $try_rollback ) { |
169 /** This filter is documented in wp-admin/includes/update-core.php */ |
192 /** This filter is documented in wp-admin/includes/update-core.php */ |
170 apply_filters( 'update_feedback', $result ); |
193 apply_filters( 'update_feedback', $result ); |
173 apply_filters( 'update_feedback', $this->strings['start_rollback'] ); |
196 apply_filters( 'update_feedback', $this->strings['start_rollback'] ); |
174 |
197 |
175 $rollback_result = $this->upgrade( $current, array_merge( $parsed_args, array( 'do_rollback' => true ) ) ); |
198 $rollback_result = $this->upgrade( $current, array_merge( $parsed_args, array( 'do_rollback' => true ) ) ); |
176 |
199 |
177 $original_result = $result; |
200 $original_result = $result; |
178 $result = new WP_Error( 'rollback_was_required', $this->strings['rollback_was_required'], (object) array( 'update' => $original_result, 'rollback' => $rollback_result ) ); |
201 $result = new WP_Error( |
|
202 'rollback_was_required', |
|
203 $this->strings['rollback_was_required'], |
|
204 (object) array( |
|
205 'update' => $original_result, |
|
206 'rollback' => $rollback_result, |
|
207 ) |
|
208 ); |
179 } |
209 } |
180 } |
210 } |
181 |
211 |
182 /** This action is documented in wp-admin/includes/class-wp-upgrader.php */ |
212 /** This action is documented in wp-admin/includes/class-wp-upgrader.php */ |
183 do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'core' ) ); |
213 do_action( |
|
214 'upgrader_process_complete', |
|
215 $this, |
|
216 array( |
|
217 'action' => 'update', |
|
218 'type' => 'core', |
|
219 ) |
|
220 ); |
184 |
221 |
185 // Clear the current updates |
222 // Clear the current updates |
186 delete_site_transient( 'update_core' ); |
223 delete_site_transient( 'update_core' ); |
187 |
224 |
188 if ( ! $parsed_args['do_rollback'] ) { |
225 if ( ! $parsed_args['do_rollback'] ) { |
189 $stats = array( |
226 $stats = array( |
190 'update_type' => $current->response, |
227 'update_type' => $current->response, |
191 'success' => true, |
228 'success' => true, |
192 'fs_method' => $wp_filesystem->method, |
229 'fs_method' => $wp_filesystem->method, |
193 'fs_method_forced' => defined( 'FS_METHOD' ) || has_filter( 'filesystem_method' ), |
230 'fs_method_forced' => defined( 'FS_METHOD' ) || has_filter( 'filesystem_method' ), |
194 'fs_method_direct' => !empty( $GLOBALS['_wp_filesystem_direct_method'] ) ? $GLOBALS['_wp_filesystem_direct_method'] : '', |
231 'fs_method_direct' => ! empty( $GLOBALS['_wp_filesystem_direct_method'] ) ? $GLOBALS['_wp_filesystem_direct_method'] : '', |
195 'time_taken' => time() - $start_time, |
232 'time_taken' => time() - $start_time, |
196 'reported' => $wp_version, |
233 'reported' => $wp_version, |
197 'attempted' => $current->version, |
234 'attempted' => $current->version, |
198 ); |
235 ); |
199 |
236 |
226 /** |
263 /** |
227 * Determines if this WordPress Core version should update to an offered version or not. |
264 * Determines if this WordPress Core version should update to an offered version or not. |
228 * |
265 * |
229 * @since 3.7.0 |
266 * @since 3.7.0 |
230 * |
267 * |
231 * @static |
|
232 * |
|
233 * @param string $offered_ver The offered version, of the format x.y.z. |
268 * @param string $offered_ver The offered version, of the format x.y.z. |
234 * @return bool True if we should update to the offered version, otherwise false. |
269 * @return bool True if we should update to the offered version, otherwise false. |
235 */ |
270 */ |
236 public static function should_update_to_version( $offered_ver ) { |
271 public static function should_update_to_version( $offered_ver ) { |
237 include( ABSPATH . WPINC . '/version.php' ); // $wp_version; // x.y.z |
272 include( ABSPATH . WPINC . '/version.php' ); // $wp_version; // x.y.z |
238 |
273 |
239 $current_branch = implode( '.', array_slice( preg_split( '/[.-]/', $wp_version ), 0, 2 ) ); // x.y |
274 $current_branch = implode( '.', array_slice( preg_split( '/[.-]/', $wp_version ), 0, 2 ) ); // x.y |
240 $new_branch = implode( '.', array_slice( preg_split( '/[.-]/', $offered_ver ), 0, 2 ) ); // x.y |
275 $new_branch = implode( '.', array_slice( preg_split( '/[.-]/', $offered_ver ), 0, 2 ) ); // x.y |
241 $current_is_development_version = (bool) strpos( $wp_version, '-' ); |
276 $current_is_development_version = (bool) strpos( $wp_version, '-' ); |
242 |
277 |
243 // Defaults: |
278 // Defaults: |
244 $upgrade_dev = true; |
279 $upgrade_dev = true; |
245 $upgrade_minor = true; |
280 $upgrade_minor = true; |
253 } elseif ( true === WP_AUTO_UPDATE_CORE ) { |
288 } elseif ( true === WP_AUTO_UPDATE_CORE ) { |
254 // ALL updates for core |
289 // ALL updates for core |
255 $upgrade_dev = $upgrade_minor = $upgrade_major = true; |
290 $upgrade_dev = $upgrade_minor = $upgrade_major = true; |
256 } elseif ( 'minor' === WP_AUTO_UPDATE_CORE ) { |
291 } elseif ( 'minor' === WP_AUTO_UPDATE_CORE ) { |
257 // Only minor updates for core |
292 // Only minor updates for core |
258 $upgrade_dev = $upgrade_major = false; |
293 $upgrade_dev = $upgrade_major = false; |
259 $upgrade_minor = true; |
294 $upgrade_minor = true; |
260 } |
295 } |
261 } |
296 } |
262 |
297 |
263 // 1: If we're already on that version, not much point in updating? |
298 // 1: If we're already on that version, not much point in updating? |
264 if ( $offered_ver == $wp_version ) |
299 if ( $offered_ver == $wp_version ) { |
265 return false; |
300 return false; |
|
301 } |
266 |
302 |
267 // 2: If we're running a newer version, that's a nope |
303 // 2: If we're running a newer version, that's a nope |
268 if ( version_compare( $wp_version, $offered_ver, '>' ) ) |
304 if ( version_compare( $wp_version, $offered_ver, '>' ) ) { |
269 return false; |
305 return false; |
|
306 } |
270 |
307 |
271 $failure_data = get_site_option( 'auto_core_update_failed' ); |
308 $failure_data = get_site_option( 'auto_core_update_failed' ); |
272 if ( $failure_data ) { |
309 if ( $failure_data ) { |
273 // If this was a critical update failure, cannot update. |
310 // If this was a critical update failure, cannot update. |
274 if ( ! empty( $failure_data['critical'] ) ) |
311 if ( ! empty( $failure_data['critical'] ) ) { |
275 return false; |
312 return false; |
|
313 } |
276 |
314 |
277 // Don't claim we can update on update-core.php if we have a non-critical failure logged. |
315 // Don't claim we can update on update-core.php if we have a non-critical failure logged. |
278 if ( $wp_version == $failure_data['current'] && false !== strpos( $offered_ver, '.1.next.minor' ) ) |
316 if ( $wp_version == $failure_data['current'] && false !== strpos( $offered_ver, '.1.next.minor' ) ) { |
279 return false; |
317 return false; |
|
318 } |
280 |
319 |
281 // Cannot update if we're retrying the same A to B update that caused a non-critical failure. |
320 // Cannot update if we're retrying the same A to B update that caused a non-critical failure. |
282 // Some non-critical failures do allow retries, like download_failed. |
321 // Some non-critical failures do allow retries, like download_failed. |
283 // 3.7.1 => 3.7.2 resulted in files_not_writable, if we are still on 3.7.1 and still trying to update to 3.7.2. |
322 // 3.7.1 => 3.7.2 resulted in files_not_writable, if we are still on 3.7.1 and still trying to update to 3.7.2. |
284 if ( empty( $failure_data['retry'] ) && $wp_version == $failure_data['current'] && $offered_ver == $failure_data['attempted'] ) |
323 if ( empty( $failure_data['retry'] ) && $wp_version == $failure_data['current'] && $offered_ver == $failure_data['attempted'] ) { |
285 return false; |
324 return false; |
|
325 } |
286 } |
326 } |
287 |
327 |
288 // 3: 3.7-alpha-25000 -> 3.7-alpha-25678 -> 3.7-beta1 -> 3.7-beta2 |
328 // 3: 3.7-alpha-25000 -> 3.7-alpha-25678 -> 3.7-beta1 -> 3.7-beta2 |
289 if ( $current_is_development_version ) { |
329 if ( $current_is_development_version ) { |
290 |
330 |