138 |
139 |
139 if ( $this->is_disabled() ) { |
140 if ( $this->is_disabled() ) { |
140 return false; |
141 return false; |
141 } |
142 } |
142 |
143 |
143 // Only relax the filesystem checks when the update doesn't include new files |
144 // Only relax the filesystem checks when the update doesn't include new files. |
144 $allow_relaxed_file_ownership = false; |
145 $allow_relaxed_file_ownership = false; |
145 if ( 'core' == $type && isset( $item->new_files ) && ! $item->new_files ) { |
146 if ( 'core' === $type && isset( $item->new_files ) && ! $item->new_files ) { |
146 $allow_relaxed_file_ownership = true; |
147 $allow_relaxed_file_ownership = true; |
147 } |
148 } |
148 |
149 |
149 // If we can't do an auto core update, we may still be able to email the user. |
150 // If we can't do an auto core update, we may still be able to email the user. |
150 if ( ! $skin->request_filesystem_credentials( false, $context, $allow_relaxed_file_ownership ) || $this->is_vcs_checkout( $context ) ) { |
151 if ( ! $skin->request_filesystem_credentials( false, $context, $allow_relaxed_file_ownership ) || $this->is_vcs_checkout( $context ) ) { |
151 if ( 'core' == $type ) { |
152 if ( 'core' === $type ) { |
152 $this->send_core_update_notification_email( $item ); |
153 $this->send_core_update_notification_email( $item ); |
153 } |
154 } |
154 return false; |
155 return false; |
155 } |
156 } |
156 |
157 |
157 // Next up, is this an item we can update? |
158 // Next up, is this an item we can update? |
158 if ( 'core' == $type ) { |
159 if ( 'core' === $type ) { |
159 $update = Core_Upgrader::should_update_to_version( $item->current ); |
160 $update = Core_Upgrader::should_update_to_version( $item->current ); |
|
161 } elseif ( 'plugin' === $type || 'theme' === $type ) { |
|
162 $update = ! empty( $item->autoupdate ); |
|
163 |
|
164 if ( ! $update && wp_is_auto_update_enabled_for_type( $type ) ) { |
|
165 // Check if the site admin has enabled auto-updates by default for the specific item. |
|
166 $auto_updates = (array) get_site_option( "auto_update_{$type}s", array() ); |
|
167 $update = in_array( $item->{$type}, $auto_updates, true ); |
|
168 } |
160 } else { |
169 } else { |
161 $update = ! empty( $item->autoupdate ); |
170 $update = ! empty( $item->autoupdate ); |
162 } |
171 } |
163 |
172 |
|
173 // If the `disable_autoupdate` flag is set, override any user-choice, but allow filters. |
|
174 if ( ! empty( $item->disable_autoupdate ) ) { |
|
175 $update = $item->disable_autoupdate; |
|
176 } |
|
177 |
164 /** |
178 /** |
165 * Filters whether to automatically update core, a plugin, a theme, or a language. |
179 * Filters whether to automatically update core, a plugin, a theme, or a language. |
166 * |
180 * |
167 * The dynamic portion of the hook name, `$type`, refers to the type of update |
181 * The dynamic portion of the hook name, `$type`, refers to the type of update |
168 * being checked. Can be 'core', 'theme', 'plugin', or 'translation'. |
182 * being checked. Potential hook names include: |
|
183 * |
|
184 * - `auto_update_core` |
|
185 * - `auto_update_plugin` |
|
186 * - `auto_update_theme` |
|
187 * - `auto_update_translation` |
169 * |
188 * |
170 * Generally speaking, plugins, themes, and major core versions are not updated |
189 * Generally speaking, plugins, themes, and major core versions are not updated |
171 * by default, while translations and minor and development versions for core |
190 * by default, while translations and minor and development versions for core |
172 * are updated by default. |
191 * are updated by default. |
173 * |
192 * |
174 * See the {@see 'allow_dev_auto_core_updates'}, {@see 'allow_minor_auto_core_updates'}, |
193 * See the {@see 'allow_dev_auto_core_updates'}, {@see 'allow_minor_auto_core_updates'}, |
175 * and {@see 'allow_major_auto_core_updates'} filters for a more straightforward way to |
194 * and {@see 'allow_major_auto_core_updates'} filters for a more straightforward way to |
176 * adjust core updates. |
195 * adjust core updates. |
177 * |
196 * |
178 * @since 3.7.0 |
197 * @since 3.7.0 |
179 * |
198 * @since 5.5.0 The `$update` parameter accepts the value of null. |
180 * @param bool $update Whether to update. |
199 * |
181 * @param object $item The update offer. |
200 * @param bool|null $update Whether to update. The value of null is internally used |
|
201 * to detect whether nothing has hooked into this filter. |
|
202 * @param object $item The update offer. |
182 */ |
203 */ |
183 $update = apply_filters( "auto_update_{$type}", $update, $item ); |
204 $update = apply_filters( "auto_update_{$type}", $update, $item ); |
184 |
205 |
185 if ( ! $update ) { |
206 if ( ! $update ) { |
186 if ( 'core' == $type ) { |
207 if ( 'core' === $type ) { |
187 $this->send_core_update_notification_email( $item ); |
208 $this->send_core_update_notification_email( $item ); |
188 } |
209 } |
189 return false; |
210 return false; |
190 } |
211 } |
191 |
212 |
192 // If it's a core update, are we actually compatible with its requirements? |
213 // If it's a core update, are we actually compatible with its requirements? |
193 if ( 'core' == $type ) { |
214 if ( 'core' === $type ) { |
194 global $wpdb; |
215 global $wpdb; |
195 |
216 |
196 $php_compat = version_compare( phpversion(), $item->php_version, '>=' ); |
217 $php_compat = version_compare( phpversion(), $item->php_version, '>=' ); |
197 if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) ) { |
218 if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) ) { |
198 $mysql_compat = true; |
219 $mysql_compat = true; |
312 do_action( 'pre_auto_update', $type, $item, $context ); |
332 do_action( 'pre_auto_update', $type, $item, $context ); |
313 |
333 |
314 $upgrader_item = $item; |
334 $upgrader_item = $item; |
315 switch ( $type ) { |
335 switch ( $type ) { |
316 case 'core': |
336 case 'core': |
317 /* translators: %s: WordPress version */ |
337 /* translators: %s: WordPress version. */ |
318 $skin->feedback( __( 'Updating to WordPress %s' ), $item->version ); |
338 $skin->feedback( __( 'Updating to WordPress %s' ), $item->version ); |
319 /* translators: %s: WordPress version */ |
339 /* translators: %s: WordPress version. */ |
320 $item_name = sprintf( __( 'WordPress %s' ), $item->version ); |
340 $item_name = sprintf( __( 'WordPress %s' ), $item->version ); |
321 break; |
341 break; |
322 case 'theme': |
342 case 'theme': |
323 $upgrader_item = $item->theme; |
343 $upgrader_item = $item->theme; |
324 $theme = wp_get_theme( $upgrader_item ); |
344 $theme = wp_get_theme( $upgrader_item ); |
325 $item_name = $theme->Get( 'Name' ); |
345 $item_name = $theme->Get( 'Name' ); |
326 /* translators: %s: Theme name */ |
346 /* translators: %s: Theme name. */ |
327 $skin->feedback( __( 'Updating theme: %s' ), $item_name ); |
347 $skin->feedback( __( 'Updating theme: %s' ), $item_name ); |
328 break; |
348 break; |
329 case 'plugin': |
349 case 'plugin': |
330 $upgrader_item = $item->plugin; |
350 $upgrader_item = $item->plugin; |
331 $plugin_data = get_plugin_data( $context . '/' . $upgrader_item ); |
351 $plugin_data = get_plugin_data( $context . '/' . $upgrader_item ); |
332 $item_name = $plugin_data['Name']; |
352 $item_name = $plugin_data['Name']; |
333 /* translators: %s: Plugin name */ |
353 /* translators: %s: Plugin name. */ |
334 $skin->feedback( __( 'Updating plugin: %s' ), $item_name ); |
354 $skin->feedback( __( 'Updating plugin: %s' ), $item_name ); |
335 break; |
355 break; |
336 case 'translation': |
356 case 'translation': |
337 $language_item_name = $upgrader->get_name_for_update( $item ); |
357 $language_item_name = $upgrader->get_name_for_update( $item ); |
338 /* translators: %s: Name of language item */ |
358 /* translators: %s: Project name (plugin, theme, or WordPress). */ |
339 $item_name = sprintf( __( 'Translations for %s' ), $language_item_name ); |
359 $item_name = sprintf( __( 'Translations for %s' ), $language_item_name ); |
340 /* translators: 1: Name of language item, 2: Language */ |
360 /* translators: 1: Project name (plugin, theme, or WordPress), 2: Language. */ |
341 $skin->feedback( sprintf( __( 'Updating translations for %1$s (%2$s)…' ), $language_item_name, $item->language ) ); |
361 $skin->feedback( sprintf( __( 'Updating translations for %1$s (%2$s)…' ), $language_item_name, $item->language ) ); |
342 break; |
362 break; |
343 } |
363 } |
344 |
364 |
345 $allow_relaxed_file_ownership = false; |
365 $allow_relaxed_file_ownership = false; |
346 if ( 'core' == $type && isset( $item->new_files ) && ! $item->new_files ) { |
366 if ( 'core' === $type && isset( $item->new_files ) && ! $item->new_files ) { |
347 $allow_relaxed_file_ownership = true; |
367 $allow_relaxed_file_ownership = true; |
348 } |
368 } |
349 |
369 |
350 // Boom, This sites about to get a whole new splash of paint! |
370 // Boom, this site's about to get a whole new splash of paint! |
351 $upgrade_result = $upgrader->upgrade( |
371 $upgrade_result = $upgrader->upgrade( |
352 $upgrader_item, |
372 $upgrader_item, |
353 array( |
373 array( |
354 'clear_update_cache' => false, |
374 'clear_update_cache' => false, |
355 // Always use partial builds if possible for core updates. |
375 // Always use partial builds if possible for core updates. |
356 'pre_check_md5' => false, |
376 'pre_check_md5' => false, |
357 // Only available for core updates. |
377 // Only available for core updates. |
358 'attempt_rollback' => true, |
378 'attempt_rollback' => true, |
359 // Allow relaxed file ownership in some scenarios |
379 // Allow relaxed file ownership in some scenarios. |
360 'allow_relaxed_file_ownership' => $allow_relaxed_file_ownership, |
380 'allow_relaxed_file_ownership' => $allow_relaxed_file_ownership, |
361 ) |
381 ) |
362 ); |
382 ); |
363 |
383 |
364 // If the filesystem is unavailable, false is returned. |
384 // If the filesystem is unavailable, false is returned. |
365 if ( false === $upgrade_result ) { |
385 if ( false === $upgrade_result ) { |
366 $upgrade_result = new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) ); |
386 $upgrade_result = new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) ); |
367 } |
387 } |
368 |
388 |
369 if ( 'core' == $type ) { |
389 if ( 'core' === $type ) { |
370 if ( is_wp_error( $upgrade_result ) && ( 'up_to_date' == $upgrade_result->get_error_code() || 'locked' == $upgrade_result->get_error_code() ) ) { |
390 if ( is_wp_error( $upgrade_result ) |
371 // These aren't actual errors, treat it as a skipped-update instead to avoid triggering the post-core update failure routines. |
391 && ( 'up_to_date' === $upgrade_result->get_error_code() |
|
392 || 'locked' === $upgrade_result->get_error_code() ) |
|
393 ) { |
|
394 // These aren't actual errors, treat it as a skipped-update instead |
|
395 // to avoid triggering the post-core update failure routines. |
372 return false; |
396 return false; |
373 } |
397 } |
374 |
398 |
375 // Core doesn't output this, so let's append it so we don't get confused. |
399 // Core doesn't output this, so let's append it so we don't get confused. |
376 if ( is_wp_error( $upgrade_result ) ) { |
400 if ( is_wp_error( $upgrade_result ) ) { |
377 $skin->error( __( 'Installation Failed' ), $upgrade_result ); |
401 $skin->error( __( 'Installation failed.' ), $upgrade_result ); |
378 } else { |
402 } else { |
379 $skin->feedback( __( 'WordPress updated successfully' ) ); |
403 $skin->feedback( __( 'WordPress updated successfully.' ) ); |
380 } |
404 } |
381 } |
405 } |
382 |
406 |
383 $this->update_results[ $type ][] = (object) array( |
407 $this->update_results[ $type ][] = (object) array( |
384 'item' => $item, |
408 'item' => $item, |
406 |
430 |
407 if ( ! WP_Upgrader::create_lock( 'auto_updater' ) ) { |
431 if ( ! WP_Upgrader::create_lock( 'auto_updater' ) ) { |
408 return; |
432 return; |
409 } |
433 } |
410 |
434 |
411 // Don't automatically run these thins, as we'll handle it ourselves |
435 // Don't automatically run these things, as we'll handle it ourselves. |
412 remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); |
436 remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); |
413 remove_action( 'upgrader_process_complete', 'wp_version_check' ); |
437 remove_action( 'upgrader_process_complete', 'wp_version_check' ); |
414 remove_action( 'upgrader_process_complete', 'wp_update_plugins' ); |
438 remove_action( 'upgrader_process_complete', 'wp_update_plugins' ); |
415 remove_action( 'upgrader_process_complete', 'wp_update_themes' ); |
439 remove_action( 'upgrader_process_complete', 'wp_update_themes' ); |
416 |
440 |
417 // Next, Plugins |
441 // Next, plugins. |
418 wp_update_plugins(); // Check for Plugin updates |
442 wp_update_plugins(); // Check for plugin updates. |
419 $plugin_updates = get_site_transient( 'update_plugins' ); |
443 $plugin_updates = get_site_transient( 'update_plugins' ); |
420 if ( $plugin_updates && ! empty( $plugin_updates->response ) ) { |
444 if ( $plugin_updates && ! empty( $plugin_updates->response ) ) { |
421 foreach ( $plugin_updates->response as $plugin ) { |
445 foreach ( $plugin_updates->response as $plugin ) { |
422 $this->update( 'plugin', $plugin ); |
446 $this->update( 'plugin', $plugin ); |
423 } |
447 } |
424 // Force refresh of plugin update information |
448 // Force refresh of plugin update information. |
425 wp_clean_plugins_cache(); |
449 wp_clean_plugins_cache(); |
426 } |
450 } |
427 |
451 |
428 // Next, those themes we all love |
452 // Next, those themes we all love. |
429 wp_update_themes(); // Check for Theme updates |
453 wp_update_themes(); // Check for theme updates. |
430 $theme_updates = get_site_transient( 'update_themes' ); |
454 $theme_updates = get_site_transient( 'update_themes' ); |
431 if ( $theme_updates && ! empty( $theme_updates->response ) ) { |
455 if ( $theme_updates && ! empty( $theme_updates->response ) ) { |
432 foreach ( $theme_updates->response as $theme ) { |
456 foreach ( $theme_updates->response as $theme ) { |
433 $this->update( 'theme', (object) $theme ); |
457 $this->update( 'theme', (object) $theme ); |
434 } |
458 } |
435 // Force refresh of theme update information |
459 // Force refresh of theme update information. |
436 wp_clean_themes_cache(); |
460 wp_clean_themes_cache(); |
437 } |
461 } |
438 |
462 |
439 // Next, Process any core update |
463 // Next, process any core update. |
440 wp_version_check(); // Check for Core updates |
464 wp_version_check(); // Check for core updates. |
441 $core_update = find_core_auto_update(); |
465 $core_update = find_core_auto_update(); |
442 |
466 |
443 if ( $core_update ) { |
467 if ( $core_update ) { |
444 $this->update( 'core', $core_update ); |
468 $this->update( 'core', $core_update ); |
445 } |
469 } |
446 |
470 |
447 // Clean up, and check for any pending translations |
471 // Clean up, and check for any pending translations. |
448 // (Core_Upgrader checks for core updates) |
472 // (Core_Upgrader checks for core updates.) |
449 $theme_stats = array(); |
473 $theme_stats = array(); |
450 if ( isset( $this->update_results['theme'] ) ) { |
474 if ( isset( $this->update_results['theme'] ) ) { |
451 foreach ( $this->update_results['theme'] as $upgrade ) { |
475 foreach ( $this->update_results['theme'] as $upgrade ) { |
452 $theme_stats[ $upgrade->item->theme ] = ( true === $upgrade->result ); |
476 $theme_stats[ $upgrade->item->theme ] = ( true === $upgrade->result ); |
453 } |
477 } |
454 } |
478 } |
455 wp_update_themes( $theme_stats ); // Check for Theme updates |
479 wp_update_themes( $theme_stats ); // Check for theme updates. |
456 |
480 |
457 $plugin_stats = array(); |
481 $plugin_stats = array(); |
458 if ( isset( $this->update_results['plugin'] ) ) { |
482 if ( isset( $this->update_results['plugin'] ) ) { |
459 foreach ( $this->update_results['plugin'] as $upgrade ) { |
483 foreach ( $this->update_results['plugin'] as $upgrade ) { |
460 $plugin_stats[ $upgrade->item->plugin ] = ( true === $upgrade->result ); |
484 $plugin_stats[ $upgrade->item->plugin ] = ( true === $upgrade->result ); |
461 } |
485 } |
462 } |
486 } |
463 wp_update_plugins( $plugin_stats ); // Check for Plugin updates |
487 wp_update_plugins( $plugin_stats ); // Check for plugin updates. |
464 |
488 |
465 // Finally, Process any new translations |
489 // Finally, process any new translations. |
466 $language_updates = wp_get_translation_updates(); |
490 $language_updates = wp_get_translation_updates(); |
467 if ( $language_updates ) { |
491 if ( $language_updates ) { |
468 foreach ( $language_updates as $update ) { |
492 foreach ( $language_updates as $update ) { |
469 $this->update( 'translation', $update ); |
493 $this->update( 'translation', $update ); |
470 } |
494 } |
471 |
495 |
472 // Clear existing caches |
496 // Clear existing caches. |
473 wp_clean_update_cache(); |
497 wp_clean_update_cache(); |
474 |
498 |
475 wp_version_check(); // check for Core updates |
499 wp_version_check(); // Check for core updates. |
476 wp_update_themes(); // Check for Theme updates |
500 wp_update_themes(); // Check for theme updates. |
477 wp_update_plugins(); // Check for Plugin updates |
501 wp_update_plugins(); // Check for plugin updates. |
478 } |
502 } |
479 |
503 |
480 // Send debugging email to admin for all development installations. |
504 // Send debugging email to admin for all development installations. |
481 if ( ! empty( $this->update_results ) ) { |
505 if ( ! empty( $this->update_results ) ) { |
482 $development_version = false !== strpos( get_bloginfo( 'version' ), '-' ); |
506 $development_version = false !== strpos( get_bloginfo( 'version' ), '-' ); |
665 |
693 |
666 default: |
694 default: |
667 return; |
695 return; |
668 } |
696 } |
669 |
697 |
670 // If the auto update is not to the latest version, say that the current version of WP is available instead. |
698 // If the auto-update is not to the latest version, say that the current version of WP is available instead. |
671 $version = 'success' === $type ? $core_update->current : $next_user_core_update->current; |
699 $version = 'success' === $type ? $core_update->current : $next_user_core_update->current; |
672 $subject = sprintf( $subject, wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), $version ); |
700 $subject = sprintf( $subject, wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), $version ); |
673 |
701 |
674 $body = ''; |
702 $body = ''; |
675 |
703 |
676 switch ( $type ) { |
704 switch ( $type ) { |
677 case 'success': |
705 case 'success': |
678 /* translators: 1: Home URL, 2: WordPress version */ |
706 $body .= sprintf( |
679 $body .= sprintf( __( 'Howdy! Your site at %1$s has been updated automatically to WordPress %2$s.' ), home_url(), $core_update->current ); |
707 /* translators: 1: Home URL, 2: WordPress version. */ |
|
708 __( 'Howdy! Your site at %1$s has been updated automatically to WordPress %2$s.' ), |
|
709 home_url(), |
|
710 $core_update->current |
|
711 ); |
680 $body .= "\n\n"; |
712 $body .= "\n\n"; |
681 if ( ! $newer_version_available ) { |
713 if ( ! $newer_version_available ) { |
682 $body .= __( 'No further action is needed on your part.' ) . ' '; |
714 $body .= __( 'No further action is needed on your part.' ) . ' '; |
683 } |
715 } |
684 |
716 |
685 // Can only reference the About screen if their update was successful. |
717 // Can only reference the About screen if their update was successful. |
686 list( $about_version ) = explode( '-', $core_update->current, 2 ); |
718 list( $about_version ) = explode( '-', $core_update->current, 2 ); |
687 /* translators: %s: WordPress core version */ |
719 /* translators: %s: WordPress version. */ |
688 $body .= sprintf( __( 'For more on version %s, see the About WordPress screen:' ), $about_version ); |
720 $body .= sprintf( __( 'For more on version %s, see the About WordPress screen:' ), $about_version ); |
689 $body .= "\n" . admin_url( 'about.php' ); |
721 $body .= "\n" . admin_url( 'about.php' ); |
690 |
722 |
691 if ( $newer_version_available ) { |
723 if ( $newer_version_available ) { |
692 /* translators: %s: WordPress core latest version */ |
724 /* translators: %s: WordPress latest version. */ |
693 $body .= "\n\n" . sprintf( __( 'WordPress %s is also now available.' ), $next_user_core_update->current ) . ' '; |
725 $body .= "\n\n" . sprintf( __( 'WordPress %s is also now available.' ), $next_user_core_update->current ) . ' '; |
694 $body .= __( 'Updating is easy and only takes a few moments:' ); |
726 $body .= __( 'Updating is easy and only takes a few moments:' ); |
695 $body .= "\n" . network_admin_url( 'update-core.php' ); |
727 $body .= "\n" . network_admin_url( 'update-core.php' ); |
696 } |
728 } |
697 |
729 |
698 break; |
730 break; |
699 |
731 |
700 case 'fail': |
732 case 'fail': |
701 case 'manual': |
733 case 'manual': |
702 /* translators: 1: Home URL, 2: WordPress core latest version */ |
734 $body .= sprintf( |
703 $body .= sprintf( __( 'Please update your site at %1$s to WordPress %2$s.' ), home_url(), $next_user_core_update->current ); |
735 /* translators: 1: Home URL, 2: WordPress version. */ |
|
736 __( 'Please update your site at %1$s to WordPress %2$s.' ), |
|
737 home_url(), |
|
738 $next_user_core_update->current |
|
739 ); |
704 |
740 |
705 $body .= "\n\n"; |
741 $body .= "\n\n"; |
706 |
742 |
707 // Don't show this message if there is a newer version available. |
743 // Don't show this message if there is a newer version available. |
708 // Potential for confusion, and also not useful for them to know at this point. |
744 // Potential for confusion, and also not useful for them to know at this point. |
709 if ( 'fail' == $type && ! $newer_version_available ) { |
745 if ( 'fail' === $type && ! $newer_version_available ) { |
710 $body .= __( 'We tried but were unable to update your site automatically.' ) . ' '; |
746 $body .= __( 'We tried but were unable to update your site automatically.' ) . ' '; |
711 } |
747 } |
712 |
748 |
713 $body .= __( 'Updating is easy and only takes a few moments:' ); |
749 $body .= __( 'Updating is easy and only takes a few moments:' ); |
714 $body .= "\n" . network_admin_url( 'update-core.php' ); |
750 $body .= "\n" . network_admin_url( 'update-core.php' ); |
715 break; |
751 break; |
716 |
752 |
717 case 'critical': |
753 case 'critical': |
718 if ( $newer_version_available ) { |
754 if ( $newer_version_available ) { |
719 /* translators: 1: Home URL, 2: WordPress core latest version */ |
755 $body .= sprintf( |
720 $body .= sprintf( __( 'Your site at %1$s experienced a critical failure while trying to update WordPress to version %2$s.' ), home_url(), $core_update->current ); |
756 /* translators: 1: Home URL, 2: WordPress version. */ |
|
757 __( 'Your site at %1$s experienced a critical failure while trying to update WordPress to version %2$s.' ), |
|
758 home_url(), |
|
759 $core_update->current |
|
760 ); |
721 } else { |
761 } else { |
722 /* translators: 1: Home URL, 2: Core update version */ |
762 $body .= sprintf( |
723 $body .= sprintf( __( 'Your site at %1$s experienced a critical failure while trying to update to the latest version of WordPress, %2$s.' ), home_url(), $core_update->current ); |
763 /* translators: 1: Home URL, 2: WordPress latest version. */ |
|
764 __( 'Your site at %1$s experienced a critical failure while trying to update to the latest version of WordPress, %2$s.' ), |
|
765 home_url(), |
|
766 $core_update->current |
|
767 ); |
724 } |
768 } |
725 |
769 |
726 $body .= "\n\n" . __( "This means your site may be offline or broken. Don't panic; this can be fixed." ); |
770 $body .= "\n\n" . __( "This means your site may be offline or broken. Don't panic; this can be fixed." ); |
727 |
771 |
728 $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:" ); |
772 $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:" ); |
731 } |
775 } |
732 |
776 |
733 $critical_support = 'critical' === $type && ! empty( $core_update->support_email ); |
777 $critical_support = 'critical' === $type && ! empty( $core_update->support_email ); |
734 if ( $critical_support ) { |
778 if ( $critical_support ) { |
735 // Support offer if available. |
779 // Support offer if available. |
736 /* translators: %s: Support e-mail */ |
780 $body .= "\n\n" . sprintf( |
737 $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 ); |
781 /* translators: %s: Support email address. */ |
|
782 __( '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.' ), |
|
783 $core_update->support_email |
|
784 ); |
738 } else { |
785 } else { |
739 // Add a note about the support forums. |
786 // Add a note about the support forums. |
740 $body .= "\n\n" . __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' ); |
787 $body .= "\n\n" . __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' ); |
741 $body .= "\n" . __( 'https://wordpress.org/support/' ); |
788 $body .= "\n" . __( 'https://wordpress.org/support/forums/' ); |
742 } |
789 } |
743 |
790 |
744 // Updates are important! |
791 // Updates are important! |
745 if ( $type != 'success' || $newer_version_available ) { |
792 if ( 'success' !== $type || $newer_version_available ) { |
746 $body .= "\n\n" . __( 'Keeping your site updated is important for security. It also makes the internet a safer place for you and your readers.' ); |
793 $body .= "\n\n" . __( 'Keeping your site updated is important for security. It also makes the internet a safer place for you and your readers.' ); |
747 } |
794 } |
748 |
795 |
749 if ( $critical_support ) { |
796 if ( $critical_support ) { |
750 $body .= ' ' . __( "If you reach out to us, we'll also ensure you'll never have this problem again." ); |
797 $body .= ' ' . __( "If you reach out to us, we'll also ensure you'll never have this problem again." ); |
751 } |
798 } |
752 |
799 |
753 // If things are successful and we're now on the latest, mention plugins and themes if any are out of date. |
800 // If things are successful and we're now on the latest, mention plugins and themes if any are out of date. |
754 if ( $type == 'success' && ! $newer_version_available && ( get_plugin_updates() || get_theme_updates() ) ) { |
801 if ( 'success' === $type && ! $newer_version_available && ( get_plugin_updates() || get_theme_updates() ) ) { |
755 $body .= "\n\n" . __( 'You also have some plugins or themes with updates available. Update them now:' ); |
802 $body .= "\n\n" . __( 'You also have some plugins or themes with updates available. Update them now:' ); |
756 $body .= "\n" . network_admin_url(); |
803 $body .= "\n" . network_admin_url(); |
757 } |
804 } |
758 |
805 |
759 $body .= "\n\n" . __( 'The WordPress Team' ) . "\n"; |
806 $body .= "\n\n" . __( 'The WordPress Team' ) . "\n"; |
760 |
807 |
761 if ( 'critical' == $type && is_wp_error( $result ) ) { |
808 if ( 'critical' === $type && is_wp_error( $result ) ) { |
762 $body .= "\n***\n\n"; |
809 $body .= "\n***\n\n"; |
763 /* translators: %s: WordPress version */ |
810 /* translators: %s: WordPress version. */ |
764 $body .= sprintf( __( 'Your site was running version %s.' ), get_bloginfo( 'version' ) ); |
811 $body .= sprintf( __( 'Your site was running version %s.' ), get_bloginfo( 'version' ) ); |
765 $body .= ' ' . __( 'We have some data that describes the error your site encountered.' ); |
812 $body .= ' ' . __( 'We have some data that describes the error your site encountered.' ); |
766 $body .= ' ' . __( 'Your hosting company, support forum volunteers, or a friendly developer may be able to use this information to help you:' ); |
813 $body .= ' ' . __( 'Your hosting company, support forum volunteers, or a friendly developer may be able to use this information to help you:' ); |
767 |
814 |
768 // If we had a rollback and we're still critical, then the rollback failed too. |
815 // If we had a rollback and we're still critical, then the rollback failed too. |
769 // Loop through all errors (the main WP_Error, the update result, the rollback result) for code, data, etc. |
816 // Loop through all errors (the main WP_Error, the update result, the rollback result) for code, data, etc. |
770 if ( 'rollback_was_required' == $result->get_error_code() ) { |
817 if ( 'rollback_was_required' === $result->get_error_code() ) { |
771 $errors = array( $result, $result->get_error_data()->update, $result->get_error_data()->rollback ); |
818 $errors = array( $result, $result->get_error_data()->update, $result->get_error_data()->rollback ); |
772 } else { |
819 } else { |
773 $errors = array( $result ); |
820 $errors = array( $result ); |
774 } |
821 } |
775 |
822 |
776 foreach ( $errors as $error ) { |
823 foreach ( $errors as $error ) { |
777 if ( ! is_wp_error( $error ) ) { |
824 if ( ! is_wp_error( $error ) ) { |
778 continue; |
825 continue; |
779 } |
826 } |
|
827 |
780 $error_code = $error->get_error_code(); |
828 $error_code = $error->get_error_code(); |
781 /* translators: %s: Error code */ |
829 /* translators: %s: Error code. */ |
782 $body .= "\n\n" . sprintf( __( 'Error code: %s' ), $error_code ); |
830 $body .= "\n\n" . sprintf( __( 'Error code: %s' ), $error_code ); |
783 if ( 'rollback_was_required' == $error_code ) { |
831 |
|
832 if ( 'rollback_was_required' === $error_code ) { |
784 continue; |
833 continue; |
785 } |
834 } |
|
835 |
786 if ( $error->get_error_message() ) { |
836 if ( $error->get_error_message() ) { |
787 $body .= "\n" . $error->get_error_message(); |
837 $body .= "\n" . $error->get_error_message(); |
788 } |
838 } |
|
839 |
789 $error_data = $error->get_error_data(); |
840 $error_data = $error->get_error_data(); |
790 if ( $error_data ) { |
841 if ( $error_data ) { |
791 $body .= "\n" . implode( ', ', (array) $error_data ); |
842 $body .= "\n" . implode( ', ', (array) $error_data ); |
792 } |
843 } |
793 } |
844 } |
|
845 |
794 $body .= "\n"; |
846 $body .= "\n"; |
795 } |
847 } |
796 |
848 |
797 $to = get_site_option( 'admin_email' ); |
849 $to = get_site_option( 'admin_email' ); |
798 $headers = ''; |
850 $headers = ''; |
821 $email = apply_filters( 'auto_core_update_email', $email, $type, $core_update, $result ); |
873 $email = apply_filters( 'auto_core_update_email', $email, $type, $core_update, $result ); |
822 |
874 |
823 wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] ); |
875 wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] ); |
824 } |
876 } |
825 |
877 |
|
878 |
|
879 /** |
|
880 * If we tried to perform plugin or theme updates, check if we should send an email. |
|
881 * |
|
882 * @since 5.5.0 |
|
883 * |
|
884 * @param array $update_results The results of update tasks. |
|
885 */ |
|
886 protected function after_plugin_theme_update( $update_results ) { |
|
887 $successful_updates = array(); |
|
888 $failed_updates = array(); |
|
889 |
|
890 /** |
|
891 * Filters whether to send an email following an automatic background plugin update. |
|
892 * |
|
893 * @since 5.5.0 |
|
894 * @since 5.5.1 Added the $update_results parameter. |
|
895 * |
|
896 * @param bool $enabled True if plugins notifications are enabled, false otherwise. |
|
897 * @param array $update_results The results of plugins update tasks. |
|
898 */ |
|
899 $notifications_enabled = apply_filters( 'auto_plugin_update_send_email', true, $update_results['plugin'] ); |
|
900 |
|
901 if ( ! empty( $update_results['plugin'] ) && $notifications_enabled ) { |
|
902 foreach ( $update_results['plugin'] as $update_result ) { |
|
903 if ( true === $update_result->result ) { |
|
904 $successful_updates['plugin'][] = $update_result; |
|
905 } else { |
|
906 $failed_updates['plugin'][] = $update_result; |
|
907 } |
|
908 } |
|
909 } |
|
910 |
|
911 /** |
|
912 * Filters whether to send an email following an automatic background theme update. |
|
913 * |
|
914 * @since 5.5.0 |
|
915 * @since 5.5.1 Added the $update_results parameter. |
|
916 * |
|
917 * @param bool $enabled True if notifications are enabled, false otherwise. |
|
918 * @param array $update_results The results of theme update tasks. |
|
919 */ |
|
920 $notifications_enabled = apply_filters( 'auto_theme_update_send_email', true, $update_results['theme'] ); |
|
921 |
|
922 if ( ! empty( $update_results['theme'] ) && $notifications_enabled ) { |
|
923 foreach ( $update_results['theme'] as $update_result ) { |
|
924 if ( true === $update_result->result ) { |
|
925 $successful_updates['theme'][] = $update_result; |
|
926 } else { |
|
927 $failed_updates['theme'][] = $update_result; |
|
928 } |
|
929 } |
|
930 } |
|
931 |
|
932 if ( empty( $successful_updates ) && empty( $failed_updates ) ) { |
|
933 return; |
|
934 } |
|
935 |
|
936 if ( empty( $failed_updates ) ) { |
|
937 $this->send_plugin_theme_email( 'success', $successful_updates, $failed_updates ); |
|
938 } elseif ( empty( $successful_updates ) ) { |
|
939 $this->send_plugin_theme_email( 'fail', $successful_updates, $failed_updates ); |
|
940 } else { |
|
941 $this->send_plugin_theme_email( 'mixed', $successful_updates, $failed_updates ); |
|
942 } |
|
943 } |
|
944 |
|
945 /** |
|
946 * Sends an email upon the completion or failure of a plugin or theme background update. |
|
947 * |
|
948 * @since 5.5.0 |
|
949 * |
|
950 * @param string $type The type of email to send. Can be one of 'success', 'fail', 'mixed'. |
|
951 * @param array $successful_updates A list of updates that succeeded. |
|
952 * @param array $failed_updates A list of updates that failed. |
|
953 */ |
|
954 protected function send_plugin_theme_email( $type, $successful_updates, $failed_updates ) { |
|
955 // No updates were attempted. |
|
956 if ( empty( $successful_updates ) && empty( $failed_updates ) ) { |
|
957 return; |
|
958 } |
|
959 |
|
960 $unique_failures = false; |
|
961 $past_failure_emails = get_option( 'auto_plugin_theme_update_emails', array() ); |
|
962 |
|
963 /* |
|
964 * When only failures have occurred, an email should only be sent if there are unique failures. |
|
965 * A failure is considered unique if an email has not been sent for an update attempt failure |
|
966 * to a plugin or theme with the same new_version. |
|
967 */ |
|
968 if ( 'fail' === $type ) { |
|
969 foreach ( $failed_updates as $update_type => $failures ) { |
|
970 foreach ( $failures as $failed_update ) { |
|
971 if ( ! isset( $past_failure_emails[ $failed_update->item->{$update_type} ] ) ) { |
|
972 $unique_failures = true; |
|
973 continue; |
|
974 } |
|
975 |
|
976 // Check that the failure represents a new failure based on the new_version. |
|
977 if ( version_compare( $past_failure_emails[ $failed_update->item->{$update_type} ], $failed_update->item->new_version, '<' ) ) { |
|
978 $unique_failures = true; |
|
979 } |
|
980 } |
|
981 } |
|
982 |
|
983 if ( ! $unique_failures ) { |
|
984 return; |
|
985 } |
|
986 } |
|
987 |
|
988 $body = array(); |
|
989 $successful_plugins = ( ! empty( $successful_updates['plugin'] ) ); |
|
990 $successful_themes = ( ! empty( $successful_updates['theme'] ) ); |
|
991 $failed_plugins = ( ! empty( $failed_updates['plugin'] ) ); |
|
992 $failed_themes = ( ! empty( $failed_updates['theme'] ) ); |
|
993 |
|
994 switch ( $type ) { |
|
995 case 'success': |
|
996 if ( $successful_plugins && $successful_themes ) { |
|
997 /* translators: %s: Site title. */ |
|
998 $subject = __( '[%s] Some plugins and themes have automatically updated' ); |
|
999 $body[] = sprintf( |
|
1000 /* translators: %s: Home URL. */ |
|
1001 __( 'Howdy! Some plugins and themes have automatically updated to their latest versions on your site at %s. No further action is needed on your part.' ), |
|
1002 home_url() |
|
1003 ); |
|
1004 } elseif ( $successful_plugins ) { |
|
1005 /* translators: %s: Site title. */ |
|
1006 $subject = __( '[%s] Some plugins were automatically updated' ); |
|
1007 $body[] = sprintf( |
|
1008 /* translators: %s: Home URL. */ |
|
1009 __( 'Howdy! Some plugins have automatically updated to their latest versions on your site at %s. No further action is needed on your part.' ), |
|
1010 home_url() |
|
1011 ); |
|
1012 } else { |
|
1013 /* translators: %s: Site title. */ |
|
1014 $subject = __( '[%s] Some themes were automatically updated' ); |
|
1015 $body[] = sprintf( |
|
1016 /* translators: %s: Home URL. */ |
|
1017 __( 'Howdy! Some themes have automatically updated to their latest versions on your site at %s. No further action is needed on your part.' ), |
|
1018 home_url() |
|
1019 ); |
|
1020 } |
|
1021 |
|
1022 break; |
|
1023 case 'fail': |
|
1024 case 'mixed': |
|
1025 if ( $failed_plugins && $failed_themes ) { |
|
1026 /* translators: %s: Site title. */ |
|
1027 $subject = __( '[%s] Some plugins and themes have failed to update' ); |
|
1028 $body[] = sprintf( |
|
1029 /* translators: %s: Home URL. */ |
|
1030 __( 'Howdy! Plugins and themes failed to update on your site at %s.' ), |
|
1031 home_url() |
|
1032 ); |
|
1033 } elseif ( $failed_plugins ) { |
|
1034 /* translators: %s: Site title. */ |
|
1035 $subject = __( '[%s] Some plugins have failed to update' ); |
|
1036 $body[] = sprintf( |
|
1037 /* translators: %s: Home URL. */ |
|
1038 __( 'Howdy! Plugins failed to update on your site at %s.' ), |
|
1039 home_url() |
|
1040 ); |
|
1041 } else { |
|
1042 /* translators: %s: Site title. */ |
|
1043 $subject = __( '[%s] Some themes have failed to update' ); |
|
1044 $body[] = sprintf( |
|
1045 /* translators: %s: Home URL. */ |
|
1046 __( 'Howdy! Themes failed to update on your site at %s.' ), |
|
1047 home_url() |
|
1048 ); |
|
1049 } |
|
1050 |
|
1051 break; |
|
1052 } |
|
1053 |
|
1054 if ( in_array( $type, array( 'fail', 'mixed' ), true ) ) { |
|
1055 $body[] = "\n"; |
|
1056 $body[] = __( 'Please check your site now. It’s possible that everything is working. If there are updates available, you should update.' ); |
|
1057 $body[] = "\n"; |
|
1058 |
|
1059 // List failed plugin updates. |
|
1060 if ( ! empty( $failed_updates['plugin'] ) ) { |
|
1061 $body[] = __( 'These plugins failed to update:' ); |
|
1062 |
|
1063 foreach ( $failed_updates['plugin'] as $item ) { |
|
1064 $body[] = sprintf( |
|
1065 /* translators: 1: Plugin name, 2: Version number. */ |
|
1066 __( '- %1$s version %2$s' ), |
|
1067 $item->name, |
|
1068 $item->item->new_version |
|
1069 ); |
|
1070 |
|
1071 $past_failure_emails[ $item->item->plugin ] = $item->item->new_version; |
|
1072 } |
|
1073 |
|
1074 $body[] = "\n"; |
|
1075 } |
|
1076 |
|
1077 // List failed theme updates. |
|
1078 if ( ! empty( $failed_updates['theme'] ) ) { |
|
1079 $body[] = __( 'These themes failed to update:' ); |
|
1080 |
|
1081 foreach ( $failed_updates['theme'] as $item ) { |
|
1082 $body[] = sprintf( |
|
1083 /* translators: 1: Theme name, 2: Version number. */ |
|
1084 __( '- %1$s version %2$s' ), |
|
1085 $item->name, |
|
1086 $item->item->new_version |
|
1087 ); |
|
1088 |
|
1089 $past_failure_emails[ $item->item->theme ] = $item->item->new_version; |
|
1090 } |
|
1091 |
|
1092 $body[] = "\n"; |
|
1093 } |
|
1094 } |
|
1095 |
|
1096 // List successful updates. |
|
1097 if ( in_array( $type, array( 'success', 'mixed' ), true ) ) { |
|
1098 $body[] = "\n"; |
|
1099 |
|
1100 // List successful plugin updates. |
|
1101 if ( ! empty( $successful_updates['plugin'] ) ) { |
|
1102 $body[] = __( 'These plugins are now up to date:' ); |
|
1103 |
|
1104 foreach ( $successful_updates['plugin'] as $item ) { |
|
1105 $body[] = sprintf( |
|
1106 /* translators: 1: Plugin name, 2: Version number. */ |
|
1107 __( '- %1$s version %2$s' ), |
|
1108 $item->name, |
|
1109 $item->item->new_version |
|
1110 ); |
|
1111 |
|
1112 unset( $past_failure_emails[ $item->item->plugin ] ); |
|
1113 } |
|
1114 |
|
1115 $body[] = "\n"; |
|
1116 } |
|
1117 |
|
1118 // List successful theme updates. |
|
1119 if ( ! empty( $successful_updates['theme'] ) ) { |
|
1120 $body[] = __( 'These themes are now up to date:' ); |
|
1121 |
|
1122 foreach ( $successful_updates['theme'] as $item ) { |
|
1123 $body[] = sprintf( |
|
1124 /* translators: 1: Theme name, 2: Version number. */ |
|
1125 __( '- %1$s version %2$s' ), |
|
1126 $item->name, |
|
1127 $item->item->new_version |
|
1128 ); |
|
1129 |
|
1130 unset( $past_failure_emails[ $item->item->theme ] ); |
|
1131 } |
|
1132 |
|
1133 $body[] = "\n"; |
|
1134 } |
|
1135 } |
|
1136 |
|
1137 if ( $failed_plugins ) { |
|
1138 $body[] = sprintf( |
|
1139 /* translators: %s: Plugins screen URL. */ |
|
1140 __( 'To manage plugins on your site, visit the Plugins page: %s' ), |
|
1141 admin_url( 'plugins.php' ) |
|
1142 ); |
|
1143 $body[] = "\n"; |
|
1144 } |
|
1145 |
|
1146 if ( $failed_themes ) { |
|
1147 $body[] = sprintf( |
|
1148 /* translators: %s: Themes screen URL. */ |
|
1149 __( 'To manage themes on your site, visit the Themes page: %s' ), |
|
1150 admin_url( 'themes.php' ) |
|
1151 ); |
|
1152 $body[] = "\n"; |
|
1153 } |
|
1154 |
|
1155 // Add a note about the support forums. |
|
1156 $body[] = __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' ); |
|
1157 $body[] = __( 'https://wordpress.org/support/forums/' ); |
|
1158 $body[] = "\n" . __( 'The WordPress Team' ); |
|
1159 |
|
1160 $body = implode( "\n", $body ); |
|
1161 $to = get_site_option( 'admin_email' ); |
|
1162 $subject = sprintf( $subject, wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ) ); |
|
1163 $headers = ''; |
|
1164 |
|
1165 $email = compact( 'to', 'subject', 'body', 'headers' ); |
|
1166 |
|
1167 /** |
|
1168 * Filters the email sent following an automatic background update for plugins and themes. |
|
1169 * |
|
1170 * @since 5.5.0 |
|
1171 * |
|
1172 * @param array $email { |
|
1173 * Array of email arguments that will be passed to wp_mail(). |
|
1174 * |
|
1175 * @type string $to The email recipient. An array of emails |
|
1176 * can be returned, as handled by wp_mail(). |
|
1177 * @type string $subject The email's subject. |
|
1178 * @type string $body The email message body. |
|
1179 * @type string $headers Any email headers, defaults to no headers. |
|
1180 * } |
|
1181 * @param string $type The type of email being sent. Can be one of 'success', 'fail', 'mixed'. |
|
1182 * @param array $successful_updates A list of updates that succeeded. |
|
1183 * @param array $failed_updates A list of updates that failed. |
|
1184 */ |
|
1185 $email = apply_filters( 'auto_plugin_theme_update_email', $email, $type, $successful_updates, $failed_updates ); |
|
1186 |
|
1187 $result = wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] ); |
|
1188 |
|
1189 if ( $result ) { |
|
1190 update_option( 'auto_plugin_theme_update_emails', $past_failure_emails ); |
|
1191 } |
|
1192 } |
|
1193 |
826 /** |
1194 /** |
827 * Prepares and sends an email of a full log of background update results, useful for debugging and geekery. |
1195 * Prepares and sends an email of a full log of background update results, useful for debugging and geekery. |
828 * |
1196 * |
829 * @since 3.7.0 |
1197 * @since 3.7.0 |
830 */ |
1198 */ |