wp/wp-includes/functions.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 13 d255fe9cd479
--- a/wp/wp-includes/functions.php	Mon Oct 14 18:06:33 2019 +0200
+++ b/wp/wp-includes/functions.php	Mon Oct 14 18:28:13 2019 +0200
@@ -24,21 +24,25 @@
  * @return string|int|bool Formatted date string or Unix timestamp. False if $date is empty.
  */
 function mysql2date( $format, $date, $translate = true ) {
-	if ( empty( $date ) )
+	if ( empty( $date ) ) {
 		return false;
-
-	if ( 'G' == $format )
+	}
+
+	if ( 'G' == $format ) {
 		return strtotime( $date . ' +0000' );
+	}
 
 	$i = strtotime( $date );
 
-	if ( 'U' == $format )
+	if ( 'U' == $format ) {
 		return $i;
-
-	if ( $translate )
+	}
+
+	if ( $translate ) {
 		return date_i18n( $format, $i );
-	else
+	} else {
 		return date( $format, $i );
+	}
 }
 
 /**
@@ -65,12 +69,13 @@
 		case 'timestamp':
 			return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
 		default:
-			return ( $gmt ) ? date( $type ) : date( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
-	}
-}
-
-/**
- * Retrieve the date in localized format, based on timestamp.
+			return ( $gmt ) ? gmdate( $type ) : gmdate( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
+	}
+}
+
+/**
+ * Retrieve the date in localized format, based on a sum of Unix timestamp and
+ * timezone offset in seconds.
  *
  * If the locale specifies the locale month and weekday, then the locale will
  * take over the format for the date. If it isn't, then the date format string
@@ -80,15 +85,17 @@
  *
  * @global WP_Locale $wp_locale
  *
- * @param string   $dateformatstring Format to display the date.
- * @param bool|int $unixtimestamp    Optional. Unix timestamp. Default false.
- * @param bool     $gmt              Optional. Whether to use GMT timezone. Default false.
+ * @param string   $dateformatstring      Format to display the date.
+ * @param int|bool $timestamp_with_offset Optional. A sum of Unix timestamp and timezone offset in seconds.
+ *                                        Default false.
+ * @param bool     $gmt                   Optional. Whether to use GMT timezone. Only applies if timestamp is
+ *                                        not provided. Default false.
  *
  * @return string The date, translated if locale specifies it.
  */
-function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
+function date_i18n( $dateformatstring, $timestamp_with_offset = false, $gmt = false ) {
 	global $wp_locale;
-	$i = $unixtimestamp;
+	$i = $timestamp_with_offset;
 
 	if ( false === $i ) {
 		$i = current_time( 'timestamp', $gmt );
@@ -100,36 +107,72 @@
 	 */
 	$req_format = $dateformatstring;
 
-	if ( ( !empty( $wp_locale->month ) ) && ( !empty( $wp_locale->weekday ) ) ) {
-		$datemonth = $wp_locale->get_month( date( 'm', $i ) );
-		$datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth );
-		$dateweekday = $wp_locale->get_weekday( date( 'w', $i ) );
-		$dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday );
-		$datemeridiem = $wp_locale->get_meridiem( date( 'a', $i ) );
+	$dateformatstring = preg_replace( '/(?<!\\\\)c/', DATE_W3C, $dateformatstring );
+	$dateformatstring = preg_replace( '/(?<!\\\\)r/', DATE_RFC2822, $dateformatstring );
+
+	if ( ( ! empty( $wp_locale->month ) ) && ( ! empty( $wp_locale->weekday ) ) ) {
+		$datemonth            = $wp_locale->get_month( date( 'm', $i ) );
+		$datemonth_abbrev     = $wp_locale->get_month_abbrev( $datemonth );
+		$dateweekday          = $wp_locale->get_weekday( date( 'w', $i ) );
+		$dateweekday_abbrev   = $wp_locale->get_weekday_abbrev( $dateweekday );
+		$datemeridiem         = $wp_locale->get_meridiem( date( 'a', $i ) );
 		$datemeridiem_capital = $wp_locale->get_meridiem( date( 'A', $i ) );
-		$dateformatstring = ' '.$dateformatstring;
-		$dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
-		$dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring );
-		$dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . backslashit( $dateweekday ), $dateformatstring );
-		$dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
-		$dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . backslashit( $datemeridiem ), $dateformatstring );
-		$dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
-
-		$dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
-	}
-	$timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' );
+		$dateformatstring     = ' ' . $dateformatstring;
+		$dateformatstring     = preg_replace( '/([^\\\])D/', "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
+		$dateformatstring     = preg_replace( '/([^\\\])F/', "\\1" . backslashit( $datemonth ), $dateformatstring );
+		$dateformatstring     = preg_replace( '/([^\\\])l/', "\\1" . backslashit( $dateweekday ), $dateformatstring );
+		$dateformatstring     = preg_replace( '/([^\\\])M/', "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
+		$dateformatstring     = preg_replace( '/([^\\\])a/', "\\1" . backslashit( $datemeridiem ), $dateformatstring );
+		$dateformatstring     = preg_replace( '/([^\\\])A/', "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
+
+		$dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) - 1 );
+	}
+	$timezone_formats    = array( 'P', 'I', 'O', 'T', 'Z', 'e' );
 	$timezone_formats_re = implode( '|', $timezone_formats );
 	if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) {
 		$timezone_string = get_option( 'timezone_string' );
+		if ( false === $timestamp_with_offset && $gmt ) {
+			$timezone_string = 'UTC';
+		}
 		if ( $timezone_string ) {
 			$timezone_object = timezone_open( $timezone_string );
-			$date_object = date_create( null, $timezone_object );
+			$date_object     = date_create( null, $timezone_object );
 			foreach ( $timezone_formats as $timezone_format ) {
 				if ( false !== strpos( $dateformatstring, $timezone_format ) ) {
-					$formatted = date_format( $date_object, $timezone_format );
-					$dateformatstring = ' '.$dateformatstring;
+					$formatted        = date_format( $date_object, $timezone_format );
+					$dateformatstring = ' ' . $dateformatstring;
 					$dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring );
-					$dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
+					$dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) - 1 );
+				}
+			}
+		} else {
+			$offset = get_option( 'gmt_offset' );
+			foreach ( $timezone_formats as $timezone_format ) {
+				if ( 'I' === $timezone_format ) {
+					continue;
+				}
+
+				if ( false !== strpos( $dateformatstring, $timezone_format ) ) {
+					if ( 'Z' === $timezone_format ) {
+						$formatted = (string) ( $offset * HOUR_IN_SECONDS );
+					} else {
+						$prefix    = '';
+						$hours     = (int) $offset;
+						$separator = '';
+						$minutes   = abs( ( $offset - $hours ) * 60 );
+
+						if ( 'T' === $timezone_format ) {
+							$prefix = 'GMT';
+						} elseif ( 'e' === $timezone_format || 'P' === $timezone_format ) {
+							$separator = ':';
+						}
+
+						$formatted = sprintf( '%s%+03d%s%02d', $prefix, $hours, $separator, $minutes );
+					}
+
+					$dateformatstring = ' ' . $dateformatstring;
+					$dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring );
+					$dateformatstring = substr( $dateformatstring, 1 );
 				}
 			}
 		}
@@ -143,8 +186,9 @@
 	 *
 	 * @param string $j          Formatted date string.
 	 * @param string $req_format Format to display the date.
-	 * @param int    $i          Unix timestamp.
-	 * @param bool   $gmt        Whether to convert to GMT for time. Default false.
+	 * @param int    $i          A sum of Unix timestamp and timezone offset in seconds.
+	 * @param bool   $gmt        Whether to use GMT timezone. Only applies if timestamp was
+	 *                           not provided. Default false.
 	 */
 	$j = apply_filters( 'date_i18n', $j, $req_format, $i, $gmt );
 	return $j;
@@ -227,7 +271,7 @@
 	 * Filters the number formatted based on the locale.
 	 *
 	 * @since 2.8.0
-	 * @since 4.9.0 The `$number` and `$decimals` arguments were added.
+	 * @since 4.9.0 The `$number` and `$decimals` parameters were added.
 	 *
 	 * @param string $formatted Converted number in string format.
 	 * @param float  $number    The number to convert based on locale.
@@ -279,6 +323,76 @@
 }
 
 /**
+ * Convert a duration to human readable format.
+ *
+ * @since 5.1.0
+ *
+ * @param string $duration Duration will be in string format (HH:ii:ss) OR (ii:ss),
+ *                         with a possible prepended negative sign (-).
+ * @return string|false A human readable duration string, false on failure.
+ */
+function human_readable_duration( $duration = '' ) {
+	if ( ( empty( $duration ) || ! is_string( $duration ) ) ) {
+		return false;
+	}
+
+	$duration = trim( $duration );
+
+	// Remove prepended negative sign.
+	if ( '-' === substr( $duration, 0, 1 ) ) {
+		$duration = substr( $duration, 1 );
+	}
+
+	// Extract duration parts.
+	$duration_parts = array_reverse( explode( ':', $duration ) );
+	$duration_count = count( $duration_parts );
+
+	$hour   = null;
+	$minute = null;
+	$second = null;
+
+	if ( 3 === $duration_count ) {
+		// Validate HH:ii:ss duration format.
+		if ( ! ( (bool) preg_match( '/^([0-9]+):([0-5]?[0-9]):([0-5]?[0-9])$/', $duration ) ) ) {
+			return false;
+		}
+		// Three parts: hours, minutes & seconds.
+		list( $second, $minute, $hour ) = $duration_parts;
+	} elseif ( 2 === $duration_count ) {
+		// Validate ii:ss duration format.
+		if ( ! ( (bool) preg_match( '/^([0-5]?[0-9]):([0-5]?[0-9])$/', $duration ) ) ) {
+			return false;
+		}
+		// Two parts: minutes & seconds.
+		list( $second, $minute ) = $duration_parts;
+	} else {
+		return false;
+	}
+
+	$human_readable_duration = array();
+
+	// Add the hour part to the string.
+	if ( is_numeric( $hour ) ) {
+		/* translators: Time duration in hour or hours. */
+		$human_readable_duration[] = sprintf( _n( '%s hour', '%s hours', $hour ), (int) $hour );
+	}
+
+	// Add the minute part to the string.
+	if ( is_numeric( $minute ) ) {
+		/* translators: Time duration in minute or minutes. */
+		$human_readable_duration[] = sprintf( _n( '%s minute', '%s minutes', $minute ), (int) $minute );
+	}
+
+	// Add the second part to the string.
+	if ( is_numeric( $second ) ) {
+		/* translators: Time duration in second or seconds. */
+		$human_readable_duration[] = sprintf( _n( '%s second', '%s seconds', $second ), (int) $second );
+	}
+
+	return implode( ', ', $human_readable_duration );
+}
+
+/**
  * Get the week start and end from the datetime or date string from MySQL.
  *
  * @since 0.71
@@ -303,11 +417,13 @@
 	// The day of the week from the timestamp.
 	$weekday = date( 'w', $day );
 
-	if ( !is_numeric($start_of_week) )
+	if ( ! is_numeric( $start_of_week ) ) {
 		$start_of_week = get_option( 'start_of_week' );
-
-	if ( $weekday < $start_of_week )
+	}
+
+	if ( $weekday < $start_of_week ) {
 		$weekday += 7;
+	}
 
 	// The most recent week start day on or before $day.
 	$start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week );
@@ -326,8 +442,9 @@
  * @return mixed Unserialized data can be any type.
  */
 function maybe_unserialize( $original ) {
-	if ( is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in
+	if ( is_serialized( $original ) ) { // don't attempt to unserialize data that wasn't serialized going in
 		return @unserialize( $original );
+	}
 	return $original;
 }
 
@@ -349,7 +466,7 @@
 		return false;
 	}
 	$data = trim( $data );
- 	if ( 'N;' == $data ) {
+	if ( 'N;' == $data ) {
 		return true;
 	}
 	if ( strlen( $data ) < 4 ) {
@@ -367,17 +484,20 @@
 		$semicolon = strpos( $data, ';' );
 		$brace     = strpos( $data, '}' );
 		// Either ; or } must exist.
-		if ( false === $semicolon && false === $brace )
+		if ( false === $semicolon && false === $brace ) {
 			return false;
+		}
 		// But neither must be in the first X characters.
-		if ( false !== $semicolon && $semicolon < 3 )
+		if ( false !== $semicolon && $semicolon < 3 ) {
 			return false;
-		if ( false !== $brace && $brace < 4 )
+		}
+		if ( false !== $brace && $brace < 4 ) {
 			return false;
+		}
 	}
 	$token = $data[0];
 	switch ( $token ) {
-		case 's' :
+		case 's':
 			if ( $strict ) {
 				if ( '"' !== substr( $data, -2, 1 ) ) {
 					return false;
@@ -386,12 +506,12 @@
 				return false;
 			}
 			// or else fall through
-		case 'a' :
-		case 'O' :
+		case 'a':
+		case 'O':
 			return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
-		case 'b' :
-		case 'i' :
-		case 'd' :
+		case 'b':
+		case 'i':
+		case 'd':
 			$end = $strict ? '$' : '';
 			return (bool) preg_match( "/^{$token}:[0-9.E-]+;$end/", $data );
 	}
@@ -436,14 +556,16 @@
  * @return mixed A scalar data
  */
 function maybe_serialize( $data ) {
-	if ( is_array( $data ) || is_object( $data ) )
+	if ( is_array( $data ) || is_object( $data ) ) {
 		return serialize( $data );
+	}
 
 	// Double serialization is required for backward compatibility.
 	// See https://core.trac.wordpress.org/ticket/12930
 	// Also the world will end. See WP 3.6.1.
-	if ( is_serialized( $data, false ) )
+	if ( is_serialized( $data, false ) ) {
 		return serialize( $data );
+	}
 
 	return $data;
 }
@@ -522,16 +644,16 @@
 function wp_extract_urls( $content ) {
 	preg_match_all(
 		"#([\"']?)("
-			. "(?:([\w-]+:)?//?)"
-			. "[^\s()<>]+"
-			. "[.]"
-			. "(?:"
-				. "\([\w\d]+\)|"
-				. "(?:"
+			. '(?:([\w-]+:)?//?)'
+			. '[^\s()<>]+'
+			. '[.]'
+			. '(?:'
+				. '\([\w\d]+\)|'
+				. '(?:'
 					. "[^`!()\[\]{};:'\".,<>«»“”‘’\s]|"
-					. "(?:[:]\d+)?/?"
-				. ")+"
-			. ")"
+					. '(?:[:]\d+)?/?'
+				. ')+'
+			. ')'
 		. ")\\1#",
 		$content,
 		$post_links
@@ -570,21 +692,24 @@
 
 	foreach ( $pung as $link_test ) {
 		if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post
-			$mids = $wpdb->get_col( $wpdb->prepare("SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post_ID, $wpdb->esc_like( $link_test ) . '%') );
-			foreach ( $mids as $mid )
+			$mids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post_ID, $wpdb->esc_like( $link_test ) . '%' ) );
+			foreach ( $mids as $mid ) {
 				delete_metadata_by_mid( 'post', $mid );
+			}
 		}
 	}
 
 	foreach ( (array) $post_links_temp as $link_test ) {
-		if ( !in_array( $link_test, $pung ) ) { // If we haven't pung it already
+		if ( ! in_array( $link_test, $pung ) ) { // If we haven't pung it already
 			$test = @parse_url( $link_test );
-			if ( false === $test )
+			if ( false === $test ) {
 				continue;
-			if ( isset( $test['query'] ) )
+			}
+			if ( isset( $test['query'] ) ) {
 				$post_links[] = $link_test;
-			elseif ( isset($test['path']) && ( $test['path'] != '/' ) &&  ($test['path'] != '' ) )
+			} elseif ( isset( $test['path'] ) && ( $test['path'] != '/' ) && ( $test['path'] != '' ) ) {
 				$post_links[] = $link_test;
+			}
 		}
 	}
 
@@ -602,11 +727,11 @@
 	$post_links = apply_filters( 'enclosure_links', $post_links, $post_ID );
 
 	foreach ( (array) $post_links as $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 ) . '%' ) ) ) {
-
-			if ( $headers = wp_get_http_headers( $url) ) {
-				$len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
-				$type = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
+		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 ) . '%' ) ) ) {
+
+			if ( $headers = wp_get_http_headers( $url ) ) {
+				$len           = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
+				$type          = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
 				$allowed_types = array( 'video', 'audio' );
 
 				// Check to see if we can figure out the mime type from
@@ -614,7 +739,7 @@
 				$url_parts = @parse_url( $url );
 				if ( false !== $url_parts ) {
 					$extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
-					if ( !empty( $extension ) ) {
+					if ( ! empty( $extension ) ) {
 						foreach ( wp_get_mime_types() as $exts => $mime ) {
 							if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
 								$type = $mime;
@@ -624,7 +749,7 @@
 					}
 				}
 
-				if ( in_array( substr( $type, 0, strpos( $type, "/" ) ), $allowed_types ) ) {
+				if ( in_array( substr( $type, 0, strpos( $type, '/' ) ), $allowed_types ) ) {
 					add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" );
 				}
 			}
@@ -642,20 +767,26 @@
  * @return bool|string False on failure, headers on success.
  */
 function wp_get_http_headers( $url, $deprecated = false ) {
-	if ( !empty( $deprecated ) )
+	if ( ! empty( $deprecated ) ) {
 		_deprecated_argument( __FUNCTION__, '2.7.0' );
+	}
 
 	$response = wp_safe_remote_head( $url );
 
-	if ( is_wp_error( $response ) )
+	if ( is_wp_error( $response ) ) {
 		return false;
+	}
 
 	return wp_remote_retrieve_headers( $response );
 }
 
 /**
- * Whether the publish date of the current post in the loop is different from the
- * publish date of the previous post in the loop.
+ * Determines whether the publish date of the current post in the loop is different
+ * from the publish date of the previous post in the loop.
+ *
+ * For more information on this and similar theme functions, check out
+ * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
+ * Conditional Tags} article in the Theme Developer Handbook.
  *
  * @since 0.71
  *
@@ -666,10 +797,11 @@
  */
 function is_new_day() {
 	global $currentday, $previousday;
-	if ( $currentday != $previousday )
+	if ( $currentday != $previousday ) {
 		return 1;
-	else
+	} else {
 		return 0;
+	}
 }
 
 /**
@@ -682,7 +814,7 @@
  *
  * @see _http_build_query() Used to build the query
  * @link https://secure.php.net/manual/en/function.http-build-query.php for more on what
- *		 http_build_query() does.
+ *       http_build_query() does.
  *
  * @param array $data URL-encode key/value pairs.
  * @return string URL-encoded string.
@@ -713,29 +845,35 @@
 	$ret = array();
 
 	foreach ( (array) $data as $k => $v ) {
-		if ( $urlencode)
-			$k = urlencode($k);
-		if ( is_int($k) && $prefix != null )
-			$k = $prefix.$k;
-		if ( !empty($key) )
+		if ( $urlencode ) {
+			$k = urlencode( $k );
+		}
+		if ( is_int( $k ) && $prefix != null ) {
+			$k = $prefix . $k;
+		}
+		if ( ! empty( $key ) ) {
 			$k = $key . '%5B' . $k . '%5D';
-		if ( $v === null )
+		}
+		if ( $v === null ) {
 			continue;
-		elseif ( $v === false )
+		} elseif ( $v === false ) {
 			$v = '0';
-
-		if ( is_array($v) || is_object($v) )
-			array_push($ret,_http_build_query($v, '', $sep, $k, $urlencode));
-		elseif ( $urlencode )
-			array_push($ret, $k.'='.urlencode($v));
-		else
-			array_push($ret, $k.'='.$v);
-	}
-
-	if ( null === $sep )
-		$sep = ini_get('arg_separator.output');
-
-	return implode($sep, $ret);
+		}
+
+		if ( is_array( $v ) || is_object( $v ) ) {
+			array_push( $ret, _http_build_query( $v, '', $sep, $k, $urlencode ) );
+		} elseif ( $urlencode ) {
+			array_push( $ret, $k . '=' . urlencode( $v ) );
+		} else {
+			array_push( $ret, $k . '=' . $v );
+		}
+	}
+
+	if ( null === $sep ) {
+		$sep = ini_get( 'arg_separator.output' );
+	}
+
+	return implode( $sep, $ret );
 }
 
 /**
@@ -776,40 +914,43 @@
 function add_query_arg() {
 	$args = func_get_args();
 	if ( is_array( $args[0] ) ) {
-		if ( count( $args ) < 2 || false === $args[1] )
+		if ( count( $args ) < 2 || false === $args[1] ) {
 			$uri = $_SERVER['REQUEST_URI'];
-		else
+		} else {
 			$uri = $args[1];
+		}
 	} else {
-		if ( count( $args ) < 3 || false === $args[2] )
+		if ( count( $args ) < 3 || false === $args[2] ) {
 			$uri = $_SERVER['REQUEST_URI'];
-		else
+		} else {
 			$uri = $args[2];
-	}
-
-	if ( $frag = strstr( $uri, '#' ) )
+		}
+	}
+
+	if ( $frag = strstr( $uri, '#' ) ) {
 		$uri = substr( $uri, 0, -strlen( $frag ) );
-	else
+	} else {
 		$frag = '';
+	}
 
 	if ( 0 === stripos( $uri, 'http://' ) ) {
 		$protocol = 'http://';
-		$uri = substr( $uri, 7 );
+		$uri      = substr( $uri, 7 );
 	} elseif ( 0 === stripos( $uri, 'https://' ) ) {
 		$protocol = 'https://';
-		$uri = substr( $uri, 8 );
+		$uri      = substr( $uri, 8 );
 	} else {
 		$protocol = '';
 	}
 
 	if ( strpos( $uri, '?' ) !== false ) {
 		list( $base, $query ) = explode( '?', $uri, 2 );
-		$base .= '?';
+		$base                .= '?';
 	} elseif ( $protocol || strpos( $uri, '=' ) === false ) {
-		$base = $uri . '?';
+		$base  = $uri . '?';
 		$query = '';
 	} else {
-		$base = '';
+		$base  = '';
 		$query = $uri;
 	}
 
@@ -824,8 +965,9 @@
 	}
 
 	foreach ( $qs as $k => $v ) {
-		if ( $v === false )
-			unset( $qs[$k] );
+		if ( $v === false ) {
+			unset( $qs[ $k ] );
+		}
 	}
 
 	$ret = build_query( $qs );
@@ -847,8 +989,9 @@
  */
 function remove_query_arg( $key, $query = false ) {
 	if ( is_array( $key ) ) { // removing multiple keys
-		foreach ( $key as $k )
+		foreach ( $key as $k ) {
 			$query = add_query_arg( $k, false, $query );
+		}
 		return $query;
 	}
 	return add_query_arg( $key, false, $query );
@@ -909,9 +1052,9 @@
 function add_magic_quotes( $array ) {
 	foreach ( (array) $array as $k => $v ) {
 		if ( is_array( $v ) ) {
-			$array[$k] = add_magic_quotes( $v );
+			$array[ $k ] = add_magic_quotes( $v );
 		} else {
-			$array[$k] = addslashes( $v );
+			$array[ $k ] = addslashes( $v );
 		}
 	}
 	return $array;
@@ -930,16 +1073,18 @@
 function wp_remote_fopen( $uri ) {
 	$parsed_url = @parse_url( $uri );
 
-	if ( !$parsed_url || !is_array( $parsed_url ) )
+	if ( ! $parsed_url || ! is_array( $parsed_url ) ) {
 		return false;
-
-	$options = array();
+	}
+
+	$options            = array();
 	$options['timeout'] = 10;
 
 	$response = wp_safe_remote_get( $uri, $options );
 
-	if ( is_wp_error( $response ) )
+	if ( is_wp_error( $response ) ) {
 		return false;
+	}
 
 	return wp_remote_retrieve_body( $response );
 }
@@ -959,14 +1104,18 @@
 	global $wp, $wp_query, $wp_the_query;
 	$wp->main( $query_vars );
 
-	if ( !isset($wp_the_query) )
+	if ( ! isset( $wp_the_query ) ) {
 		$wp_the_query = $wp_query;
+	}
 }
 
 /**
  * Retrieve the description for the HTTP status.
  *
  * @since 2.3.0
+ * @since 3.9.0 Added status codes 418, 428, 429, 431, and 511.
+ * @since 4.5.0 Added status codes 308, 421, and 451.
+ * @since 5.1.0 Added status code 103.
  *
  * @global array $wp_header_to_desc
  *
@@ -978,11 +1127,12 @@
 
 	$code = absint( $code );
 
-	if ( !isset( $wp_header_to_desc ) ) {
+	if ( ! isset( $wp_header_to_desc ) ) {
 		$wp_header_to_desc = array(
 			100 => 'Continue',
 			101 => 'Switching Protocols',
 			102 => 'Processing',
+			103 => 'Early Hints',
 
 			200 => 'OK',
 			201 => 'Created',
@@ -1046,10 +1196,11 @@
 		);
 	}
 
-	if ( isset( $wp_header_to_desc[$code] ) )
-		return $wp_header_to_desc[$code];
-	else
+	if ( isset( $wp_header_to_desc[ $code ] ) ) {
+		return $wp_header_to_desc[ $code ];
+	} else {
 		return '';
+	}
 }
 
 /**
@@ -1072,9 +1223,9 @@
 		return;
 	}
 
-	$protocol = wp_get_server_protocol();
+	$protocol      = wp_get_server_protocol();
 	$status_header = "$protocol $code $description";
-	if ( function_exists( 'apply_filters' ) )
+	if ( function_exists( 'apply_filters' ) ) {
 
 		/**
 		 * Filters an HTTP status header.
@@ -1087,6 +1238,7 @@
 		 * @param string $protocol      Server protocol.
 		 */
 		$status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol );
+	}
 
 	@header( $status_header, true, $code );
 }
@@ -1103,11 +1255,11 @@
  */
 function wp_get_nocache_headers() {
 	$headers = array(
-		'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
+		'Expires'       => 'Wed, 11 Jan 1984 05:00:00 GMT',
 		'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
 	);
 
-	if ( function_exists('apply_filters') ) {
+	if ( function_exists( 'apply_filters' ) ) {
 		/**
 		 * Filters the cache-controlling headers.
 		 *
@@ -1158,8 +1310,9 @@
 		}
 	}
 
-	foreach ( $headers as $name => $field_value )
-		@header("{$name}: {$field_value}");
+	foreach ( $headers as $name => $field_value ) {
+		@header( "{$name}: {$field_value}" );
+	}
 }
 
 /**
@@ -1170,9 +1323,9 @@
 function cache_javascript_headers() {
 	$expiresOffset = 10 * DAY_IN_SECONDS;
 
-	header( "Content-Type: text/javascript; charset=" . get_bloginfo( 'charset' ) );
-	header( "Vary: Accept-Encoding" ); // Handle proxies
-	header( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $expiresOffset ) . " GMT" );
+	header( 'Content-Type: text/javascript; charset=' . get_bloginfo( 'charset' ) );
+	header( 'Vary: Accept-Encoding' ); // Handle proxies
+	header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + $expiresOffset ) . ' GMT' );
 }
 
 /**
@@ -1223,8 +1376,9 @@
 	// Remove the pad, if present.
 	$feed = preg_replace( '/^_+/', '', $feed );
 
-	if ( $feed == '' || $feed == 'feed' )
+	if ( $feed == '' || $feed == 'feed' ) {
 		$feed = get_default_feed();
+	}
 
 	if ( ! has_action( "do_feed_{$feed}" ) ) {
 		wp_die( __( 'ERROR: This is not a valid feed template.' ), '', array( 'response' => 404 ) );
@@ -1277,10 +1431,11 @@
  * @param bool $for_comments True for the comment feed, false for normal feed.
  */
 function do_feed_rss2( $for_comments ) {
-	if ( $for_comments )
+	if ( $for_comments ) {
 		load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
-	else
+	} else {
 		load_template( ABSPATH . WPINC . '/feed-rss2.php' );
+	}
 }
 
 /**
@@ -1293,10 +1448,11 @@
  * @param bool $for_comments True for the comment feed, false for normal feed.
  */
 function do_feed_atom( $for_comments ) {
-	if ($for_comments)
-		load_template( ABSPATH . WPINC . '/feed-atom-comments.php');
-	else
+	if ( $for_comments ) {
+		load_template( ABSPATH . WPINC . '/feed-atom-comments.php' );
+	} else {
 		load_template( ABSPATH . WPINC . '/feed-atom.php' );
+	}
 }
 
 /**
@@ -1323,9 +1479,9 @@
 		$output .= "Disallow: /\n";
 	} else {
 		$site_url = parse_url( site_url() );
-		$path = ( !empty( $site_url['path'] ) ) ? $site_url['path'] : '';
-		$output .= "Disallow: $path/wp-admin/\n";
-		$output .= "Allow: $path/wp-admin/admin-ajax.php\n";
+		$path     = ( ! empty( $site_url['path'] ) ) ? $site_url['path'] : '';
+		$output  .= "Disallow: $path/wp-admin/\n";
+		$output  .= "Allow: $path/wp-admin/admin-ajax.php\n";
 	}
 
 	/**
@@ -1340,7 +1496,7 @@
 }
 
 /**
- * Test whether WordPress is already installed.
+ * Determines whether WordPress is already installed.
  *
  * The cache will be checked first. If you have a cache plugin, which saves
  * the cache values, then this will work. If you use the default WordPress
@@ -1348,6 +1504,10 @@
  *
  * Checks for the 'siteurl' option for whether WordPress is installed.
  *
+ * For more information on this and similar theme functions, check out
+ * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
+ * Conditional Tags} article in the Theme Developer Handbook.
+ *
  * @since 2.1.0
  *
  * @global wpdb $wpdb WordPress database abstraction object.
@@ -1361,29 +1521,33 @@
 	 * Check cache first. If options table goes away and we have true
 	 * cached, oh well.
 	 */
-	if ( wp_cache_get( 'is_blog_installed' ) )
+	if ( wp_cache_get( 'is_blog_installed' ) ) {
 		return true;
+	}
 
 	$suppress = $wpdb->suppress_errors();
 	if ( ! wp_installing() ) {
 		$alloptions = wp_load_alloptions();
 	}
 	// If siteurl is not set to autoload, check it specifically
-	if ( !isset( $alloptions['siteurl'] ) )
+	if ( ! isset( $alloptions['siteurl'] ) ) {
 		$installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
-	else
+	} else {
 		$installed = $alloptions['siteurl'];
+	}
 	$wpdb->suppress_errors( $suppress );
 
-	$installed = !empty( $installed );
+	$installed = ! empty( $installed );
 	wp_cache_set( 'is_blog_installed', $installed );
 
-	if ( $installed )
+	if ( $installed ) {
 		return true;
+	}
 
 	// If visiting repair.php, return true and let it take over.
-	if ( defined( 'WP_REPAIRING' ) )
+	if ( defined( 'WP_REPAIRING' ) ) {
 		return true;
+	}
 
 	$suppress = $wpdb->suppress_errors();
 
@@ -1395,13 +1559,16 @@
 	$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.
-		if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table )
+		if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table ) {
 			continue;
-		if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table )
+		}
+		if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table ) {
 			continue;
-
-		if ( ! $wpdb->get_results( "DESCRIBE $table;" ) )
+		}
+
+		if ( ! $wpdb->get_results( "DESCRIBE $table;" ) ) {
 			continue;
+		}
 
 		// One or more tables exist. We are insane.
 
@@ -1465,15 +1632,17 @@
  * @param bool       $echo    Optional. Whether to display or return hidden form field. Default true.
  * @return string Nonce field HTML markup.
  */
-function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $echo = true ) {
-	$name = esc_attr( $name );
+function wp_nonce_field( $action = -1, $name = '_wpnonce', $referer = true, $echo = true ) {
+	$name        = esc_attr( $name );
 	$nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';
 
-	if ( $referer )
+	if ( $referer ) {
 		$nonce_field .= wp_referer_field( false );
-
-	if ( $echo )
+	}
+
+	if ( $echo ) {
 		echo $nonce_field;
+	}
 
 	return $nonce_field;
 }
@@ -1490,10 +1659,11 @@
  * @return string Referer field HTML markup.
  */
 function wp_referer_field( $echo = true ) {
-	$referer_field = '<input type="hidden" name="_wp_http_referer" value="'. esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
-
-	if ( $echo )
+	$referer_field = '<input type="hidden" name="_wp_http_referer" value="' . esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
+
+	if ( $echo ) {
 		echo $referer_field;
+	}
 	return $referer_field;
 }
 
@@ -1516,8 +1686,9 @@
 		$ref = 'previous' == $jump_back_to ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] );
 	}
 	$orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( $ref ) . '" />';
-	if ( $echo )
+	if ( $echo ) {
 		echo $orig_referer_field;
+	}
 	return $orig_referer_field;
 }
 
@@ -1556,7 +1727,7 @@
 function wp_get_raw_referer() {
 	if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
 		return wp_unslash( $_REQUEST['_wp_http_referer'] );
-	} else if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
+	} elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
 		return wp_unslash( $_SERVER['HTTP_REFERER'] );
 	}
 
@@ -1571,8 +1742,9 @@
  * @return string|false False if no original referer or original referer if set.
  */
 function wp_get_original_referer() {
-	if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) && function_exists( 'wp_validate_redirect' ) )
+	if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) && function_exists( 'wp_validate_redirect' ) ) {
 		return wp_validate_redirect( wp_unslash( $_REQUEST['_wp_original_http_referer'] ), false );
+	}
 	return false;
 }
 
@@ -1606,12 +1778,14 @@
 	 * Safe mode fails with a trailing slash under certain PHP versions.
 	 * Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
 	 */
-	$target = rtrim($target, '/');
-	if ( empty($target) )
+	$target = rtrim( $target, '/' );
+	if ( empty( $target ) ) {
 		$target = '/';
-
-	if ( file_exists( $target ) )
+	}
+
+	if ( file_exists( $target ) ) {
 		return @is_dir( $target );
+	}
 
 	// We need to find the permissions of the parent folder that exists and inherit that.
 	$target_parent = dirname( $target );
@@ -1657,18 +1831,29 @@
  */
 function path_is_absolute( $path ) {
 	/*
+	 * Check to see if the path is a stream and check to see if its an actual
+	 * path or file as realpath() does not support stream wrappers.
+	 */
+	if ( wp_is_stream( $path ) && ( is_dir( $path ) || is_file( $path ) ) ) {
+		return true;
+	}
+
+	/*
 	 * This is definitive if true but fails if $path does not exist or contains
 	 * a symbolic link.
 	 */
-	if ( realpath($path) == $path )
+	if ( realpath( $path ) == $path ) {
 		return true;
-
-	if ( strlen($path) == 0 || $path[0] == '.' )
+	}
+
+	if ( strlen( $path ) == 0 || $path[0] == '.' ) {
 		return false;
+	}
 
 	// Windows allows absolute paths like this.
-	if ( preg_match('#^[a-zA-Z]:\\\\#', $path) )
+	if ( preg_match( '#^[a-zA-Z]:\\\\#', $path ) ) {
 		return true;
+	}
 
 	// A path starting with / or \ is absolute; anything else is relative.
 	return ( $path[0] == '/' || $path[0] == '\\' );
@@ -1687,10 +1872,11 @@
  * @return string The path with the base or absolute path.
  */
 function path_join( $base, $path ) {
-	if ( path_is_absolute($path) )
+	if ( path_is_absolute( $path ) ) {
 		return $path;
-
-	return rtrim($base, '/') . '/' . ltrim($path, '/');
+	}
+
+	return rtrim( $base, '/' ) . '/' . ltrim( $path, '/' );
 }
 
 /**
@@ -1713,7 +1899,7 @@
 	$wrapper = '';
 	if ( wp_is_stream( $path ) ) {
 		list( $wrapper, $path ) = explode( '://', $path, 2 );
-		$wrapper .= '://';
+		$wrapper               .= '://';
 	}
 
 	// Standardise all paths to use /
@@ -1748,25 +1934,30 @@
  */
 function get_temp_dir() {
 	static $temp = '';
-	if ( defined('WP_TEMP_DIR') )
-		return trailingslashit(WP_TEMP_DIR);
-
-	if ( $temp )
+	if ( defined( 'WP_TEMP_DIR' ) ) {
+		return trailingslashit( WP_TEMP_DIR );
+	}
+
+	if ( $temp ) {
 		return trailingslashit( $temp );
-
-	if ( function_exists('sys_get_temp_dir') ) {
+	}
+
+	if ( function_exists( 'sys_get_temp_dir' ) ) {
 		$temp = sys_get_temp_dir();
-		if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
+		if ( @is_dir( $temp ) && wp_is_writable( $temp ) ) {
 			return trailingslashit( $temp );
-	}
-
-	$temp = ini_get('upload_tmp_dir');
-	if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
+		}
+	}
+
+	$temp = ini_get( 'upload_tmp_dir' );
+	if ( @is_dir( $temp ) && wp_is_writable( $temp ) ) {
 		return trailingslashit( $temp );
+	}
 
 	$temp = WP_CONTENT_DIR . '/';
-	if ( is_dir( $temp ) && wp_is_writable( $temp ) )
+	if ( is_dir( $temp ) && wp_is_writable( $temp ) ) {
 		return $temp;
+	}
 
 	return '/tmp/';
 }
@@ -1785,10 +1976,11 @@
  * @return bool Whether the path is writable.
  */
 function wp_is_writable( $path ) {
-	if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) )
+	if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) ) {
 		return win_is_writable( $path );
-	else
+	} else {
 		return @is_writable( $path );
+	}
 }
 
 /**
@@ -1809,19 +2001,21 @@
  */
 function win_is_writable( $path ) {
 
-	if ( $path[strlen( $path ) - 1] == '/' ) { // if it looks like a directory, check a random file within the directory
-		return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp');
+	if ( $path[ strlen( $path ) - 1 ] == '/' ) { // if it looks like a directory, check a random file within the directory
+		return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp' );
 	} elseif ( is_dir( $path ) ) { // If it's a directory (and not a file) check a random file within the directory
 		return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
 	}
 	// check tmp file for read/write capabilities
-	$should_delete_tmp_file = !file_exists( $path );
-	$f = @fopen( $path, 'a' );
-	if ( $f === false )
+	$should_delete_tmp_file = ! file_exists( $path );
+	$f                      = @fopen( $path, 'a' );
+	if ( $f === false ) {
 		return false;
+	}
 	fclose( $f );
-	if ( $should_delete_tmp_file )
+	if ( $should_delete_tmp_file ) {
 		unlink( $path );
+	}
 	return true;
 }
 
@@ -1910,7 +2104,7 @@
 				if ( 0 === strpos( $uploads['basedir'], ABSPATH ) ) {
 					$error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
 				} else {
-					$error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
+					$error_path = wp_basename( $uploads['basedir'] ) . $uploads['subdir'];
 				}
 
 				$uploads['error'] = sprintf(
@@ -1937,7 +2131,7 @@
  * @return array See wp_upload_dir()
  */
 function _wp_upload_dir( $time = null ) {
-	$siteurl = get_option( 'siteurl' );
+	$siteurl     = get_option( 'siteurl' );
 	$upload_path = trim( get_option( 'upload_path' ) );
 
 	if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) {
@@ -1949,11 +2143,12 @@
 		$dir = $upload_path;
 	}
 
-	if ( !$url = get_option( 'upload_url_path' ) ) {
-		if ( empty($upload_path) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) )
+	if ( ! $url = get_option( 'upload_url_path' ) ) {
+		if ( empty( $upload_path ) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) ) {
 			$url = WP_CONTENT_URL . '/uploads';
-		else
+		} else {
 			$url = trailingslashit( $siteurl ) . $upload_path;
+		}
 	}
 
 	/*
@@ -1978,10 +2173,11 @@
 			 * had wp-content/uploads for the main site.)
 			 */
 
-			if ( defined( 'MULTISITE' ) )
+			if ( defined( 'MULTISITE' ) ) {
 				$ms_dir = '/sites/' . get_current_blog_id();
-			else
+			} else {
 				$ms_dir = '/' . get_current_blog_id();
+			}
 
 			$dir .= $ms_dir;
 			$url .= $ms_dir;
@@ -2001,10 +2197,11 @@
 			 * rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
 			 */
 
-			if ( defined( 'BLOGUPLOADDIR' ) )
+			if ( defined( 'BLOGUPLOADDIR' ) ) {
 				$dir = untrailingslashit( BLOGUPLOADDIR );
-			else
+			} else {
 				$dir = ABSPATH . UPLOADS;
+			}
 			$url = trailingslashit( $siteurl ) . 'files';
 		}
 	}
@@ -2015,10 +2212,11 @@
 	$subdir = '';
 	if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
 		// Generate the yearly and monthly dirs
-		if ( !$time )
+		if ( ! $time ) {
 			$time = current_time( 'mysql' );
-		$y = substr( $time, 0, 4 );
-		$m = substr( $time, 5, 2 );
+		}
+		$y      = substr( $time, 0, 4 );
+		$m      = substr( $time, 5, 2 );
 		$subdir = "/$y/$m";
 	}
 
@@ -2054,10 +2252,10 @@
  */
 function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) {
 	// Sanitize the file name before we begin processing.
-	$filename = sanitize_file_name($filename);
+	$filename = sanitize_file_name( $filename );
 
 	// Separate the filename into a name and extension.
-	$ext = pathinfo( $filename, PATHINFO_EXTENSION );
+	$ext  = pathinfo( $filename, PATHINFO_EXTENSION );
 	$name = pathinfo( $filename, PATHINFO_BASENAME );
 	if ( $ext ) {
 		$ext = '.' . $ext;
@@ -2078,16 +2276,16 @@
 		$number = '';
 
 		// Change '.ext' to lower case.
-		if ( $ext && strtolower($ext) != $ext ) {
-			$ext2 = strtolower($ext);
-			$filename2 = preg_replace( '|' . preg_quote($ext) . '$|', $ext2, $filename );
+		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") ) {
+			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;
+				$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;
 			}
 
 			/**
@@ -2108,7 +2306,7 @@
 			if ( '' == "$number$ext" ) {
 				$filename = "$filename-" . $new_number;
 			} else {
-				$filename = str_replace( array( "-$number$ext", "$number$ext" ), "-" . $new_number . $ext, $filename );
+				$filename = str_replace( array( "-$number$ext", "$number$ext" ), '-' . $new_number . $ext, $filename );
 			}
 			$number = $new_number;
 		}
@@ -2142,20 +2340,24 @@
  * @return array
  */
 function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
-	if ( !empty( $deprecated ) )
+	if ( ! empty( $deprecated ) ) {
 		_deprecated_argument( __FUNCTION__, '2.0.0' );
-
-	if ( empty( $name ) )
+	}
+
+	if ( empty( $name ) ) {
 		return array( 'error' => __( 'Empty filename' ) );
+	}
 
 	$wp_filetype = wp_check_filetype( $name );
-	if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) )
+	if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) ) {
 		return array( 'error' => __( 'Sorry, this file type is not permitted for security reasons.' ) );
+	}
 
 	$upload = wp_upload_dir( $time );
 
-	if ( $upload['error'] !== false )
+	if ( $upload['error'] !== false ) {
 		return $upload;
+	}
 
 	/**
 	 * Filters whether to treat the upload bits as an error.
@@ -2167,9 +2369,16 @@
 	 *
 	 * @param mixed $upload_bits_error An array of upload bits data, or a non-array error to return.
 	 */
-	$upload_bits_error = apply_filters( 'wp_upload_bits', array( 'name' => $name, 'bits' => $bits, 'time' => $time ) );
-	if ( !is_array( $upload_bits_error ) ) {
-		$upload[ 'error' ] = $upload_bits_error;
+	$upload_bits_error = apply_filters(
+		'wp_upload_bits',
+		array(
+			'name' => $name,
+			'bits' => $bits,
+			'time' => $time,
+		)
+	);
+	if ( ! is_array( $upload_bits_error ) ) {
+		$upload['error'] = $upload_bits_error;
 		return $upload;
 	}
 
@@ -2177,10 +2386,11 @@
 
 	$new_file = $upload['path'] . "/$filename";
 	if ( ! wp_mkdir_p( dirname( $new_file ) ) ) {
-		if ( 0 === strpos( $upload['basedir'], ABSPATH ) )
+		if ( 0 === strpos( $upload['basedir'], ABSPATH ) ) {
 			$error_path = str_replace( ABSPATH, '', $upload['basedir'] ) . $upload['subdir'];
-		else
-			$error_path = basename( $upload['basedir'] ) . $upload['subdir'];
+		} else {
+			$error_path = wp_basename( $upload['basedir'] ) . $upload['subdir'];
+		}
 
 		$message = sprintf(
 			/* translators: %s: directory path */
@@ -2191,15 +2401,16 @@
 	}
 
 	$ifp = @ fopen( $new_file, 'wb' );
-	if ( ! $ifp )
+	if ( ! $ifp ) {
 		return array( 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) );
+	}
 
 	@fwrite( $ifp, $bits );
 	fclose( $ifp );
 	clearstatcache();
 
 	// Set correct file permissions
-	$stat = @ stat( dirname( $new_file ) );
+	$stat  = @ stat( dirname( $new_file ) );
 	$perms = $stat['mode'] & 0007777;
 	$perms = $perms & 0000666;
 	@ chmod( $new_file, $perms );
@@ -2209,7 +2420,16 @@
 	$url = $upload['url'] . "/$filename";
 
 	/** This filter is documented in wp-admin/includes/file.php */
-	return apply_filters( 'wp_handle_upload', array( 'file' => $new_file, 'url' => $url, 'type' => $wp_filetype['type'], 'error' => false ), 'sideload' );
+	return apply_filters(
+		'wp_handle_upload',
+		array(
+			'file'  => $new_file,
+			'url'   => $url,
+			'type'  => $wp_filetype['type'],
+			'error' => false,
+		),
+		'sideload'
+	);
 }
 
 /**
@@ -2224,9 +2444,11 @@
 	$ext = strtolower( $ext );
 
 	$ext2type = wp_get_ext_types();
-	foreach ( $ext2type as $type => $exts )
-		if ( in_array( $ext, $exts ) )
+	foreach ( $ext2type as $type => $exts ) {
+		if ( in_array( $ext, $exts ) ) {
 			return $type;
+		}
+	}
 }
 
 /**
@@ -2241,16 +2463,17 @@
  * @return array Values with extension first and mime type.
  */
 function wp_check_filetype( $filename, $mimes = null ) {
-	if ( empty($mimes) )
+	if ( empty( $mimes ) ) {
 		$mimes = get_allowed_mime_types();
+	}
 	$type = false;
-	$ext = false;
+	$ext  = false;
 
 	foreach ( $mimes as $ext_preg => $mime_match ) {
 		$ext_preg = '!\.(' . $ext_preg . ')$!i';
 		if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
 			$type = $mime_match;
-			$ext = $ext_matches[1];
+			$ext  = $ext_matches[1];
 			break;
 		}
 	}
@@ -2282,8 +2505,8 @@
 
 	// Do basic extension validation and MIME mapping
 	$wp_filetype = wp_check_filetype( $filename, $mimes );
-	$ext = $wp_filetype['ext'];
-	$type = $wp_filetype['type'];
+	$ext         = $wp_filetype['ext'];
+	$type        = $wp_filetype['type'];
 
 	// We can't do any further validation without a file to work with
 	if ( ! file_exists( $file ) ) {
@@ -2306,28 +2529,31 @@
 			 *
 			 * @param  array $mime_to_ext Array of image mime types and their matching extensions.
 			 */
-			$mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array(
-				'image/jpeg' => 'jpg',
-				'image/png'  => 'png',
-				'image/gif'  => 'gif',
-				'image/bmp'  => 'bmp',
-				'image/tiff' => 'tif',
-			) );
+			$mime_to_ext = apply_filters(
+				'getimagesize_mimes_to_exts',
+				array(
+					'image/jpeg' => 'jpg',
+					'image/png'  => 'png',
+					'image/gif'  => 'gif',
+					'image/bmp'  => 'bmp',
+					'image/tiff' => 'tif',
+				)
+			);
 
 			// Replace whatever is after the last period in the filename with the correct extension
 			if ( ! empty( $mime_to_ext[ $real_mime ] ) ) {
 				$filename_parts = explode( '.', $filename );
 				array_pop( $filename_parts );
 				$filename_parts[] = $mime_to_ext[ $real_mime ];
-				$new_filename = implode( '.', $filename_parts );
+				$new_filename     = implode( '.', $filename_parts );
 
 				if ( $new_filename != $filename ) {
 					$proper_filename = $new_filename; // Mark that it changed
 				}
 				// Redefine the extension / MIME
 				$wp_filetype = wp_check_filetype( $new_filename, $mimes );
-				$ext = $wp_filetype['ext'];
-				$type = $wp_filetype['type'];
+				$ext         = $wp_filetype['ext'];
+				$type        = $wp_filetype['type'];
 			} else {
 				// Reset $real_mime and try validating again.
 				$real_mime = false;
@@ -2337,21 +2563,82 @@
 
 	// Validate files that didn't get validated during previous checks.
 	if ( $type && ! $real_mime && extension_loaded( 'fileinfo' ) ) {
-		$finfo = finfo_open( FILEINFO_MIME_TYPE );
+		$finfo     = finfo_open( FILEINFO_MIME_TYPE );
 		$real_mime = finfo_file( $finfo, $file );
 		finfo_close( $finfo );
 
+		// fileinfo often misidentifies obscure files as one of these types
+		$nonspecific_types = array(
+			'application/octet-stream',
+			'application/encrypted',
+			'application/CDFV2-encrypted',
+			'application/zip',
+		);
+
 		/*
-		 * If $real_mime doesn't match what we're expecting, we need to do some extra
-		 * vetting of application mime types to make sure this type of file is allowed.
-		 * Other mime types are assumed to be safe, but should be considered unverified.
+		 * If $real_mime doesn't match the content type we're expecting from the file's extension,
+		 * we need to do some additional vetting. Media types and those listed in $nonspecific_types are
+		 * allowed some leeway, but anything else must exactly match the real content type.
 		 */
-		if ( $real_mime && ( $real_mime !== $type ) && ( 0 === strpos( $real_mime, 'application' ) ) ) {
-			$allowed = get_allowed_mime_types();
-
-			if ( ! in_array( $real_mime, $allowed ) ) {
+		if ( in_array( $real_mime, $nonspecific_types, true ) ) {
+			// File is a non-specific binary type. That's ok if it's a type that generally tends to be binary.
+			if ( ! in_array( substr( $type, 0, strcspn( $type, '/' ) ), array( 'application', 'video', 'audio' ) ) ) {
+				$type = $ext = false;
+			}
+		} elseif ( 0 === strpos( $real_mime, 'video/' ) || 0 === strpos( $real_mime, 'audio/' ) ) {
+			/*
+			 * For these types, only the major type must match the real value.
+			 * This means that common mismatches are forgiven: application/vnd.apple.numbers is often misidentified as application/zip,
+			 * and some media files are commonly named with the wrong extension (.mov instead of .mp4)
+			 */
+			if ( substr( $real_mime, 0, strcspn( $real_mime, '/' ) ) !== substr( $type, 0, strcspn( $type, '/' ) ) ) {
 				$type = $ext = false;
 			}
+		} elseif ( 'text/plain' === $real_mime ) {
+			// A few common file types are occasionally detected as text/plain; allow those.
+			if ( ! in_array(
+				$type,
+				array(
+					'text/plain',
+					'text/csv',
+					'text/richtext',
+					'text/tsv',
+					'text/vtt',
+				)
+			)
+			) {
+				$type = $ext = false;
+			}
+		} elseif ( 'text/rtf' === $real_mime ) {
+			// Special casing for RTF files.
+			if ( ! in_array(
+				$type,
+				array(
+					'text/rtf',
+					'text/plain',
+					'application/rtf',
+				)
+			)
+			) {
+				$type = $ext = false;
+			}
+		} else {
+			if ( $type !== $real_mime ) {
+				/*
+				 * Everything else including image/* and application/*:
+				 * If the real content type doesn't match the file extension, assume it's dangerous.
+				 */
+				$type = $ext = false;
+			}
+		}
+	}
+
+	// The mime type must be allowed
+	if ( $type ) {
+		$allowed = get_allowed_mime_types();
+
+		if ( ! in_array( $type, $allowed ) ) {
+			$type = $ext = false;
 		}
 	}
 
@@ -2359,15 +2646,17 @@
 	 * Filters the "real" file type of the given file.
 	 *
 	 * @since 3.0.0
+	 * @since 5.1.0 The $real_mime parameter was added.
 	 *
-	 * @param array  $wp_check_filetype_and_ext File data array containing 'ext', 'type', and
-	 *                                          'proper_filename' keys.
-	 * @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 array  $mimes                     Key is the file extension with value as the mime type.
+	 * @param array       $wp_check_filetype_and_ext File data array containing 'ext', 'type', and
+	 *                                               'proper_filename' keys.
+	 * @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 array       $mimes                     Key is the file extension with value as the mime type.
+	 * @param string|bool $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 );
+	return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes, $real_mime );
 }
 
 /**
@@ -2389,10 +2678,10 @@
 	try {
 		if ( is_callable( 'exif_imagetype' ) ) {
 			$imagetype = exif_imagetype( $file );
-			$mime = ( $imagetype ) ? image_type_to_mime_type( $imagetype ) : false;
+			$mime      = ( $imagetype ) ? image_type_to_mime_type( $imagetype ) : false;
 		} elseif ( function_exists( 'getimagesize' ) ) {
 			$imagesize = getimagesize( $file );
-			$mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
+			$mime      = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
 		} else {
 			$mime = false;
 		}
@@ -2423,109 +2712,112 @@
 	 * @param array $wp_get_mime_types Mime types keyed by the file extension regex
 	 *                                 corresponding to those types.
 	 */
-	return apply_filters( 'mime_types', array(
-	// Image formats.
-	'jpg|jpeg|jpe' => 'image/jpeg',
-	'gif' => 'image/gif',
-	'png' => 'image/png',
-	'bmp' => 'image/bmp',
-	'tiff|tif' => 'image/tiff',
-	'ico' => 'image/x-icon',
-	// Video formats.
-	'asf|asx' => 'video/x-ms-asf',
-	'wmv' => 'video/x-ms-wmv',
-	'wmx' => 'video/x-ms-wmx',
-	'wm' => 'video/x-ms-wm',
-	'avi' => 'video/avi',
-	'divx' => 'video/divx',
-	'flv' => 'video/x-flv',
-	'mov|qt' => 'video/quicktime',
-	'mpeg|mpg|mpe' => 'video/mpeg',
-	'mp4|m4v' => 'video/mp4',
-	'ogv' => 'video/ogg',
-	'webm' => 'video/webm',
-	'mkv' => 'video/x-matroska',
-	'3gp|3gpp' => 'video/3gpp', // Can also be audio
-	'3g2|3gp2' => 'video/3gpp2', // Can also be audio
-	// Text formats.
-	'txt|asc|c|cc|h|srt' => 'text/plain',
-	'csv' => 'text/csv',
-	'tsv' => 'text/tab-separated-values',
-	'ics' => 'text/calendar',
-	'rtx' => 'text/richtext',
-	'css' => 'text/css',
-	'htm|html' => 'text/html',
-	'vtt' => 'text/vtt',
-	'dfxp' => 'application/ttaf+xml',
-	// Audio formats.
-	'mp3|m4a|m4b' => 'audio/mpeg',
-	'aac' => 'audio/aac',
-	'ra|ram' => 'audio/x-realaudio',
-	'wav' => 'audio/wav',
-	'ogg|oga' => 'audio/ogg',
-	'flac' => 'audio/flac',
-	'mid|midi' => 'audio/midi',
-	'wma' => 'audio/x-ms-wma',
-	'wax' => 'audio/x-ms-wax',
-	'mka' => 'audio/x-matroska',
-	// Misc application formats.
-	'rtf' => 'application/rtf',
-	'js' => 'application/javascript',
-	'pdf' => 'application/pdf',
-	'swf' => 'application/x-shockwave-flash',
-	'class' => 'application/java',
-	'tar' => 'application/x-tar',
-	'zip' => 'application/zip',
-	'gz|gzip' => 'application/x-gzip',
-	'rar' => 'application/rar',
-	'7z' => 'application/x-7z-compressed',
-	'exe' => 'application/x-msdownload',
-	'psd' => 'application/octet-stream',
-	'xcf' => 'application/octet-stream',
-	// MS Office formats.
-	'doc' => 'application/msword',
-	'pot|pps|ppt' => 'application/vnd.ms-powerpoint',
-	'wri' => 'application/vnd.ms-write',
-	'xla|xls|xlt|xlw' => 'application/vnd.ms-excel',
-	'mdb' => 'application/vnd.ms-access',
-	'mpp' => 'application/vnd.ms-project',
-	'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-	'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
-	'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
-	'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
-	'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
-	'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
-	'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
-	'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
-	'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
-	'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
-	'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
-	'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
-	'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
-	'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
-	'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
-	'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
-	'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
-	'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
-	'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
-	'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
-	'oxps' => 'application/oxps',
-	'xps' => 'application/vnd.ms-xpsdocument',
-	// OpenOffice formats.
-	'odt' => 'application/vnd.oasis.opendocument.text',
-	'odp' => 'application/vnd.oasis.opendocument.presentation',
-	'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
-	'odg' => 'application/vnd.oasis.opendocument.graphics',
-	'odc' => 'application/vnd.oasis.opendocument.chart',
-	'odb' => 'application/vnd.oasis.opendocument.database',
-	'odf' => 'application/vnd.oasis.opendocument.formula',
-	// WordPerfect formats.
-	'wp|wpd' => 'application/wordperfect',
-	// iWork formats.
-	'key' => 'application/vnd.apple.keynote',
-	'numbers' => 'application/vnd.apple.numbers',
-	'pages' => 'application/vnd.apple.pages',
-	) );
+	return apply_filters(
+		'mime_types',
+		array(
+			// Image formats.
+			'jpg|jpeg|jpe'                 => 'image/jpeg',
+			'gif'                          => 'image/gif',
+			'png'                          => 'image/png',
+			'bmp'                          => 'image/bmp',
+			'tiff|tif'                     => 'image/tiff',
+			'ico'                          => 'image/x-icon',
+			// Video formats.
+			'asf|asx'                      => 'video/x-ms-asf',
+			'wmv'                          => 'video/x-ms-wmv',
+			'wmx'                          => 'video/x-ms-wmx',
+			'wm'                           => 'video/x-ms-wm',
+			'avi'                          => 'video/avi',
+			'divx'                         => 'video/divx',
+			'flv'                          => 'video/x-flv',
+			'mov|qt'                       => 'video/quicktime',
+			'mpeg|mpg|mpe'                 => 'video/mpeg',
+			'mp4|m4v'                      => 'video/mp4',
+			'ogv'                          => 'video/ogg',
+			'webm'                         => 'video/webm',
+			'mkv'                          => 'video/x-matroska',
+			'3gp|3gpp'                     => 'video/3gpp', // Can also be audio
+			'3g2|3gp2'                     => 'video/3gpp2', // Can also be audio
+			// Text formats.
+			'txt|asc|c|cc|h|srt'           => 'text/plain',
+			'csv'                          => 'text/csv',
+			'tsv'                          => 'text/tab-separated-values',
+			'ics'                          => 'text/calendar',
+			'rtx'                          => 'text/richtext',
+			'css'                          => 'text/css',
+			'htm|html'                     => 'text/html',
+			'vtt'                          => 'text/vtt',
+			'dfxp'                         => 'application/ttaf+xml',
+			// Audio formats.
+			'mp3|m4a|m4b'                  => 'audio/mpeg',
+			'aac'                          => 'audio/aac',
+			'ra|ram'                       => 'audio/x-realaudio',
+			'wav'                          => 'audio/wav',
+			'ogg|oga'                      => 'audio/ogg',
+			'flac'                         => 'audio/flac',
+			'mid|midi'                     => 'audio/midi',
+			'wma'                          => 'audio/x-ms-wma',
+			'wax'                          => 'audio/x-ms-wax',
+			'mka'                          => 'audio/x-matroska',
+			// Misc application formats.
+			'rtf'                          => 'application/rtf',
+			'js'                           => 'application/javascript',
+			'pdf'                          => 'application/pdf',
+			'swf'                          => 'application/x-shockwave-flash',
+			'class'                        => 'application/java',
+			'tar'                          => 'application/x-tar',
+			'zip'                          => 'application/zip',
+			'gz|gzip'                      => 'application/x-gzip',
+			'rar'                          => 'application/rar',
+			'7z'                           => 'application/x-7z-compressed',
+			'exe'                          => 'application/x-msdownload',
+			'psd'                          => 'application/octet-stream',
+			'xcf'                          => 'application/octet-stream',
+			// MS Office formats.
+			'doc'                          => 'application/msword',
+			'pot|pps|ppt'                  => 'application/vnd.ms-powerpoint',
+			'wri'                          => 'application/vnd.ms-write',
+			'xla|xls|xlt|xlw'              => 'application/vnd.ms-excel',
+			'mdb'                          => 'application/vnd.ms-access',
+			'mpp'                          => 'application/vnd.ms-project',
+			'docx'                         => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+			'docm'                         => 'application/vnd.ms-word.document.macroEnabled.12',
+			'dotx'                         => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+			'dotm'                         => 'application/vnd.ms-word.template.macroEnabled.12',
+			'xlsx'                         => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+			'xlsm'                         => 'application/vnd.ms-excel.sheet.macroEnabled.12',
+			'xlsb'                         => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
+			'xltx'                         => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+			'xltm'                         => 'application/vnd.ms-excel.template.macroEnabled.12',
+			'xlam'                         => 'application/vnd.ms-excel.addin.macroEnabled.12',
+			'pptx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+			'pptm'                         => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
+			'ppsx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+			'ppsm'                         => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
+			'potx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.template',
+			'potm'                         => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
+			'ppam'                         => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
+			'sldx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
+			'sldm'                         => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
+			'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
+			'oxps'                         => 'application/oxps',
+			'xps'                          => 'application/vnd.ms-xpsdocument',
+			// OpenOffice formats.
+			'odt'                          => 'application/vnd.oasis.opendocument.text',
+			'odp'                          => 'application/vnd.oasis.opendocument.presentation',
+			'ods'                          => 'application/vnd.oasis.opendocument.spreadsheet',
+			'odg'                          => 'application/vnd.oasis.opendocument.graphics',
+			'odc'                          => 'application/vnd.oasis.opendocument.chart',
+			'odb'                          => 'application/vnd.oasis.opendocument.database',
+			'odf'                          => 'application/vnd.oasis.opendocument.formula',
+			// WordPerfect formats.
+			'wp|wpd'                       => 'application/wordperfect',
+			// iWork formats.
+			'key'                          => 'application/vnd.apple.keynote',
+			'numbers'                      => 'application/vnd.apple.numbers',
+			'pages'                        => 'application/vnd.apple.pages',
+		)
+	);
 }
 
 /**
@@ -2547,17 +2839,20 @@
 	 * @param array $ext2type Multi-dimensional array with extensions for a default set
 	 *                        of file types.
 	 */
-	return apply_filters( 'ext2type', array(
-		'image'       => array( 'jpg', 'jpeg', 'jpe',  'gif',  'png',  'bmp',   'tif',  'tiff', 'ico' ),
-		'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' ),
-		'spreadsheet' => array( 'numbers',     'ods',  'xls',  'xlsx', 'xlsm',  'xlsb' ),
-		'interactive' => array( 'swf', 'key',  'ppt',  'pptx', 'pptm', 'pps',   'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ),
-		'text'        => array( 'asc', 'csv',  'tsv',  'txt' ),
-		'archive'     => array( 'bz2', 'cab',  'dmg',  'gz',   'rar',  'sea',   'sit',  'sqx',  'tar',  'tgz',  'zip', '7z' ),
-		'code'        => array( 'css', 'htm',  'html', 'php',  'js' ),
-	) );
+	return apply_filters(
+		'ext2type',
+		array(
+			'image'       => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico' ),
+			'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' ),
+			'spreadsheet' => array( 'numbers', 'ods', 'xls', 'xlsx', 'xlsm', 'xlsb' ),
+			'interactive' => array( 'swf', 'key', 'ppt', 'pptx', 'pptm', 'pps', 'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ),
+			'text'        => array( 'asc', 'csv', 'tsv', 'txt' ),
+			'archive'     => array( 'bz2', 'cab', 'dmg', 'gz', 'rar', 'sea', 'sit', 'sqx', 'tar', 'tgz', 'zip', '7z' ),
+			'code'        => array( 'css', 'htm', 'html', 'php', 'js' ),
+		)
+	);
 }
 
 /**
@@ -2573,8 +2868,9 @@
 	$t = wp_get_mime_types();
 
 	unset( $t['swf'], $t['exe'] );
-	if ( function_exists( 'current_user_can' ) )
+	if ( function_exists( 'current_user_can' ) ) {
 		$unfiltered = $user ? user_can( $user, 'unfiltered_html' ) : current_user_can( 'unfiltered_html' );
+	}
 
 	if ( empty( $unfiltered ) ) {
 		unset( $t['htm|html'], $t['js'] );
@@ -2610,9 +2906,9 @@
 			__( 'You are attempting to log out of %s' ),
 			get_bloginfo( 'name' )
 		);
-		$html .= '</p><p>';
+		$html       .= '</p><p>';
 		$redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
-		$html .= sprintf(
+		$html       .= sprintf(
 			/* translators: %s: logout URL */
 			__( 'Do you really want to <a href="%s">log out</a>?' ),
 			wp_logout_url( $redirect_to )
@@ -2621,7 +2917,8 @@
 		$html = __( 'The link you followed has expired.' );
 		if ( wp_get_referer() ) {
 			$html .= '</p><p>';
-			$html .= sprintf( '<a href="%s">%s</a>',
+			$html .= sprintf(
+				'<a href="%s">%s</a>',
 				esc_url( remove_query_arg( 'updated', wp_get_referer() ) ),
 				__( 'Please try again.' )
 			);
@@ -2632,7 +2929,7 @@
 }
 
 /**
- * Kill WordPress execution and display HTML message with error message.
+ * Kills WordPress execution and displays HTML page with an error message.
  *
  * This function complements the `die()` PHP function. The difference is that
  * HTML will be displayed to the user. It is recommended to use this function
@@ -2646,6 +2943,9 @@
  * @since 2.0.4
  * @since 4.1.0 The `$title` and `$args` parameters were changed to optionally accept
  *              an integer to be used as the response code.
+ * @since 5.1.0 The `$link_url`, `$link_text`, and `$exit` arguments were added.
+ *
+ * @global WP_Query $wp_query Global WP_Query instance.
  *
  * @param string|WP_Error  $message Optional. Error message. If this is a WP_Error object,
  *                                  and not an Ajax or XML-RPC request, the error's messages are used.
@@ -2659,13 +2959,21 @@
  *     as the response code. Default empty array.
  *
  *     @type int    $response       The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
+ *     @type string $link_url       A URL to include a link to. Only works in combination with $link_text.
+ *                                  Default empty string.
+ *     @type string $link_text      A label for the link to include. Only works in combination with $link_url.
+ *                                  Default empty string.
  *     @type bool   $back_link      Whether to include a link to go back. Default false.
  *     @type string $text_direction The text direction. This is only useful internally, when WordPress
  *                                  is still loading and the site's locale is not set up yet. Accepts 'rtl'.
  *                                  Default is the value of is_rtl().
+ *     @type string $code           Error code to use. Default is 'wp_die', or the main error code if $message
+ *                                  is a WP_Error.
+ *     @type bool   $exit           Whether to exit the process after completion. Default true.
  * }
  */
 function wp_die( $message = '', $title = '', $args = array() ) {
+	global $wp_query;
 
 	if ( is_int( $args ) ) {
 		$args = array( 'response' => $args );
@@ -2683,6 +2991,24 @@
 		 * @param callable $function Callback function name.
 		 */
 		$function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
+	} elseif ( wp_is_json_request() ) {
+		/**
+		 * Filters the callback for killing WordPress execution for JSON requests.
+		 *
+		 * @since 5.1.0
+		 *
+		 * @param callable $function Callback function name.
+		 */
+		$function = apply_filters( 'wp_die_json_handler', '_json_wp_die_handler' );
+	} elseif ( wp_is_jsonp_request() ) {
+		/**
+		 * Filters the callback for killing WordPress execution for JSONP requests.
+		 *
+		 * @since 5.2.0
+		 *
+		 * @param callable $function Callback function name.
+		 */
+		$function = apply_filters( 'wp_die_jsonp_handler', '_jsonp_wp_die_handler' );
 	} elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
 		/**
 		 * Filters the callback for killing WordPress execution for XML-RPC requests.
@@ -2692,9 +3018,22 @@
 		 * @param callable $function Callback function name.
 		 */
 		$function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
+	} elseif ( wp_is_xml_request()
+		|| isset( $wp_query ) &&
+			( function_exists( 'is_feed' ) && is_feed()
+			|| function_exists( 'is_comment_feed' ) && is_comment_feed()
+			|| function_exists( 'is_trackback' ) && is_trackback() ) ) {
+		/**
+		 * Filters the callback for killing WordPress execution for XML requests.
+		 *
+		 * @since 5.2.0
+		 *
+		 * @param callable $function Callback function name.
+		 */
+		$function = apply_filters( 'wp_die_xml_handler', '_xml_wp_die_handler' );
 	} else {
 		/**
-		 * Filters the callback for killing WordPress execution for all non-Ajax, non-XML-RPC requests.
+		 * Filters the callback for killing WordPress execution for all non-Ajax, non-JSON, non-XML requests.
 		 *
 		 * @since 3.0.0
 		 *
@@ -2707,10 +3046,10 @@
 }
 
 /**
- * Kills WordPress execution and display HTML message with error message.
- *
- * This is the default handler for wp_die if you want a custom one for your
- * site then you can overload using the {@see 'wp_die_handler'} filter in wp_die().
+ * Kills WordPress execution and displays HTML page with an error message.
+ *
+ * This is the default handler for wp_die(). If you want a custom one,
+ * you can override this using the {@see 'wp_die_handler'} filter in wp_die().
  *
  * @since 3.0.0
  * @access private
@@ -2720,65 +3059,61 @@
  * @param string|array    $args    Optional. Arguments to control behavior. Default empty array.
  */
 function _default_wp_die_handler( $message, $title = '', $args = array() ) {
-	$defaults = array( 'response' => 500 );
-	$r = wp_parse_args($args, $defaults);
-
-	$have_gettext = function_exists('__');
-
-	if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
-		if ( empty( $title ) ) {
-			$error_data = $message->get_error_data();
-			if ( is_array( $error_data ) && isset( $error_data['title'] ) )
-				$title = $error_data['title'];
+	list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args );
+
+	if ( is_string( $message ) ) {
+		if ( ! empty( $r['additional_errors'] ) ) {
+			$message = array_merge(
+				array( $message ),
+				wp_list_pluck( $r['additional_errors'], 'message' )
+			);
+			$message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $message ) . "</li>\n\t</ul>";
+		} else {
+			$message = "<p>$message</p>";
 		}
-		$errors = $message->get_error_messages();
-		switch ( count( $errors ) ) {
-		case 0 :
-			$message = '';
-			break;
-		case 1 :
-			$message = "<p>{$errors[0]}</p>";
-			break;
-		default :
-			$message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $errors ) . "</li>\n\t</ul>";
-			break;
+	}
+
+	$have_gettext = function_exists( '__' );
+
+	if ( ! empty( $r['link_url'] ) && ! empty( $r['link_text'] ) ) {
+		$link_url = $r['link_url'];
+		if ( function_exists( 'esc_url' ) ) {
+			$link_url = esc_url( $link_url );
 		}
-	} elseif ( is_string( $message ) ) {
-		$message = "<p>$message</p>";
+		$link_text = $r['link_text'];
+		$message  .= "\n<p><a href='{$link_url}'>{$link_text}</a></p>";
 	}
 
 	if ( isset( $r['back_link'] ) && $r['back_link'] ) {
-		$back_text = $have_gettext? __('&laquo; Back') : '&laquo; Back';
-		$message .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
+		$back_text = $have_gettext ? __( '&laquo; Back' ) : '&laquo; Back';
+		$message  .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
 	}
 
 	if ( ! did_action( 'admin_head' ) ) :
-		if ( !headers_sent() ) {
+		if ( ! headers_sent() ) {
+			header( 'Content-Type: text/html; charset=utf-8' );
 			status_header( $r['response'] );
 			nocache_headers();
-			header( 'Content-Type: text/html; charset=utf-8' );
 		}
 
-		if ( empty($title) )
-			$title = $have_gettext ? __('WordPress &rsaquo; Error') : 'WordPress &rsaquo; Error';
-
-		$text_direction = 'ltr';
-		if ( isset($r['text_direction']) && 'rtl' == $r['text_direction'] )
-			$text_direction = 'rtl';
-		elseif ( function_exists( 'is_rtl' ) && is_rtl() )
-			$text_direction = 'rtl';
-?>
+		$text_direction = $r['text_direction'];
+		if ( function_exists( 'language_attributes' ) && function_exists( 'is_rtl' ) ) {
+			$dir_attr = get_language_attributes();
+		} else {
+			$dir_attr = "dir='$text_direction'";
+		}
+		?>
 <!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" <?php if ( function_exists( 'language_attributes' ) && function_exists( 'is_rtl' ) ) language_attributes(); else echo "dir='$text_direction'"; ?>>
+<html xmlns="http://www.w3.org/1999/xhtml" <?php echo $dir_attr; ?>>
 <head>
 	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 	<meta name="viewport" content="width=device-width">
-	<?php
-	if ( function_exists( 'wp_no_robots' ) ) {
-		wp_no_robots();
-	}
-	?>
-	<title><?php echo $title ?></title>
+		<?php
+		if ( function_exists( 'wp_no_robots' ) ) {
+			wp_no_robots();
+		}
+		?>
+	<title><?php echo $title; ?></title>
 	<style type="text/css">
 		html {
 			background: #f1f1f1;
@@ -2790,8 +3125,8 @@
 			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 3px rgba(0, 0, 0, 0.13);
+			box-shadow: 0 1px 3px rgba(0, 0, 0, 0.13);
 		}
 		h1 {
 			border-bottom: 1px solid #dadada;
@@ -2826,12 +3161,12 @@
 		}
 		a:focus {
 			color: #124964;
-		    -webkit-box-shadow:
-		    	0 0 0 1px #5b9dd9,
-				0 0 2px 1px rgba(30, 140, 190, .8);
-		    box-shadow:
-		    	0 0 0 1px #5b9dd9,
-				0 0 2px 1px rgba(30, 140, 190, .8);
+			-webkit-box-shadow:
+				0 0 0 1px #5b9dd9,
+				0 0 2px 1px rgba(30, 140, 190, 0.8);
+			box-shadow:
+				0 0 0 1px #5b9dd9,
+				0 0 2px 1px rgba(30, 140, 190, 0.8);
 			outline: none;
 		}
 		.button {
@@ -2856,7 +3191,7 @@
 
 			-webkit-box-shadow: 0 1px 0 #ccc;
 			box-shadow: 0 1px 0 #ccc;
-		 	vertical-align: top;
+			 vertical-align: top;
 		}
 
 		.button.button-large {
@@ -2872,21 +3207,21 @@
 			color: #23282d;
 		}
 
-		.button:focus  {
+		.button:focus {
 			border-color: #5b9dd9;
-			-webkit-box-shadow: 0 0 3px rgba( 0, 115, 170, .8 );
-			box-shadow: 0 0 3px rgba( 0, 115, 170, .8 );
+			-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;
 		}
 
 		.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 );
-		 	-webkit-transform: translateY(1px);
-		 	-ms-transform: translateY(1px);
-		 	transform: translateY(1px);
+			 -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);
+			 -webkit-transform: translateY(1px);
+			 -ms-transform: translateY(1px);
+			 transform: translateY(1px);
 		}
 
 		<?php
@@ -2901,14 +3236,138 @@
 	<?php echo $message; ?>
 </body>
 </html>
-<?php
-	die();
-}
-
-/**
- * Kill WordPress execution and display XML message with error message.
- *
- * This is the handler for wp_die when processing XMLRPC requests.
+	<?php
+	if ( $r['exit'] ) {
+		die();
+	}
+}
+
+/**
+ * Kills WordPress execution and displays Ajax response with an error message.
+ *
+ * This is the handler for wp_die() when processing Ajax requests.
+ *
+ * @since 3.4.0
+ * @access private
+ *
+ * @param string       $message Error message.
+ * @param string       $title   Optional. Error title (unused). Default empty.
+ * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
+ */
+function _ajax_wp_die_handler( $message, $title = '', $args = array() ) {
+	// Set default 'response' to 200 for AJAX requests.
+	$args = wp_parse_args(
+		$args,
+		array( 'response' => 200 )
+	);
+
+	list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args );
+
+	if ( ! headers_sent() ) {
+		// This is intentional. For backward-compatibility, support passing null here.
+		if ( null !== $args['response'] ) {
+			status_header( $r['response'] );
+		}
+		nocache_headers();
+	}
+
+	if ( is_scalar( $message ) ) {
+		$message = (string) $message;
+	} else {
+		$message = '0';
+	}
+
+	if ( $r['exit'] ) {
+		die( $message );
+	}
+
+	echo $message;
+}
+
+/**
+ * Kills WordPress execution and displays JSON response with an error message.
+ *
+ * This is the handler for wp_die() when processing JSON requests.
+ *
+ * @since 5.1.0
+ * @access private
+ *
+ * @param string       $message Error message.
+ * @param string       $title   Optional. Error title. Default empty.
+ * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
+ */
+function _json_wp_die_handler( $message, $title = '', $args = array() ) {
+	list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args );
+
+	$data = array(
+		'code'              => $r['code'],
+		'message'           => $message,
+		'data'              => array(
+			'status' => $r['response'],
+		),
+		'additional_errors' => $r['additional_errors'],
+	);
+
+	if ( ! headers_sent() ) {
+		header( 'Content-Type: application/json; charset=utf-8' );
+		if ( null !== $r['response'] ) {
+			status_header( $r['response'] );
+		}
+		nocache_headers();
+	}
+
+	echo wp_json_encode( $data );
+	if ( $r['exit'] ) {
+		die();
+	}
+}
+
+/**
+ * Kills WordPress execution and displays JSONP response with an error message.
+ *
+ * This is the handler for wp_die() when processing JSONP requests.
+ *
+ * @since 5.2.0
+ * @access private
+ *
+ * @param string       $message Error message.
+ * @param string       $title   Optional. Error title. Default empty.
+ * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
+ */
+function _jsonp_wp_die_handler( $message, $title = '', $args = array() ) {
+	list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args );
+
+	$data = array(
+		'code'              => $r['code'],
+		'message'           => $message,
+		'data'              => array(
+			'status' => $r['response'],
+		),
+		'additional_errors' => $r['additional_errors'],
+	);
+
+	if ( ! headers_sent() ) {
+		header( 'Content-Type: application/javascript; charset=utf-8' );
+		header( 'X-Content-Type-Options: nosniff' );
+		header( 'X-Robots-Tag: noindex' );
+		if ( null !== $r['response'] ) {
+			status_header( $r['response'] );
+		}
+		nocache_headers();
+	}
+
+	$result         = wp_json_encode( $data );
+	$jsonp_callback = $_GET['_jsonp'];
+	echo '/**/' . $jsonp_callback . '(' . $result . ')';
+	if ( $r['exit'] ) {
+		die();
+	}
+}
+
+/**
+ * Kills WordPress execution and displays XML response with an error message.
+ *
+ * This is the handler for wp_die() when processing XMLRPC requests.
  *
  * @since 3.2.0
  * @access private
@@ -2921,58 +3380,170 @@
  */
 function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
 	global $wp_xmlrpc_server;
-	$defaults = array( 'response' => 500 );
-
-	$r = wp_parse_args($args, $defaults);
+
+	list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args );
+
+	if ( ! headers_sent() ) {
+		nocache_headers();
+	}
 
 	if ( $wp_xmlrpc_server ) {
-		$error = new IXR_Error( $r['response'] , $message);
+		$error = new IXR_Error( $r['response'], $message );
 		$wp_xmlrpc_server->output( $error->getXml() );
 	}
-	die();
-}
-
-/**
- * Kill WordPress ajax execution.
- *
- * This is the handler for wp_die when processing Ajax requests.
- *
- * @since 3.4.0
+	if ( $r['exit'] ) {
+		die();
+	}
+}
+
+/**
+ * Kills WordPress execution and displays XML response with an error message.
+ *
+ * This is the handler for wp_die() when processing XML requests.
+ *
+ * @since 5.2.0
  * @access private
  *
  * @param string       $message Error message.
+ * @param string       $title   Optional. Error title. Default empty.
+ * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
+ */
+function _xml_wp_die_handler( $message, $title = '', $args = array() ) {
+	list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args );
+
+	$message = htmlspecialchars( $message );
+	$title   = htmlspecialchars( $title );
+
+	$xml = <<<EOD
+<error>
+    <code>{$r['code']}</code>
+    <title><![CDATA[{$title}]]></title>
+    <message><![CDATA[{$message}]]></message>
+    <data>
+        <status>{$r['response']}</status>
+    </data>
+</error>
+
+EOD;
+
+	if ( ! headers_sent() ) {
+		header( 'Content-Type: text/xml; charset=utf-8' );
+		if ( null !== $r['response'] ) {
+			status_header( $r['response'] );
+		}
+		nocache_headers();
+	}
+
+	echo $xml;
+	if ( $r['exit'] ) {
+		die();
+	}
+}
+
+/**
+ * Kills WordPress execution and displays an error message.
+ *
+ * This is the handler for wp_die() when processing APP requests.
+ *
+ * @since 3.4.0
+ * @since 5.1.0 Added the $title and $args parameters.
+ * @access private
+ *
+ * @param string       $message Optional. Response to print. Default empty.
  * @param string       $title   Optional. Error title (unused). Default empty.
  * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
  */
-function _ajax_wp_die_handler( $message, $title = '', $args = array() ) {
+function _scalar_wp_die_handler( $message = '', $title = '', $args = array() ) {
+	list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args );
+
+	if ( $r['exit'] ) {
+		if ( is_scalar( $message ) ) {
+			die( (string) $message );
+		}
+		die();
+	}
+
+	if ( is_scalar( $message ) ) {
+		echo (string) $message;
+	}
+}
+
+/**
+ * Processes arguments passed to wp_die() consistently for its handlers.
+ *
+ * @since 5.1.0
+ * @access private
+ *
+ * @param string       $message Error message.
+ * @param string       $title   Optional. Error title. Default empty.
+ * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
+ * @return array List of processed $message string, $title string, and $args array.
+ */
+function _wp_die_process_input( $message, $title = '', $args = array() ) {
 	$defaults = array(
-		'response' => 200,
+		'response'          => 0,
+		'code'              => '',
+		'exit'              => true,
+		'back_link'         => false,
+		'link_url'          => '',
+		'link_text'         => '',
+		'text_direction'    => '',
+		'additional_errors' => array(),
 	);
-	$r = wp_parse_args( $args, $defaults );
-
-	if ( ! headers_sent() && null !== $r['response'] ) {
-		status_header( $r['response'] );
-	}
-
-	if ( is_scalar( $message ) )
-		die( (string) $message );
-	die( '0' );
-}
-
-/**
- * Kill WordPress execution.
- *
- * This is the handler for wp_die when processing APP requests.
- *
- * @since 3.4.0
- * @access private
- *
- * @param string $message Optional. Response to print. Default empty.
- */
-function _scalar_wp_die_handler( $message = '' ) {
-	if ( is_scalar( $message ) )
-		die( (string) $message );
-	die();
+
+	$args = wp_parse_args( $args, $defaults );
+
+	if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
+		if ( ! empty( $message->errors ) ) {
+			$errors = array();
+			foreach ( (array) $message->errors as $error_code => $error_messages ) {
+				foreach ( (array) $error_messages as $error_message ) {
+					$errors[] = array(
+						'code'    => $error_code,
+						'message' => $error_message,
+						'data'    => $message->get_error_data( $error_code ),
+					);
+				}
+			}
+
+			$message = $errors[0]['message'];
+			if ( empty( $args['code'] ) ) {
+				$args['code'] = $errors[0]['code'];
+			}
+			if ( empty( $args['response'] ) && is_array( $errors[0]['data'] ) && ! empty( $errors[0]['data']['status'] ) ) {
+				$args['response'] = $errors[0]['data']['status'];
+			}
+			if ( empty( $title ) && is_array( $errors[0]['data'] ) && ! empty( $errors[0]['data']['title'] ) ) {
+				$title = $errors[0]['data']['title'];
+			}
+
+			unset( $errors[0] );
+			$args['additional_errors'] = array_values( $errors );
+		} else {
+			$message = '';
+		}
+	}
+
+	$have_gettext = function_exists( '__' );
+
+	// The $title and these specific $args must always have a non-empty value.
+	if ( empty( $args['code'] ) ) {
+		$args['code'] = 'wp_die';
+	}
+	if ( empty( $args['response'] ) ) {
+		$args['response'] = 500;
+	}
+	if ( empty( $title ) ) {
+		$title = $have_gettext ? __( 'WordPress &rsaquo; Error' ) : 'WordPress &rsaquo; Error';
+	}
+	if ( empty( $args['text_direction'] ) || ! in_array( $args['text_direction'], array( 'ltr', 'rtl' ), true ) ) {
+		$args['text_direction'] = 'ltr';
+		if ( function_exists( 'is_rtl' ) && is_rtl() ) {
+			$args['text_direction'] = 'rtl';
+		}
+	}
+
+	return array( $message, $title, $args );
 }
 
 /**
@@ -3008,7 +3579,7 @@
 	// If json_encode() was successful, no need to do more sanity checking.
 	// ... unless we're in an old version of PHP, and json_encode() returned
 	// a string containing 'null'. Then we need to do more sanity checking.
-	if ( false !== $json && ( version_compare( PHP_VERSION, '5.5', '>=' ) || false === strpos( $json, 'null' ) ) )  {
+	if ( false !== $json && ( version_compare( PHP_VERSION, '5.5', '>=' ) || false === strpos( $json, 'null' ) ) ) {
 		return $json;
 	}
 
@@ -3184,9 +3755,13 @@
 	echo wp_json_encode( $response );
 
 	if ( wp_doing_ajax() ) {
-		wp_die( '', '', array(
-			'response' => null,
-		) );
+		wp_die(
+			'',
+			'',
+			array(
+				'response' => null,
+			)
+		);
 	} else {
 		die;
 	}
@@ -3204,8 +3779,9 @@
 function wp_send_json_success( $data = null, $status_code = null ) {
 	$response = array( 'success' => true );
 
-	if ( isset( $data ) )
+	if ( isset( $data ) ) {
 		$response['data'] = $data;
+	}
 
 	wp_send_json( $response, $status_code );
 }
@@ -3233,7 +3809,10 @@
 			$result = array();
 			foreach ( $data->errors as $code => $messages ) {
 				foreach ( $messages as $message ) {
-					$result[] = array( 'code' => $code, 'message' => $message );
+					$result[] = array(
+						'code'    => $code,
+						'message' => $message,
+					);
 				}
 			}
 
@@ -3284,8 +3863,9 @@
  * @return string Homepage location.
  */
 function _config_wp_home( $url = '' ) {
-	if ( defined( 'WP_HOME' ) )
+	if ( defined( 'WP_HOME' ) ) {
 		return untrailingslashit( WP_HOME );
+	}
 	return $url;
 }
 
@@ -3305,8 +3885,9 @@
  * @return string The WordPress Site URL.
  */
 function _config_wp_siteurl( $url = '' ) {
-	if ( defined( 'WP_SITEURL' ) )
+	if ( defined( 'WP_SITEURL' ) ) {
 		return untrailingslashit( WP_SITEURL );
+	}
 	return $url;
 }
 
@@ -3340,7 +3921,7 @@
 function _mce_set_direction( $mce_init ) {
 	if ( is_rtl() ) {
 		$mce_init['directionality'] = 'rtl';
-		$mce_init['rtl_ui'] = true;
+		$mce_init['rtl_ui']         = true;
 
 		if ( ! empty( $mce_init['plugins'] ) && strpos( $mce_init['plugins'], 'directionality' ) === false ) {
 			$mce_init['plugins'] .= ',directionality';
@@ -3381,56 +3962,57 @@
 	global $wpsmiliestrans, $wp_smiliessearch;
 
 	// don't bother setting up smilies if they are disabled
-	if ( !get_option( 'use_smilies' ) )
+	if ( ! get_option( 'use_smilies' ) ) {
 		return;
-
-	if ( !isset( $wpsmiliestrans ) ) {
+	}
+
+	if ( ! isset( $wpsmiliestrans ) ) {
 		$wpsmiliestrans = array(
-		':mrgreen:' => 'mrgreen.png',
-		':neutral:' => "\xf0\x9f\x98\x90",
-		':twisted:' => "\xf0\x9f\x98\x88",
-		  ':arrow:' => "\xe2\x9e\xa1",
-		  ':shock:' => "\xf0\x9f\x98\xaf",
-		  ':smile:' => "\xf0\x9f\x99\x82",
-		    ':???:' => "\xf0\x9f\x98\x95",
-		   ':cool:' => "\xf0\x9f\x98\x8e",
-		   ':evil:' => "\xf0\x9f\x91\xbf",
-		   ':grin:' => "\xf0\x9f\x98\x80",
-		   ':idea:' => "\xf0\x9f\x92\xa1",
-		   ':oops:' => "\xf0\x9f\x98\xb3",
-		   ':razz:' => "\xf0\x9f\x98\x9b",
-		   ':roll:' => "\xf0\x9f\x99\x84",
-		   ':wink:' => "\xf0\x9f\x98\x89",
-		    ':cry:' => "\xf0\x9f\x98\xa5",
-		    ':eek:' => "\xf0\x9f\x98\xae",
-		    ':lol:' => "\xf0\x9f\x98\x86",
-		    ':mad:' => "\xf0\x9f\x98\xa1",
-		    ':sad:' => "\xf0\x9f\x99\x81",
-		      '8-)' => "\xf0\x9f\x98\x8e",
-		      '8-O' => "\xf0\x9f\x98\xaf",
-		      ':-(' => "\xf0\x9f\x99\x81",
-		      ':-)' => "\xf0\x9f\x99\x82",
-		      ':-?' => "\xf0\x9f\x98\x95",
-		      ':-D' => "\xf0\x9f\x98\x80",
-		      ':-P' => "\xf0\x9f\x98\x9b",
-		      ':-o' => "\xf0\x9f\x98\xae",
-		      ':-x' => "\xf0\x9f\x98\xa1",
-		      ':-|' => "\xf0\x9f\x98\x90",
-		      ';-)' => "\xf0\x9f\x98\x89",
-		// This one transformation breaks regular text with frequency.
-		//     '8)' => "\xf0\x9f\x98\x8e",
-		       '8O' => "\xf0\x9f\x98\xaf",
-		       ':(' => "\xf0\x9f\x99\x81",
-		       ':)' => "\xf0\x9f\x99\x82",
-		       ':?' => "\xf0\x9f\x98\x95",
-		       ':D' => "\xf0\x9f\x98\x80",
-		       ':P' => "\xf0\x9f\x98\x9b",
-		       ':o' => "\xf0\x9f\x98\xae",
-		       ':x' => "\xf0\x9f\x98\xa1",
-		       ':|' => "\xf0\x9f\x98\x90",
-		       ';)' => "\xf0\x9f\x98\x89",
-		      ':!:' => "\xe2\x9d\x97",
-		      ':?:' => "\xe2\x9d\x93",
+			':mrgreen:' => 'mrgreen.png',
+			':neutral:' => "\xf0\x9f\x98\x90",
+			':twisted:' => "\xf0\x9f\x98\x88",
+			':arrow:'   => "\xe2\x9e\xa1",
+			':shock:'   => "\xf0\x9f\x98\xaf",
+			':smile:'   => "\xf0\x9f\x99\x82",
+			':???:'     => "\xf0\x9f\x98\x95",
+			':cool:'    => "\xf0\x9f\x98\x8e",
+			':evil:'    => "\xf0\x9f\x91\xbf",
+			':grin:'    => "\xf0\x9f\x98\x80",
+			':idea:'    => "\xf0\x9f\x92\xa1",
+			':oops:'    => "\xf0\x9f\x98\xb3",
+			':razz:'    => "\xf0\x9f\x98\x9b",
+			':roll:'    => "\xf0\x9f\x99\x84",
+			':wink:'    => "\xf0\x9f\x98\x89",
+			':cry:'     => "\xf0\x9f\x98\xa5",
+			':eek:'     => "\xf0\x9f\x98\xae",
+			':lol:'     => "\xf0\x9f\x98\x86",
+			':mad:'     => "\xf0\x9f\x98\xa1",
+			':sad:'     => "\xf0\x9f\x99\x81",
+			'8-)'       => "\xf0\x9f\x98\x8e",
+			'8-O'       => "\xf0\x9f\x98\xaf",
+			':-('       => "\xf0\x9f\x99\x81",
+			':-)'       => "\xf0\x9f\x99\x82",
+			':-?'       => "\xf0\x9f\x98\x95",
+			':-D'       => "\xf0\x9f\x98\x80",
+			':-P'       => "\xf0\x9f\x98\x9b",
+			':-o'       => "\xf0\x9f\x98\xae",
+			':-x'       => "\xf0\x9f\x98\xa1",
+			':-|'       => "\xf0\x9f\x98\x90",
+			';-)'       => "\xf0\x9f\x98\x89",
+			// This one transformation breaks regular text with frequency.
+			//     '8)' => "\xf0\x9f\x98\x8e",
+			'8O'        => "\xf0\x9f\x98\xaf",
+			':('        => "\xf0\x9f\x99\x81",
+			':)'        => "\xf0\x9f\x99\x82",
+			':?'        => "\xf0\x9f\x98\x95",
+			':D'        => "\xf0\x9f\x98\x80",
+			':P'        => "\xf0\x9f\x98\x9b",
+			':o'        => "\xf0\x9f\x98\xae",
+			':x'        => "\xf0\x9f\x98\xa1",
+			':|'        => "\xf0\x9f\x98\x90",
+			';)'        => "\xf0\x9f\x98\x89",
+			':!:'       => "\xe2\x9d\x97",
+			':?:'       => "\xe2\x9d\x93",
 		);
 	}
 
@@ -3444,9 +4026,9 @@
 	 *
 	 * @param array $wpsmiliestrans List of the smilies.
 	 */
-	$wpsmiliestrans = apply_filters('smilies', $wpsmiliestrans);
-
-	if (count($wpsmiliestrans) == 0) {
+	$wpsmiliestrans = apply_filters( 'smilies', $wpsmiliestrans );
+
+	if ( count( $wpsmiliestrans ) == 0 ) {
 		return;
 	}
 
@@ -3455,7 +4037,7 @@
 	 * we match the longest possible smilie (:???: vs :?) as the regular
 	 * expression used below is first-match
 	 */
-	krsort($wpsmiliestrans);
+	krsort( $wpsmiliestrans );
 
 	$spaces = wp_spaces_regexp();
 
@@ -3464,21 +4046,21 @@
 
 	$subchar = '';
 	foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
-		$firstchar = substr($smiley, 0, 1);
-		$rest = substr($smiley, 1);
+		$firstchar = substr( $smiley, 0, 1 );
+		$rest      = substr( $smiley, 1 );
 
 		// new subpattern?
-		if ($firstchar != $subchar) {
-			if ($subchar != '') {
+		if ( $firstchar != $subchar ) {
+			if ( $subchar != '' ) {
 				$wp_smiliessearch .= ')(?=' . $spaces . '|$)';  // End previous "subpattern"
 				$wp_smiliessearch .= '|(?<=' . $spaces . '|^)'; // Begin another "subpattern"
 			}
-			$subchar = $firstchar;
-			$wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
+			$subchar           = $firstchar;
+			$wp_smiliessearch .= preg_quote( $firstchar, '/' ) . '(?:';
 		} else {
 			$wp_smiliessearch .= '|';
 		}
-		$wp_smiliessearch .= preg_quote($rest, '/');
+		$wp_smiliessearch .= preg_quote( $rest, '/' );
 	}
 
 	$wp_smiliessearch .= ')(?=' . $spaces . '|$)/m';
@@ -3499,19 +4081,37 @@
  * @return array Merged user defined values with defaults.
  */
 function wp_parse_args( $args, $defaults = '' ) {
-	if ( is_object( $args ) )
+	if ( is_object( $args ) ) {
 		$r = get_object_vars( $args );
-	elseif ( is_array( $args ) )
+	} elseif ( is_array( $args ) ) {
 		$r =& $args;
-	else
+	} else {
 		wp_parse_str( $args, $r );
-
-	if ( is_array( $defaults ) )
+	}
+
+	if ( is_array( $defaults ) ) {
 		return array_merge( $defaults, $r );
+	}
 	return $r;
 }
 
 /**
+ * Cleans up an array, comma- or space-separated list of scalar values.
+ *
+ * @since 5.1.0
+ *
+ * @param array|string $list List of values.
+ * @return array Sanitized array of values.
+ */
+function wp_parse_list( $list ) {
+	if ( ! is_array( $list ) ) {
+		return preg_split( '/[\s,]+/', $list, -1, PREG_SPLIT_NO_EMPTY );
+	}
+
+	return $list;
+}
+
+/**
  * Clean up an array, comma- or space-separated list of IDs.
  *
  * @since 3.0.0
@@ -3520,10 +4120,9 @@
  * @return array Sanitized array of IDs.
  */
 function wp_parse_id_list( $list ) {
-	if ( !is_array($list) )
-		$list = preg_split('/[\s,]+/', $list);
-
-	return array_unique(array_map('absint', $list));
+	$list = wp_parse_list( $list );
+
+	return array_unique( array_map( 'absint', $list ) );
 }
 
 /**
@@ -3535,15 +4134,9 @@
  * @return array Sanitized array of slugs.
  */
 function wp_parse_slug_list( $list ) {
-	if ( ! is_array( $list ) ) {
-		$list = preg_split( '/[\s,]+/', $list );
-	}
-
-	foreach ( $list as $key => $value ) {
-		$list[ $key ] = sanitize_title( $value );
-	}
-
-	return array_unique( $list );
+	$list = wp_parse_list( $list );
+
+	return array_unique( array_map( 'sanitize_title', $list ) );
 }
 
 /**
@@ -3557,9 +4150,11 @@
  */
 function wp_array_slice_assoc( $array, $keys ) {
 	$slice = array();
-	foreach ( $keys as $key )
-		if ( isset( $array[ $key ] ) )
+	foreach ( $keys as $key ) {
+		if ( isset( $array[ $key ] ) ) {
 			$slice[ $key ] = $array[ $key ];
+		}
+	}
 
 	return $slice;
 }
@@ -3577,7 +4172,7 @@
 		return false;
 	}
 
-	$keys = array_keys( $data );
+	$keys        = array_keys( $data );
 	$string_keys = array_filter( $keys, 'is_string' );
 	return count( $string_keys ) === 0;
 }
@@ -3586,7 +4181,7 @@
  * Filters a list of objects, based on a set of key => value arguments.
  *
  * @since 3.0.0
- * @since 4.7.0 Uses WP_List_Util class.
+ * @since 4.7.0 Uses `WP_List_Util` class.
  *
  * @param array       $list     An array of objects to filter
  * @param array       $args     Optional. An array of key => value arguments to match
@@ -3619,7 +4214,7 @@
  * Filters a list of objects, based on a set of key => value arguments.
  *
  * @since 3.1.0
- * @since 4.7.0 Uses WP_List_Util class.
+ * @since 4.7.0 Uses `WP_List_Util` class.
  *
  * @param array  $list     An array of objects to filter.
  * @param array  $args     Optional. An array of key => value arguments to match
@@ -3647,7 +4242,7 @@
  *
  * @since 3.1.0
  * @since 4.0.0 $index_key parameter added.
- * @since 4.7.0 Uses WP_List_Util class.
+ * @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
@@ -3667,7 +4262,7 @@
  *
  * @since 4.7.0
  *
- * @param array        $list          An array of objects to filter.
+ * @param array        $list          An array of objects to sort.
  * @param string|array $orderby       Optional. Either the field name to order by or an array
  *                                    of multiple orderby fields as $orderby => $order.
  * @param string       $order         Optional. Either 'ASC' or 'DESC'. Only used if $orderby
@@ -3723,8 +4318,9 @@
 function wp_widgets_add_menu() {
 	global $submenu;
 
-	if ( ! current_theme_supports( 'widgets' ) )
+	if ( ! current_theme_supports( 'widgets' ) ) {
 		return;
+	}
 
 	$submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' );
 	ksort( $submenu['themes.php'], SORT_NUMERIC );
@@ -3739,8 +4335,9 @@
  */
 function wp_ob_end_flush_all() {
 	$levels = ob_get_level();
-	for ($i=0; $i<$levels; $i++)
+	for ( $i = 0; $i < $levels; $i++ ) {
 		ob_end_flush();
+	}
 }
 
 /**
@@ -3773,27 +4370,12 @@
 	}
 
 	// If installing or in the admin, provide the verbose message.
-	if ( wp_installing() || defined( 'WP_ADMIN' ) )
-		wp_die($wpdb->error);
+	if ( wp_installing() || defined( 'WP_ADMIN' ) ) {
+		wp_die( $wpdb->error );
+	}
 
 	// Otherwise, be terse.
-	status_header( 500 );
-	nocache_headers();
-	header( 'Content-Type: text/html; charset=utf-8' );
-?>
-<!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-	<title><?php _e( 'Database Error' ); ?></title>
-
-</head>
-<body>
-	<h1><?php _e( 'Error establishing a database connection' ); ?></h1>
-</body>
-</html>
-<?php
-	die();
+	wp_die( '<h1>' . __( 'Error establishing a database connection' ) . '</h1>', __( 'Database Error' ) );
 }
 
 /**
@@ -3850,10 +4432,10 @@
 		if ( function_exists( '__' ) ) {
 			if ( ! is_null( $replacement ) ) {
 				/* translators: 1: PHP function name, 2: version number, 3: alternative function name */
-				trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) );
+				trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ), $function, $version, $replacement ) );
 			} else {
 				/* translators: 1: PHP function name, 2: version number */
-				trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
+				trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ), $function, $version ) );
 			}
 		} else {
 			if ( ! is_null( $replacement ) ) {
@@ -3912,20 +4494,46 @@
 		if ( function_exists( '__' ) ) {
 			if ( ! empty( $parent_class ) ) {
 				/* translators: 1: PHP class name, 2: PHP parent class name, 3: version number, 4: __construct() method */
-				trigger_error( sprintf( __( 'The called constructor method for %1$s in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.' ),
-					$class, $parent_class, $version, '<pre>__construct()</pre>' ) );
+				trigger_error(
+					sprintf(
+						__( 'The called constructor method for %1$s in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.' ),
+						$class,
+						$parent_class,
+						$version,
+						'<pre>__construct()</pre>'
+					)
+				);
 			} else {
 				/* translators: 1: PHP class name, 2: version number, 3: __construct() method */
-				trigger_error( sprintf( __( 'The called constructor method for %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
-					$class, $version, '<pre>__construct()</pre>' ) );
+				trigger_error(
+					sprintf(
+						__( 'The called constructor method for %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
+						$class,
+						$version,
+						'<pre>__construct()</pre>'
+					)
+				);
 			}
 		} else {
 			if ( ! empty( $parent_class ) ) {
-				trigger_error( sprintf( 'The called constructor method for %1$s in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.',
-					$class, $parent_class, $version, '<pre>__construct()</pre>' ) );
+				trigger_error(
+					sprintf(
+						'The called constructor method for %1$s in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.',
+						$class,
+						$parent_class,
+						$version,
+						'<pre>__construct()</pre>'
+					)
+				);
 			} else {
-				trigger_error( sprintf( 'The called constructor method for %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
-					$class, $version, '<pre>__construct()</pre>' ) );
+				trigger_error(
+					sprintf(
+						'The called constructor method for %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
+						$class,
+						$version,
+						'<pre>__construct()</pre>'
+					)
+				);
 			}
 		}
 	}
@@ -3978,10 +4586,10 @@
 		if ( function_exists( '__' ) ) {
 			if ( ! is_null( $replacement ) ) {
 				/* translators: 1: PHP file name, 2: version number, 3: alternative file name */
-				trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $file, $version, $replacement ) . $message );
+				trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ), $file, $version, $replacement ) . $message );
 			} else {
 				/* translators: 1: PHP file name, 2: version number */
-				trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $file, $version ) . $message );
+				trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ), $file, $version ) . $message );
 			}
 		} else {
 			if ( ! is_null( $replacement ) ) {
@@ -4004,7 +4612,6 @@
  *         _deprecated_argument( __FUNCTION__, '3.0.0' );
  *     }
  *
- *
  * There is a hook deprecated_argument_run that will be called that can be used
  * to get the backtrace up to what file and function used the deprecated
  * argument.
@@ -4042,10 +4649,10 @@
 		if ( function_exists( '__' ) ) {
 			if ( ! is_null( $message ) ) {
 				/* translators: 1: PHP function name, 2: version number, 3: optional message regarding the change */
-				trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s'), $function, $version, $message ) );
+				trigger_error( sprintf( __( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s' ), $function, $version, $message ) );
 			} else {
 				/* translators: 1: PHP function name, 2: version number */
-				trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
+				trigger_error( sprintf( __( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.' ), $function, $version ) );
 			}
 		} else {
 			if ( ! is_null( $message ) ) {
@@ -4142,10 +4749,14 @@
 	 * Filters whether to trigger an error for _doing_it_wrong() calls.
 	 *
 	 * @since 3.1.0
+	 * @since 5.1.0 Added the $function, $message and $version parameters.
 	 *
-	 * @param bool $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true.
+	 * @param bool   $trigger  Whether to trigger the error for _doing_it_wrong() calls. Default true.
+	 * @param string $function The function that was called.
+	 * @param string $message  A message explaining what has been done incorrectly.
+	 * @param string $version  The version of WordPress where the message was added.
 	 */
-	if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
+	if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true, $function, $message, $version ) ) {
 		if ( function_exists( '__' ) ) {
 			if ( is_null( $version ) ) {
 				$version = '';
@@ -4154,7 +4765,8 @@
 				$version = sprintf( __( '(This message was added in version %s.)' ), $version );
 			}
 			/* translators: %s: Codex URL */
-			$message .= ' ' . sprintf( __( 'Please see <a href="%s">Debugging in WordPress</a> for more information.' ),
+			$message .= ' ' . sprintf(
+				__( 'Please see <a href="%s">Debugging in WordPress</a> for more information.' ),
 				__( 'https://codex.wordpress.org/Debugging_in_WordPress' )
 			);
 			/* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message, 3: Version information message */
@@ -4165,7 +4777,8 @@
 			} else {
 				$version = sprintf( '(This message was added in version %s.)', $version );
 			}
-			$message .= sprintf( ' Please see <a href="%s">Debugging in WordPress</a> for more information.',
+			$message .= sprintf(
+				' Please see <a href="%s">Debugging in WordPress</a> for more information.',
 				'https://codex.wordpress.org/Debugging_in_WordPress'
 			);
 			trigger_error( sprintf( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s', $function, $message, $version ) );
@@ -4181,8 +4794,8 @@
  * @return bool Whether the server is running lighttpd < 1.5.0.
  */
 function is_lighttpd_before_150() {
-	$server_parts = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] )? $_SERVER['SERVER_SOFTWARE'] : '' );
-	$server_parts[1] = isset( $server_parts[1] )? $server_parts[1] : '';
+	$server_parts    = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '' );
+	$server_parts[1] = isset( $server_parts[1] ) ? $server_parts[1] : '';
 	return  'lighttpd' == $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' );
 }
 
@@ -4197,22 +4810,25 @@
  * @param bool   $default Optional. The default return value if the module is not found. Default false.
  * @return bool Whether the specified module is loaded.
  */
-function apache_mod_loaded($mod, $default = false) {
+function apache_mod_loaded( $mod, $default = false ) {
 	global $is_apache;
 
-	if ( !$is_apache )
+	if ( ! $is_apache ) {
 		return false;
+	}
 
 	if ( function_exists( 'apache_get_modules' ) ) {
 		$mods = apache_get_modules();
-		if ( in_array($mod, $mods) )
+		if ( in_array( $mod, $mods ) ) {
 			return true;
+		}
 	} elseif ( function_exists( 'phpinfo' ) && false === strpos( ini_get( 'disable_functions' ), 'phpinfo' ) ) {
 			ob_start();
-			phpinfo(8);
+			phpinfo( 8 );
 			$phpinfo = ob_get_clean();
-			if ( false !== strpos($phpinfo, $mod) )
-				return true;
+		if ( false !== strpos( $phpinfo, $mod ) ) {
+			return true;
+		}
 	}
 	return $default;
 }
@@ -4240,7 +4856,7 @@
 		 * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
 		 * via ISAPI then pretty permalinks will not work.
 		 */
-		$supports_permalinks = class_exists( 'DOMDocument', false ) && isset($_SERVER['IIS_UrlRewriteModule']) && ( PHP_SAPI == 'cgi-fcgi' );
+		$supports_permalinks = class_exists( 'DOMDocument', false ) && isset( $_SERVER['IIS_UrlRewriteModule'] ) && ( PHP_SAPI == 'cgi-fcgi' );
 	}
 
 	/**
@@ -4285,12 +4901,14 @@
 	}
 
 	// Files not in the allowed file list are not allowed:
-	if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) )
+	if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) ) {
 		return 3;
+	}
 
 	// Absolute Windows drive paths are not allowed:
-	if (':' == substr( $file, 1, 1 ) )
+	if ( ':' == substr( $file, 1, 1 ) ) {
 		return 2;
+	}
 
 	return 0;
 }
@@ -4308,9 +4926,9 @@
 function force_ssl_admin( $force = null ) {
 	static $forced = false;
 
-	if ( !is_null( $force ) ) {
+	if ( ! is_null( $force ) ) {
 		$old_forced = $forced;
-		$forced = $force;
+		$forced     = $force;
 		return $old_forced;
 	}
 
@@ -4328,17 +4946,17 @@
  * @return string The guessed URL.
  */
 function wp_guess_url() {
-	if ( defined('WP_SITEURL') && '' != WP_SITEURL ) {
+	if ( defined( 'WP_SITEURL' ) && '' != WP_SITEURL ) {
 		$url = WP_SITEURL;
 	} else {
-		$abspath_fix = str_replace( '\\', '/', ABSPATH );
+		$abspath_fix         = str_replace( '\\', '/', ABSPATH );
 		$script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
 
 		// The request is for the admin
 		if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) {
 			$path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] );
 
-		// The request is for a file in ABSPATH
+			// The request is for a file in ABSPATH
 		} elseif ( $script_filename_dir . '/' == $abspath_fix ) {
 			// Strip off any file/query params in the path
 			$path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
@@ -4348,22 +4966,22 @@
 				// Request is hitting a file inside ABSPATH
 				$directory = str_replace( ABSPATH, '', $script_filename_dir );
 				// Strip off the sub directory, and any file/query params
-				$path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] );
+				$path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '', $_SERVER['REQUEST_URI'] );
 			} elseif ( false !== strpos( $abspath_fix, $script_filename_dir ) ) {
 				// Request is hitting a file above ABSPATH
 				$subdirectory = substr( $abspath_fix, strpos( $abspath_fix, $script_filename_dir ) + strlen( $script_filename_dir ) );
 				// Strip off any file/query params from the path, appending the sub directory to the installation
-				$path = preg_replace( '#/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] ) . $subdirectory;
+				$path = preg_replace( '#/[^/]*$#i', '', $_SERVER['REQUEST_URI'] ) . $subdirectory;
 			} else {
 				$path = $_SERVER['REQUEST_URI'];
 			}
 		}
 
 		$schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
-		$url = $schema . $_SERVER['HTTP_HOST'] . $path;
-	}
-
-	return rtrim($url, '/');
+		$url    = $schema . $_SERVER['HTTP_HOST'] . $path;
+	}
+
+	return rtrim( $url, '/' );
 }
 
 /**
@@ -4386,8 +5004,9 @@
 function wp_suspend_cache_addition( $suspend = null ) {
 	static $_suspend = false;
 
-	if ( is_bool( $suspend ) )
+	if ( is_bool( $suspend ) ) {
 		$_suspend = $suspend;
+	}
 
 	return $_suspend;
 }
@@ -4409,7 +5028,7 @@
 function wp_suspend_cache_invalidation( $suspend = true ) {
 	global $_wp_suspend_cache_invalidation;
 
-	$current_suspend = $_wp_suspend_cache_invalidation;
+	$current_suspend                = $_wp_suspend_cache_invalidation;
 	$_wp_suspend_cache_invalidation = $suspend;
 	return $current_suspend;
 }
@@ -4418,7 +5037,7 @@
  * Determine whether a site is the main site of the current network.
  *
  * @since 3.0.0
- * @since 4.9.0 The $network_id parameter has been added.
+ * @since 4.9.0 The `$network_id` parameter was added.
  *
  * @param int $site_id    Optional. Site ID to test. Defaults to current site.
  * @param int $network_id Optional. Network ID of the network to check for.
@@ -4504,7 +5123,12 @@
 		// If the current network has an ID of 1, assume it is the main network.
 		$main_network_id = 1;
 	} else {
-		$_networks = get_networks( array( 'fields' => 'ids', 'number' => 1 ) );
+		$_networks       = get_networks(
+			array(
+				'fields' => 'ids',
+				'number' => 1,
+			)
+		);
 		$main_network_id = array_shift( $_networks );
 	}
 
@@ -4528,8 +5152,9 @@
  * @return bool True if multisite and global terms enabled.
  */
 function global_terms_enabled() {
-	if ( ! is_multisite() )
+	if ( ! is_multisite() ) {
 		return false;
+	}
 
 	static $global_terms = null;
 	if ( is_null( $global_terms ) ) {
@@ -4545,15 +5170,48 @@
 		 * @param null $enabled Whether global terms are enabled.
 		 */
 		$filter = apply_filters( 'global_terms_enabled', null );
-		if ( ! is_null( $filter ) )
+		if ( ! is_null( $filter ) ) {
 			$global_terms = (bool) $filter;
-		else
+		} else {
 			$global_terms = (bool) get_site_option( 'global_terms_enabled', false );
+		}
 	}
 	return $global_terms;
 }
 
 /**
+ * Determines whether site meta is enabled.
+ *
+ * This function checks whether the 'blogmeta' database table exists. The result is saved as
+ * a setting for the main network, making it essentially a global setting. Subsequent requests
+ * will refer to this setting instead of running the query.
+ *
+ * @since 5.1.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @return bool True if site meta is supported, false otherwise.
+ */
+function is_site_meta_supported() {
+	global $wpdb;
+
+	if ( ! is_multisite() ) {
+		return false;
+	}
+
+	$network_id = get_main_network_id();
+
+	$supported = get_network_option( $network_id, 'site_meta_supported', false );
+	if ( false === $supported ) {
+		$supported = $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->blogmeta}'" ) ? 1 : 0;
+
+		update_network_option( $network_id, 'site_meta_supported', $supported );
+	}
+
+	return (bool) $supported;
+}
+
+/**
  * gmt_offset modification for smart timezone handling.
  *
  * Overrides the gmt_offset option if we have a timezone_string available.
@@ -4563,7 +5221,7 @@
  * @return float|false Timezone GMT offset, false otherwise.
  */
 function wp_timezone_override_offset() {
-	if ( !$timezone_string = get_option( 'timezone_string' ) ) {
+	if ( ! $timezone_string = get_option( 'timezone_string' ) ) {
 		return false;
 	}
 
@@ -4639,12 +5297,12 @@
 function wp_timezone_choice( $selected_zone, $locale = null ) {
 	static $mo_loaded = false, $locale_loaded = null;
 
-	$continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');
+	$continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific' );
 
 	// Load translations for continents and cities.
 	if ( ! $mo_loaded || $locale !== $locale_loaded ) {
 		$locale_loaded = $locale ? $locale : get_locale();
-		$mofile = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
+		$mofile        = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
 		unload_textdomain( 'continents-cities' );
 		load_textdomain( 'continents-cities', $mofile );
 		$mo_loaded = true;
@@ -4653,12 +5311,12 @@
 	$zonen = array();
 	foreach ( timezone_identifiers_list() as $zone ) {
 		$zone = explode( '/', $zone );
-		if ( !in_array( $zone[0], $continents ) ) {
+		if ( ! in_array( $zone[0], $continents ) ) {
 			continue;
 		}
 
 		// This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
-		$exists = array(
+		$exists    = array(
 			0 => ( isset( $zone[0] ) && $zone[0] ),
 			1 => ( isset( $zone[1] ) && $zone[1] ),
 			2 => ( isset( $zone[2] ) && $zone[2] ),
@@ -4667,14 +5325,16 @@
 		$exists[4] = ( $exists[1] && $exists[3] );
 		$exists[5] = ( $exists[2] && $exists[3] );
 
+		// phpcs:disable WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText
 		$zonen[] = array(
 			'continent'   => ( $exists[0] ? $zone[0] : '' ),
 			'city'        => ( $exists[1] ? $zone[1] : '' ),
 			'subcity'     => ( $exists[2] ? $zone[2] : '' ),
 			't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
 			't_city'      => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
-			't_subcity'   => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' )
+			't_subcity'   => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' ),
 		);
+		// phpcs:enable
 	}
 	usort( $zonen, '_wp_timezone_choice_usort_callback' );
 
@@ -4695,62 +5355,120 @@
 			// It's inside a continent group
 
 			// Continent optgroup
-			if ( !isset( $zonen[$key - 1] ) || $zonen[$key - 1]['continent'] !== $zone['continent'] ) {
-				$label = $zone['t_continent'];
-				$structure[] = '<optgroup label="'. esc_attr( $label ) .'">';
+			if ( ! isset( $zonen[ $key - 1 ] ) || $zonen[ $key - 1 ]['continent'] !== $zone['continent'] ) {
+				$label       = $zone['t_continent'];
+				$structure[] = '<optgroup label="' . esc_attr( $label ) . '">';
 			}
 
 			// Add the city to the value
 			$value[] = $zone['city'];
 
 			$display = $zone['t_city'];
-			if ( !empty( $zone['subcity'] ) ) {
+			if ( ! empty( $zone['subcity'] ) ) {
 				// Add the subcity to the value
-				$value[] = $zone['subcity'];
+				$value[]  = $zone['subcity'];
 				$display .= ' - ' . $zone['t_subcity'];
 			}
 		}
 
 		// Build the value
-		$value = join( '/', $value );
+		$value    = join( '/', $value );
 		$selected = '';
 		if ( $value === $selected_zone ) {
 			$selected = 'selected="selected" ';
 		}
-		$structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . "</option>";
+		$structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . '</option>';
 
 		// Close continent optgroup
-		if ( !empty( $zone['city'] ) && ( !isset($zonen[$key + 1]) || (isset( $zonen[$key + 1] ) && $zonen[$key + 1]['continent'] !== $zone['continent']) ) ) {
+		if ( ! empty( $zone['city'] ) && ( ! isset( $zonen[ $key + 1 ] ) || ( isset( $zonen[ $key + 1 ] ) && $zonen[ $key + 1 ]['continent'] !== $zone['continent'] ) ) ) {
 			$structure[] = '</optgroup>';
 		}
 	}
 
 	// Do UTC
-	$structure[] = '<optgroup label="'. esc_attr__( 'UTC' ) .'">';
-	$selected = '';
-	if ( 'UTC' === $selected_zone )
+	$structure[] = '<optgroup label="' . esc_attr__( 'UTC' ) . '">';
+	$selected    = '';
+	if ( 'UTC' === $selected_zone ) {
 		$selected = 'selected="selected" ';
-	$structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __('UTC') . '</option>';
+	}
+	$structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __( 'UTC' ) . '</option>';
 	$structure[] = '</optgroup>';
 
 	// Do manual UTC offsets
-	$structure[] = '<optgroup label="'. esc_attr__( 'Manual Offsets' ) .'">';
-	$offset_range = array (-12, -11.5, -11, -10.5, -10, -9.5, -9, -8.5, -8, -7.5, -7, -6.5, -6, -5.5, -5, -4.5, -4, -3.5, -3, -2.5, -2, -1.5, -1, -0.5,
-		0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 5.75, 6, 6.5, 7, 7.5, 8, 8.5, 8.75, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 13.75, 14);
+	$structure[]  = '<optgroup label="' . esc_attr__( 'Manual Offsets' ) . '">';
+	$offset_range = array(
+		-12,
+		-11.5,
+		-11,
+		-10.5,
+		-10,
+		-9.5,
+		-9,
+		-8.5,
+		-8,
+		-7.5,
+		-7,
+		-6.5,
+		-6,
+		-5.5,
+		-5,
+		-4.5,
+		-4,
+		-3.5,
+		-3,
+		-2.5,
+		-2,
+		-1.5,
+		-1,
+		-0.5,
+		0,
+		0.5,
+		1,
+		1.5,
+		2,
+		2.5,
+		3,
+		3.5,
+		4,
+		4.5,
+		5,
+		5.5,
+		5.75,
+		6,
+		6.5,
+		7,
+		7.5,
+		8,
+		8.5,
+		8.75,
+		9,
+		9.5,
+		10,
+		10.5,
+		11,
+		11.5,
+		12,
+		12.75,
+		13,
+		13.75,
+		14,
+	);
 	foreach ( $offset_range as $offset ) {
-		if ( 0 <= $offset )
+		if ( 0 <= $offset ) {
 			$offset_name = '+' . $offset;
-		else
+		} else {
 			$offset_name = (string) $offset;
+		}
 
 		$offset_value = $offset_name;
-		$offset_name = str_replace(array('.25','.5','.75'), array(':15',':30',':45'), $offset_name);
-		$offset_name = 'UTC' . $offset_name;
+		$offset_name  = str_replace( array( '.25', '.5', '.75' ), array( ':15', ':30', ':45' ), $offset_name );
+		$offset_name  = 'UTC' . $offset_name;
 		$offset_value = 'UTC' . $offset_value;
-		$selected = '';
-		if ( $offset_value === $selected_zone )
+		$selected     = '';
+		if ( $offset_value === $selected_zone ) {
 			$selected = 'selected="selected" ';
-		$structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . "</option>";
+		}
+		$structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . '</option>';
 
 	}
 	$structure[] = '</optgroup>';
@@ -4770,7 +5488,7 @@
  * @return string
  */
 function _cleanup_header_comment( $str ) {
-	return trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $str));
+	return trim( preg_replace( '/\s*(?:\*\/|\?>).*/', '', $str ) );
 }
 
 /**
@@ -4788,35 +5506,37 @@
 
 	$delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
 
-	$posts_to_delete = $wpdb->get_results($wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < %d", $delete_timestamp), ARRAY_A);
+	$posts_to_delete = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < %d", $delete_timestamp ), ARRAY_A );
 
 	foreach ( (array) $posts_to_delete as $post ) {
 		$post_id = (int) $post['post_id'];
-		if ( !$post_id )
+		if ( ! $post_id ) {
 			continue;
-
-		$del_post = get_post($post_id);
-
-		if ( !$del_post || 'trash' != $del_post->post_status ) {
-			delete_post_meta($post_id, '_wp_trash_meta_status');
-			delete_post_meta($post_id, '_wp_trash_meta_time');
+		}
+
+		$del_post = get_post( $post_id );
+
+		if ( ! $del_post || 'trash' != $del_post->post_status ) {
+			delete_post_meta( $post_id, '_wp_trash_meta_status' );
+			delete_post_meta( $post_id, '_wp_trash_meta_time' );
 		} else {
-			wp_delete_post($post_id);
+			wp_delete_post( $post_id );
 		}
 	}
 
-	$comments_to_delete = $wpdb->get_results($wpdb->prepare("SELECT comment_id FROM $wpdb->commentmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < %d", $delete_timestamp), ARRAY_A);
+	$comments_to_delete = $wpdb->get_results( $wpdb->prepare( "SELECT comment_id FROM $wpdb->commentmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < %d", $delete_timestamp ), ARRAY_A );
 
 	foreach ( (array) $comments_to_delete as $comment ) {
 		$comment_id = (int) $comment['comment_id'];
-		if ( !$comment_id )
+		if ( ! $comment_id ) {
 			continue;
-
-		$del_comment = get_comment($comment_id);
-
-		if ( !$del_comment || 'trash' != $del_comment->comment_approved ) {
-			delete_comment_meta($comment_id, '_wp_trash_meta_time');
-			delete_comment_meta($comment_id, '_wp_trash_meta_status');
+		}
+
+		$del_comment = get_comment( $comment_id );
+
+		if ( ! $del_comment || 'trash' != $del_comment->comment_approved ) {
+			delete_comment_meta( $comment_id, '_wp_trash_meta_time' );
+			delete_comment_meta( $comment_id, '_wp_trash_meta_status' );
 		} else {
 			wp_delete_comment( $del_comment );
 		}
@@ -4837,8 +5557,8 @@
  *
  * @since 2.9.0
  *
- * @param string $file            Path to the file.
- * @param array  $default_headers List of headers, in the format array('HeaderKey' => 'Header Name').
+ * @param string $file            Absolute path to the file.
+ * @param array  $default_headers List of headers, in the format `array('HeaderKey' => 'Header Name')`.
  * @param string $context         Optional. If specified adds filter hook {@see 'extra_$context_headers'}.
  *                                Default empty.
  * @return array Array of file headers in `HeaderKey => Header Value` format.
@@ -4868,16 +5588,17 @@
 	 */
 	if ( $context && $extra_headers = apply_filters( "extra_{$context}_headers", array() ) ) {
 		$extra_headers = array_combine( $extra_headers, $extra_headers ); // keys equal values
-		$all_headers = array_merge( $extra_headers, (array) $default_headers );
+		$all_headers   = array_merge( $extra_headers, (array) $default_headers );
 	} else {
 		$all_headers = $default_headers;
 	}
 
 	foreach ( $all_headers as $field => $regex ) {
-		if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] )
+		if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] ) {
 			$all_headers[ $field ] = _cleanup_header_comment( $match[1] );
-		else
+		} else {
 			$all_headers[ $field ] = '';
+		}
 	}
 
 	return $all_headers;
@@ -4990,17 +5711,17 @@
  */
 function _wp_mysql_week( $column ) {
 	switch ( $start_of_week = (int) get_option( 'start_of_week' ) ) {
-	case 1 :
-		return "WEEK( $column, 1 )";
-	case 2 :
-	case 3 :
-	case 4 :
-	case 5 :
-	case 6 :
-		return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
-	case 0 :
-	default :
-		return "WEEK( $column, 0 )";
+		case 1:
+			return "WEEK( $column, 1 )";
+		case 2:
+		case 3:
+		case 4:
+		case 5:
+		case 6:
+			return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
+		case 0:
+		default:
+			return "WEEK( $column, 0 )";
 	}
 }
 
@@ -5020,8 +5741,9 @@
 function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
 	$override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
 
-	if ( !$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args ) )
+	if ( ! $arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args ) ) {
 		return array();
+	}
 
 	return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
 }
@@ -5048,26 +5770,28 @@
  */
 function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
 	$tortoise = $hare = $evanescent_hare = $start;
-	$return = array();
+	$return   = array();
 
 	// Set evanescent_hare to one past hare
 	// Increment hare two steps
 	while (
 		$tortoise
 	&&
-		( $evanescent_hare = isset( $override[$hare] ) ? $override[$hare] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
+		( $evanescent_hare = isset( $override[ $hare ] ) ? $override[ $hare ] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
 	&&
-		( $hare = isset( $override[$evanescent_hare] ) ? $override[$evanescent_hare] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
+		( $hare = isset( $override[ $evanescent_hare ] ) ? $override[ $evanescent_hare ] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
 	) {
-		if ( $_return_loop )
-			$return[$tortoise] = $return[$evanescent_hare] = $return[$hare] = true;
+		if ( $_return_loop ) {
+			$return[ $tortoise ] = $return[ $evanescent_hare ] = $return[ $hare ] = true;
+		}
 
 		// tortoise got lapped - must be a loop
-		if ( $tortoise == $evanescent_hare || $tortoise == $hare )
+		if ( $tortoise == $evanescent_hare || $tortoise == $hare ) {
 			return $_return_loop ? $return : $tortoise;
+		}
 
 		// Increment tortoise by one step
-		$tortoise = isset( $override[$tortoise] ) ? $override[$tortoise] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
+		$tortoise = isset( $override[ $tortoise ] ) ? $override[ $tortoise ] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
 	}
 
 	return false;
@@ -5096,9 +5820,11 @@
  *
  * @staticvar array $protocols
  *
- * @return array Array of allowed protocols. Defaults to an array containing 'http', 'https',
- *               'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet',
- *               'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'.
+ * @return string[] Array of allowed protocols. Defaults to an array containing 'http', 'https',
+ *                  'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet',
+ *                  'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'. This covers
+ *                  all common link protocols, except for 'javascript' which should not be
+ *                  allowed for untrusted users.
  */
 function wp_allowed_protocols() {
 	static $protocols = array();
@@ -5129,6 +5855,8 @@
  *
  * @see https://core.trac.wordpress.org/ticket/19589
  *
+ * @staticvar array $truncate_paths Array of paths to truncate.
+ *
  * @param string $ignore_class Optional. A class to ignore all function calls within - useful
  *                             when you want to just give info about the callee. Default null.
  * @param int    $skip_frames  Optional. A number of stack frames to skip - useful for unwinding
@@ -5139,55 +5867,67 @@
  *                      of individual calls.
  */
 function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
-	if ( version_compare( PHP_VERSION, '5.2.5', '>=' ) )
+	static $truncate_paths;
+
+	if ( version_compare( PHP_VERSION, '5.2.5', '>=' ) ) {
 		$trace = debug_backtrace( false );
-	else
+	} else {
 		$trace = debug_backtrace();
-
-	$caller = array();
+	}
+
+	$caller      = array();
 	$check_class = ! is_null( $ignore_class );
 	$skip_frames++; // skip this function
 
+	if ( ! isset( $truncate_paths ) ) {
+		$truncate_paths = array(
+			wp_normalize_path( WP_CONTENT_DIR ),
+			wp_normalize_path( ABSPATH ),
+		);
+	}
+
 	foreach ( $trace as $call ) {
 		if ( $skip_frames > 0 ) {
 			$skip_frames--;
 		} elseif ( isset( $call['class'] ) ) {
-			if ( $check_class && $ignore_class == $call['class'] )
+			if ( $check_class && $ignore_class == $call['class'] ) {
 				continue; // Filter out calls
+			}
 
 			$caller[] = "{$call['class']}{$call['type']}{$call['function']}";
 		} else {
-			if ( in_array( $call['function'], array( 'do_action', 'apply_filters' ) ) ) {
+			if ( in_array( $call['function'], array( 'do_action', 'apply_filters', 'do_action_ref_array', 'apply_filters_ref_array' ) ) ) {
 				$caller[] = "{$call['function']}('{$call['args'][0]}')";
 			} elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ) ) ) {
-				$caller[] = $call['function'] . "('" . str_replace( array( WP_CONTENT_DIR, ABSPATH ) , '', $call['args'][0] ) . "')";
+				$filename = isset( $call['args'][0] ) ? $call['args'][0] : '';
+				$caller[] = $call['function'] . "('" . str_replace( $truncate_paths, '', wp_normalize_path( $filename ) ) . "')";
 			} else {
 				$caller[] = $call['function'];
 			}
 		}
 	}
-	if ( $pretty )
+	if ( $pretty ) {
 		return join( ', ', array_reverse( $caller ) );
-	else
+	} else {
 		return $caller;
-}
-
-/**
- * Retrieve ids that are not already present in the cache.
+	}
+}
+
+/**
+ * Retrieve IDs that are not already present in the cache.
  *
  * @since 3.4.0
  * @access private
  *
- * @param array  $object_ids ID list.
+ * @param int[]  $object_ids Array of IDs.
  * @param string $cache_key  The cache bucket to check against.
- *
- * @return array List of ids not present in the cache.
+ * @return int[] Array of IDs not present in the cache.
  */
 function _get_non_cached_ids( $object_ids, $cache_key ) {
 	$clean = array();
 	foreach ( $object_ids as $id ) {
 		$id = (int) $id;
-		if ( !wp_cache_get( $id, $cache_key ) ) {
+		if ( ! wp_cache_get( $id, $cache_key ) ) {
 			$clean[] = $id;
 		}
 	}
@@ -5204,14 +5944,15 @@
  * @return bool Whether the device is able to upload files.
  */
 function _device_can_upload() {
-	if ( ! wp_is_mobile() )
+	if ( ! wp_is_mobile() ) {
 		return true;
+	}
 
 	$ua = $_SERVER['HTTP_USER_AGENT'];
 
-	if ( strpos($ua, 'iPhone') !== false
-		|| strpos($ua, 'iPad') !== false
-		|| strpos($ua, 'iPod') !== false ) {
+	if ( strpos( $ua, 'iPhone' ) !== false
+		|| strpos( $ua, 'iPad' ) !== false
+		|| strpos( $ua, 'iPod' ) !== false ) {
 			return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
 	}
 
@@ -5227,16 +5968,16 @@
  * @return bool True if the path is a stream URL.
  */
 function wp_is_stream( $path ) {
-	if ( false === strpos( $path, '://' ) ) {
+	$scheme_separator = strpos( $path, '://' );
+
+	if ( false === $scheme_separator ) {
 		// $path isn't a stream
 		return false;
 	}
 
-	$wrappers    = stream_get_wrappers();
-	$wrappers    = array_map( 'preg_quote', $wrappers );
-	$wrappers_re = '(' . join( '|', $wrappers ) . ')';
-
-	return preg_match( "!^$wrappers_re://!", $path ) === 1;
+	$stream = substr( $path, 0, $scheme_separator );
+
+	return in_array( $stream, stream_get_wrappers(), true );
 }
 
 /**
@@ -5244,7 +5985,7 @@
  *
  * @since 3.5.0
  *
- * @see checkdate()
+ * @link https://secure.php.net/manual/en/function.checkdate.php
  *
  * @param  int    $month       Month number.
  * @param  int    $day         Day number.
@@ -5276,15 +6017,17 @@
  * @since 3.6.0
  */
 function wp_auth_check_load() {
-	if ( ! is_admin() && ! is_user_logged_in() )
+	if ( ! is_admin() && ! is_user_logged_in() ) {
 		return;
-
-	if ( defined( 'IFRAME_REQUEST' ) )
+	}
+
+	if ( defined( 'IFRAME_REQUEST' ) ) {
 		return;
+	}
 
 	$screen = get_current_screen();
 	$hidden = array( 'update', 'update-network', 'update-core', 'update-core-network', 'upgrade', 'upgrade-network', 'network' );
-	$show = ! in_array( $screen->id, $hidden );
+	$show   = ! in_array( $screen->id, $hidden );
 
 	/**
 	 * Filters whether to load the authentication check.
@@ -5312,9 +6055,9 @@
  * @since 3.6.0
  */
 function wp_auth_check_html() {
-	$login_url = wp_login_url();
+	$login_url      = wp_login_url();
 	$current_domain = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
-	$same_domain = ( strpos( $login_url, $current_domain ) === 0 );
+	$same_domain    = ( strpos( $login_url, $current_domain ) === 0 );
 
 	/**
 	 * Filters whether the authentication check originated at the same domain.
@@ -5324,7 +6067,7 @@
 	 * @param bool $same_domain Whether the authentication check originated at the same domain.
 	 */
 	$same_domain = apply_filters( 'wp_auth_check_same_domain', $same_domain );
-	$wrap_class = $same_domain ? 'hidden' : 'hidden fallback';
+	$wrap_class  = $same_domain ? 'hidden' : 'hidden fallback';
 
 	?>
 	<div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
@@ -5334,10 +6077,13 @@
 	<?php
 
 	if ( $same_domain ) {
-		$login_src = add_query_arg( array(
-			'interim-login' => '1',
-			'wp_lang'       => get_user_locale(),
-		), $login_url );
+		$login_src = add_query_arg(
+			array(
+				'interim-login' => '1',
+				'wp_lang'       => get_user_locale(),
+			),
+			$login_url
+		);
 		?>
 		<div id="wp-auth-check-form" class="loading" data-src="<?php echo esc_url( $login_src ); ?>"></div>
 		<?php
@@ -5345,9 +6091,9 @@
 
 	?>
 	<div class="wp-auth-fallback">
-		<p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e('Session expired'); ?></b></p>
-		<p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e('Please log in again.'); ?></a>
-		<?php _e('The login page will open in a new window. After logging in you can close it and return to this page.'); ?></p>
+		<p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e( 'Session expired' ); ?></b></p>
+		<p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e( 'Please log in again.' ); ?></a>
+		<?php _e( 'The login page will open in a new tab. After logging in you can close it and return to this page.' ); ?></p>
 	</div>
 	</div>
 	</div>
@@ -5389,8 +6135,9 @@
  * @return string Tag RegEx.
  */
 function get_tag_regex( $tag ) {
-	if ( empty( $tag ) )
+	if ( empty( $tag ) ) {
 		return;
+	}
 	return sprintf( '<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)', tag_escape( $tag ) );
 }
 
@@ -5407,7 +6154,7 @@
  * @return string The canonical form of the charset.
  */
 function _canonical_charset( $charset ) {
-	if ( 'utf-8' === strtolower( $charset ) || 'utf8' === strtolower( $charset) ) {
+	if ( 'utf-8' === strtolower( $charset ) || 'utf8' === strtolower( $charset ) ) {
 
 		return 'UTF-8';
 	}
@@ -5447,14 +6194,16 @@
  *                    Default false.
  */
 function mbstring_binary_safe_encoding( $reset = false ) {
-	static $encodings = array();
+	static $encodings  = array();
 	static $overloaded = null;
 
-	if ( is_null( $overloaded ) )
+	if ( is_null( $overloaded ) ) {
 		$overloaded = function_exists( 'mb_internal_encoding' ) && ( ini_get( 'mbstring.func_overload' ) & 2 );
-
-	if ( false === $overloaded )
+	}
+
+	if ( false === $overloaded ) {
 		return;
+	}
 
 	if ( ! $reset ) {
 		$encoding = mb_internal_encoding();
@@ -5532,10 +6281,23 @@
  * @return bool True on success, false on failure.
  */
 function wp_delete_file_from_directory( $file, $directory ) {
-	$real_file = realpath( wp_normalize_path( $file ) );
-	$real_directory = realpath( wp_normalize_path( $directory ) );
-
-	if ( false === $real_file || false === $real_directory || strpos( wp_normalize_path( $real_file ), trailingslashit( wp_normalize_path( $real_directory ) ) ) !== 0 ) {
+	if ( wp_is_stream( $file ) ) {
+		$real_file      = $file;
+		$real_directory = $directory;
+	} else {
+		$real_file      = realpath( wp_normalize_path( $file ) );
+		$real_directory = realpath( wp_normalize_path( $directory ) );
+	}
+
+	if ( false !== $real_file ) {
+		$real_file = wp_normalize_path( $real_file );
+	}
+
+	if ( false !== $real_directory ) {
+		$real_directory = wp_normalize_path( $real_directory );
+	}
+
+	if ( false === $real_file || false === $real_directory || strpos( $real_file, trailingslashit( $real_directory ) ) !== 0 ) {
 		return false;
 	}
 
@@ -5581,21 +6343,21 @@
 }
 
 /**
- * Parses and formats a MySQL datetime (Y-m-d H:i:s) for ISO8601/RFC3339.
+ * Parses and formats a MySQL datetime (Y-m-d H:i:s) for ISO8601 (Y-m-d\TH:i:s).
  *
  * Explicitly strips timezones, as datetimes are not saved with any timezone
  * information. Including any information on the offset could be misleading.
  *
+ * Despite historical function name, the output does not conform to RFC3339 format,
+ * which must contain timezone.
+ *
  * @since 4.4.0
  *
  * @param string $date_string Date string to parse and format.
- * @return string Date formatted for ISO8601/RFC3339.
+ * @return string Date formatted for ISO8601 without time zone.
  */
 function mysql_to_rfc3339( $date_string ) {
-	$formatted = mysql2date( 'c', $date_string, false );
-
-	// Strip timezone information
-	return preg_replace( '/(?:Z|[+-]\d{2}(?::\d{2})?)$/', '', $formatted );
+	return mysql2date( 'Y-m-d\TH:i:s', $date_string, false );
 }
 
 /**
@@ -5713,12 +6475,16 @@
  * @return string UUID.
  */
 function wp_generate_uuid4() {
-	return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
-		mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
+	return sprintf(
+		'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
+		mt_rand( 0, 0xffff ),
+		mt_rand( 0, 0xffff ),
 		mt_rand( 0, 0xffff ),
 		mt_rand( 0, 0x0fff ) | 0x4000,
 		mt_rand( 0, 0x3fff ) | 0x8000,
-		mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
+		mt_rand( 0, 0xffff ),
+		mt_rand( 0, 0xffff ),
+		mt_rand( 0, 0xffff )
 	);
 }
 
@@ -5728,7 +6494,8 @@
  * @since 4.9.0
  *
  * @param mixed $uuid    UUID to check.
- * @param int   $version Specify which version of UUID to check against. Default is none, to accept any UUID version. Otherwise, only version allowed is `4`.
+ * @param int   $version Specify which version of UUID to check against. Default is none,
+ *                       to accept any UUID version. Otherwise, only version allowed is `4`.
  * @return bool The string is a valid UUID or false on failure.
  */
 function wp_is_uuid( $uuid, $version = null ) {
@@ -5751,6 +6518,26 @@
 }
 
 /**
+ * Get unique ID.
+ *
+ * This is a PHP implementation of Underscore's uniqueId method. A static variable
+ * contains an integer that is incremented with each call. This number is returned
+ * with the optional prefix. As such the returned value is not universally unique,
+ * but it is unique across the life of the PHP process.
+ *
+ * @since 5.0.3
+ *
+ * @staticvar int $id_counter
+ *
+ * @param string $prefix Prefix for the returned ID.
+ * @return string Unique ID.
+ */
+function wp_unique_id( $prefix = '' ) {
+	static $id_counter = 0;
+	return $prefix . (string) ++$id_counter;
+}
+
+/**
  * Get last changed date for the specified cache group.
  *
  * @since 4.7.0
@@ -5803,7 +6590,8 @@
 	}
 
 	/* translators: Do not translate OLD_EMAIL, NEW_EMAIL, SITENAME, SITEURL: those are placeholders. */
-	$email_change_text = __( 'Hi,
+	$email_change_text = __(
+		'Hi,
 
 This notice confirms that the admin email address was changed on ###SITENAME###.
 
@@ -5813,12 +6601,13 @@
 
 Regards,
 All at ###SITENAME###
-###SITEURL###' );
+###SITEURL###'
+	);
 
 	$email_change_email = array(
 		'to'      => $old_email,
 		/* translators: Site admin email change notification email subject. %s: Site title */
-		'subject' => __( '[%s] Notice of Admin Email Change' ),
+		'subject' => __( '[%s] Admin Email Changed' ),
 		'message' => $email_change_text,
 		'headers' => '',
 	);
@@ -5850,13 +6639,18 @@
 
 	$email_change_email['message'] = str_replace( '###OLD_EMAIL###', $old_email, $email_change_email['message'] );
 	$email_change_email['message'] = str_replace( '###NEW_EMAIL###', $new_email, $email_change_email['message'] );
-	$email_change_email['message'] = str_replace( '###SITENAME###',  $site_name, $email_change_email['message'] );
-	$email_change_email['message'] = str_replace( '###SITEURL###',   home_url(), $email_change_email['message'] );
-
-	wp_mail( $email_change_email['to'], sprintf(
-		$email_change_email['subject'],
-		$site_name
-	), $email_change_email['message'], $email_change_email['headers'] );
+	$email_change_email['message'] = str_replace( '###SITENAME###', $site_name, $email_change_email['message'] );
+	$email_change_email['message'] = str_replace( '###SITEURL###', home_url(), $email_change_email['message'] );
+
+	wp_mail(
+		$email_change_email['to'],
+		sprintf(
+			$email_change_email['subject'],
+			$site_name
+		),
+		$email_change_email['message'],
+		$email_change_email['headers']
+	);
 }
 
 /**
@@ -5911,7 +6705,7 @@
 		// Partially anonymize the IP by reducing it to the corresponding network ID.
 		if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) {
 			$ip_addr = inet_ntop( inet_pton( $ip_addr ) & inet_pton( $netmask ) );
-			if ( false === $ip_addr) {
+			if ( false === $ip_addr ) {
 				return '::';
 			}
 		} elseif ( ! $ipv6_fallback ) {
@@ -6050,9 +6844,12 @@
  * @since 4.9.6
  */
 function wp_privacy_delete_old_export_files() {
+	$exports_dir = wp_privacy_exports_dir();
+	if ( ! is_dir( $exports_dir ) ) {
+		return;
+	}
+
 	require_once( ABSPATH . 'wp-admin/includes/file.php' );
-
-	$exports_dir  = wp_privacy_exports_dir();
 	$export_files = list_files( $exports_dir, 100, array( 'index.html' ) );
 
 	/**
@@ -6075,3 +6872,296 @@
 		}
 	}
 }
+
+/**
+ * Gets the URL to learn more about updating the PHP version the site is running on.
+ *
+ * This URL can be overridden by specifying an environment variable `WP_UPDATE_PHP_URL` or by using the
+ * {@see 'wp_update_php_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.1.0
+ *
+ * @return string URL to learn more about updating PHP.
+ */
+function wp_get_update_php_url() {
+	$default_url = wp_get_default_update_php_url();
+
+	$update_url = $default_url;
+	if ( false !== getenv( 'WP_UPDATE_PHP_URL' ) ) {
+		$update_url = getenv( 'WP_UPDATE_PHP_URL' );
+	}
+
+	/**
+	 * Filters the URL to learn more about updating the PHP 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.1.0
+	 *
+	 * @param string $update_url URL to learn more about updating PHP.
+	 */
+	$update_url = apply_filters( 'wp_update_php_url', $update_url );
+
+	if ( empty( $update_url ) ) {
+		$update_url = $default_url;
+	}
+
+	return $update_url;
+}
+
+/**
+ * Gets the default URL to learn more about updating the PHP version the site is running on.
+ *
+ * Do not use this function to retrieve this URL. Instead, use {@see wp_get_update_php_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.1.0
+ * @access private
+ *
+ * @return string Default URL to learn more about updating PHP.
+ */
+function wp_get_default_update_php_url() {
+	return _x( 'https://wordpress.org/support/update-php/', 'localized PHP upgrade information page' );
+}
+
+/**
+ * Prints the default annotation for the web host altering the "Update PHP" page URL.
+ *
+ * This function is to be used after {@see wp_get_update_php_url()} to display a consistent
+ * annotation if the web host has altered the default "Update PHP" page URL.
+ *
+ * @since 5.1.0
+ * @since 5.2.0 Added the `$before` and `$after` parameters.
+ *
+ * @param string $before Markup to output before the annotation. Default `<p class="description">`.
+ * @param string $after  Markup to output after the annotation. Default `</p>`.
+ */
+function wp_update_php_annotation( $before = '<p class="description">', $after = '</p>' ) {
+	$annotation = wp_get_update_php_annotation();
+
+	if ( $annotation ) {
+		echo $before . $annotation . $after;
+	}
+}
+
+/**
+ * Returns the default annotation for the web hosting altering the "Update PHP" page URL.
+ *
+ * This function is to be used after {@see wp_get_update_php_url()} to return a consistent
+ * annotation if the web host has altered the default "Update PHP" page URL.
+ *
+ * @since 5.2.0
+ *
+ * @return string $message Update PHP page annotation. An empty string if no custom URLs are provided.
+ */
+function wp_get_update_php_annotation() {
+	$update_url  = wp_get_update_php_url();
+	$default_url = wp_get_default_update_php_url();
+
+	if ( $update_url === $default_url ) {
+		return '';
+	}
+
+	$annotation = sprintf(
+		/* translators: %s: default Update PHP page URL */
+		__( 'This resource is provided by your web host, and is specific to your site. For more information, <a href="%s" target="_blank">see the official WordPress documentation</a>.' ),
+		esc_url( $default_url )
+	);
+
+	return $annotation;
+}
+
+/**
+ * Gets the URL for directly updating the PHP version the site is running on.
+ *
+ * A URL will only be returned if the `WP_DIRECT_UPDATE_PHP_URL` environment variable is specified or
+ * by using the {@see 'wp_direct_php_update_url'} filter. This allows hosts to send users directly to
+ * the page where they can update PHP to a newer version.
+ *
+ * @since 5.1.1
+ *
+ * @return string URL for directly updating PHP or empty string.
+ */
+function wp_get_direct_php_update_url() {
+	$direct_update_url = '';
+
+	if ( false !== getenv( 'WP_DIRECT_UPDATE_PHP_URL' ) ) {
+		$direct_update_url = getenv( 'WP_DIRECT_UPDATE_PHP_URL' );
+	}
+
+	/**
+	 * Filters the URL for directly updating the PHP version the site is running on from the host.
+	 *
+	 * @since 5.1.1
+	 *
+	 * @param string $direct_update_url URL for directly updating PHP.
+	 */
+	$direct_update_url = apply_filters( 'wp_direct_php_update_url', $direct_update_url );
+
+	return $direct_update_url;
+}
+
+/**
+ * Display a button directly linking to a PHP update process.
+ *
+ * This provides hosts with a way for users to be sent directly to their PHP update process.
+ *
+ * The button is only displayed if a URL is returned by `wp_get_direct_php_update_url()`.
+ *
+ * @since 5.1.1
+ */
+function wp_direct_php_update_button() {
+	$direct_update_url = wp_get_direct_php_update_url();
+
+	if ( empty( $direct_update_url ) ) {
+		return;
+	}
+
+	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>',
+		esc_url( $direct_update_url ),
+		__( 'Update PHP' ),
+		/* translators: accessibility text */
+		__( '(opens in a new tab)' )
+	);
+	echo '</p>';
+}
+
+/**
+ * Get the size of a directory.
+ *
+ * A helper function that is used primarily to check whether
+ * a blog has exceeded its allowed upload space.
+ *
+ * @since MU (3.0.0)
+ * @since 5.2.0 $max_execution_time parameter added.
+ *
+ * @param string $directory Full path of a directory.
+ * @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.
+ * @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 );
+	} else {
+		$dirsize[ $directory ]['size'] = recurse_dirsize( $directory, null, $max_execution_time );
+	}
+
+	set_transient( 'dirsize_cache', $dirsize, HOUR_IN_SECONDS );
+	return $dirsize[ $directory ]['size'];
+}
+
+/**
+ * Get the size of a directory recursively.
+ *
+ * Used by get_dirsize() to get a directory's 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.
+ *
+ * @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.
+ * @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 );
+
+	if ( ! file_exists( $directory ) || ! is_dir( $directory ) || ! is_readable( $directory ) ) {
+		return false;
+	}
+
+	if (
+		( is_string( $exclude ) && $directory === $exclude ) ||
+		( is_array( $exclude ) && in_array( $directory, $exclude, true ) )
+	) {
+		return false;
+	}
+
+	if ( $max_execution_time === null ) {
+		// Keep the previous behavior but attempt to prevent fatal errors from timeout if possible.
+		if ( function_exists( 'ini_get' ) ) {
+			$max_execution_time = ini_get( 'max_execution_time' );
+		} else {
+			// Disable...
+			$max_execution_time = 0;
+		}
+
+		// Leave 1 second "buffer" for other operations if $max_execution_time has reasonable value.
+		if ( $max_execution_time > 10 ) {
+			$max_execution_time -= 1;
+		}
+	}
+
+	if ( $handle = opendir( $directory ) ) {
+		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;
+					}
+				}
+
+				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 );
+	}
+	return $size;
+}
+
+/**
+* Checks compatibility with the current WordPress version.
+*
+* @since 5.2.0
+*
+* @param string $required Minimum required WordPress version.
+* @return bool True if required version is compatible or empty, false if not.
+*/
+function is_wp_version_compatible( $required ) {
+	return empty( $required ) || version_compare( get_bloginfo( 'version' ), $required, '>=' );
+}
+
+/**
+ * Checks compatibility with the current PHP version.
+ *
+ * @since 5.2.0
+ *
+ * @param string $required Minimum required PHP version.
+ * @return bool True if required version is compatible or empty, false if not.
+ */
+function is_php_version_compatible( $required ) {
+	return empty( $required ) || version_compare( phpversion(), $required, '>=' );
+}