diff -r 7b1b88e27a20 -r 48c4eec2b7e6 wp/wp-includes/update.php --- a/wp/wp-includes/update.php Thu Sep 29 08:06:27 2022 +0200 +++ b/wp/wp-includes/update.php Fri Sep 05 18:40:08 2025 +0200 @@ -1,13 +1,13 @@ updates = array(); $current->version_checked = $wp_version; } @@ -73,7 +74,9 @@ $current->last_checked = time(); set_site_transient( 'update_core', $current ); - if ( method_exists( $wpdb, 'db_version' ) ) { + if ( method_exists( $wpdb, 'db_server_info' ) ) { + $mysql_version = $wpdb->db_server_info(); + } elseif ( method_exists( $wpdb, 'db_version' ) ) { $mysql_version = preg_replace( '/[^0-9.].*/', '', $wpdb->db_version() ); } else { $mysql_version = 'N/A'; @@ -89,6 +92,8 @@ $wp_install = home_url( '/' ); } + $extensions = get_loaded_extensions(); + sort( $extensions, SORT_STRING | SORT_FLAG_CASE ); $query = array( 'version' => $wp_version, 'php' => $php_version, @@ -99,8 +104,42 @@ 'users' => get_user_count(), 'multisite_enabled' => $multisite_enabled, 'initial_db_version' => get_site_option( 'initial_db_version' ), + 'extensions' => array_combine( $extensions, array_map( 'phpversion', $extensions ) ), + 'platform_flags' => array( + 'os' => PHP_OS, + 'bits' => PHP_INT_SIZE === 4 ? 32 : 64, + ), + 'image_support' => array(), ); + if ( function_exists( 'gd_info' ) ) { + $gd_info = gd_info(); + // Filter to supported values. + $gd_info = array_filter( $gd_info ); + + // Add data for GD WebP and AVIF support. + $query['image_support']['gd'] = array_keys( + array_filter( + array( + 'webp' => isset( $gd_info['WebP Support'] ), + 'avif' => isset( $gd_info['AVIF Support'] ), + ) + ) + ); + } + + if ( class_exists( 'Imagick' ) ) { + // Add data for Imagick WebP and AVIF support. + $query['image_support']['imagick'] = array_keys( + array_filter( + array( + 'webp' => ! empty( Imagick::queryFormats( 'WEBP' ) ), + 'avif' => ! empty( Imagick::queryFormats( 'AVIF' ) ), + ) + ) + ); + } + /** * Filters the query arguments sent as part of the core version check. * @@ -163,7 +202,8 @@ $response = wp_remote_post( $url, $options ); if ( $ssl && is_wp_error( $response ) ) { - trigger_error( + wp_trigger_error( + __FUNCTION__, sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the support forums.' ), @@ -290,10 +330,10 @@ $current = get_site_transient( 'update_plugins' ); if ( ! is_object( $current ) ) { - $current = new stdClass; + $current = new stdClass(); } - $updates = new stdClass; + $updates = new stdClass(); $updates->last_checked = time(); $updates->response = array(); $updates->translations = array(); @@ -363,13 +403,13 @@ * @since 3.7.0 * @since 4.5.0 The default value of the `$locales` parameter changed to include all locales. * - * @param array $locales Plugin locales. Default is all available locales of the site. + * @param string[] $locales Plugin locales. Default is all available locales of the site. */ $locales = apply_filters( 'plugins_update_check_locales', $locales ); $locales = array_unique( $locales ); if ( $doing_cron ) { - $timeout = 30; + $timeout = 30; // 30 seconds. } else { // Three seconds, plus one extra second for every 10 plugins. $timeout = 3 + (int) ( count( $plugins ) / 10 ); @@ -401,7 +441,8 @@ $raw_response = wp_remote_post( $url, $options ); if ( $ssl && is_wp_error( $raw_response ) ) { - trigger_error( + wp_trigger_error( + __FUNCTION__, sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the support forums.' ), @@ -430,7 +471,7 @@ continue; } - $hostname = wp_parse_url( esc_url_raw( $plugin_data['UpdateURI'] ), PHP_URL_HOST ); + $hostname = wp_parse_url( sanitize_url( $plugin_data['UpdateURI'] ), PHP_URL_HOST ); /** * Filters the update response for a given plugin hostname. @@ -469,7 +510,7 @@ * } * @param array $plugin_data Plugin headers. * @param string $plugin_file Plugin filename. - * @param array $locales Installed locales to look translations for. + * @param string[] $locales Installed locales to look up translations for. */ $update = apply_filters( "update_plugins_{$hostname}", false, $plugin_data, $plugin_file, $locales ); @@ -514,7 +555,7 @@ } } - $sanitize_plugin_update_payload = static function( &$item ) { + $sanitize_plugin_update_payload = static function ( &$item ) { $item = (object) $item; unset( $item->translations, $item->compatibility ); @@ -558,7 +599,7 @@ $last_update = get_site_transient( 'update_themes' ); if ( ! is_object( $last_update ) ) { - $last_update = new stdClass; + $last_update = new stdClass(); } $themes = array(); @@ -577,6 +618,7 @@ 'Version' => $theme->get( 'Version' ), 'Author' => $theme->get( 'Author' ), 'Author URI' => $theme->get( 'AuthorURI' ), + 'UpdateURI' => $theme->get( 'UpdateURI' ), 'Template' => $theme->get_template(), 'Stylesheet' => $theme->get_stylesheet(), ); @@ -644,13 +686,13 @@ * @since 3.7.0 * @since 4.5.0 The default value of the `$locales` parameter changed to include all locales. * - * @param array $locales Theme locales. Default is all available locales of the site. + * @param string[] $locales Theme locales. Default is all available locales of the site. */ $locales = apply_filters( 'themes_update_check_locales', $locales ); $locales = array_unique( $locales ); if ( $doing_cron ) { - $timeout = 30; + $timeout = 30; // 30 seconds. } else { // Three seconds, plus one extra second for every 10 themes. $timeout = 3 + (int) ( count( $themes ) / 10 ); @@ -681,7 +723,8 @@ $raw_response = wp_remote_post( $url, $options ); if ( $ssl && is_wp_error( $raw_response ) ) { - trigger_error( + wp_trigger_error( + __FUNCTION__, sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the support forums.' ), @@ -696,7 +739,7 @@ return; } - $new_update = new stdClass; + $new_update = new stdClass(); $new_update->last_checked = time(); $new_update->checked = $checked; @@ -708,6 +751,92 @@ $new_update->translations = $response['translations']; } + // Support updates for any themes using the `Update URI` header field. + foreach ( $themes as $theme_stylesheet => $theme_data ) { + if ( ! $theme_data['UpdateURI'] || isset( $new_update->response[ $theme_stylesheet ] ) ) { + continue; + } + + $hostname = wp_parse_url( sanitize_url( $theme_data['UpdateURI'] ), PHP_URL_HOST ); + + /** + * Filters the update response for a given theme hostname. + * + * The dynamic portion of the hook name, `$hostname`, refers to the hostname + * of the URI specified in the `Update URI` header field. + * + * @since 6.1.0 + * + * @param array|false $update { + * The theme update data with the latest details. Default false. + * + * @type string $id Optional. ID of the theme for update purposes, should be a URI + * specified in the `Update URI` header field. + * @type string $theme Directory name of the theme. + * @type string $version The version of the theme. + * @type string $url The URL for details of the theme. + * @type string $package Optional. The update ZIP for the theme. + * @type string $tested Optional. The version of WordPress the theme is tested against. + * @type string $requires_php Optional. The version of PHP which the theme requires. + * @type bool $autoupdate Optional. Whether the theme should automatically update. + * @type array $translations { + * Optional. List of translation updates for the theme. + * + * @type string $language The language the translation update is for. + * @type string $version The version of the theme this translation is for. + * This is not the version of the language file. + * @type string $updated The update timestamp of the translation file. + * Should be a date in the `YYYY-MM-DD HH:MM:SS` format. + * @type string $package The ZIP location containing the translation update. + * @type string $autoupdate Whether the translation should be automatically installed. + * } + * } + * @param array $theme_data Theme headers. + * @param string $theme_stylesheet Theme stylesheet. + * @param string[] $locales Installed locales to look up translations for. + */ + $update = apply_filters( "update_themes_{$hostname}", false, $theme_data, $theme_stylesheet, $locales ); + + if ( ! $update ) { + continue; + } + + $update = (object) $update; + + // Is it valid? We require at least a version. + if ( ! isset( $update->version ) ) { + continue; + } + + // This should remain constant. + $update->id = $theme_data['UpdateURI']; + + // WordPress needs the version field specified as 'new_version'. + if ( ! isset( $update->new_version ) ) { + $update->new_version = $update->version; + } + + // Handle any translation updates. + if ( ! empty( $update->translations ) ) { + foreach ( $update->translations as $translation ) { + if ( isset( $translation['language'], $translation['package'] ) ) { + $translation['type'] = 'theme'; + $translation['slug'] = isset( $update->theme ) ? $update->theme : $update->id; + + $new_update->translations[] = $translation; + } + } + } + + unset( $new_update->no_update[ $theme_stylesheet ], $new_update->response[ $theme_stylesheet ] ); + + if ( version_compare( $update->new_version, $theme_data['Version'], '>' ) ) { + $new_update->response[ $theme_stylesheet ] = (array) $update; + } else { + $new_update->no_update[ $theme_stylesheet ] = (array) $update; + } + } + set_site_transient( 'update_themes', $new_update ); } @@ -719,10 +848,10 @@ * @since 3.7.0 */ function wp_maybe_auto_update() { - include_once ABSPATH . 'wp-admin/includes/admin.php'; + require_once ABSPATH . 'wp-admin/includes/admin.php'; require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; - $upgrader = new WP_Automatic_Updater; + $upgrader = new WP_Automatic_Updater(); $upgrader->run(); } @@ -757,7 +886,7 @@ } /** - * Collect counts and UI strings for available updates + * Collects counts and UI strings for available updates. * * @since 3.3.0 * @@ -875,7 +1004,7 @@ wp_version_check(); } /** - * Check the last time plugins were run before checking plugin versions. + * Checks the last time plugins were run before checking plugin versions. * * This might have been backported to WordPress 2.6.1 for performance reasons. * This is used for the wp-admin to check only so often instead of every page @@ -897,7 +1026,7 @@ } /** - * Check themes versions only after a duration of time. + * Checks themes versions only after a duration of time. * * This is for performance reasons to make sure that on the theme version * checker is not run on every page load. @@ -918,7 +1047,7 @@ } /** - * Schedule core, theme, and plugin update checks. + * Schedules core, theme, and plugin update checks. * * @since 3.1.0 */ @@ -937,7 +1066,7 @@ } /** - * Clear existing update caches for plugins, themes, and core. + * Clears existing update caches for plugins, themes, and core. * * @since 4.1.0 */ @@ -953,6 +1082,73 @@ delete_site_transient( 'update_core' ); } +/** + * Schedules the removal of all contents in the temporary backup directory. + * + * @since 6.3.0 + */ +function wp_delete_all_temp_backups() { + /* + * Check if there is a lock, or if currently performing an Ajax request, + * in which case there is a chance an update is running. + * Reschedule for an hour from now and exit early. + */ + if ( get_option( 'core_updater.lock' ) || get_option( 'auto_updater.lock' ) || wp_doing_ajax() ) { + wp_schedule_single_event( time() + HOUR_IN_SECONDS, 'wp_delete_temp_updater_backups' ); + return; + } + + // This action runs on shutdown to make sure there are no plugin updates currently running. + add_action( 'shutdown', '_wp_delete_all_temp_backups' ); +} + +/** + * Deletes all contents in the temporary backup directory. + * + * @since 6.3.0 + * + * @access private + * + * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. + * + * @return void|WP_Error Void on success, or a WP_Error object on failure. + */ +function _wp_delete_all_temp_backups() { + global $wp_filesystem; + + if ( ! function_exists( 'WP_Filesystem' ) ) { + require_once ABSPATH . '/wp-admin/includes/file.php'; + } + + ob_start(); + $credentials = request_filesystem_credentials( '' ); + ob_end_clean(); + + if ( false === $credentials || ! WP_Filesystem( $credentials ) ) { + return new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) ); + } + + if ( ! $wp_filesystem->wp_content_dir() ) { + return new WP_Error( + 'fs_no_content_dir', + /* translators: %s: Directory name. */ + sprintf( __( 'Unable to locate WordPress content directory (%s).' ), 'wp-content' ) + ); + } + + $temp_backup_dir = $wp_filesystem->wp_content_dir() . 'upgrade-temp-backup/'; + $dirlist = $wp_filesystem->dirlist( $temp_backup_dir ); + $dirlist = $dirlist ? $dirlist : array(); + + foreach ( array_keys( $dirlist ) as $dir ) { + if ( '.' === $dir || '..' === $dir ) { + continue; + } + + $wp_filesystem->delete( $temp_backup_dir . $dir, true ); + } +} + if ( ( ! is_main_site() && ! is_network_admin() ) || wp_doing_ajax() ) { return; } @@ -977,3 +1173,5 @@ add_action( 'wp_maybe_auto_update', 'wp_maybe_auto_update' ); add_action( 'init', 'wp_schedule_update_checks' ); + +add_action( 'wp_delete_temp_updater_backups', 'wp_delete_all_temp_backups' );