Make WordPress Core


Ignore:
Timestamp:
05/04/2023 02:34:58 AM (18 months ago)
Author:
SergeyBiryukov
Message:

Upgrade/Install: Create a temporary backup of plugins and themes before updating.

This aims to make the update process more reliable and ensures that if a plugin or theme update fails, the previous version can be safely restored.

  • When updating a plugin or theme, the old version is moved to a temporary backup directory:
    • wp-content/upgrade-temp-backup/plugins/[plugin-slug] for plugins
    • wp-content/upgrade-temp-backup/themes/[theme-slug] for themes.
  • If the update fails, then the backup kept in the temporary backup directory is restored to its original location.
  • If the update succeeds, the temporary backup is deleted.

To further help troubleshoot plugin and theme updates, two new checks were added to the Site Health screen:

  • A check to make sure that the upgrade-temp-backup directory is writable.
  • A check that there is enough disk space available to safely perform updates.

To avoid confusion: The temporary backup directory will NOT be used to “roll back” a plugin to a previous version after a completed update. This directory will simply contain a transient backup of the previous version of a plugin or theme being updated, and as soon as the update process finishes, the directory will be empty.

Follow-up to [55204], [55220].

Props afragen, costdev, pbiron, azaozz, hellofromTonya, aristath, peterwilsoncc, TJNowell, bronsonquick, Clorith, dd32, poena, TimothyBlynJacobs, audrasjb, mikeschroder, a2hosting, KZeni, galbaras, richards1052, Boniu91, mai21, francina, TobiasBg, desrosj, noisysocks, johnbillion, dlh, chaion07, davidbaumwald, jrf, thisisyeasin, ignatggeorgiev, SergeyBiryukov.
Fixes #51857.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-wp-site-health.php

    r55703 r55720  
    19271927
    19281928    /**
     1929     * Tests available disk space for updates.
     1930     *
     1931     * @since 6.3.0
     1932     *
     1933     * @return array The test results.
     1934     */
     1935    public function get_test_available_updates_disk_space() {
     1936        $available_space = function_exists( 'disk_free_space' ) ? @disk_free_space( WP_CONTENT_DIR . '/upgrade/' ) : false;
     1937
     1938        $available_space = false !== $available_space
     1939            ? (int) $available_space
     1940            : 0;
     1941
     1942        $result = array(
     1943            'label'       => __( 'Disk space available to safely perform updates' ),
     1944            'status'      => 'good',
     1945            'badge'       => array(
     1946                'label' => __( 'Security' ),
     1947                'color' => 'blue',
     1948            ),
     1949            'description' => sprintf(
     1950                /* translators: %s: Available disk space in MB or GB. */
     1951                '<p>' . __( '%s available disk space was detected, update routines can be performed safely.' ) . '</p>',
     1952                size_format( $available_space )
     1953            ),
     1954            'actions'     => '',
     1955            'test'        => 'available_updates_disk_space',
     1956        );
     1957
     1958        if ( $available_space < 100 * MB_IN_BYTES ) {
     1959            $result['description'] = __( 'Available disk space is low, less than 100 MB available.' );
     1960            $result['status']      = 'recommended';
     1961        }
     1962
     1963        if ( $available_space < 20 * MB_IN_BYTES ) {
     1964            $result['description'] = __( 'Available disk space is critically low, less than 20 MB available. Proceed with caution, updates may fail.' );
     1965            $result['status']      = 'critical';
     1966        }
     1967
     1968        if ( ! $available_space ) {
     1969            $result['description'] = __( 'Could not determine available disk space for updates.' );
     1970            $result['status']      = 'recommended';
     1971        }
     1972
     1973        return $result;
     1974    }
     1975
     1976    /**
     1977     * Tests if plugin and theme temporary backup directories are writable or can be created.
     1978     *
     1979     * @since 6.3.0
     1980     *
     1981     * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
     1982     *
     1983     * @return array The test results.
     1984     */
     1985    public function get_test_update_temp_backup_writable() {
     1986        global $wp_filesystem;
     1987
     1988        $result = array(
     1989            'label'       => __( 'Plugin and theme temporary backup directory is writable' ),
     1990            'status'      => 'good',
     1991            'badge'       => array(
     1992                'label' => __( 'Security' ),
     1993                'color' => 'blue',
     1994            ),
     1995            'description' => sprintf(
     1996                /* translators: %s: wp-content/upgrade-temp-backup */
     1997                '<p>' . __( 'The %s directory used to improve the stability of plugin and theme updates is writable.' ) . '</p>',
     1998                '<code>wp-content/upgrade-temp-backup</code>'
     1999            ),
     2000            'actions'     => '',
     2001            'test'        => 'update_temp_backup_writable',
     2002        );
     2003
     2004        if ( ! $wp_filesystem ) {
     2005            require_once ABSPATH . '/wp-admin/includes/file.php';
     2006            WP_Filesystem();
     2007        }
     2008
     2009        $wp_content = $wp_filesystem->wp_content_dir();
     2010
     2011        if ( ! $wp_content ) {
     2012            $result['status'] = 'critical';
     2013            $result['label']  = sprintf(
     2014                /* translators: %s: wp-content */
     2015                __( 'Unable to locate WordPress content directory (%s)' ),
     2016                '<code>wp-content</code>'
     2017            );
     2018            $result['description'] = sprintf(
     2019                /* translators: %s: wp-content */
     2020                '<p>' . __( 'The %s directory cannot be located.' ) . '</p>',
     2021                '<code>wp-content</code>'
     2022            );
     2023            return $result;
     2024        }
     2025
     2026        $upgrade_dir_exists      = $wp_filesystem->is_dir( "$wp_content/upgrade" );
     2027        $upgrade_dir_is_writable = $wp_filesystem->is_writable( "$wp_content/upgrade" );
     2028        $backup_dir_exists       = $wp_filesystem->is_dir( "$wp_content/upgrade-temp-backup" );
     2029        $backup_dir_is_writable  = $wp_filesystem->is_writable( "$wp_content/upgrade-temp-backup" );
     2030
     2031        $plugins_dir_exists      = $wp_filesystem->is_dir( "$wp_content/upgrade-temp-backup/plugins" );
     2032        $plugins_dir_is_writable = $wp_filesystem->is_writable( "$wp_content/upgrade-temp-backup/plugins" );
     2033        $themes_dir_exists       = $wp_filesystem->is_dir( "$wp_content/upgrade-temp-backup/themes" );
     2034        $themes_dir_is_writable  = $wp_filesystem->is_writable( "$wp_content/upgrade-temp-backup/themes" );
     2035
     2036        if ( $plugins_dir_exists && ! $plugins_dir_is_writable && $themes_dir_exists && ! $themes_dir_is_writable ) {
     2037            $result['status']      = 'critical';
     2038            $result['label']       = __( 'Plugin and theme temporary backup directories exist but are not writable' );
     2039            $result['description'] = sprintf(
     2040                /* translators: 1: wp-content/upgrade-temp-backup/plugins, 2: wp-content/upgrade-temp-backup/themes. */
     2041                '<p>' . __( 'The %1$s and %2$s directories exist but are not writable. These directories are used to improve the stability of plugin updates. Please make sure the server has write permissions to these directories.' ) . '</p>',
     2042                '<code>wp-content/upgrade-temp-backup/plugins</code>',
     2043                '<code>wp-content/upgrade-temp-backup/themes</code>'
     2044            );
     2045            return $result;
     2046        }
     2047
     2048        if ( $plugins_dir_exists && ! $plugins_dir_is_writable ) {
     2049            $result['status']      = 'critical';
     2050            $result['label']       = __( 'Plugin temporary backup directory exists but is not writable' );
     2051            $result['description'] = sprintf(
     2052                /* translators: %s: wp-content/upgrade-temp-backup/plugins */
     2053                '<p>' . __( 'The %s directory exists but is not writable. This directory is used to improve the stability of plugin updates. Please make sure the server has write permissions to this directory.' ) . '</p>',
     2054                '<code>wp-content/upgrade-temp-backup/plugins</code>'
     2055            );
     2056            return $result;
     2057        }
     2058
     2059        if ( $themes_dir_exists && ! $themes_dir_is_writable ) {
     2060            $result['status']      = 'critical';
     2061            $result['label']       = __( 'Theme temporary backup directory exists but is not writable' );
     2062            $result['description'] = sprintf(
     2063                /* translators: %s: wp-content/upgrade-temp-backup/themes */
     2064                '<p>' . __( 'The %s directory exists but is not writable. This directory is used to improve the stability of theme updates. Please make sure the server has write permissions to this directory.' ) . '</p>',
     2065                '<code>wp-content/upgrade-temp-backup/themes</code>'
     2066            );
     2067            return $result;
     2068        }
     2069
     2070        if ( ( ! $plugins_dir_exists || ! $themes_dir_exists ) && $backup_dir_exists && ! $backup_dir_is_writable ) {
     2071            $result['status']      = 'critical';
     2072            $result['label']       = __( 'The temporary backup directory exists but is not writable' );
     2073            $result['description'] = sprintf(
     2074                /* translators: %s: wp-content/upgrade-temp-backup */
     2075                '<p>' . __( 'The %s directory exists but is not writable. This directory is used to improve the stability of plugin and theme updates. Please make sure the server has write permissions to this directory.' ) . '</p>',
     2076                '<code>wp-content/upgrade-temp-backup</code>'
     2077            );
     2078            return $result;
     2079        }
     2080
     2081        if ( ! $backup_dir_exists && $upgrade_dir_exists && ! $upgrade_dir_is_writable ) {
     2082            $result['status'] = 'critical';
     2083            $result['label']  = sprintf(
     2084                /* translators: %s: upgrade */
     2085                __( 'The %s directory exists but is not writable' ),
     2086                'upgrade'
     2087            );
     2088            $result['description'] = sprintf(
     2089                /* translators: %s: wp-content/upgrade */
     2090                '<p>' . __( 'The %s directory exists but is not writable. This directory is used for plugin and theme updates. Please make sure the server has write permissions to this directory.' ) . '</p>',
     2091                '<code>wp-content/upgrade</code>'
     2092            );
     2093            return $result;
     2094        }
     2095
     2096        if ( ! $upgrade_dir_exists && ! $wp_filesystem->is_writable( $wp_content ) ) {
     2097            $result['status'] = 'critical';
     2098            $result['label']  = sprintf(
     2099                /* translators: %s: upgrade */
     2100                __( 'The %s directory cannot be created' ),
     2101                'upgrade'
     2102            );
     2103            $result['description'] = sprintf(
     2104                /* translators: 1: wp-content/upgrade, 2: wp-content. */
     2105                '<p>' . __( 'The %1$s directory does not exist, and the server does not have write permissions in %2$s to create it. This directory is used for plugin and theme updates. Please make sure the server has write permissions in %2$s.' ) . '</p>',
     2106                '<code>wp-content/upgrade</code>',
     2107                '<code>wp-content</code>'
     2108            );
     2109            return $result;
     2110        }
     2111
     2112        return $result;
     2113    }
     2114
     2115    /**
    19292116     * Tests if loopbacks work as expected.
    19302117     *
     
    25332720        $tests = array(
    25342721            'direct' => array(
    2535                 'wordpress_version'         => array(
     2722                'wordpress_version'            => array(
    25362723                    'label' => __( 'WordPress Version' ),
    25372724                    'test'  => 'wordpress_version',
    25382725                ),
    2539                 'plugin_version'            => array(
     2726                'plugin_version'               => array(
    25402727                    'label' => __( 'Plugin Versions' ),
    25412728                    'test'  => 'plugin_version',
    25422729                ),
    2543                 'theme_version'             => array(
     2730                'theme_version'                => array(
    25442731                    'label' => __( 'Theme Versions' ),
    25452732                    'test'  => 'theme_version',
    25462733                ),
    2547                 'php_version'               => array(
     2734                'php_version'                  => array(
    25482735                    'label' => __( 'PHP Version' ),
    25492736                    'test'  => 'php_version',
    25502737                ),
    2551                 'php_extensions'            => array(
     2738                'php_extensions'               => array(
    25522739                    'label' => __( 'PHP Extensions' ),
    25532740                    'test'  => 'php_extensions',
    25542741                ),
    2555                 'php_default_timezone'      => array(
     2742                'php_default_timezone'         => array(
    25562743                    'label' => __( 'PHP Default Timezone' ),
    25572744                    'test'  => 'php_default_timezone',
    25582745                ),
    2559                 'php_sessions'              => array(
     2746                'php_sessions'                 => array(
    25602747                    'label' => __( 'PHP Sessions' ),
    25612748                    'test'  => 'php_sessions',
    25622749                ),
    2563                 'sql_server'                => array(
     2750                'sql_server'                   => array(
    25642751                    'label' => __( 'Database Server version' ),
    25652752                    'test'  => 'sql_server',
    25662753                ),
    2567                 'utf8mb4_support'           => array(
     2754                'utf8mb4_support'              => array(
    25682755                    'label' => __( 'MySQL utf8mb4 support' ),
    25692756                    'test'  => 'utf8mb4_support',
    25702757                ),
    2571                 'ssl_support'               => array(
     2758                'ssl_support'                  => array(
    25722759                    'label' => __( 'Secure communication' ),
    25732760                    'test'  => 'ssl_support',
    25742761                ),
    2575                 'scheduled_events'          => array(
     2762                'scheduled_events'             => array(
    25762763                    'label' => __( 'Scheduled events' ),
    25772764                    'test'  => 'scheduled_events',
    25782765                ),
    2579                 'http_requests'             => array(
     2766                'http_requests'                => array(
    25802767                    'label' => __( 'HTTP Requests' ),
    25812768                    'test'  => 'http_requests',
    25822769                ),
    2583                 'rest_availability'         => array(
     2770                'rest_availability'            => array(
    25842771                    'label'     => __( 'REST API availability' ),
    25852772                    'test'      => 'rest_availability',
    25862773                    'skip_cron' => true,
    25872774                ),
    2588                 'debug_enabled'             => array(
     2775                'debug_enabled'                => array(
    25892776                    'label' => __( 'Debugging enabled' ),
    25902777                    'test'  => 'is_in_debug_mode',
    25912778                ),
    2592                 'file_uploads'              => array(
     2779                'file_uploads'                 => array(
    25932780                    'label' => __( 'File uploads' ),
    25942781                    'test'  => 'file_uploads',
    25952782                ),
    2596                 'plugin_theme_auto_updates' => array(
     2783                'plugin_theme_auto_updates'    => array(
    25972784                    'label' => __( 'Plugin and theme auto-updates' ),
    25982785                    'test'  => 'plugin_theme_auto_updates',
     2786                ),
     2787                'update_temp_backup_writable'  => array(
     2788                    'label' => __( 'Plugin and theme temporary backup directory access' ),
     2789                    'test'  => 'update_temp_backup_writable',
     2790                ),
     2791                'available_updates_disk_space' => array(
     2792                    'label' => __( 'Available disk space' ),
     2793                    'test'  => 'available_updates_disk_space',
    25992794                ),
    26002795            ),
Note: See TracChangeset for help on using the changeset viewer.