WordPress 4.6.1
[autoinstalls/wordpress.git] / wp-includes / functions.php
index 76013c934e6186668067bc609cbf9bbbec0f1923..ff09f3459d3bdf150462f8194727046ace99bee7 100644 (file)
@@ -78,6 +78,8 @@ function current_time( $type, $gmt = 0 ) {
  *
  * @since 0.71
  *
+ * @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.
@@ -130,7 +132,7 @@ function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
                if ( $timezone_string ) {
                        $timezone_object = timezone_open( $timezone_string );
                        $date_object = date_create( null, $timezone_object );
-                       foreach( $timezone_formats as $timezone_format ) {
+                       foreach ( $timezone_formats as $timezone_format ) {
                                if ( false !== strpos( $dateformatstring, $timezone_format ) ) {
                                        $formatted = date_format( $date_object, $timezone_format );
                                        $dateformatstring = ' '.$dateformatstring;
@@ -143,7 +145,7 @@ function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
        $j = @$datefunc( $dateformatstring, $i );
 
        /**
-        * Filter the date formatted based on the locale.
+        * Filters the date formatted based on the locale.
         *
         * @since 2.8.0
         *
@@ -157,20 +159,78 @@ function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
 }
 
 /**
- * Convert integer number to format based on the locale.
+ * Determines if the date should be declined.
+ *
+ * If the locale specifies that month names require a genitive case in certain
+ * formats (like 'j F Y'), the month name will be replaced with a correct form.
+ *
+ * @since 4.4.0
+ *
+ * @param string $date Formatted date string.
+ * @return string The date, declined if locale specifies it.
+ */
+function wp_maybe_decline_date( $date ) {
+       global $wp_locale;
+
+       // i18n functions are not available in SHORTINIT mode
+       if ( ! function_exists( '_x' ) ) {
+               return $date;
+       }
+
+       /* translators: If months in your language require a genitive case,
+        * translate this to 'on'. Do not translate into your own language.
+        */
+       if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) {
+               // Match a format like 'j F Y' or 'j. F'
+               if ( @preg_match( '#^\d{1,2}\.? [^\d ]+#u', $date ) ) {
+                       $months          = $wp_locale->month;
+                       $months_genitive = $wp_locale->month_genitive;
+
+                       foreach ( $months as $key => $month ) {
+                               $months[ $key ] = '# ' . $month . '( |$)#u';
+                       }
+
+                       foreach ( $months_genitive as $key => $month ) {
+                               $months_genitive[ $key ] = ' ' . $month . '$1';
+                       }
+
+                       $date = preg_replace( $months, $months_genitive, $date );
+               }
+       }
+
+       // Used for locale-specific rules
+       $locale = get_locale();
+
+       if ( 'ca' === $locale ) {
+               // " de abril| de agost| de octubre..." -> " d'abril| d'agost| d'octubre..."
+               $date = preg_replace( '# de ([ao])#i', " d'\\1", $date );
+       }
+
+       return $date;
+}
+
+/**
+ * Convert float number to format based on the locale.
  *
  * @since 2.3.0
  *
- * @param int $number   The number to convert based on locale.
- * @param int $decimals Optional. Precision of the number of decimal places. Default 0.
+ * @global WP_Locale $wp_locale
+ *
+ * @param float $number   The number to convert based on locale.
+ * @param int   $decimals Optional. Precision of the number of decimal places. Default 0.
  * @return string Converted number in string format.
  */
 function number_format_i18n( $number, $decimals = 0 ) {
        global $wp_locale;
-       $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
+
+       if ( isset( $wp_locale ) ) {
+               $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
+       } else {
+               $formatted = number_format( $number, absint( $decimals ) );
+       }
 
        /**
-        * Filter the number formatted based on the locale.
+        * Filters the number formatted based on the locale.
         *
         * @since  2.8.0
         *
@@ -182,7 +242,7 @@ function number_format_i18n( $number, $decimals = 0 ) {
 /**
  * Convert number of bytes largest unit bytes will fit into.
  *
- * It is easier to read 1kB than 1024 bytes and 1MB than 1048576 bytes. Converts
+ * It is easier to read 1 KB than 1024 bytes and 1 MB than 1048576 bytes. Converts
  * number of bytes to human readable number by taking the number of that unit
  * that the bytes will go into it. Supports TB value.
  *
@@ -201,16 +261,22 @@ function number_format_i18n( $number, $decimals = 0 ) {
  */
 function size_format( $bytes, $decimals = 0 ) {
        $quant = array(
-               // ========================= Origin ====
-               'TB' => 1099511627776,  // pow( 1024, 4)
-               'GB' => 1073741824,     // pow( 1024, 3)
-               'MB' => 1048576,        // pow( 1024, 2)
-               'kB' => 1024,           // pow( 1024, 1)
-               'B ' => 1,              // pow( 1024, 0)
+               'TB' => TB_IN_BYTES,
+               'GB' => GB_IN_BYTES,
+               'MB' => MB_IN_BYTES,
+               'KB' => KB_IN_BYTES,
+               'B'  => 1,
        );
-       foreach ( $quant as $unit => $mag )
-               if ( doubleval($bytes) >= $mag )
+
+       if ( 0 === $bytes ) {
+               return number_format_i18n( 0, $decimals ) . ' B';
+       }
+
+       foreach ( $quant as $unit => $mag ) {
+               if ( doubleval( $bytes ) >= $mag ) {
                        return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
+               }
+       }
 
        return false;
 }
@@ -249,8 +315,8 @@ function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
        // The most recent week start day on or before $day.
        $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week );
 
-       // $start + 7 days - 1 second.
-       $end = $start + 7 * DAY_IN_SECONDS - 1;
+       // $start + 1 week - 1 second.
+       $end = $start + WEEK_IN_SECONDS - 1;
        return compact( 'start', 'end' );
 }
 
@@ -378,6 +444,7 @@ function maybe_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 ) )
                return serialize( $data );
 
@@ -487,10 +554,10 @@ function wp_extract_urls( $content ) {
  *
  * @since 1.5.0
  *
- * @see $wpdb
+ * @global wpdb $wpdb WordPress database abstraction object.
  *
  * @param string $content Post Content.
- * @param int $post_ID Post ID.
+ * @param int    $post_ID Post ID.
  */
 function do_enclose( $content, $post_ID ) {
        global $wpdb;
@@ -524,6 +591,19 @@ function do_enclose( $content, $post_ID ) {
                }
        }
 
+       /**
+        * Filters the list of enclosure links before querying the database.
+        *
+        * Allows for the addition and/or removal of potential enclosures to save
+        * to postmeta before checking the database for existing enclosures.
+        *
+        * @since 4.4.0
+        *
+        * @param array $post_links An array of enclosure links.
+        * @param int   $post_ID    Post ID.
+        */
+       $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 ) . '%' ) ) ) {
 
@@ -555,62 +635,6 @@ function do_enclose( $content, $post_ID ) {
        }
 }
 
-/**
- * Perform a HTTP HEAD or GET request.
- *
- * If $file_path is a writable filename, this will do a GET request and write
- * the file to that path.
- *
- * @since 2.5.0
- *
- * @param string      $url       URL to fetch.
- * @param string|bool $file_path Optional. File path to write request to. Default false.
- * @param int         $red       Optional. The number of Redirects followed, Upon 5 being hit,
- *                               returns false. Default 1.
- * @return bool|string False on failure and string of headers if HEAD request.
- */
-function wp_get_http( $url, $file_path = false, $red = 1 ) {
-       @set_time_limit( 60 );
-
-       if ( $red > 5 )
-               return false;
-
-       $options = array();
-       $options['redirection'] = 5;
-
-       if ( false == $file_path )
-               $options['method'] = 'HEAD';
-       else
-               $options['method'] = 'GET';
-
-       $response = wp_safe_remote_request( $url, $options );
-
-       if ( is_wp_error( $response ) )
-               return false;
-
-       $headers = wp_remote_retrieve_headers( $response );
-       $headers['response'] = wp_remote_retrieve_response_code( $response );
-
-       // WP_HTTP no longer follows redirects for HEAD requests.
-       if ( 'HEAD' == $options['method'] && in_array($headers['response'], array(301, 302)) && isset( $headers['location'] ) ) {
-               return wp_get_http( $headers['location'], $file_path, ++$red );
-       }
-
-       if ( false == $file_path )
-               return $headers;
-
-       // GET request - write it to the supplied filename
-       $out_fp = fopen($file_path, 'w');
-       if ( !$out_fp )
-               return $headers;
-
-       fwrite( $out_fp,  wp_remote_retrieve_body( $response ) );
-       fclose($out_fp);
-       clearstatcache();
-
-       return $headers;
-}
-
 /**
  * Retrieve HTTP Headers from URL.
  *
@@ -622,7 +646,7 @@ function wp_get_http( $url, $file_path = false, $red = 1 ) {
  */
 function wp_get_http_headers( $url, $deprecated = false ) {
        if ( !empty( $deprecated ) )
-               _deprecated_argument( __FUNCTION__, '2.7' );
+               _deprecated_argument( __FUNCTION__, '2.7.0' );
 
        $response = wp_safe_remote_head( $url );
 
@@ -660,8 +684,8 @@ function is_new_day() {
  * @since 2.3.0
  *
  * @see _http_build_query() Used to build the query
- * @see http://us2.php.net/manual/en/function.http-build-query.php for more on what
- *             http_build_query() does.
+ * @link https://secure.php.net/manual/en/function.http-build-query.php for more on what
+ *              http_build_query() does.
  *
  * @param array $data URL-encode key/value pairs.
  * @return string URL-encoded string.
@@ -676,7 +700,7 @@ function build_query( $data ) {
  * @since 3.2.0
  * @access private
  *
- * @see http://us1.php.net/manual/en/function.http-build-query.php
+ * @see https://secure.php.net/manual/en/function.http-build-query.php
  *
  * @param array|object  $data       An array or object of data. Converted to array.
  * @param string        $prefix     Optional. Numeric index. If set, start parameter numbering with it.
@@ -700,7 +724,7 @@ function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urle
                        $k = $key . '%5B' . $k . '%5D';
                if ( $v === null )
                        continue;
-               elseif ( $v === FALSE )
+               elseif ( $v === false )
                        $v = '0';
 
                if ( is_array($v) || is_object($v) )
@@ -718,22 +742,39 @@ function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urle
 }
 
 /**
- * Retrieve a modified URL query string.
+ * Retrieves a modified URL query string.
+ *
+ * You can rebuild the URL and append query variables to the URL query by using this function.
+ * There are two ways to use this function; either a single key and value, or an associative array.
+ *
+ * Using a single key and value:
+ *
+ *     add_query_arg( 'key', 'value', 'http://example.com' );
  *
- * You can rebuild the URL and append a new query variable to the URL query by
- * using this function. You can also retrieve the full URL with query data.
+ * Using an associative array:
  *
- * Adding a single key & value or an associative array. Setting a key value to
- * an empty string removes the key. Omitting oldquery_or_uri uses the $_SERVER
- * value. Additional values provided are expected to be encoded appropriately
- * with urlencode() or rawurlencode().
+ *     add_query_arg( array(
+ *         'key1' => 'value1',
+ *         'key2' => 'value2',
+ *     ), 'http://example.com' );
+ *
+ * Omitting the URL from either use results in the current URL being used
+ * (the value of `$_SERVER['REQUEST_URI']`).
+ *
+ * Values are expected to be encoded appropriately with urlencode() or rawurlencode().
+ *
+ * Setting any query variable's value to boolean false removes the key (see remove_query_arg()).
+ *
+ * Important: The return value of add_query_arg() is not escaped by default. Output should be
+ * late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
+ * (XSS) attacks.
  *
  * @since 1.5.0
  *
- * @param string|array $param1 Either newkey or an associative_array.
- * @param string       $param2 Either newvalue or oldquery or URI.
- * @param string       $param3 Optional. Old query or URI.
- * @return string New URL query string.
+ * @param string|array $key   Either a query variable key, or an associative array of query variables.
+ * @param string       $value Optional. Either a query variable value, or a URL to act upon.
+ * @param string       $url   Optional. A URL to act upon.
+ * @return string New URL query string (unescaped).
  */
 function add_query_arg() {
        $args = func_get_args();
@@ -778,8 +819,9 @@ function add_query_arg() {
        wp_parse_str( $query, $qs );
        $qs = urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string
        if ( is_array( $args[0] ) ) {
-               $kayvees = $args[0];
-               $qs = array_merge( $qs, $kayvees );
+               foreach ( $args[0] as $k => $v ) {
+                       $qs[ $k ] = $v;
+               }
        } else {
                $qs[ $args[0] ] = $args[1];
        }
@@ -798,12 +840,12 @@ function add_query_arg() {
 }
 
 /**
- * Removes an item or list from the query string.
+ * Removes an item or items from a query string.
  *
  * @since 1.5.0
  *
  * @param string|array $key   Query key or keys to remove.
- * @param bool|string  $query Optional. When false uses the $_SERVER value. Default false.
+ * @param bool|string  $query Optional. When false uses the current URL. Default false.
  * @return string New URL query string.
  */
 function remove_query_arg( $key, $query = false ) {
@@ -815,6 +857,50 @@ function remove_query_arg( $key, $query = false ) {
        return add_query_arg( $key, false, $query );
 }
 
+/**
+ * Returns an array of single-use query variable names that can be removed from a URL.
+ *
+ * @since 4.4.0
+ *
+ * @return array An array of parameters to remove from the URL.
+ */
+function wp_removable_query_args() {
+       $removable_query_args = array(
+               'activate',
+               'activated',
+               'approved',
+               'deactivate',
+               'deleted',
+               'disabled',
+               'enabled',
+               'error',
+               'hotkeys_highlight_first',
+               'hotkeys_highlight_last',
+               'locked',
+               'message',
+               'same',
+               'saved',
+               'settings-updated',
+               'skipped',
+               'spammed',
+               'trashed',
+               'unspammed',
+               'untrashed',
+               'update',
+               'updated',
+               'wp-post-new-reload',
+       );
+
+       /**
+        * Filters the list of query variables to remove.
+        *
+        * @since 4.2.0
+        *
+        * @param array $removable_query_args An array of query variables to remove from a URL.
+        */
+       return apply_filters( 'removable_query_args', $removable_query_args );
+}
+
 /**
  * Walks the array while sanitizing the contents.
  *
@@ -866,7 +952,11 @@ function wp_remote_fopen( $uri ) {
  *
  * @since 2.0.0
  *
- * @param string $query_vars Default WP_Query arguments.
+ * @global WP       $wp_locale
+ * @global WP_Query $wp_query
+ * @global WP_Query $wp_the_query
+ *
+ * @param string|array $query_vars Default WP_Query arguments.
  */
 function wp( $query_vars = '' ) {
        global $wp, $wp_query, $wp_the_query;
@@ -881,6 +971,8 @@ function wp( $query_vars = '' ) {
  *
  * @since 2.3.0
  *
+ * @global array $wp_header_to_desc
+ *
  * @param int $code HTTP status code.
  * @return string Empty string if not found, or description if found.
  */
@@ -913,6 +1005,7 @@ function get_status_header_desc( $code ) {
                        305 => 'Use Proxy',
                        306 => 'Reserved',
                        307 => 'Temporary Redirect',
+                       308 => 'Permanent Redirect',
 
                        400 => 'Bad Request',
                        401 => 'Unauthorized',
@@ -933,6 +1026,7 @@ function get_status_header_desc( $code ) {
                        416 => 'Requested Range Not Satisfiable',
                        417 => 'Expectation Failed',
                        418 => 'I\'m a teapot',
+                       421 => 'Misdirected Request',
                        422 => 'Unprocessable Entity',
                        423 => 'Locked',
                        424 => 'Failed Dependency',
@@ -940,6 +1034,7 @@ function get_status_header_desc( $code ) {
                        428 => 'Precondition Required',
                        429 => 'Too Many Requests',
                        431 => 'Request Header Fields Too Large',
+                       451 => 'Unavailable For Legal Reasons',
 
                        500 => 'Internal Server Error',
                        501 => 'Not Implemented',
@@ -964,25 +1059,28 @@ function get_status_header_desc( $code ) {
  * Set HTTP status header.
  *
  * @since 2.0.0
+ * @since 4.4.0 Added the `$description` parameter.
  *
  * @see get_status_header_desc()
  *
- * @param int $code HTTP status code.
+ * @param int    $code        HTTP status code.
+ * @param string $description Optional. A custom description for the HTTP status.
  */
-function status_header( $code ) {
-       $description = get_status_header_desc( $code );
+function status_header( $code, $description = '' ) {
+       if ( ! $description ) {
+               $description = get_status_header_desc( $code );
+       }
 
-       if ( empty( $description ) )
+       if ( empty( $description ) ) {
                return;
+       }
 
-       $protocol = $_SERVER['SERVER_PROTOCOL'];
-       if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol )
-               $protocol = 'HTTP/1.0';
+       $protocol = wp_get_server_protocol();
        $status_header = "$protocol $code $description";
        if ( function_exists( 'apply_filters' ) )
 
                /**
-                * Filter an HTTP status header.
+                * Filters an HTTP status header.
                 *
                 * @since 2.2.0
                 *
@@ -1010,12 +1108,11 @@ function wp_get_nocache_headers() {
        $headers = array(
                'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
                'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
-               'Pragma' => 'no-cache',
        );
 
        if ( function_exists('apply_filters') ) {
                /**
-                * Filter the cache-controlling headers.
+                * Filters the cache-controlling headers.
                 *
                 * @since 2.8.0
                 *
@@ -1026,7 +1123,6 @@ function wp_get_nocache_headers() {
                 *
                 *     @type string $Expires       Expires header.
                 *     @type string $Cache-Control Cache-Control header.
-                *     @type string $Pragma        Pragma header.
                 * }
                 */
                $headers = (array) apply_filters( 'nocache_headers', $headers );
@@ -1065,7 +1161,7 @@ function nocache_headers() {
                }
        }
 
-       foreach( $headers as $name => $field_value )
+       foreach ( $headers as $name => $field_value )
                @header("{$name}: {$field_value}");
 }
 
@@ -1120,7 +1216,7 @@ function bool_from_yn( $yn ) {
  *
  * @since 2.1.0
  *
- * @uses $wp_query Used to tell if the use a comment feed.
+ * @global WP_Query $wp_query Used to tell if the use a comment feed.
  */
 function do_feed() {
        global $wp_query;
@@ -1133,20 +1229,23 @@ function do_feed() {
        if ( $feed == '' || $feed == 'feed' )
                $feed = get_default_feed();
 
-       $hook = 'do_feed_' . $feed;
-       if ( ! has_action( $hook ) )
+       if ( ! has_action( "do_feed_{$feed}" ) ) {
                wp_die( __( 'ERROR: This is not a valid feed template.' ), '', array( 'response' => 404 ) );
+       }
 
        /**
         * Fires once the given feed is loaded.
         *
-        * The dynamic hook name, $hook, refers to the feed name.
+        * The dynamic portion of the hook name, `$feed`, refers to the feed template name.
+        * Possible values include: 'rdf', 'rss', 'rss2', and 'atom'.
         *
         * @since 2.1.0
+        * @since 4.4.0 The `$feed` parameter was added.
         *
-        * @param bool $is_comment_feed Whether the feed is a comment feed.
+        * @param bool   $is_comment_feed Whether the feed is a comment feed.
+        * @param string $feed            The feed name.
         */
-       do_action( $hook, $wp_query->is_comment_feed );
+       do_action( "do_feed_{$feed}", $wp_query->is_comment_feed, $feed );
 }
 
 /**
@@ -1229,10 +1328,11 @@ function do_robots() {
                $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";
        }
 
        /**
-        * Filter the robots.txt output.
+        * Filters the robots.txt output.
         *
         * @since 3.0.0
         *
@@ -1243,7 +1343,7 @@ function do_robots() {
 }
 
 /**
- * Test whether blog is already installed.
+ * Test 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
@@ -1255,7 +1355,7 @@ function do_robots() {
  *
  * @global wpdb $wpdb WordPress database abstraction object.
  *
- * @return bool Whether the blog is already installed.
+ * @return bool Whether the site is already installed.
  */
 function is_blog_installed() {
        global $wpdb;
@@ -1268,7 +1368,7 @@ function is_blog_installed() {
                return true;
 
        $suppress = $wpdb->suppress_errors();
-       if ( ! defined( 'WP_INSTALLING' ) ) {
+       if ( ! wp_installing() ) {
                $alloptions = wp_load_alloptions();
        }
        // If siteurl is not set to autoload, check it specifically
@@ -1429,16 +1529,35 @@ function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) {
  * @return false|string False on failure. Referer URL on success.
  */
 function wp_get_referer() {
-       if ( ! function_exists( 'wp_validate_redirect' ) )
+       if ( ! function_exists( 'wp_validate_redirect' ) ) {
                return false;
-       $ref = false;
-       if ( ! empty( $_REQUEST['_wp_http_referer'] ) )
-               $ref = wp_unslash( $_REQUEST['_wp_http_referer'] );
-       else if ( ! empty( $_SERVER['HTTP_REFERER'] ) )
-               $ref = wp_unslash( $_SERVER['HTTP_REFERER'] );
+       }
 
-       if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) )
+       $ref = wp_get_raw_referer();
+
+       if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) && $ref !== home_url() . wp_unslash( $_SERVER['REQUEST_URI'] ) ) {
                return wp_validate_redirect( $ref, false );
+       }
+
+       return false;
+}
+
+/**
+ * Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer.
+ *
+ * Do not use for redirects, use wp_get_referer() instead.
+ *
+ * @since 4.5.0
+ *
+ * @return string|false Referer URL on success, false on failure.
+ */
+function wp_get_raw_referer() {
+       if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
+               return wp_unslash( $_REQUEST['_wp_http_referer'] );
+       } else if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
+               return wp_unslash( $_SERVER['HTTP_REFERER'] );
+       }
+
        return false;
 }
 
@@ -1469,7 +1588,7 @@ function wp_mkdir_p( $target ) {
        $wrapper = null;
 
        // Strip the protocol.
-       if( wp_is_stream( $target ) ) {
+       if ( wp_is_stream( $target ) ) {
                list( $wrapper, $target ) = explode( '://', $target, 2 );
        }
 
@@ -1477,7 +1596,7 @@ function wp_mkdir_p( $target ) {
        $target = str_replace( '//', '/', $target );
 
        // Put the wrapper back on the target.
-       if( $wrapper !== null ) {
+       if ( $wrapper !== null ) {
                $target = $wrapper . '://' . $target;
        }
 
@@ -1513,7 +1632,7 @@ function wp_mkdir_p( $target ) {
                 */
                if ( $dir_perms != ( $dir_perms & ~umask() ) ) {
                        $folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) );
-                       for ( $i = 1; $i <= count( $folder_parts ); $i++ ) {
+                       for ( $i = 1, $c = count( $folder_parts ); $i <= $c; $i++ ) {
                                @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms );
                        }
                }
@@ -1575,17 +1694,24 @@ function path_join( $base, $path ) {
 /**
  * Normalize a filesystem path.
  *
- * Replaces backslashes with forward slashes for Windows systems, and ensures
- * no duplicate slashes exist.
+ * On windows systems, replaces backslashes with forward slashes
+ * and forces upper-case drive letters.
+ * Allows for two leading slashes for Windows network shares, but
+ * ensures that all other duplicate slashes are reduced to a single.
  *
  * @since 3.9.0
+ * @since 4.4.0 Ensures upper-case drive letters on Windows systems.
+ * @since 4.5.0 Allows for Windows network shares.
  *
  * @param string $path Path to normalize.
  * @return string Normalized path.
  */
 function wp_normalize_path( $path ) {
        $path = str_replace( '\\', '/', $path );
-       $path = preg_replace( '|/+|','/', $path );
+       $path = preg_replace( '|(?<=.)/+|', '/', $path );
+       if ( ':' === substr( $path, 1, 1 ) ) {
+               $path = ucfirst( $path );
+       }
        return $path;
 }
 
@@ -1601,10 +1727,12 @@ function wp_normalize_path( $path ) {
  *
  * @since 2.5.0
  *
+ * @staticvar string $temp
+ *
  * @return string Writable temporary directory.
  */
 function get_temp_dir() {
-       static $temp;
+       static $temp = '';
        if ( defined('WP_TEMP_DIR') )
                return trailingslashit(WP_TEMP_DIR);
 
@@ -1625,8 +1753,7 @@ function get_temp_dir() {
        if ( is_dir( $temp ) && wp_is_writable( $temp ) )
                return $temp;
 
-       $temp = '/tmp/';
-       return $temp;
+       return '/tmp/';
 }
 
 /**
@@ -1659,19 +1786,19 @@ function wp_is_writable( $path ) {
  *
  * @since 2.8.0
  *
- * @see http://bugs.php.net/bug.php?id=27609
- * @see http://bugs.php.net/bug.php?id=30931
+ * @see https://bugs.php.net/bug.php?id=27609
+ * @see https://bugs.php.net/bug.php?id=30931
  *
  * @param string $path Windows path to check for write-ability.
  * @return bool Whether the path is writable.
  */
 function win_is_writable( $path ) {
 
-       if ( $path[strlen( $path ) - 1] == '/' ) // if it looks like a directory, check a random file within the directory
+       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');
-       else if ( is_dir( $path ) ) // If it's a directory (and not a file) check a random file within the directory
+       } 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' );
@@ -1683,6 +1810,23 @@ function win_is_writable( $path ) {
        return true;
 }
 
+/**
+ * Retrieves uploads directory information.
+ *
+ * Same as wp_upload_dir() but "light weight" as it doesn't attempt to create the uploads directory.
+ * Intended for use in themes, when only 'basedir' and 'baseurl' are needed, generally in all cases
+ * when not uploading files.
+ *
+ * @since 4.5.0
+ *
+ * @see wp_upload_dir()
+ *
+ * @return array See wp_upload_dir() for description.
+ */
+function wp_get_upload_dir() {
+       return wp_upload_dir( null, false );
+}
+
 /**
  * Get an array containing the current upload directory's path and url.
  *
@@ -1708,14 +1852,68 @@ function win_is_writable( $path ) {
  * 'subdir' - sub directory if uploads use year/month folders option is on.
  * 'basedir' - path without subdir.
  * 'baseurl' - URL path without subdir.
- * 'error' - set to false.
+ * 'error' - false or error message.
  *
  * @since 2.0.0
+ * @uses _wp_upload_dir()
  *
  * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
+ * @param bool   $create_dir Optional. Whether to check and create the uploads directory.
+ *                           Default true for backward compatibility.
+ * @param bool   $refresh_cache Optional. Whether to refresh the cache. Default false.
  * @return array See above for description.
  */
-function wp_upload_dir( $time = null ) {
+function wp_upload_dir( $time = null, $create_dir = true, $refresh_cache = false ) {
+       static $cache = array(), $tested_paths = array();
+
+       $key = sprintf( '%d-%s', get_current_blog_id(), (string) $time );
+
+       if ( $refresh_cache || empty( $cache[ $key ] ) ) {
+               $cache[ $key ] = _wp_upload_dir( $time );
+       }
+
+       /**
+        * Filters the uploads directory data.
+        *
+        * @since 2.0.0
+        *
+        * @param array $uploads Array of upload directory data with keys of 'path',
+        *                       'url', 'subdir, 'basedir', and 'error'.
+        */
+       $uploads = apply_filters( 'upload_dir', $cache[ $key ] );
+
+       if ( $create_dir ) {
+               $path = $uploads['path'];
+
+               if ( array_key_exists( $path, $tested_paths ) ) {
+                       $uploads['error'] = $tested_paths[ $path ];
+               } else {
+                       if ( ! wp_mkdir_p( $path ) ) {
+                               if ( 0 === strpos( $uploads['basedir'], ABSPATH ) ) {
+                                       $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
+                               } else {
+                                       $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
+                               }
+
+                               $uploads['error'] = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), esc_html( $error_path ) );
+                       }
+
+                       $tested_paths[ $path ] = $uploads['error'];
+               }
+       }
+
+       return $uploads;
+}
+
+/**
+ * A non-filtered, non-cached version of wp_upload_dir() that doesn't check the path.
+ *
+ * @access private
+ *
+ * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
+ * @return array See wp_upload_dir()
+ */
+function _wp_upload_dir( $time = null ) {
        $siteurl = get_option( 'siteurl' );
        $upload_path = trim( get_option( 'upload_path' ) );
 
@@ -1804,36 +2002,14 @@ function wp_upload_dir( $time = null ) {
        $dir .= $subdir;
        $url .= $subdir;
 
-       /**
-        * Filter the uploads directory data.
-        *
-        * @since 2.0.0
-        *
-        * @param array $uploads Array of upload directory data with keys of 'path',
-        *                       'url', 'subdir, 'basedir', and 'error'.
-        */
-       $uploads = apply_filters( 'upload_dir',
-               array(
-                       'path'    => $dir,
-                       'url'     => $url,
-                       'subdir'  => $subdir,
-                       'basedir' => $basedir,
-                       'baseurl' => $baseurl,
-                       'error'   => false,
-               ) );
-
-       // Make sure we have an uploads directory.
-       if ( ! wp_mkdir_p( $uploads['path'] ) ) {
-               if ( 0 === strpos( $uploads['basedir'], ABSPATH ) )
-                       $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
-               else
-                       $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
-
-               $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
-               $uploads['error'] = $message;
-       }
-
-       return $uploads;
+       return array(
+               'path'    => $dir,
+               'url'     => $url,
+               'subdir'  => $subdir,
+               'basedir' => $basedir,
+               'baseurl' => $baseurl,
+               'error'   => false,
+       );
 }
 
 /**
@@ -1850,7 +2026,7 @@ function wp_upload_dir( $time = null ) {
  *
  * @param string   $dir                      Directory.
  * @param string   $filename                 File name.
- * @param callback $unique_filename_callback Callback. Default null.
+ * @param callable $unique_filename_callback Callback. Default null.
  * @return string New filename, if given wasn't unique.
  */
 function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) {
@@ -1883,22 +2059,35 @@ function wp_unique_filename( $dir, $filename, $unique_filename_callback = null )
                        // Check for both lower and upper case extension or image sub-sizes may be overwritten.
                        while ( file_exists($dir . "/$filename") || file_exists($dir . "/$filename2") ) {
                                $new_number = $number + 1;
-                               $filename = str_replace( "$number$ext", "$new_number$ext", $filename );
-                               $filename2 = str_replace( "$number$ext2", "$new_number$ext2", $filename2 );
+                               $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;
                        }
-                       return $filename2;
+
+                       /**
+                        * Filters the result when generating a unique file name.
+                        *
+                        * @since 4.5.0
+                        *
+                        * @param string        $filename                 Unique file name.
+                        * @param string        $ext                      File extension, eg. ".png".
+                        * @param string        $dir                      Directory path.
+                        * @param callable|null $unique_filename_callback Callback function that generates the unique file name.
+                        */
+                       return apply_filters( 'wp_unique_filename', $filename2, $ext, $dir, $unique_filename_callback );
                }
 
                while ( file_exists( $dir . "/$filename" ) ) {
-                       if ( '' == "$number$ext" )
-                               $filename = $filename . ++$number . $ext;
-                       else
-                               $filename = str_replace( "$number$ext", ++$number . $ext, $filename );
+                       if ( '' == "$number$ext" ) {
+                               $filename = "$filename-" . ++$number;
+                       } else {
+                               $filename = str_replace( array( "-$number$ext", "$number$ext" ), "-" . ++$number . $ext, $filename );
+                       }
                }
        }
 
-       return $filename;
+       /** This filter is documented in wp-includes/functions.php */
+       return apply_filters( 'wp_unique_filename', $filename, $ext, $dir, $unique_filename_callback );
 }
 
 /**
@@ -1926,7 +2115,7 @@ function wp_unique_filename( $dir, $filename, $unique_filename_callback = null )
  */
 function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
        if ( !empty( $deprecated ) )
-               _deprecated_argument( __FUNCTION__, '2.0' );
+               _deprecated_argument( __FUNCTION__, '2.0.0' );
 
        if ( empty( $name ) )
                return array( 'error' => __( 'Empty filename' ) );
@@ -1941,7 +2130,7 @@ function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
                return $upload;
 
        /**
-        * Filter whether to treat the upload bits as an error.
+        * Filters whether to treat the upload bits as an error.
         *
         * Passing a non-array to the filter will effectively short-circuit preparing
         * the upload bits, returning that value instead.
@@ -1987,7 +2176,8 @@ function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
        // Compute the URL
        $url = $upload['url'] . "/$filename";
 
-       return array( 'file' => $new_file, 'url' => $url, 'error' => false );
+       /** 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' );
 }
 
 /**
@@ -1996,39 +2186,15 @@ function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
  * @since 2.5.0
  *
  * @param string $ext The extension to search.
- * @return string|null The file type, example: audio, video, document, spreadsheet, etc.
- *                     Null if not found.
+ * @return string|void The file type, example: audio, video, document, spreadsheet, etc.
  */
 function wp_ext2type( $ext ) {
        $ext = strtolower( $ext );
 
-       /**
-        * Filter file type based on the extension name.
-        *
-        * @since 2.5.0
-        *
-        * @see wp_ext2type()
-        *
-        * @param array $ext2type Multi-dimensional array with extensions for a default set
-        *                        of file types.
-        */
-       $ext2type = apply_filters( 'ext2type', array(
-               'image'       => array( 'jpg', 'jpeg', 'jpe',  'gif',  'png',  'bmp',   'tif',  'tiff', 'ico' ),
-               'audio'       => array( 'aac', 'ac3',  'aif',  'aiff', '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' ),
-               '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' ),
-       ) );
-
+       $ext2type = wp_get_ext_types();
        foreach ( $ext2type as $type => $exts )
                if ( in_array( $ext, $exts ) )
                        return $type;
-
-       return null;
 }
 
 /**
@@ -2049,7 +2215,7 @@ function wp_check_filetype( $filename, $mimes = null ) {
        $ext = false;
 
        foreach ( $mimes as $ext_preg => $mime_match ) {
-               $ext_preg = '!\.(' . $ext_preg . ')(\?.*)?$!i';
+               $ext_preg = '!\.(' . $ext_preg . ')$!i';
                if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
                        $type = $mime_match;
                        $ext = $ext_matches[1];
@@ -2080,7 +2246,6 @@ function wp_check_filetype( $filename, $mimes = null ) {
  *               if original $filename is valid.
  */
 function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
-
        $proper_filename = false;
 
        // Do basic extension validation and MIME mapping
@@ -2102,7 +2267,7 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
                // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME
                if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) {
                        /**
-                        * Filter the list mapping image mime types to their respective extensions.
+                        * Filters the list mapping image mime types to their respective extensions.
                         *
                         * @since 3.0.0
                         *
@@ -2135,7 +2300,7 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
        }
 
        /**
-        * Filter the "real" file type of the given file.
+        * Filters the "real" file type of the given file.
         *
         * @since 3.0.0
         *
@@ -2153,15 +2318,16 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
  * Retrieve list of mime types and file extensions.
  *
  * @since 3.5.0
+ * @since 4.2.0 Support was added for GIMP (xcf) files.
  *
  * @return array Array of mime types keyed by the file extension regex corresponding to those types.
  */
 function wp_get_mime_types() {
        /**
-        * Filter the list of mime types and file extensions.
+        * Filters the list of mime types and file extensions.
         *
         * This filter should be used to add, not remove, mime types. To remove
-        * mime types, use the 'upload_mimes' filter.
+        * mime types, use the {@see 'upload_mimes'} filter.
         *
         * @since 3.5.0
         *
@@ -2174,7 +2340,7 @@ function wp_get_mime_types() {
        'gif' => 'image/gif',
        'png' => 'image/png',
        'bmp' => 'image/bmp',
-       'tif|tiff' => 'image/tiff',
+       'tiff|tif' => 'image/tiff',
        'ico' => 'image/x-icon',
        // Video formats.
        'asf|asx' => 'video/x-ms-asf',
@@ -2224,6 +2390,7 @@ function wp_get_mime_types() {
        '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',
@@ -2269,6 +2436,39 @@ function wp_get_mime_types() {
        'pages' => 'application/vnd.apple.pages',
        ) );
 }
+
+/**
+ * Retrieves the list of common file extensions and their types.
+ *
+ * @since 4.6.0
+ *
+ * @return array Array of file extensions types keyed by the type of file.
+ */
+function wp_get_ext_types() {
+
+       /**
+        * Filters file type based on the extension name.
+        *
+        * @since 2.5.0
+        *
+        * @see wp_ext2type()
+        *
+        * @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', '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' ),
+       ) );
+}
+
 /**
  * Retrieve list of allowed mime types and file extensions.
  *
@@ -2289,7 +2489,7 @@ function get_allowed_mime_types( $user = null ) {
                unset( $t['htm|html'] );
 
        /**
-        * Filter list of allowed mime types and file extensions.
+        * Filters list of allowed mime types and file extensions.
         *
         * @since 2.0.0
         *
@@ -2341,7 +2541,7 @@ function wp_nonce_ays( $action ) {
  * @since 4.1.0 The `$title` and `$args` parameters were changed to optionally accept
  *              an integer to be used as the response code.
  *
- * @param string|WP_Error  $message Optional. Error message. If this is a {@see WP_Error} object,
+ * @param string|WP_Error  $message Optional. Error message. If this is a WP_Error object,
  *                                  the error's messages are used. Default empty.
  * @param string|int       $title   Optional. Error title. If `$message` is a `WP_Error` object,
  *                                  error data with the key 'title' may be used to specify the title.
@@ -2355,7 +2555,7 @@ function wp_nonce_ays( $action ) {
  *     @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 {@see is_rtl()}.
+ *                                  Default is the value of is_rtl().
  * }
  */
 function wp_die( $message = '', $title = '', $args = array() ) {
@@ -2369,29 +2569,29 @@ function wp_die( $message = '', $title = '', $args = array() ) {
 
        if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
                /**
-                * Filter callback for killing WordPress execution for AJAX requests.
+                * Filters the callback for killing WordPress execution for Ajax requests.
                 *
                 * @since 3.4.0
                 *
-                * @param callback $function Callback function name.
+                * @param callable $function Callback function name.
                 */
                $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
        } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
                /**
-                * Filter callback for killing WordPress execution for XML-RPC requests.
+                * Filters the callback for killing WordPress execution for XML-RPC requests.
                 *
                 * @since 3.4.0
                 *
-                * @param callback $function Callback function name.
+                * @param callable $function Callback function name.
                 */
                $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
        } else {
                /**
-                * Filter 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-XML-RPC requests.
                 *
                 * @since 3.0.0
                 *
-                * @param callback $function Callback function name.
+                * @param callable $function Callback function name.
                 */
                $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
        }
@@ -2400,10 +2600,10 @@ function wp_die( $message = '', $title = '', $args = array() ) {
 }
 
 /**
- * Kill WordPress execution and display HTML message with error message.
+ * 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 wp_die_handler filter in wp_die
+ * site then you can overload using the {@see 'wp_die_handler'} filter in wp_die().
  *
  * @since 3.0.0
  * @access private
@@ -2467,6 +2667,12 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) {
 <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'"; ?>>
 <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>
        <style type="text/css">
                html {
@@ -2475,7 +2681,7 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) {
                body {
                        background: #fff;
                        color: #444;
-                       font-family: "Open Sans", sans-serif;
+                       font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
                        margin: 2em auto;
                        padding: 1em 2em;
                        max-width: 700px;
@@ -2486,7 +2692,7 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) {
                        border-bottom: 1px solid #dadada;
                        clear: both;
                        color: #666;
-                       font: 24px "Open Sans", sans-serif;
+                       font-size: 24px;
                        margin: 30px 0 0 0;
                        padding: 0;
                        padding-bottom: 7px;
@@ -2507,15 +2713,25 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) {
                        font-size: 14px ;
                }
                a {
-                       color: #21759B;
-                       text-decoration: none;
+                       color: #0073aa;
+               }
+               a:hover,
+               a:active {
+                       color: #00a0d2;
                }
-               a:hover {
-                       color: #D54E21;
+               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);
+                       outline: none;
                }
                .button {
                        background: #f7f7f7;
-                       border: 1px solid #cccccc;
+                       border: 1px solid #ccc;
                        color: #555;
                        display: inline-block;
                        text-decoration: none;
@@ -2533,40 +2749,46 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) {
                        -moz-box-sizing:    border-box;
                        box-sizing:         border-box;
 
-                       -webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
-                       box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
+                       -webkit-box-shadow: 0 1px 0 #ccc;
+                       box-shadow: 0 1px 0 #ccc;
                        vertical-align: top;
                }
 
                .button.button-large {
-                       height: 29px;
+                       height: 30px;
                        line-height: 28px;
-                       padding: 0 12px;
+                       padding: 0 12px 2px;
                }
 
                .button:hover,
                .button:focus {
                        background: #fafafa;
                        border-color: #999;
-                       color: #222;
+                       color: #23282d;
                }
 
                .button:focus  {
-                       -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,.2);
-                       box-shadow: 1px 1px 1px rgba(0,0,0,.2);
+                       border-color: #5b9dd9;
+                       -webkit-box-shadow: 0 0 3px rgba( 0, 115, 170, .8 );
+                       box-shadow: 0 0 3px rgba( 0, 115, 170, .8 );
+                       outline: none;
                }
 
                .button:active {
                        background: #eee;
                        border-color: #999;
-                       color: #333;
-                       -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
+                       -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 if ( 'rtl' == $text_direction ) : ?>
-               body { font-family: Tahoma, Arial; }
-               <?php endif; ?>
+               <?php
+               if ( 'rtl' == $text_direction ) {
+                       echo 'body { font-family: Tahoma, Arial; }';
+               }
+               ?>
        </style>
 </head>
 <body id="error-page">
@@ -2586,6 +2808,8 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) {
  * @since 3.2.0
  * @access private
  *
+ * @global wp_xmlrpc_server $wp_xmlrpc_server
+ *
  * @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.
@@ -2644,7 +2868,7 @@ function _scalar_wp_die_handler( $message = '' ) {
  * @param int   $options Optional. Options to be passed to json_encode(). Default 0.
  * @param int   $depth   Optional. Maximum depth to walk through $data. Must be
  *                       greater than 0. Default 512.
- * @return bool|string The JSON encoded string, or false if it cannot be encoded.
+ * @return string|false The JSON encoded string, or false if it cannot be encoded.
  */
 function wp_json_encode( $data, $options = 0, $depth = 512 ) {
        /*
@@ -2660,7 +2884,10 @@ function wp_json_encode( $data, $options = 0, $depth = 512 ) {
                $args = array( $data );
        }
 
-       $json = call_user_func_array( 'json_encode', $args );
+       // Prepare the data for JSON serialization.
+       $args[0] = _wp_json_prepare_data( $data );
+
+       $json = @call_user_func_array( 'json_encode', $args );
 
        // 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
@@ -2681,11 +2908,11 @@ function wp_json_encode( $data, $options = 0, $depth = 512 ) {
 /**
  * Perform sanity checks on data that shall be encoded to JSON.
  *
- * @see wp_json_encode()
- *
+ * @ignore
  * @since 4.1.0
  * @access private
- * @internal
+ *
+ * @see wp_json_encode()
  *
  * @param mixed $data  Variable (usually an array or object) to encode as JSON.
  * @param int   $depth Maximum depth to walk through $data. Must be greater than 0.
@@ -2744,11 +2971,13 @@ function _wp_json_sanity_check( $data, $depth ) {
 /**
  * Convert a string to UTF-8, so that it can be safely encoded to JSON.
  *
- * @see _wp_json_sanity_check()
- *
+ * @ignore
  * @since 4.1.0
  * @access private
- * @internal
+ *
+ * @see _wp_json_sanity_check()
+ *
+ * @staticvar bool $use_mb
  *
  * @param string $string The string which is to be converted.
  * @return string The checked string.
@@ -2771,6 +3000,56 @@ function _wp_json_convert_string( $string ) {
        }
 }
 
+/**
+ * Prepares response data to be serialized to JSON.
+ *
+ * This supports the JsonSerializable interface for PHP 5.2-5.3 as well.
+ *
+ * @ignore
+ * @since 4.4.0
+ * @access private
+ *
+ * @param mixed $data Native representation.
+ * @return bool|int|float|null|string|array Data ready for `json_encode()`.
+ */
+function _wp_json_prepare_data( $data ) {
+       if ( ! defined( 'WP_JSON_SERIALIZE_COMPATIBLE' ) || WP_JSON_SERIALIZE_COMPATIBLE === false ) {
+               return $data;
+       }
+
+       switch ( gettype( $data ) ) {
+               case 'boolean':
+               case 'integer':
+               case 'double':
+               case 'string':
+               case 'NULL':
+                       // These values can be passed through.
+                       return $data;
+
+               case 'array':
+                       // Arrays must be mapped in case they also return objects.
+                       return array_map( '_wp_json_prepare_data', $data );
+
+               case 'object':
+                       // If this is an incomplete object (__PHP_Incomplete_Class), bail.
+                       if ( ! is_object( $data ) ) {
+                               return null;
+                       }
+
+                       if ( $data instanceof JsonSerializable ) {
+                               $data = $data->jsonSerialize();
+                       } else {
+                               $data = get_object_vars( $data );
+                       }
+
+                       // Now, pass the array (or whatever was returned from jsonSerialize through).
+                       return _wp_json_prepare_data( $data );
+
+               default:
+                       return null;
+       }
+}
+
 /**
  * Send a JSON response back to an Ajax request.
  *
@@ -2807,14 +3086,13 @@ function wp_send_json_success( $data = null ) {
 /**
  * Send a JSON response back to an Ajax request, indicating failure.
  *
- * If the `$data` parameter is a {@see WP_Error} object, the errors
+ * If the `$data` parameter is a WP_Error object, the errors
  * within the object are processed and output as an array of error
  * codes and corresponding messages. All other types are output
  * without further processing.
  *
  * @since 3.5.0
- * @since 4.1.0 The `$data` parameter is now processed if a {@see WP_Error}
- *              object is passed in.
+ * @since 4.1.0 The `$data` parameter is now processed if a WP_Error object is passed in.
  *
  * @param mixed $data Data to encode as JSON, then print and die.
  */
@@ -2839,6 +3117,28 @@ function wp_send_json_error( $data = null ) {
        wp_send_json( $response );
 }
 
+/**
+ * Checks that a JSONP callback is a valid JavaScript callback.
+ *
+ * Only allows alphanumeric characters and the dot character in callback
+ * function names. This helps to mitigate XSS attacks caused by directly
+ * outputting user input.
+ *
+ * @since 4.6.0
+ *
+ * @param string $callback Supplied JSONP callback function.
+ * @return bool True if valid callback, otherwise false.
+ */
+function wp_check_jsonp_callback( $callback ) {
+       if ( ! is_string( $callback ) ) {
+               return false;
+       }
+
+       $jsonp_callback = preg_replace( '/[^\w\.]/', '', $callback, -1, $illegal_char_count );
+
+       return 0 === $illegal_char_count;
+}
+
 /**
  * Retrieve the WordPress home page URL.
  *
@@ -2890,22 +3190,29 @@ function _config_wp_siteurl( $url = '' ) {
  * Fills in the 'directionality' setting, enables the 'directionality'
  * plugin, and adds the 'ltr' button to 'toolbar1', formerly
  * 'theme_advanced_buttons1' array keys. These keys are then returned
- * in the $input (TinyMCE settings) array.
+ * in the $mce_init (TinyMCE settings) array.
  *
  * @since 2.1.0
  * @access private
  *
- * @param array $input MCE settings array.
+ * @param array $mce_init MCE settings array.
  * @return array Direction set for 'rtl', if needed by locale.
  */
-function _mce_set_direction( $input ) {
+function _mce_set_direction( $mce_init ) {
        if ( is_rtl() ) {
-               $input['directionality'] = 'rtl';
-               $input['plugins'] .= ',directionality';
-               $input['toolbar1'] .= ',ltr';
+               $mce_init['directionality'] = 'rtl';
+               $mce_init['rtl_ui'] = true;
+
+               if ( ! empty( $mce_init['plugins'] ) && strpos( $mce_init['plugins'], 'directionality' ) === false ) {
+                       $mce_init['plugins'] .= ',directionality';
+               }
+
+               if ( ! empty( $mce_init['toolbar1'] ) && ! preg_match( '/\bltr\b/', $mce_init['toolbar1'] ) ) {
+                       $mce_init['toolbar1'] .= ',ltr';
+               }
        }
 
-       return $input;
+       return $mce_init;
 }
 
 
@@ -2940,51 +3247,51 @@ function smilies_init() {
 
        if ( !isset( $wpsmiliestrans ) ) {
                $wpsmiliestrans = array(
-               ':mrgreen:' => 'icon_mrgreen.gif',
-               ':neutral:' => 'icon_neutral.gif',
-               ':twisted:' => 'icon_twisted.gif',
-                 ':arrow:' => 'icon_arrow.gif',
-                 ':shock:' => 'icon_eek.gif',
-                 ':smile:' => 'icon_smile.gif',
-                   ':???:' => 'icon_confused.gif',
-                  ':cool:' => 'icon_cool.gif',
-                  ':evil:' => 'icon_evil.gif',
-                  ':grin:' => 'icon_biggrin.gif',
-                  ':idea:' => 'icon_idea.gif',
-                  ':oops:' => 'icon_redface.gif',
-                  ':razz:' => 'icon_razz.gif',
-                  ':roll:' => 'icon_rolleyes.gif',
-                  ':wink:' => 'icon_wink.gif',
-                   ':cry:' => 'icon_cry.gif',
-                   ':eek:' => 'icon_surprised.gif',
-                   ':lol:' => 'icon_lol.gif',
-                   ':mad:' => 'icon_mad.gif',
-                   ':sad:' => 'icon_sad.gif',
-                     '8-)' => 'icon_cool.gif',
-                     '8-O' => 'icon_eek.gif',
-                     ':-(' => 'icon_sad.gif',
-                     ':-)' => 'icon_smile.gif',
-                     ':-?' => 'icon_confused.gif',
-                     ':-D' => 'icon_biggrin.gif',
-                     ':-P' => 'icon_razz.gif',
-                     ':-o' => 'icon_surprised.gif',
-                     ':-x' => 'icon_mad.gif',
-                     ':-|' => 'icon_neutral.gif',
-                     ';-)' => 'icon_wink.gif',
+               ':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)' => 'icon_cool.gif',
-                      '8O' => 'icon_eek.gif',
-                      ':(' => 'icon_sad.gif',
-                      ':)' => 'icon_smile.gif',
-                      ':?' => 'icon_confused.gif',
-                      ':D' => 'icon_biggrin.gif',
-                      ':P' => 'icon_razz.gif',
-                      ':o' => 'icon_surprised.gif',
-                      ':x' => 'icon_mad.gif',
-                      ':|' => 'icon_neutral.gif',
-                      ';)' => 'icon_wink.gif',
-                     ':!:' => 'icon_exclaim.gif',
-                     ':?:' => 'icon_question.gif',
+               //     '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",
                );
        }
 
@@ -3085,6 +3392,24 @@ function wp_array_slice_assoc( $array, $keys ) {
        return $slice;
 }
 
+/**
+ * Determines if the variable is a numeric-indexed array.
+ *
+ * @since 4.4.0
+ *
+ * @param mixed $data Variable to check.
+ * @return bool Whether the variable is a list.
+ */
+function wp_is_numeric_array( $data ) {
+       if ( ! is_array( $data ) ) {
+               return false;
+       }
+
+       $keys = array_keys( $data );
+       $string_keys = array_filter( $keys, 'is_string' );
+       return count( $string_keys ) === 0;
+}
+
 /**
  * Filters a list of objects, based on a set of key => value arguments.
  *
@@ -3095,7 +3420,8 @@ function wp_array_slice_assoc( $array, $keys ) {
  *                              against each object. Default empty array.
  * @param string      $operator Optional. The logical operation to perform. 'or' means
  *                              only one element from the array needs to match; 'and'
- *                              means all elements must match. Default 'and'.
+ *                              means all elements must match; 'not' means no elements may
+ *                              match. Default 'and'.
  * @param bool|string $field    A field from the object to place instead of the entire object.
  *                              Default false.
  * @return array A list of objects or object fields.
@@ -3169,8 +3495,9 @@ function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
  * @param int|string $field     Field from the object to place instead of the entire object
  * @param int|string $index_key Optional. Field from the object to use as keys for the new array.
  *                              Default null.
- * @return array Array of found values. If $index_key is set, an array of found values with keys
- *               corresponding to $index_key.
+ * @return array Array of found values. If `$index_key` is set, an array of found values with keys
+ *               corresponding to `$index_key`. If `$index_key` is null, array keys from the original
+ *               `$list` will be preserved in the results.
  */
 function wp_list_pluck( $list, $field, $index_key = null ) {
        if ( ! $index_key ) {
@@ -3222,7 +3549,7 @@ function wp_list_pluck( $list, $field, $index_key = null ) {
  */
 function wp_maybe_load_widgets() {
        /**
-        * Filter whether to load the Widgets library.
+        * Filters whether to load the Widgets library.
         *
         * Passing a falsey value to the filter will effectively short-circuit
         * the Widgets library from loading.
@@ -3245,6 +3572,8 @@ function wp_maybe_load_widgets() {
  * Append the Widgets menu to the themes main menu.
  *
  * @since 2.2.0
+ *
+ * @global array $submenu
  */
 function wp_widgets_add_menu() {
        global $submenu;
@@ -3299,7 +3628,7 @@ function dead_db() {
        }
 
        // If installing or in the admin, provide the verbose message.
-       if ( defined('WP_INSTALLING') || defined('WP_ADMIN') )
+       if ( wp_installing() || defined( 'WP_ADMIN' ) )
                wp_die($wpdb->error);
 
        // Otherwise, be terse.
@@ -3337,11 +3666,11 @@ function absint( $maybeint ) {
 /**
  * Mark a function as deprecated and inform when it has been used.
  *
- * There is a hook deprecated_function_run that will be called that can be used
+ * There is a {@see 'hook deprecated_function_run'} that will be called that can be used
  * to get the backtrace up to what file and function called the deprecated
  * function.
  *
- * The current behavior is to trigger a user error if WP_DEBUG is true.
+ * The current behavior is to trigger a user error if `WP_DEBUG` is true.
  *
  * This function is to be used in every function that is deprecated.
  *
@@ -3366,7 +3695,7 @@ function _deprecated_function( $function, $version, $replacement = null ) {
        do_action( 'deprecated_function_run', $function, $replacement, $version );
 
        /**
-        * Filter whether to trigger an error for deprecated functions.
+        * Filters whether to trigger an error for deprecated functions.
         *
         * @since 2.5.0
         *
@@ -3387,14 +3716,81 @@ function _deprecated_function( $function, $version, $replacement = null ) {
        }
 }
 
+/**
+ * Marks a constructor as deprecated and informs when it has been used.
+ *
+ * Similar to _deprecated_function(), but with different strings. Used to
+ * remove PHP4 style constructors.
+ *
+ * The current behavior is to trigger a user error if `WP_DEBUG` is true.
+ *
+ * This function is to be used in every PHP4 style constructor method that is deprecated.
+ *
+ * @since 4.3.0
+ * @since 4.5.0 Added the `$parent_class` parameter.
+ *
+ * @access private
+ *
+ * @param string $class        The class containing the deprecated constructor.
+ * @param string $version      The version of WordPress that deprecated the function.
+ * @param string $parent_class Optional. The parent class calling the deprecated constructor.
+ *                             Default empty string.
+ */
+function _deprecated_constructor( $class, $version, $parent_class = '' ) {
+
+       /**
+        * Fires when a deprecated constructor is called.
+        *
+        * @since 4.3.0
+        * @since 4.5.0 Added the `$parent_class` parameter.
+        *
+        * @param string $class        The class containing the deprecated constructor.
+        * @param string $version      The version of WordPress that deprecated the function.
+        * @param string $parent_class The parent class calling the deprecated constructor.
+        */
+       do_action( 'deprecated_constructor_run', $class, $version, $parent_class );
+
+       /**
+        * Filters whether to trigger an error for deprecated functions.
+        *
+        * `WP_DEBUG` must be true in addition to the filter evaluating to true.
+        *
+        * @since 4.3.0
+        *
+        * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
+        */
+       if ( WP_DEBUG && apply_filters( 'deprecated_constructor_trigger_error', true ) ) {
+               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>' ) );
+                       } 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>' ) );
+                       }
+               } 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>' ) );
+                       } 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>' ) );
+                       }
+               }
+       }
+
+}
+
 /**
  * Mark a file as deprecated and inform when it has been used.
  *
- * There is a hook deprecated_file_included that will be called that can be used
+ * There is a hook {@see 'deprecated_file_included'} that will be called that can be used
  * to get the backtrace up to what file and function included the deprecated
  * file.
  *
- * The current behavior is to trigger a user error if WP_DEBUG is true.
+ * The current behavior is to trigger a user error if `WP_DEBUG` is true.
  *
  * This function is to be used in every file that is deprecated.
  *
@@ -3422,7 +3818,7 @@ function _deprecated_file( $file, $version, $replacement = null, $message = '' )
        do_action( 'deprecated_file_included', $file, $replacement, $version, $message );
 
        /**
-        * Filter whether to trigger an error for deprecated files.
+        * Filters whether to trigger an error for deprecated files.
         *
         * @since 2.5.0
         *
@@ -3452,7 +3848,7 @@ function _deprecated_file( $file, $version, $replacement = null, $message = '' )
  * For example:
  *
  *     if ( ! empty( $deprecated ) ) {
- *         _deprecated_argument( __FUNCTION__, '3.0' );
+ *         _deprecated_argument( __FUNCTION__, '3.0.0' );
  *     }
  *
  *
@@ -3483,7 +3879,7 @@ function _deprecated_argument( $function, $version, $message = null ) {
        do_action( 'deprecated_argument_run', $function, $message, $version );
 
        /**
-        * Filter whether to trigger an error for deprecated arguments.
+        * Filters whether to trigger an error for deprecated arguments.
         *
         * @since 3.0.0
         *
@@ -3504,14 +3900,64 @@ function _deprecated_argument( $function, $version, $message = null ) {
        }
 }
 
+/**
+ * Marks a deprecated action or filter hook as deprecated and throws a notice.
+ *
+ * Use the {@see 'deprecated_hook_run'} action to get the backtrace describing where
+ * the deprecated hook was called.
+ *
+ * Default behavior is to trigger a user error if `WP_DEBUG` is true.
+ *
+ * This function is called by the do_action_deprecated() and apply_filters_deprecated()
+ * functions, and so generally does not need to be called directly.
+ *
+ * @since 4.6.0
+ * @access private
+ *
+ * @param string $hook        The hook that was used.
+ * @param string $version     The version of WordPress that deprecated the hook.
+ * @param string $replacement Optional. The hook that should have been used.
+ * @param string $message     Optional. A message regarding the change.
+ */
+function _deprecated_hook( $hook, $version, $replacement = null, $message = null ) {
+       /**
+        * Fires when a deprecated hook is called.
+        *
+        * @since 4.6.0
+        *
+        * @param string $hook        The hook that was called.
+        * @param string $replacement The hook that should be used as a replacement.
+        * @param string $version     The version of WordPress that deprecated the argument used.
+        * @param string $message     A message regarding the change.
+        */
+       do_action( 'deprecated_hook_run', $hook, $replacement, $version, $message );
+
+       /**
+        * Filters whether to trigger deprecated hook errors.
+        *
+        * @since 4.6.0
+        *
+        * @param bool $trigger Whether to trigger deprecated hook errors. Requires
+        *                      `WP_DEBUG` to be defined true.
+        */
+       if ( WP_DEBUG && apply_filters( 'deprecated_hook_trigger_error', true ) ) {
+               $message = empty( $message ) ? '' : ' ' . $message;
+               if ( ! is_null( $replacement ) ) {
+                       trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ), $hook, $version, $replacement ) . $message );
+               } else {
+                       trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ), $hook, $version ) . $message );
+               }
+       }
+}
+
 /**
  * Mark something as being incorrectly called.
  *
- * There is a hook doing_it_wrong_run that will be called that can be used
+ * There is a hook {@see 'doing_it_wrong_run'} that will be called that can be used
  * to get the backtrace up to what file and function called the deprecated
  * function.
  *
- * The current behavior is to trigger a user error if WP_DEBUG is true.
+ * The current behavior is to trigger a user error if `WP_DEBUG` is true.
  *
  * @since 3.1.0
  * @access private
@@ -3534,7 +3980,7 @@ function _doing_it_wrong( $function, $message, $version ) {
        do_action( 'doing_it_wrong_run', $function, $message, $version );
 
        /**
-        * Filter whether to trigger an error for _doing_it_wrong() calls.
+        * Filters whether to trigger an error for _doing_it_wrong() calls.
         *
         * @since 3.1.0
         *
@@ -3543,11 +3989,16 @@ function _doing_it_wrong( $function, $message, $version ) {
        if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
                if ( function_exists( '__' ) ) {
                        $version = is_null( $version ) ? '' : sprintf( __( '(This message was added in version %s.)' ), $version );
-                       $message .= ' ' . __( 'Please see <a href="http://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.' );
+                       /* translators: %s: Codex URL */
+                       $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 ) );
                } else {
                        $version = is_null( $version ) ? '' : sprintf( '(This message was added in version %s.)', $version );
-                       $message .= ' Please see <a href="http://codex.wordpress.org/Debugging_in_WordPress">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 ) );
                }
        }
@@ -3571,6 +4022,8 @@ function is_lighttpd_before_150() {
  *
  * @since 2.5.0
  *
+ * @global bool $is_apache
+ *
  * @param string $mod     The module, e.g. mod_rewrite.
  * @param bool   $default Optional. The default return value if the module is not found. Default false.
  * @return bool Whether the specified module is loaded.
@@ -3600,6 +4053,8 @@ function apache_mod_loaded($mod, $default = false) {
  *
  * @since 2.8.0
  *
+ * @global bool $is_iis7
+ *
  * @return bool Whether IIS7 supports permalinks.
  */
 function iis7_supports_permalinks() {
@@ -3616,11 +4071,11 @@ function iis7_supports_permalinks() {
                 * 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') && isset($_SERVER['IIS_UrlRewriteModule']) && ( php_sapi_name() == 'cgi-fcgi' );
+               $supports_permalinks = class_exists( 'DOMDocument', false ) && isset($_SERVER['IIS_UrlRewriteModule']) && ( PHP_SAPI == 'cgi-fcgi' );
        }
 
        /**
-        * Filter whether IIS 7+ supports pretty permalinks.
+        * Filters whether IIS 7+ supports pretty permalinks.
         *
         * @since 2.8.0
         *
@@ -3640,7 +4095,7 @@ function iis7_supports_permalinks() {
  * @since 1.2.0
  *
  * @param string $file File path.
- * @param array $allowed_files List of allowed files.
+ * @param array  $allowed_files List of allowed files.
  * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
  */
 function validate_file( $file, $allowed_files = '' ) {
@@ -3659,44 +4114,13 @@ function validate_file( $file, $allowed_files = '' ) {
        return 0;
 }
 
-/**
- * Determine if SSL is used.
- *
- * @since 2.6.0
- *
- * @return bool True if SSL, false if not used.
- */
-function is_ssl() {
-       if ( isset($_SERVER['HTTPS']) ) {
-               if ( 'on' == strtolower($_SERVER['HTTPS']) )
-                       return true;
-               if ( '1' == $_SERVER['HTTPS'] )
-                       return true;
-       } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
-               return true;
-       }
-       return false;
-}
-
-/**
- * Whether SSL login should be forced.
- *
- * @since 2.6.0
- *
- * @see force_ssl_admin()
- *
- * @param string|bool $force Optional Whether to force SSL login. Default null.
- * @return bool True if forced, false if not forced.
- */
-function force_ssl_login( $force = null ) {
-       return force_ssl_admin( $force );
-}
-
 /**
  * Whether to force SSL used for the Administration Screens.
  *
  * @since 2.6.0
  *
+ * @staticvar bool $forced
+ *
  * @param string|bool $force Optional. Whether to force SSL in admin screens. Default null.
  * @return bool True if forced, false if not forced.
  */
@@ -3742,7 +4166,7 @@ function wp_guess_url() {
                        if ( false !== strpos( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
                                // Request is hitting a file inside ABSPATH
                                $directory = str_replace( ABSPATH, '', $script_filename_dir );
-                               // Strip off the sub directory, and any file/query paramss
+                               // Strip off the sub directory, and any file/query params
                                $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
@@ -3773,6 +4197,8 @@ function wp_guess_url() {
  *
  * @since 3.3.0
  *
+ * @staticvar bool $_suspend
+ *
  * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
  * @return bool The current suspend setting
  */
@@ -3794,6 +4220,8 @@ function wp_suspend_cache_addition( $suspend = null ) {
  *
  * @since 2.7.0
  *
+ * @global bool $_wp_suspend_cache_invalidation
+ *
  * @param bool $suspend Optional. Whether to suspend or enable cache invalidation. Default true.
  * @return bool The current suspend setting.
  */
@@ -3810,8 +4238,9 @@ function wp_suspend_cache_invalidation( $suspend = true ) {
  *
  * @since 3.0.0
  *
+ * @global object $current_site
+ *
  * @param int $site_id Optional. Site ID to test. Defaults to current site.
- *                     Defaults to current site.
  * @return bool True if $site_id is the main site of the network, or if not
  *              running Multisite.
  */
@@ -3837,32 +4266,61 @@ function is_main_site( $site_id = null ) {
  * @return bool True if $network_id is the main network, or if not running Multisite.
  */
 function is_main_network( $network_id = null ) {
-       global $wpdb;
-
-       if ( ! is_multisite() )
+       if ( ! is_multisite() ) {
                return true;
+       }
 
        $current_network_id = (int) get_current_site()->id;
 
-       if ( ! $network_id )
+       if ( null === $network_id ) {
                $network_id = $current_network_id;
+       }
+
        $network_id = (int) $network_id;
 
-       if ( defined( 'PRIMARY_NETWORK_ID' ) )
-               return $network_id === (int) PRIMARY_NETWORK_ID;
+       return ( $network_id === get_main_network_id() );
+}
 
-       if ( 1 === $current_network_id )
-               return $network_id === $current_network_id;
+/**
+ * Get the main network ID.
+ *
+ * @since 4.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @return int The ID of the main network.
+ */
+function get_main_network_id() {
+       global $wpdb;
+
+       if ( ! is_multisite() ) {
+               return 1;
+       }
 
-       $primary_network_id = (int) wp_cache_get( 'primary_network_id', 'site-options' );
+       $current_site = get_current_site();
 
-       if ( $primary_network_id )
-               return $network_id === $primary_network_id;
+       if ( defined( 'PRIMARY_NETWORK_ID' ) ) {
+               $main_network_id = PRIMARY_NETWORK_ID;
+       } elseif ( isset( $current_site->id ) && 1 === (int) $current_site->id ) {
+               // If the current network has an ID of 1, assume it is the main network.
+               $main_network_id = 1;
+       } else {
+               $main_network_id = wp_cache_get( 'primary_network_id', 'site-options' );
 
-       $primary_network_id = (int) $wpdb->get_var( "SELECT id FROM $wpdb->site ORDER BY id LIMIT 1" );
-       wp_cache_add( 'primary_network_id', $primary_network_id, 'site-options' );
+               if ( false === $main_network_id ) {
+                       $main_network_id = (int) $wpdb->get_var( "SELECT id FROM {$wpdb->site} ORDER BY id LIMIT 1" );
+                       wp_cache_add( 'primary_network_id', $main_network_id, 'site-options' );
+               }
+       }
 
-       return $network_id === $primary_network_id;
+       /**
+        * Filters the main network ID.
+        *
+        * @since 4.3.0
+        *
+        * @param int $main_network_id The ID of the main network.
+        */
+       return (int) apply_filters( 'get_main_network_id', $main_network_id );
 }
 
 /**
@@ -3870,6 +4328,8 @@ function is_main_network( $network_id = null ) {
  *
  * @since 3.0.0
  *
+ * @staticvar bool $global_terms
+ *
  * @return bool True if multisite and global terms enabled.
  */
 function global_terms_enabled() {
@@ -3880,14 +4340,14 @@ function global_terms_enabled() {
        if ( is_null( $global_terms ) ) {
 
                /**
-                * Filter whether global terms are enabled.
+                * Filters whether global terms are enabled.
                 *
                 * Passing a non-null value to the filter will effectively short-circuit the function,
                 * returning the value of the 'global_terms_enabled' site option instead.
                 *
                 * @since 3.0.0
                 *
-                * @param null $anbled Whether global terms are enabled.
+                * @param null $enabled Whether global terms are enabled.
                 */
                $filter = apply_filters( 'global_terms_enabled', null );
                if ( ! is_null( $filter ) )
@@ -3905,7 +4365,7 @@ function global_terms_enabled() {
  *
  * @since 2.8.0
  *
- * @return float|bool Timezone GMT offset, false otherwise.
+ * @return float|false Timezone GMT offset, false otherwise.
  */
 function wp_timezone_override_offset() {
        if ( !$timezone_string = get_option( 'timezone_string' ) ) {
@@ -3973,6 +4433,8 @@ function _wp_timezone_choice_usort_callback( $a, $b ) {
  *
  * @since 2.9.0
  *
+ * @staticvar bool $mo_loaded
+ *
  * @param string $selected_zone Selected timezone.
  * @return string
  */
@@ -4113,10 +4575,14 @@ function _cleanup_header_comment( $str ) {
 }
 
 /**
- * Permanently delete posts, pages, attachments, and comments which have been
- * in the trash for EMPTY_TRASH_DAYS.
+ * Permanently delete comments or posts of any type that have held a status
+ * of 'trash' for the number of days defined in EMPTY_TRASH_DAYS.
+ *
+ * The default value of `EMPTY_TRASH_DAYS` is 30 (days).
  *
  * @since 2.9.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
  */
 function wp_scheduled_delete() {
        global $wpdb;
@@ -4153,7 +4619,7 @@ function wp_scheduled_delete() {
                        delete_comment_meta($comment_id, '_wp_trash_meta_time');
                        delete_comment_meta($comment_id, '_wp_trash_meta_status');
                } else {
-                       wp_delete_comment($comment_id);
+                       wp_delete_comment( $del_comment );
                }
        }
 }
@@ -4168,13 +4634,13 @@ function wp_scheduled_delete() {
  * If the file data is not within that first 8kiB, then the author should correct
  * their plugin file and move the data headers to the top.
  *
- * @link http://codex.wordpress.org/File_Header
+ * @link https://codex.wordpress.org/File_Header
  *
  * @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 $context         Optional. If specified adds filter hook "extra_{$context}_headers".
+ * @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.
  */
@@ -4192,7 +4658,7 @@ function get_file_data( $file, $default_headers, $context = '' ) {
        $file_data = str_replace( "\r", "\n", $file_data );
 
        /**
-        * Filter extra file headers by context.
+        * Filters extra file headers by context.
         *
         * The dynamic portion of the hook name, `$context`, refers to
         * the context where extra headers might be loaded.
@@ -4227,7 +4693,7 @@ function get_file_data( $file, $default_headers, $context = '' ) {
  *
  * @see __return_false()
  *
- * @return bool True.
+ * @return true True.
  */
 function __return_true() {
        return true;
@@ -4242,7 +4708,7 @@ function __return_true() {
  *
  * @see __return_true()
  *
- * @return bool False.
+ * @return false False.
  */
 function __return_false() {
        return false;
@@ -4307,8 +4773,8 @@ function __return_empty_string() {
  *
  * @since 3.0.0
  *
- * @see http://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
- * @see http://src.chromium.org/viewvc/chrome?view=rev&revision=6985
+ * @see https://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
+ * @see https://src.chromium.org/viewvc/chrome?view=rev&revision=6985
  */
 function send_nosniff_header() {
        @header( 'X-Content-Type-Options: nosniff' );
@@ -4317,7 +4783,7 @@ function send_nosniff_header() {
 /**
  * Return a MySQL expression for selecting the week number based on the start_of_week option.
  *
- * @internal
+ * @ignore
  * @since 3.0.0
  *
  * @param string $column Database column.
@@ -4345,7 +4811,7 @@ function _wp_mysql_week( $column ) {
  * @since 3.1.0
  * @access private
  *
- * @param callback $callback      Function that accepts ( ID, $callback_args ) and outputs parent_ID.
+ * @param callable $callback      Function that accepts ( ID, $callback_args ) and outputs parent_ID.
  * @param int      $start         The ID to start the loop check at.
  * @param int      $start_parent  The parent_ID of $start to use instead of calling $callback( $start ).
  *                                Use null to always use $callback
@@ -4370,7 +4836,7 @@ function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_arg
  * @since 3.1.0
  * @access private
  *
- * @param callback $callback      Function that accepts ( ID, callback_arg, ... ) and outputs parent_ID.
+ * @param callable $callback      Function that accepts ( ID, callback_arg, ... ) and outputs parent_ID.
  * @param int      $start         The ID to start the loop check at.
  * @param array    $override      Optional. An array of ( ID => parent_ID, ... ) to use instead of $callback.
  *                                Default empty array.
@@ -4423,20 +4889,25 @@ function send_frame_options_header() {
  * Retrieve a list of protocols to allow in HTML attributes.
  *
  * @since 3.3.0
+ * @since 4.3.0 Added 'webcal' to the protocols array.
  *
  * @see wp_kses()
  * @see esc_url()
  *
- * @return array Array of allowed protocols.
+ * @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', and 'webcal'.
  */
 function wp_allowed_protocols() {
-       static $protocols;
+       static $protocols = array();
 
        if ( empty( $protocols ) ) {
-               $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp' );
+               $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal' );
 
                /**
-                * Filter the list of protocols allowed in HTML attributes.
+                * Filters the list of protocols allowed in HTML attributes.
                 *
                 * @since 3.0.0
                 *
@@ -4528,7 +4999,7 @@ function _get_non_cached_ids( $object_ids, $cache_key ) {
  * @since 3.4.0
  * @access private
  *
- * @return bool true|false Whether the device is able to upload files.
+ * @return bool Whether the device is able to upload files.
  */
 function _device_can_upload() {
        if ( ! wp_is_mobile() )
@@ -4573,7 +5044,7 @@ function wp_is_stream( $path ) {
  */
 function wp_checkdate( $month, $day, $year, $source_date ) {
        /**
-        * Filter whether the given date is valid for the Gregorian calendar.
+        * Filters whether the given date is valid for the Gregorian calendar.
         *
         * @since 3.5.0
         *
@@ -4589,7 +5060,7 @@ function wp_checkdate( $month, $day, $year, $source_date ) {
  * Can be disabled with remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
  *
  * This is disabled for certain screens where a login screen could cause an
- * inconvenient interruption. A filter called wp_auth_check_load can be used
+ * inconvenient interruption. A filter called {@see 'wp_auth_check_load'} can be used
  * for fine-grained control.
  *
  * @since 3.6.0
@@ -4606,7 +5077,7 @@ function wp_auth_check_load() {
        $show = ! in_array( $screen->id, $hidden );
 
        /**
-        * Filter whether to load the authentication check.
+        * Filters whether to load the authentication check.
         *
         * Passing a falsey value to the filter will effectively short-circuit
         * loading the authentication check.
@@ -4636,7 +5107,7 @@ function wp_auth_check_html() {
        $same_domain = ( strpos( $login_url, $current_domain ) === 0 );
 
        /**
-        * Filter whether the authentication check originated at the same domain.
+        * Filters whether the authentication check originated at the same domain.
         *
         * @since 3.6.0
         *
@@ -4649,12 +5120,12 @@ function wp_auth_check_html() {
        <div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
        <div id="wp-auth-check-bg"></div>
        <div id="wp-auth-check">
-       <div class="wp-auth-check-close" tabindex="0" title="<?php esc_attr_e('Close'); ?>"></div>
+       <button type="button" class="wp-auth-check-close button-link"><span class="screen-reader-text"><?php _e( 'Close dialog' ); ?></span></button>
        <?php
 
        if ( $same_domain ) {
                ?>
-               <div id="wp-auth-check-form" data-src="<?php echo esc_url( add_query_arg( array( 'interim-login' => 1 ), $login_url ) ); ?>"></div>
+               <div id="wp-auth-check-form" class="loading" data-src="<?php echo esc_url( add_query_arg( array( 'interim-login' => 1 ), $login_url ) ); ?>"></div>
                <?php
        }
 
@@ -4677,9 +5148,10 @@ function wp_auth_check_html() {
  *
  * @since 3.6.0
  *
- * @param array|object $response  The Heartbeat response object or array.
- * @return array|object $response The Heartbeat response object or array with 'wp-auth-check'
- *                                value set.
+ * @global int $login_grace_period
+ *
+ * @param array $response  The Heartbeat response.
+ * @return array $response The Heartbeat response with 'wp-auth-check' value set.
  */
 function wp_auth_check( $response ) {
        $response['wp-auth-check'] = is_user_logged_in() && empty( $GLOBALS['login_grace_period'] );
@@ -4752,6 +5224,9 @@ function _canonical_charset( $charset ) {
  *
  * @see reset_mbstring_encoding()
  *
+ * @staticvar array $encodings
+ * @staticvar bool  $overloaded
+ *
  * @param bool $reset Optional. Whether to reset the encoding back to a previously-set encoding.
  *                    Default false.
  */
@@ -4809,3 +5284,183 @@ function wp_validate_boolean( $var ) {
 
        return (bool) $var;
 }
+
+/**
+ * Delete a file
+ *
+ * @since 4.2.0
+ *
+ * @param string $file The path to the file to delete.
+ */
+function wp_delete_file( $file ) {
+       /**
+        * Filters the path of the file to delete.
+        *
+        * @since 2.1.0
+        *
+        * @param string $medium Path to the file to delete.
+        */
+       $delete = apply_filters( 'wp_delete_file', $file );
+       if ( ! empty( $delete ) ) {
+               @unlink( $delete );
+       }
+}
+
+/**
+ * Outputs a small JS snippet on preview tabs/windows to remove `window.name` on unload.
+ *
+ * This prevents reusing the same tab for a preview when the user has navigated away.
+ *
+ * @since 4.3.0
+ */
+function wp_post_preview_js() {
+       global $post;
+
+       if ( ! is_preview() || empty( $post ) ) {
+               return;
+       }
+
+       // Has to match the window name used in post_submit_meta_box()
+       $name = 'wp-preview-' . (int) $post->ID;
+
+       ?>
+       <script>
+       ( function() {
+               var query = document.location.search;
+
+               if ( query && query.indexOf( 'preview=true' ) !== -1 ) {
+                       window.name = '<?php echo $name; ?>';
+               }
+
+               if ( window.addEventListener ) {
+                       window.addEventListener( 'unload', function() { window.name = ''; }, false );
+               }
+       }());
+       </script>
+       <?php
+}
+
+/**
+ * Parses and formats a MySQL datetime (Y-m-d H:i:s) for ISO8601/RFC3339.
+ *
+ * Explicitly strips timezones, as datetimes are not saved with any timezone
+ * information. Including any information on the offset could be misleading.
+ *
+ * @since 4.4.0
+ *
+ * @param string $date_string Date string to parse and format.
+ * @return string Date formatted for ISO8601/RFC3339.
+ */
+function mysql_to_rfc3339( $date_string ) {
+       $formatted = mysql2date( 'c', $date_string, false );
+
+       // Strip timezone information
+       return preg_replace( '/(?:Z|[+-]\d{2}(?::\d{2})?)$/', '', $formatted );
+}
+
+/**
+ * Attempts to raise the PHP memory limit for memory intensive processes.
+ *
+ * Only allows raising the existing limit and prevents lowering it.
+ *
+ * @since 4.6.0
+ *
+ * @param string $context Optional. Context in which the function is called. Accepts either 'admin',
+ *                        'image', or an arbitrary other context. If an arbitrary context is passed,
+ *                        the similarly arbitrary {@see '{$context}_memory_limit'} filter will be
+ *                        invoked. Default 'admin'.
+ * @return bool|int|string The limit that was set or false on failure.
+ */
+function wp_raise_memory_limit( $context = 'admin' ) {
+       // Exit early if the limit cannot be changed.
+       if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
+               return false;
+       }
+
+       $current_limit     = @ini_get( 'memory_limit' );
+       $current_limit_int = wp_convert_hr_to_bytes( $current_limit );
+
+       if ( -1 === $current_limit_int ) {
+               return false;
+       }
+
+       $wp_max_limit     = WP_MAX_MEMORY_LIMIT;
+       $wp_max_limit_int = wp_convert_hr_to_bytes( $wp_max_limit );
+       $filtered_limit   = $wp_max_limit;
+
+       switch ( $context ) {
+               case 'admin':
+                       /**
+                        * Filters the maximum memory limit available for administration screens.
+                        *
+                        * This only applies to administrators, who may require more memory for tasks
+                        * like updates. Memory limits when processing images (uploaded or edited by
+                        * users of any role) are handled separately.
+                        *
+                        * The `WP_MAX_MEMORY_LIMIT` constant specifically defines the maximum memory
+                        * limit available when in the administration back end. The default is 256M
+                        * (256 megabytes of memory) or the original `memory_limit` php.ini value if
+                        * this is higher.
+                        *
+                        * @since 3.0.0
+                        * @since 4.6.0 The default now takes the original `memory_limit` into account.
+                        *
+                        * @param int|string $filtered_limit The maximum WordPress memory limit. Accepts an integer
+                        *                                   (bytes), or a shorthand string notation, such as '256M'.
+                        */
+                       $filtered_limit = apply_filters( 'admin_memory_limit', $filtered_limit );
+                       break;
+
+               case 'image':
+                       /**
+                        * Filters the memory limit allocated for image manipulation.
+                        *
+                        * @since 3.5.0
+                        * @since 4.6.0 The default now takes the original `memory_limit` into account.
+                        *
+                        * @param int|string $filtered_limit Maximum memory limit to allocate for images.
+                        *                                   Default `WP_MAX_MEMORY_LIMIT` or the original
+                        *                                   php.ini `memory_limit`, whichever is higher.
+                        *                                   Accepts an integer (bytes), or a shorthand string
+                        *                                   notation, such as '256M'.
+                        */
+                       $filtered_limit = apply_filters( 'image_memory_limit', $filtered_limit );
+                       break;
+
+               default:
+                       /**
+                        * Filters the memory limit allocated for arbitrary contexts.
+                        *
+                        * The dynamic portion of the hook name, `$context`, refers to an arbitrary
+                        * context passed on calling the function. This allows for plugins to define
+                        * their own contexts for raising the memory limit.
+                        *
+                        * @since 4.6.0
+                        *
+                        * @param int|string $filtered_limit Maximum memory limit to allocate for images.
+                        *                                   Default '256M' or the original php.ini `memory_limit`,
+                        *                                   whichever is higher. Accepts an integer (bytes), or a
+                        *                                   shorthand string notation, such as '256M'.
+                        */
+                       $filtered_limit = apply_filters( "{$context}_memory_limit", $filtered_limit );
+                       break;
+       }
+
+       $filtered_limit_int = wp_convert_hr_to_bytes( $filtered_limit );
+
+       if ( -1 === $filtered_limit_int || ( $filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) {
+               if ( false !== @ini_set( 'memory_limit', $filtered_limit ) ) {
+                       return $filtered_limit;
+               } else {
+                       return false;
+               }
+       } elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) {
+               if ( false !== @ini_set( 'memory_limit', $wp_max_limit ) ) {
+                       return $wp_max_limit;
+               } else {
+                       return false;
+               }
+       }
+
+       return false;
+}