--- a/wp/wp-includes/functions.php Tue Dec 15 15:52:01 2020 +0100
+++ b/wp/wp-includes/functions.php Wed Sep 21 18:19:35 2022 +0200
@@ -467,7 +467,7 @@
}
foreach ( $quant as $unit => $mag ) {
- if ( doubleval( $bytes ) >= $mag ) {
+ if ( (float) $bytes >= $mag ) {
return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
}
}
@@ -830,14 +830,16 @@
* @since 1.5.0
* @since 5.3.0 The `$content` parameter was made optional, and the `$post` parameter was
* updated to accept a post ID or a WP_Post object.
+ * @since 5.6.0 The `$content` parameter is no longer optional, but passing `null` to skip it
+ * is still supported.
*
* @global wpdb $wpdb WordPress database abstraction object.
*
- * @param string $content Post content. If `null`, the `post_content` field from `$post` is used.
+ * @param string|null $content Post content. If `null`, the `post_content` field from `$post` is used.
* @param int|WP_Post $post Post ID or post object.
- * @return null|bool Returns false if post is not found.
- */
-function do_enclose( $content = null, $post ) {
+ * @return void|false Void on success, false if the post is not found.
+ */
+function do_enclose( $content, $post ) {
global $wpdb;
// @todo Tidy this code and make the debug code optional.
@@ -897,6 +899,8 @@
$post_links = apply_filters( 'enclosure_links', $post_links, $post->ID );
foreach ( (array) $post_links as $url ) {
+ $url = strip_fragment_from_url( $url );
+
if ( '' !== $url && ! $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $url ) . '%' ) ) ) {
$headers = wp_get_http_headers( $url );
@@ -934,7 +938,7 @@
*
* @param string $url URL to retrieve HTTP headers from.
* @param bool $deprecated Not Used.
- * @return bool|string False on failure, headers on success.
+ * @return string|false Headers on success, false on failure.
*/
function wp_get_http_headers( $url, $deprecated = false ) {
if ( ! empty( $deprecated ) ) {
@@ -1155,8 +1159,8 @@
*
* @since 1.5.0
*
- * @param string|array $key Query key or keys to remove.
- * @param bool|string $query Optional. When false uses the current URL. Default false.
+ * @param string|string[] $key Query key or keys to remove.
+ * @param false|string $query Optional. When false uses the current URL. Default false.
* @return string New URL query string.
*/
function remove_query_arg( $key, $query = false ) {
@@ -1174,7 +1178,7 @@
*
* @since 4.4.0
*
- * @return string[] An array of parameters to remove from the URL.
+ * @return string[] An array of query variable names to remove from the URL.
*/
function wp_removable_query_args() {
$removable_query_args = array(
@@ -1182,6 +1186,7 @@
'activated',
'admin_email_remind_later',
'approved',
+ 'core-major-auto-updates-saved',
'deactivate',
'delete_count',
'deleted',
@@ -1191,6 +1196,7 @@
'error',
'hotkeys_highlight_first',
'hotkeys_highlight_last',
+ 'ids',
'locked',
'message',
'same',
@@ -1207,11 +1213,11 @@
);
/**
- * Filters the list of query variables to remove.
+ * Filters the list of query variable names to remove.
*
* @since 4.2.0
*
- * @param string[] $removable_query_args An array of query variables to remove from a URL.
+ * @param string[] $removable_query_args An array of query variable names to remove from a URL.
*/
return apply_filters( 'removable_query_args', $removable_query_args );
}
@@ -1562,7 +1568,13 @@
* Fires once the given feed is loaded.
*
* The dynamic portion of the hook name, `$feed`, refers to the feed template name.
- * Possible values include: 'rdf', 'rss', 'rss2', and 'atom'.
+ *
+ * Possible hook names include:
+ *
+ * - `do_feed_atom`
+ * - `do_feed_rdf`
+ * - `do_feed_rss`
+ * - `do_feed_rss2`
*
* @since 2.1.0
* @since 4.4.0 The `$feed` parameter was added.
@@ -1634,7 +1646,8 @@
*
* @since 2.1.0
* @since 5.3.0 Remove the "Disallow: /" output if search engine visiblity is
- * discouraged in favor of robots meta HTML tag in wp_no_robots().
+ * discouraged in favor of robots meta HTML tag via wp_robots_no_robots()
+ * filter callback.
*/
function do_robots() {
header( 'Content-Type: text/plain; charset=utf-8' );
@@ -1745,7 +1758,7 @@
*/
$wp_tables = $wpdb->tables();
foreach ( $wp_tables as $table ) {
- // The existence of custom user tables shouldn't suggest an insane state or prevent a clean installation.
+ // The existence of custom user tables shouldn't suggest an unwise state or prevent a clean installation.
if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table ) {
continue;
}
@@ -1753,11 +1766,15 @@
continue;
}
- if ( ! $wpdb->get_results( "DESCRIBE $table;" ) ) {
+ $described_table = $wpdb->get_results( "DESCRIBE $table;" );
+ if (
+ ( ! $described_table && empty( $wpdb->last_error ) ) ||
+ ( is_array( $described_table ) && 0 === count( $described_table ) )
+ ) {
continue;
}
- // One or more tables exist. We are insane.
+ // One or more tables exist. This is not good.
wp_load_translations_early();
@@ -2468,6 +2485,10 @@
$filename = sanitize_file_name( $filename );
$ext2 = null;
+ // Initialize vars used in the wp_unique_filename filter.
+ $number = '';
+ $alt_filenames = array();
+
// Separate the filename into a name and extension.
$ext = pathinfo( $filename, PATHINFO_EXTENSION );
$name = pathinfo( $filename, PATHINFO_BASENAME );
@@ -2488,8 +2509,7 @@
if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
$filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
} else {
- $number = '';
- $fname = pathinfo( $filename, PATHINFO_FILENAME );
+ $fname = pathinfo( $filename, PATHINFO_FILENAME );
// Always append a number to file names that can potentially match image sub-size file names.
if ( $fname && preg_match( '/-(?:\d+x\d+|scaled|rotated)$/', $fname ) ) {
@@ -2499,37 +2519,54 @@
$filename = str_replace( "{$fname}{$ext}", "{$fname}-{$number}{$ext}", $filename );
}
- // Change '.ext' to lower case.
- if ( $ext && strtolower( $ext ) != $ext ) {
- $ext2 = strtolower( $ext );
- $filename2 = preg_replace( '|' . preg_quote( $ext ) . '$|', $ext2, $filename );
-
- // Check for both lower and upper case extension or image sub-sizes may be overwritten.
- while ( file_exists( $dir . "/{$filename}" ) || file_exists( $dir . "/{$filename2}" ) ) {
- $new_number = (int) $number + 1;
- $filename = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename );
- $filename2 = str_replace( array( "-{$number}{$ext2}", "{$number}{$ext2}" ), "-{$new_number}{$ext2}", $filename2 );
- $number = $new_number;
+ // Get the mime type. Uploaded files were already checked with wp_check_filetype_and_ext()
+ // in _wp_handle_upload(). Using wp_check_filetype() would be sufficient here.
+ $file_type = wp_check_filetype( $filename );
+ $mime_type = $file_type['type'];
+
+ $is_image = ( ! empty( $mime_type ) && 0 === strpos( $mime_type, 'image/' ) );
+ $upload_dir = wp_get_upload_dir();
+ $lc_filename = null;
+
+ $lc_ext = strtolower( $ext );
+ $_dir = trailingslashit( $dir );
+
+ // If the extension is uppercase add an alternate file name with lowercase extension. Both need to be tested
+ // for uniqueness as the extension will be changed to lowercase for better compatibility with different filesystems.
+ // Fixes an inconsistency in WP < 2.9 where uppercase extensions were allowed but image sub-sizes were created with
+ // lowercase extensions.
+ if ( $ext && $lc_ext !== $ext ) {
+ $lc_filename = preg_replace( '|' . preg_quote( $ext ) . '$|', $lc_ext, $filename );
+ }
+
+ // Increment the number added to the file name if there are any files in $dir whose names match one of the
+ // possible name variations.
+ while ( file_exists( $_dir . $filename ) || ( $lc_filename && file_exists( $_dir . $lc_filename ) ) ) {
+ $new_number = (int) $number + 1;
+
+ if ( $lc_filename ) {
+ $lc_filename = str_replace( array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), "-{$new_number}{$lc_ext}", $lc_filename );
}
- $filename = $filename2;
- } else {
- while ( file_exists( $dir . "/{$filename}" ) ) {
- $new_number = (int) $number + 1;
-
- if ( '' === "{$number}{$ext}" ) {
- $filename = "{$filename}-{$new_number}";
- } else {
- $filename = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename );
- }
-
- $number = $new_number;
+ if ( '' === "{$number}{$ext}" ) {
+ $filename = "{$filename}-{$new_number}";
+ } else {
+ $filename = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename );
}
+
+ $number = $new_number;
+ }
+
+ // Change the extension to lowercase if needed.
+ if ( $lc_filename ) {
+ $filename = $lc_filename;
}
// Prevent collisions with existing file names that contain dimension-like strings
// (whether they are subsizes or originals uploaded prior to #42437).
- $upload_dir = wp_get_upload_dir();
+
+ $files = array();
+ $count = 10000;
// The (resized) image files would have name and extension, and will be in the uploads dir.
if ( $name && $ext && @is_dir( $dir ) && false !== strpos( $dir, $upload_dir['basedir'] ) ) {
@@ -2559,18 +2596,77 @@
}
if ( ! empty( $files ) ) {
- // The extension case may have changed above.
- $new_ext = ! empty( $ext2 ) ? $ext2 : $ext;
+ $count = count( $files );
// Ensure this never goes into infinite loop
// as it uses pathinfo() and regex in the check, but string replacement for the changes.
- $count = count( $files );
- $i = 0;
+ $i = 0;
while ( $i <= $count && _wp_check_existing_file_names( $filename, $files ) ) {
$new_number = (int) $number + 1;
- $filename = str_replace( array( "-{$number}{$new_ext}", "{$number}{$new_ext}" ), "-{$new_number}{$new_ext}", $filename );
- $number = $new_number;
+
+ // If $ext is uppercase it was replaced with the lowercase version after the previous loop.
+ $filename = str_replace( array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), "-{$new_number}{$lc_ext}", $filename );
+
+ $number = $new_number;
+ $i++;
+ }
+ }
+ }
+
+ // Check if an image will be converted after uploading or some existing images sub-sizes file names may conflict
+ // when regenerated. If yes, ensure the new file name will be unique and will produce unique sub-sizes.
+ if ( $is_image ) {
+ $output_formats = apply_filters( 'image_editor_output_format', array(), $_dir . $filename, $mime_type );
+ $alt_types = array();
+
+ if ( ! empty( $output_formats[ $mime_type ] ) ) {
+ // The image will be converted to this format/mime type.
+ $alt_mime_type = $output_formats[ $mime_type ];
+
+ // Other types of images whose names may conflict if their sub-sizes are regenerated.
+ $alt_types = array_keys( array_intersect( $output_formats, array( $mime_type, $alt_mime_type ) ) );
+ $alt_types[] = $alt_mime_type;
+ } elseif ( ! empty( $output_formats ) ) {
+ $alt_types = array_keys( array_intersect( $output_formats, array( $mime_type ) ) );
+ }
+
+ // Remove duplicates and the original mime type. It will be added later if needed.
+ $alt_types = array_unique( array_diff( $alt_types, array( $mime_type ) ) );
+
+ foreach ( $alt_types as $alt_type ) {
+ $alt_ext = wp_get_default_extension_for_mime_type( $alt_type );
+
+ if ( ! $alt_ext ) {
+ continue;
+ }
+
+ $alt_ext = ".{$alt_ext}";
+ $alt_filename = preg_replace( '|' . preg_quote( $lc_ext ) . '$|', $alt_ext, $filename );
+
+ $alt_filenames[ $alt_ext ] = $alt_filename;
+ }
+
+ if ( ! empty( $alt_filenames ) ) {
+ // Add the original filename. It needs to be checked again together with the alternate filenames
+ // when $number is incremented.
+ $alt_filenames[ $lc_ext ] = $filename;
+
+ // Ensure no infinite loop.
+ $i = 0;
+
+ while ( $i <= $count && _wp_check_alternate_file_names( $alt_filenames, $_dir, $files ) ) {
+ $new_number = (int) $number + 1;
+
+ foreach ( $alt_filenames as $alt_ext => $alt_filename ) {
+ $alt_filenames[ $alt_ext ] = str_replace( array( "-{$number}{$alt_ext}", "{$number}{$alt_ext}" ), "-{$new_number}{$alt_ext}", $alt_filename );
+ }
+
+ // Also update the $number in (the output) $filename.
+ // If the extension was uppercase it was already replaced with the lowercase version.
+ $filename = str_replace( array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), "-{$new_number}{$lc_ext}", $filename );
+
+ $number = $new_number;
$i++;
}
}
@@ -2581,13 +2677,42 @@
* Filters the result when generating a unique file name.
*
* @since 4.5.0
+ * @since 5.8.1 The `$alt_filenames` and `$number` parameters were added.
*
* @param string $filename Unique file name.
* @param string $ext File extension, eg. ".png".
* @param string $dir Directory path.
* @param callable|null $unique_filename_callback Callback function that generates the unique file name.
+ * @param string[] $alt_filenames Array of alternate file names that were checked for collisions.
+ * @param int|string $number The highest number that was used to make the file name unique
+ * or an empty string if unused.
*/
- return apply_filters( 'wp_unique_filename', $filename, $ext, $dir, $unique_filename_callback );
+ return apply_filters( 'wp_unique_filename', $filename, $ext, $dir, $unique_filename_callback, $alt_filenames, $number );
+}
+
+/**
+ * Helper function to test if each of an array of file names could conflict with existing files.
+ *
+ * @since 5.8.1
+ * @access private
+ *
+ * @param string[] $filenames Array of file names to check.
+ * @param string $dir The directory containing the files.
+ * @param array $files An array of existing files in the directory. May be empty.
+ * @return bool True if the tested file name could match an existing file, false otherwise.
+ */
+function _wp_check_alternate_file_names( $filenames, $dir, $files ) {
+ foreach ( $filenames as $filename ) {
+ if ( file_exists( $dir . $filename ) ) {
+ return true;
+ }
+
+ if ( ! empty( $files ) && _wp_check_existing_file_names( $filename, $files ) ) {
+ return true;
+ }
+ }
+
+ return false;
}
/**
@@ -2737,6 +2862,10 @@
// Compute the URL.
$url = $upload['url'] . "/$filename";
+ if ( is_multisite() ) {
+ clean_dirsize_cache( $new_file );
+ }
+
/** This filter is documented in wp-admin/includes/file.php */
return apply_filters(
'wp_handle_upload',
@@ -2770,6 +2899,26 @@
}
/**
+ * Returns first matched extension for the mime-type,
+ * as mapped from wp_get_mime_types().
+ *
+ * @since 5.8.1
+ *
+ * @param string $mime_type
+ *
+ * @return string|false
+ */
+function wp_get_default_extension_for_mime_type( $mime_type ) {
+ $extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) );
+
+ if ( empty( $extensions[0] ) ) {
+ return false;
+ }
+
+ return $extensions[0];
+}
+
+/**
* Retrieve the file type from the file name.
*
* You can optionally define the mime array, if needed.
@@ -2777,7 +2926,7 @@
* @since 2.0.4
*
* @param string $filename File name or path.
- * @param string[] $mimes Optional. Array of mime types keyed by their file extension regex.
+ * @param string[] $mimes Optional. Array of allowed mime types keyed by their file extension regex.
* @return array {
* Values for the extension and mime type.
*
@@ -2819,7 +2968,7 @@
* @param string $file Full path to the file.
* @param string $filename The name of the file (may differ from $file due to $file being
* in a tmp directory).
- * @param string[] $mimes Optional. Array of mime types keyed by their file extension regex.
+ * @param string[] $mimes Optional. Array of allowed mime types keyed by their file extension regex.
* @return array {
* Values for the extension, mime type, and corrected filename.
*
@@ -2865,6 +3014,7 @@
'image/gif' => 'gif',
'image/bmp' => 'bmp',
'image/tiff' => 'tif',
+ 'image/webp' => 'webp',
)
);
@@ -2931,6 +3081,7 @@
array(
'text/plain',
'text/csv',
+ 'application/csv',
'text/richtext',
'text/tsv',
'text/vtt',
@@ -2941,6 +3092,21 @@
$type = false;
$ext = false;
}
+ } elseif ( 'application/csv' === $real_mime ) {
+ // Special casing for CSV files.
+ if ( ! in_array(
+ $type,
+ array(
+ 'text/csv',
+ 'text/plain',
+ 'application/csv',
+ ),
+ true
+ )
+ ) {
+ $type = false;
+ $ext = false;
+ }
} elseif ( 'text/rtf' === $real_mime ) {
// Special casing for RTF files.
if ( ! in_array(
@@ -2984,18 +3150,18 @@
* @since 3.0.0
* @since 5.1.0 The $real_mime parameter was added.
*
- * @param array $wp_check_filetype_and_ext {
+ * @param array $wp_check_filetype_and_ext {
* Values for the extension, mime type, and corrected filename.
*
* @type string|false $ext File extension, or false if the file doesn't match a mime type.
* @type string|false $type File mime type, or false if the file doesn't match a mime type.
* @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined.
* }
- * @param string $file Full path to the file.
- * @param string $filename The name of the file (may differ from $file due to
- * $file being in a tmp directory).
- * @param string[] $mimes Array of mime types keyed by their file extension regex.
- * @param string|bool $real_mime The actual mime type or false if the type cannot be determined.
+ * @param string $file Full path to the file.
+ * @param string $filename The name of the file (may differ from $file due to
+ * $file being in a tmp directory).
+ * @param string[] $mimes Array of mime types keyed by their file extension regex.
+ * @param string|false $real_mime The actual mime type or false if the type cannot be determined.
*/
return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes, $real_mime );
}
@@ -3006,6 +3172,7 @@
* This depends on exif_imagetype() or getimagesize() to determine real mime types.
*
* @since 4.7.1
+ * @since 5.8.0 Added support for WebP images.
*
* @param string $file Full path to the file.
* @return string|false The actual mime type or false if the type cannot be determined.
@@ -3021,11 +3188,52 @@
$imagetype = exif_imagetype( $file );
$mime = ( $imagetype ) ? image_type_to_mime_type( $imagetype ) : false;
} elseif ( function_exists( 'getimagesize' ) ) {
- $imagesize = @getimagesize( $file );
- $mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
+ // Don't silence errors when in debug mode, unless running unit tests.
+ if ( defined( 'WP_DEBUG' ) && WP_DEBUG
+ && ! defined( 'WP_RUN_CORE_TESTS' )
+ ) {
+ // Not using wp_getimagesize() here to avoid an infinite loop.
+ $imagesize = getimagesize( $file );
+ } else {
+ // phpcs:ignore WordPress.PHP.NoSilencedErrors
+ $imagesize = @getimagesize( $file );
+ }
+
+ $mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
} else {
$mime = false;
}
+
+ if ( false !== $mime ) {
+ return $mime;
+ }
+
+ $handle = fopen( $file, 'rb' );
+ if ( false === $handle ) {
+ return false;
+ }
+
+ $magic = fread( $handle, 12 );
+ if ( false === $magic ) {
+ return false;
+ }
+
+ /*
+ * Add WebP fallback detection when image library doesn't support WebP.
+ * Note: detection values come from LibWebP, see
+ * https://github.com/webmproject/libwebp/blob/master/imageio/image_dec.c#L30
+ */
+ $magic = bin2hex( $magic );
+ if (
+ // RIFF.
+ ( 0 === strpos( $magic, '52494646' ) ) &&
+ // WEBP.
+ ( 16 === strpos( $magic, '57454250' ) )
+ ) {
+ $mime = 'image/webp';
+ }
+
+ fclose( $handle );
} catch ( Exception $e ) {
$mime = false;
}
@@ -3064,6 +3272,7 @@
'png' => 'image/png',
'bmp' => 'image/bmp',
'tiff|tif' => 'image/tiff',
+ 'webp' => 'image/webp',
'ico' => 'image/x-icon',
'heic' => 'image/heic',
// Video formats.
@@ -3185,7 +3394,7 @@
return apply_filters(
'ext2type',
array(
- 'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'heic' ),
+ 'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'heic', 'webp' ),
'audio' => array( 'aac', 'ac3', 'aif', 'aiff', 'flac', 'm3a', 'm4a', 'm4b', 'mka', 'mp1', 'mp2', 'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
'video' => array( '3g2', '3gp', '3gpp', 'asf', 'avi', 'divx', 'dv', 'flv', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt', 'rm', 'vob', 'wmv' ),
'document' => array( 'doc', 'docx', 'docm', 'dotm', 'odt', 'pages', 'pdf', 'xps', 'oxps', 'rtf', 'wp', 'wpd', 'psd', 'xcf' ),
@@ -3345,9 +3554,9 @@
* @param callable $function Callback function name.
*/
$function = apply_filters( 'wp_die_json_handler', '_json_wp_die_handler' );
- } elseif ( wp_is_jsonp_request() ) {
+ } elseif ( defined( 'REST_REQUEST' ) && REST_REQUEST && wp_is_jsonp_request() ) {
/**
- * Filters the callback for killing WordPress execution for JSONP requests.
+ * Filters the callback for killing WordPress execution for JSONP REST requests.
*
* @since 5.2.0
*
@@ -3412,7 +3621,7 @@
array( $message ),
wp_list_pluck( $parsed_args['additional_errors'], 'message' )
);
- $message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $message ) . "</li>\n\t</ul>";
+ $message = "<ul>\n\t\t<li>" . implode( "</li>\n\t\t<li>", $message ) . "</li>\n\t</ul>";
}
$message = sprintf(
@@ -3461,8 +3670,9 @@
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $parsed_args['charset']; ?>" />
<meta name="viewport" content="width=device-width">
<?php
- if ( function_exists( 'wp_no_robots' ) ) {
- wp_no_robots();
+ if ( function_exists( 'wp_robots' ) && function_exists( 'wp_robots_no_robots' ) && function_exists( 'add_filter' ) ) {
+ add_filter( 'wp_robots', 'wp_robots_no_robots' );
+ wp_robots();
}
?>
<title><?php echo $title; ?></title>
@@ -3472,13 +3682,14 @@
}
body {
background: #fff;
+ border: 1px solid #ccd0d4;
color: #444;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
margin: 2em auto;
padding: 1em 2em;
max-width: 700px;
- -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.13);
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.13);
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
+ box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
}
h1 {
border-bottom: 1px solid #dadada;
@@ -3523,9 +3734,9 @@
outline: none;
}
.button {
- background: #f7f7f7;
- border: 1px solid #ccc;
- color: #555;
+ background: #f3f5f6;
+ border: 1px solid #016087;
+ color: #016087;
display: inline-block;
text-decoration: none;
font-size: 13px;
@@ -3542,36 +3753,35 @@
-moz-box-sizing: border-box;
box-sizing: border-box;
- -webkit-box-shadow: 0 1px 0 #ccc;
- box-shadow: 0 1px 0 #ccc;
vertical-align: top;
}
.button.button-large {
- height: 30px;
- line-height: 2.15384615;
- padding: 0 12px 2px;
+ line-height: 2.30769231;
+ min-height: 32px;
+ padding: 0 12px;
}
.button:hover,
.button:focus {
- background: #fafafa;
- border-color: #999;
- color: #23282d;
+ background: #f1f1f1;
}
.button:focus {
- border-color: #5b9dd9;
- -webkit-box-shadow: 0 0 3px rgba(0, 115, 170, 0.8);
- box-shadow: 0 0 3px rgba(0, 115, 170, 0.8);
- outline: none;
+ background: #f3f5f6;
+ border-color: #007cba;
+ -webkit-box-shadow: 0 0 0 1px #007cba;
+ box-shadow: 0 0 0 1px #007cba;
+ color: #016087;
+ outline: 2px solid transparent;
+ outline-offset: 0;
}
.button:active {
- background: #eee;
- border-color: #999;
- -webkit-box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5);
- box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5);
+ background: #f3f5f6;
+ border-color: #7e8993;
+ -webkit-box-shadow: none;
+ box-shadow: none;
}
<?php
@@ -4055,12 +4265,14 @@
*
* @since 3.5.0
* @since 4.7.0 The `$status_code` parameter was added.
+ * @since 5.6.0 The `$options` parameter was added.
*
* @param mixed $response Variable (usually an array or object) to encode as JSON,
* then print and die.
- * @param int $status_code The HTTP status code to output.
- */
-function wp_send_json( $response, $status_code = null ) {
+ * @param int $status_code Optional. The HTTP status code to output. Default null.
+ * @param int $options Optional. Options to be passed to json_encode(). Default 0.
+ */
+function wp_send_json( $response, $status_code = null, $options = 0 ) {
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
_doing_it_wrong(
__FUNCTION__,
@@ -4081,7 +4293,7 @@
}
}
- echo wp_json_encode( $response );
+ echo wp_json_encode( $response, $options );
if ( wp_doing_ajax() ) {
wp_die(
@@ -4101,18 +4313,20 @@
*
* @since 3.5.0
* @since 4.7.0 The `$status_code` parameter was added.
- *
- * @param mixed $data Data to encode as JSON, then print and die.
- * @param int $status_code The HTTP status code to output.
- */
-function wp_send_json_success( $data = null, $status_code = null ) {
+ * @since 5.6.0 The `$options` parameter was added.
+ *
+ * @param mixed $data Optional. Data to encode as JSON, then print and die. Default null.
+ * @param int $status_code Optional. The HTTP status code to output. Default null.
+ * @param int $options Optional. Options to be passed to json_encode(). Default 0.
+ */
+function wp_send_json_success( $data = null, $status_code = null, $options = 0 ) {
$response = array( 'success' => true );
if ( isset( $data ) ) {
$response['data'] = $data;
}
- wp_send_json( $response, $status_code );
+ wp_send_json( $response, $status_code, $options );
}
/**
@@ -4126,11 +4340,13 @@
* @since 3.5.0
* @since 4.1.0 The `$data` parameter is now processed if a WP_Error object is passed in.
* @since 4.7.0 The `$status_code` parameter was added.
- *
- * @param mixed $data Data to encode as JSON, then print and die.
- * @param int $status_code The HTTP status code to output.
- */
-function wp_send_json_error( $data = null, $status_code = null ) {
+ * @since 5.6.0 The `$options` parameter was added.
+ *
+ * @param mixed $data Optional. Data to encode as JSON, then print and die. Default null.
+ * @param int $status_code Optional. The HTTP status code to output. Default null.
+ * @param int $options Optional. Options to be passed to json_encode(). Default 0.
+ */
+function wp_send_json_error( $data = null, $status_code = null, $options = 0 ) {
$response = array( 'success' => false );
if ( isset( $data ) ) {
@@ -4151,7 +4367,7 @@
}
}
- wp_send_json( $response, $status_code );
+ wp_send_json( $response, $status_code, $options );
}
/**
@@ -4397,7 +4613,7 @@
}
/**
- * Merge user defined arguments into defaults array.
+ * Merges user defined arguments into defaults array.
*
* This function is used throughout WordPress to allow for both string or array
* to be merged into another array.
@@ -4426,12 +4642,12 @@
}
/**
- * Cleans up an array, comma- or space-separated list of scalar values.
+ * Converts a comma- or space-separated list of scalar values to an array.
*
* @since 5.1.0
*
* @param array|string $list List of values.
- * @return array Sanitized array of values.
+ * @return array Array of values.
*/
function wp_parse_list( $list ) {
if ( ! is_array( $list ) ) {
@@ -4442,9 +4658,10 @@
}
/**
- * Clean up an array, comma- or space-separated list of IDs.
+ * Cleans up an array, comma- or space-separated list of IDs.
*
* @since 3.0.0
+ * @since 5.1.0 Refactored to use wp_parse_list().
*
* @param array|string $list List of IDs.
* @return int[] Sanitized array of IDs.
@@ -4456,9 +4673,10 @@
}
/**
- * Clean up an array, comma- or space-separated list of slugs.
+ * Cleans up an array, comma- or space-separated list of slugs.
*
* @since 4.7.0
+ * @since 5.1.0 Refactored to use wp_parse_list().
*
* @param array|string $list List of slugs.
* @return string[] Sanitized array of slugs.
@@ -4480,6 +4698,7 @@
*/
function wp_array_slice_assoc( $array, $keys ) {
$slice = array();
+
foreach ( $keys as $key ) {
if ( isset( $array[ $key ] ) ) {
$slice[ $key ] = $array[ $key ];
@@ -4490,6 +4709,200 @@
}
/**
+ * Accesses an array in depth based on a path of keys.
+ *
+ * It is the PHP equivalent of JavaScript's `lodash.get()` and mirroring it may help other components
+ * retain some symmetry between client and server implementations.
+ *
+ * Example usage:
+ *
+ * $array = array(
+ * 'a' => array(
+ * 'b' => array(
+ * 'c' => 1,
+ * ),
+ * ),
+ * );
+ * _wp_array_get( $array, array( 'a', 'b', 'c' ) );
+ *
+ * @internal
+ *
+ * @since 5.6.0
+ * @access private
+ *
+ * @param array $array An array from which we want to retrieve some information.
+ * @param array $path An array of keys describing the path with which to retrieve information.
+ * @param mixed $default The return value if the path does not exist within the array,
+ * or if `$array` or `$path` are not arrays.
+ * @return mixed The value from the path specified.
+ */
+function _wp_array_get( $array, $path, $default = null ) {
+ // Confirm $path is valid.
+ if ( ! is_array( $path ) || 0 === count( $path ) ) {
+ return $default;
+ }
+
+ foreach ( $path as $path_element ) {
+ if (
+ ! is_array( $array ) ||
+ ( ! is_string( $path_element ) && ! is_integer( $path_element ) && ! is_null( $path_element ) ) ||
+ ! array_key_exists( $path_element, $array )
+ ) {
+ return $default;
+ }
+ $array = $array[ $path_element ];
+ }
+
+ return $array;
+}
+
+/**
+ * Sets an array in depth based on a path of keys.
+ *
+ * It is the PHP equivalent of JavaScript's `lodash.set()` and mirroring it may help other components
+ * retain some symmetry between client and server implementations.
+ *
+ * Example usage:
+ *
+ * $array = array();
+ * _wp_array_set( $array, array( 'a', 'b', 'c', 1 ) );
+ *
+ * $array becomes:
+ * array(
+ * 'a' => array(
+ * 'b' => array(
+ * 'c' => 1,
+ * ),
+ * ),
+ * );
+ *
+ * @internal
+ *
+ * @since 5.8.0
+ * @access private
+ *
+ * @param array $array An array that we want to mutate to include a specific value in a path.
+ * @param array $path An array of keys describing the path that we want to mutate.
+ * @param mixed $value The value that will be set.
+ */
+function _wp_array_set( &$array, $path, $value = null ) {
+ // Confirm $array is valid.
+ if ( ! is_array( $array ) ) {
+ return;
+ }
+
+ // Confirm $path is valid.
+ if ( ! is_array( $path ) ) {
+ return;
+ }
+
+ $path_length = count( $path );
+
+ if ( 0 === $path_length ) {
+ return;
+ }
+
+ foreach ( $path as $path_element ) {
+ if (
+ ! is_string( $path_element ) && ! is_integer( $path_element ) &&
+ ! is_null( $path_element )
+ ) {
+ return;
+ }
+ }
+
+ for ( $i = 0; $i < $path_length - 1; ++$i ) {
+ $path_element = $path[ $i ];
+ if (
+ ! array_key_exists( $path_element, $array ) ||
+ ! is_array( $array[ $path_element ] )
+ ) {
+ $array[ $path_element ] = array();
+ }
+ $array = &$array[ $path_element ]; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.VariableRedeclaration
+ }
+
+ $array[ $path[ $i ] ] = $value;
+}
+
+/**
+ * This function is trying to replicate what
+ * lodash's kebabCase (JS library) does in the client.
+ *
+ * The reason we need this function is that we do some processing
+ * in both the client and the server (e.g.: we generate
+ * preset classes from preset slugs) that needs to
+ * create the same output.
+ *
+ * We can't remove or update the client's library due to backward compatibility
+ * (some of the output of lodash's kebabCase is saved in the post content).
+ * We have to make the server behave like the client.
+ *
+ * Changes to this function should follow updates in the client
+ * with the same logic.
+ *
+ * @link https://github.com/lodash/lodash/blob/4.17/dist/lodash.js#L14369
+ * @link https://github.com/lodash/lodash/blob/4.17/dist/lodash.js#L278
+ * @link https://github.com/lodash-php/lodash-php/blob/master/src/String/kebabCase.php
+ * @link https://github.com/lodash-php/lodash-php/blob/master/src/internal/unicodeWords.php
+ *
+ * @param string $string The string to kebab-case.
+ *
+ * @return string kebab-cased-string.
+ */
+function _wp_to_kebab_case( $string ) {
+ //phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
+ // ignore the camelCase names for variables so the names are the same as lodash
+ // so comparing and porting new changes is easier.
+
+ /*
+ * Some notable things we've removed compared to the lodash version are:
+ *
+ * - non-alphanumeric characters: rsAstralRange, rsEmoji, etc
+ * - the groups that processed the apostrophe, as it's removed before passing the string to preg_match: rsApos, rsOptContrLower, and rsOptContrUpper
+ *
+ */
+
+ /** Used to compose unicode character classes. */
+ $rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff';
+ $rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf';
+ $rsPunctuationRange = '\\x{2000}-\\x{206f}';
+ $rsSpaceRange = ' \\t\\x0b\\f\\xa0\\x{feff}\\n\\r\\x{2028}\\x{2029}\\x{1680}\\x{180e}\\x{2000}\\x{2001}\\x{2002}\\x{2003}\\x{2004}\\x{2005}\\x{2006}\\x{2007}\\x{2008}\\x{2009}\\x{200a}\\x{202f}\\x{205f}\\x{3000}';
+ $rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde';
+ $rsBreakRange = $rsNonCharRange . $rsPunctuationRange . $rsSpaceRange;
+
+ /** Used to compose unicode capture groups. */
+ $rsBreak = '[' . $rsBreakRange . ']';
+ $rsDigits = '\\d+'; // The last lodash version in GitHub uses a single digit here and expands it when in use.
+ $rsLower = '[' . $rsLowerRange . ']';
+ $rsMisc = '[^' . $rsBreakRange . $rsDigits . $rsLowerRange . $rsUpperRange . ']';
+ $rsUpper = '[' . $rsUpperRange . ']';
+
+ /** Used to compose unicode regexes. */
+ $rsMiscLower = '(?:' . $rsLower . '|' . $rsMisc . ')';
+ $rsMiscUpper = '(?:' . $rsUpper . '|' . $rsMisc . ')';
+ $rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])';
+ $rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])';
+
+ $regexp = '/' . implode(
+ '|',
+ array(
+ $rsUpper . '?' . $rsLower . '+' . '(?=' . implode( '|', array( $rsBreak, $rsUpper, '$' ) ) . ')',
+ $rsMiscUpper . '+' . '(?=' . implode( '|', array( $rsBreak, $rsUpper . $rsMiscLower, '$' ) ) . ')',
+ $rsUpper . '?' . $rsMiscLower . '+',
+ $rsUpper . '+',
+ $rsOrdUpper,
+ $rsOrdLower,
+ $rsDigits,
+ )
+ ) . '/u';
+
+ preg_match_all( $regexp, str_replace( "'", '', $string ), $matches );
+ return strtolower( implode( '-', $matches[0] ) );
+ //phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
+}
+
+/**
* Determines if the variable is a numeric-indexed array.
*
* @since 4.4.0
@@ -4504,24 +4917,36 @@
$keys = array_keys( $data );
$string_keys = array_filter( $keys, 'is_string' );
+
return count( $string_keys ) === 0;
}
/**
* Filters a list of objects, based on a set of key => value arguments.
*
+ * Retrieves the objects from the list that match the given arguments.
+ * Key represents property name, and value represents property value.
+ *
+ * If an object has more properties than those specified in arguments,
+ * that will not disqualify it. When using the 'AND' operator,
+ * any missing properties will disqualify it.
+ *
+ * When using the `$field` argument, this function can also retrieve
+ * a particular field from all matching objects, whereas wp_list_filter()
+ * only does the filtering.
+ *
* @since 3.0.0
* @since 4.7.0 Uses `WP_List_Util` class.
*
- * @param array $list An array of objects to filter
+ * @param array $list An array of objects to filter.
* @param array $args Optional. An array of key => value arguments to match
* against each object. Default empty array.
- * @param string $operator Optional. The logical operation to perform. 'or' means
- * only one element from the array needs to match; 'and'
- * means all elements must match; 'not' means no elements may
- * match. Default 'and'.
- * @param bool|string $field A field from the object to place instead of the entire object.
- * Default false.
+ * @param string $operator Optional. The logical operation to perform. 'AND' means
+ * all elements from the array must match. 'OR' means only
+ * one element needs to match. 'NOT' means no elements may
+ * match. Default 'AND'.
+ * @param bool|string $field Optional. A field from the object to place instead
+ * of the entire object. Default false.
* @return array A list of objects or object fields.
*/
function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
@@ -4543,6 +4968,16 @@
/**
* Filters a list of objects, based on a set of key => value arguments.
*
+ * Retrieves the objects from the list that match the given arguments.
+ * Key represents property name, and value represents property value.
+ *
+ * If an object has more properties than those specified in arguments,
+ * that will not disqualify it. When using the 'AND' operator,
+ * any missing properties will disqualify it.
+ *
+ * If you want to retrieve a particular field from all matching objects,
+ * use wp_filter_object_list() instead.
+ *
* @since 3.1.0
* @since 4.7.0 Uses `WP_List_Util` class.
*
@@ -4561,6 +4996,7 @@
}
$util = new WP_List_Util( $list );
+
return $util->filter( $args, $operator );
}
@@ -4574,8 +5010,8 @@
* @since 4.0.0 $index_key parameter added.
* @since 4.7.0 Uses `WP_List_Util` class.
*
- * @param array $list List of objects or arrays
- * @param int|string $field Field from the object to place instead of the entire object
+ * @param array $list List of objects or arrays.
+ * @param int|string $field Field from the object to place instead of the entire object.
* @param int|string $index_key Optional. Field from the object to use as keys for the new array.
* Default null.
* @return array Array of found values. If `$index_key` is set, an array of found values with keys
@@ -4584,6 +5020,7 @@
*/
function wp_list_pluck( $list, $field, $index_key = null ) {
$util = new WP_List_Util( $list );
+
return $util->pluck( $field, $index_key );
}
@@ -4606,6 +5043,7 @@
}
$util = new WP_List_Util( $list );
+
return $util->sort( $orderby, $order, $preserve_keys );
}
@@ -4717,7 +5155,7 @@
* @return int A non-negative integer.
*/
function absint( $maybeint ) {
- return abs( intval( $maybeint ) );
+ return abs( (int) $maybeint );
}
/**
@@ -5827,7 +6265,7 @@
}
// Build the value.
- $value = join( '/', $value );
+ $value = implode( '/', $value );
$selected = '';
if ( $value === $selected_zone ) {
$selected = 'selected="selected" ';
@@ -5928,7 +6366,7 @@
}
$structure[] = '</optgroup>';
- return join( "\n", $structure );
+ return implode( "\n", $structure );
}
/**
@@ -6022,11 +6460,15 @@
// We don't need to write to the file, so just open for reading.
$fp = fopen( $file, 'r' );
- // Pull only the first 8 KB of the file in.
- $file_data = fread( $fp, 8 * KB_IN_BYTES );
-
- // PHP will close file handle, but we are good citizens.
- fclose( $fp );
+ if ( $fp ) {
+ // Pull only the first 8 KB of the file in.
+ $file_data = fread( $fp, 8 * KB_IN_BYTES );
+
+ // PHP will close file handle, but we are good citizens.
+ fclose( $fp );
+ } else {
+ $file_data = '';
+ }
// Make sure we catch CR-only line endings.
$file_data = str_replace( "\r", "\n", $file_data );
@@ -6050,7 +6492,7 @@
}
foreach ( $all_headers as $field => $regex ) {
- if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] ) {
+ if ( preg_match( '/^(?:[ \t]*<\?php)?[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] ) {
$all_headers[ $field ] = _cleanup_header_comment( $match[1] );
} else {
$all_headers[ $field ] = '';
@@ -6277,13 +6719,14 @@
* @since 4.3.0 Added 'webcal' to the protocols array.
* @since 4.7.0 Added 'urn' to the protocols array.
* @since 5.3.0 Added 'sms' to the protocols array.
+ * @since 5.6.0 Added 'irc6' and 'ircs' to the protocols array.
*
* @see wp_kses()
* @see esc_url()
*
* @return string[] Array of allowed protocols. Defaults to an array containing 'http', 'https',
- * 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet',
- * 'mms', 'rtsp', 'sms', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'.
+ * 'ftp', 'ftps', 'mailto', 'news', 'irc', 'irc6', 'ircs', 'gopher', 'nntp', 'feed',
+ * 'telnet', 'mms', 'rtsp', 'sms', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'.
* This covers all common link protocols, except for 'javascript' which should not
* be allowed for untrusted users.
*/
@@ -6291,7 +6734,7 @@
static $protocols = array();
if ( empty( $protocols ) ) {
- $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'sms', 'svn', 'tel', 'fax', 'xmpp', 'webcal', 'urn' );
+ $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'irc6', 'ircs', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'sms', 'svn', 'tel', 'fax', 'xmpp', 'webcal', 'urn' );
}
if ( ! did_action( 'wp_loaded' ) ) {
@@ -6361,7 +6804,7 @@
}
}
if ( $pretty ) {
- return join( ', ', array_reverse( $caller ) );
+ return implode( ', ', array_reverse( $caller ) );
} else {
return $caller;
}
@@ -6650,7 +7093,13 @@
static $overloaded = null;
if ( is_null( $overloaded ) ) {
- $overloaded = function_exists( 'mb_internal_encoding' ) && ( ini_get( 'mbstring.func_overload' ) & 2 ); // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated
+ if ( function_exists( 'mb_internal_encoding' )
+ && ( (int) ini_get( 'mbstring.func_overload' ) & 2 ) // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated
+ ) {
+ $overloaded = true;
+ } else {
+ $overloaded = false;
+ }
}
if ( false === $overloaded ) {
@@ -6821,9 +7270,9 @@
*
* @param string $context Optional. Context in which the function is called. Accepts either 'admin',
* 'image', or an arbitrary other context. If an arbitrary context is passed,
- * the similarly arbitrary {@see '{$context}_memory_limit'} filter will be
+ * the similarly arbitrary {@see '$context_memory_limit'} filter will be
* invoked. Default 'admin'.
- * @return bool|int|string The limit that was set or false on failure.
+ * @return int|string|false The limit that was set or false on failure.
*/
function wp_raise_memory_limit( $context = 'admin' ) {
// Exit early if the limit cannot be changed.
@@ -7070,18 +7519,18 @@
* @since 4.9.0
*
* @param array $email_change_email {
- * Used to build wp_mail().
+ * Used to build wp_mail().
*
- * @type string $to The intended recipient.
- * @type string $subject The subject of the email.
- * @type string $message The content of the email.
- * The following strings have a special meaning and will get replaced dynamically:
- * - ###OLD_EMAIL### The old site admin email address.
- * - ###NEW_EMAIL### The new site admin email address.
- * - ###SITENAME### The name of the site.
- * - ###SITEURL### The URL to the site.
- * @type string $headers Headers.
- * }
+ * @type string $to The intended recipient.
+ * @type string $subject The subject of the email.
+ * @type string $message The content of the email.
+ * The following strings have a special meaning and will get replaced dynamically:
+ * - ###OLD_EMAIL### The old site admin email address.
+ * - ###NEW_EMAIL### The new site admin email address.
+ * - ###SITENAME### The name of the site.
+ * - ###SITEURL### The URL to the site.
+ * @type string $headers Headers.
+ * }
* @param string $old_email The old site admin email address.
* @param string $new_email The new site admin email address.
*/
@@ -7239,6 +7688,8 @@
* Filters the directory used to store personal data export files.
*
* @since 4.9.6
+ * @since 5.5.0 Exports now use relative paths, so changes to the directory
+ * via this filter should be reflected on the server.
*
* @param string $exports_dir Exports directory.
*/
@@ -7262,6 +7713,8 @@
* Filters the URL of the directory used to store personal data export files.
*
* @since 4.9.6
+ * @since 5.5.0 Exports now use relative paths, so changes to the directory URL
+ * via this filter should be reflected on the server.
*
* @param string $exports_url Exports directory URL.
*/
@@ -7301,7 +7754,7 @@
}
require_once ABSPATH . 'wp-admin/includes/file.php';
- $export_files = list_files( $exports_dir, 100, array( 'index.html' ) );
+ $export_files = list_files( $exports_dir, 100, array( 'index.php' ) );
/**
* Filters the lifetime, in seconds, of a personal data export file.
@@ -7474,7 +7927,7 @@
echo '<p class="button-container">';
printf(
- '<a class="button button-primary" href="%1$s" target="_blank" rel="noopener noreferrer">%2$s <span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
+ '<a class="button button-primary" href="%1$s" target="_blank" rel="noopener">%2$s <span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
esc_url( $direct_update_url ),
__( 'Update PHP' ),
/* translators: Accessibility text. */
@@ -7484,6 +7937,91 @@
}
/**
+ * Gets the URL to learn more about updating the site to use HTTPS.
+ *
+ * This URL can be overridden by specifying an environment variable `WP_UPDATE_HTTPS_URL` or by using the
+ * {@see 'wp_update_https_url'} filter. Providing an empty string is not allowed and will result in the
+ * default URL being used. Furthermore the page the URL links to should preferably be localized in the
+ * site language.
+ *
+ * @since 5.7.0
+ *
+ * @return string URL to learn more about updating to HTTPS.
+ */
+function wp_get_update_https_url() {
+ $default_url = wp_get_default_update_https_url();
+
+ $update_url = $default_url;
+ if ( false !== getenv( 'WP_UPDATE_HTTPS_URL' ) ) {
+ $update_url = getenv( 'WP_UPDATE_HTTPS_URL' );
+ }
+
+ /**
+ * Filters the URL to learn more about updating the HTTPS version the site is running on.
+ *
+ * Providing an empty string is not allowed and will result in the default URL being used. Furthermore
+ * the page the URL links to should preferably be localized in the site language.
+ *
+ * @since 5.7.0
+ *
+ * @param string $update_url URL to learn more about updating HTTPS.
+ */
+ $update_url = apply_filters( 'wp_update_https_url', $update_url );
+ if ( empty( $update_url ) ) {
+ $update_url = $default_url;
+ }
+
+ return $update_url;
+}
+
+/**
+ * Gets the default URL to learn more about updating the site to use HTTPS.
+ *
+ * Do not use this function to retrieve this URL. Instead, use {@see wp_get_update_https_url()} when relying on the URL.
+ * This function does not allow modifying the returned URL, and is only used to compare the actually used URL with the
+ * default one.
+ *
+ * @since 5.7.0
+ * @access private
+ *
+ * @return string Default URL to learn more about updating to HTTPS.
+ */
+function wp_get_default_update_https_url() {
+ /* translators: Documentation explaining HTTPS and why it should be used. */
+ return __( 'https://wordpress.org/support/article/why-should-i-use-https/' );
+}
+
+/**
+ * Gets the URL for directly updating the site to use HTTPS.
+ *
+ * A URL will only be returned if the `WP_DIRECT_UPDATE_HTTPS_URL` environment variable is specified or
+ * by using the {@see 'wp_direct_update_https_url'} filter. This allows hosts to send users directly to
+ * the page where they can update their site to use HTTPS.
+ *
+ * @since 5.7.0
+ *
+ * @return string URL for directly updating to HTTPS or empty string.
+ */
+function wp_get_direct_update_https_url() {
+ $direct_update_url = '';
+
+ if ( false !== getenv( 'WP_DIRECT_UPDATE_HTTPS_URL' ) ) {
+ $direct_update_url = getenv( 'WP_DIRECT_UPDATE_HTTPS_URL' );
+ }
+
+ /**
+ * Filters the URL for directly updating the PHP version the site is running on from the host.
+ *
+ * @since 5.7.0
+ *
+ * @param string $direct_update_url URL for directly updating PHP.
+ */
+ $direct_update_url = apply_filters( 'wp_direct_update_https_url', $direct_update_url );
+
+ return $direct_update_url;
+}
+
+/**
* Get the size of a directory.
*
* A helper function that is used primarily to check whether
@@ -7498,49 +8036,49 @@
* @return int|false|null Size in bytes if a valid directory. False if not. Null if timeout.
*/
function get_dirsize( $directory, $max_execution_time = null ) {
- $dirsize = get_transient( 'dirsize_cache' );
-
- if ( is_array( $dirsize ) && isset( $dirsize[ $directory ]['size'] ) ) {
- return $dirsize[ $directory ]['size'];
- }
-
- if ( ! is_array( $dirsize ) ) {
- $dirsize = array();
- }
// Exclude individual site directories from the total when checking the main site of a network,
// as they are subdirectories and should not be counted.
if ( is_multisite() && is_main_site() ) {
- $dirsize[ $directory ]['size'] = recurse_dirsize( $directory, $directory . '/sites', $max_execution_time );
+ $size = recurse_dirsize( $directory, $directory . '/sites', $max_execution_time );
} else {
- $dirsize[ $directory ]['size'] = recurse_dirsize( $directory, null, $max_execution_time );
- }
-
- set_transient( 'dirsize_cache', $dirsize, HOUR_IN_SECONDS );
- return $dirsize[ $directory ]['size'];
+ $size = recurse_dirsize( $directory, null, $max_execution_time );
+ }
+
+ return $size;
}
/**
* Get the size of a directory recursively.
*
- * Used by get_dirsize() to get a directory's size when it contains
- * other directories.
+ * Used by get_dirsize() to get a directory size when it contains other directories.
*
* @since MU (3.0.0)
- * @since 4.3.0 $exclude parameter added.
- * @since 5.2.0 $max_execution_time parameter added.
+ * @since 4.3.0 The `$exclude` parameter was added.
+ * @since 5.2.0 The `$max_execution_time` parameter was added.
+ * @since 5.6.0 The `$directory_cache` parameter was added.
*
* @param string $directory Full path of a directory.
* @param string|array $exclude Optional. Full path of a subdirectory to exclude from the total,
* or array of paths. Expected without trailing slash(es).
* @param int $max_execution_time Maximum time to run before giving up. In seconds. The timeout is global
* and is measured from the moment WordPress started to load.
+ * @param array $directory_cache Optional. Array of cached directory paths.
+ *
* @return int|false|null Size in bytes if a valid directory. False if not. Null if timeout.
*/
-function recurse_dirsize( $directory, $exclude = null, $max_execution_time = null ) {
- $size = 0;
-
- $directory = untrailingslashit( $directory );
+function recurse_dirsize( $directory, $exclude = null, $max_execution_time = null, &$directory_cache = null ) {
+ $directory = untrailingslashit( $directory );
+ $save_cache = false;
+
+ if ( ! isset( $directory_cache ) ) {
+ $directory_cache = get_transient( 'dirsize_cache' );
+ $save_cache = true;
+ }
+
+ if ( isset( $directory_cache[ $directory ] ) && is_int( $directory_cache[ $directory ] ) ) {
+ return $directory_cache[ $directory ];
+ }
if ( ! file_exists( $directory ) || ! is_dir( $directory ) || ! is_readable( $directory ) ) {
return false;
@@ -7568,33 +8106,84 @@
}
}
- $handle = opendir( $directory );
- if ( $handle ) {
- while ( ( $file = readdir( $handle ) ) !== false ) {
- $path = $directory . '/' . $file;
- if ( '.' !== $file && '..' !== $file ) {
- if ( is_file( $path ) ) {
- $size += filesize( $path );
- } elseif ( is_dir( $path ) ) {
- $handlesize = recurse_dirsize( $path, $exclude, $max_execution_time );
- if ( $handlesize > 0 ) {
- $size += $handlesize;
+ /**
+ * Filters the amount of storage space used by one directory and all its children, in megabytes.
+ *
+ * Return the actual used space to short-circuit the recursive PHP file size calculation
+ * and use something else, like a CDN API or native operating system tools for better performance.
+ *
+ * @since 5.6.0
+ *
+ * @param int|false $space_used The amount of used space, in bytes. Default false.
+ */
+ $size = apply_filters( 'pre_recurse_dirsize', false, $directory, $exclude, $max_execution_time, $directory_cache );
+
+ if ( false === $size ) {
+ $size = 0;
+
+ $handle = opendir( $directory );
+ if ( $handle ) {
+ while ( ( $file = readdir( $handle ) ) !== false ) {
+ $path = $directory . '/' . $file;
+ if ( '.' !== $file && '..' !== $file ) {
+ if ( is_file( $path ) ) {
+ $size += filesize( $path );
+ } elseif ( is_dir( $path ) ) {
+ $handlesize = recurse_dirsize( $path, $exclude, $max_execution_time, $directory_cache );
+ if ( $handlesize > 0 ) {
+ $size += $handlesize;
+ }
+ }
+
+ if ( $max_execution_time > 0 && microtime( true ) - WP_START_TIMESTAMP > $max_execution_time ) {
+ // Time exceeded. Give up instead of risking a fatal timeout.
+ $size = null;
+ break;
}
}
-
- if ( $max_execution_time > 0 && microtime( true ) - WP_START_TIMESTAMP > $max_execution_time ) {
- // Time exceeded. Give up instead of risking a fatal timeout.
- $size = null;
- break;
- }
}
- }
- closedir( $handle );
- }
+ closedir( $handle );
+ }
+ }
+
+ $directory_cache[ $directory ] = $size;
+
+ // Only write the transient on the top level call and not on recursive calls.
+ if ( $save_cache ) {
+ set_transient( 'dirsize_cache', $directory_cache );
+ }
+
return $size;
}
/**
+ * Cleans directory size cache used by recurse_dirsize().
+ *
+ * Removes the current directory and all parent directories from the `dirsize_cache` transient.
+ *
+ * @since 5.6.0
+ *
+ * @param string $path Full path of a directory or file.
+ */
+function clean_dirsize_cache( $path ) {
+ $directory_cache = get_transient( 'dirsize_cache' );
+
+ if ( empty( $directory_cache ) ) {
+ return;
+ }
+
+ $path = untrailingslashit( $path );
+ unset( $directory_cache[ $path ] );
+
+ while ( DIRECTORY_SEPARATOR !== $path && '.' !== $path && '..' !== $path ) {
+ $path = dirname( $path );
+ unset( $directory_cache[ $path ] );
+ }
+
+ set_transient( 'dirsize_cache', $directory_cache );
+}
+
+/**
* Checks compatibility with the current WordPress version.
*
* @since 5.2.0