]> scripts.mit.edu Git - autoinstalls/wordpress.git/blobdiff - wp-includes/functions.php
WordPress 4.7.1-scripts
[autoinstalls/wordpress.git] / wp-includes / functions.php
index 204211bade57cf3fc0efe57de2b78a7edc412e69..01045f038d3565c217093353a7a956c5c54ec28a 100644 (file)
@@ -91,13 +91,7 @@ function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
        $i = $unixtimestamp;
 
        if ( false === $i ) {
-               if ( ! $gmt )
-                       $i = current_time( 'timestamp' );
-               else
-                       $i = time();
-               // we should not let date() interfere with our
-               // specially computed timestamp
-               $gmt = true;
+               $i = current_time( 'timestamp', $gmt );
        }
 
        /*
@@ -106,15 +100,13 @@ function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
         */
        $req_format = $dateformatstring;
 
-       $datefunc = $gmt? 'gmdate' : 'date';
-
        if ( ( !empty( $wp_locale->month ) ) && ( !empty( $wp_locale->weekday ) ) ) {
-               $datemonth = $wp_locale->get_month( $datefunc( 'm', $i ) );
+               $datemonth = $wp_locale->get_month( date( 'm', $i ) );
                $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth );
-               $dateweekday = $wp_locale->get_weekday( $datefunc( 'w', $i ) );
+               $dateweekday = $wp_locale->get_weekday( date( 'w', $i ) );
                $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday );
-               $datemeridiem = $wp_locale->get_meridiem( $datefunc( 'a', $i ) );
-               $datemeridiem_capital = $wp_locale->get_meridiem( $datefunc( 'A', $i ) );
+               $datemeridiem = $wp_locale->get_meridiem( date( 'a', $i ) );
+               $datemeridiem_capital = $wp_locale->get_meridiem( date( 'A', $i ) );
                $dateformatstring = ' '.$dateformatstring;
                $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
                $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring );
@@ -142,7 +134,7 @@ function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
                        }
                }
        }
-       $j = @$datefunc( $dateformatstring, $i );
+       $j = @date( $dateformatstring, $i );
 
        /**
         * Filters the date formatted based on the locale.
@@ -1221,6 +1213,18 @@ function bool_from_yn( $yn ) {
 function do_feed() {
        global $wp_query;
 
+       // Determine if we are looking at the main comment feed
+       $is_main_comments_feed = ( $wp_query->is_comment_feed() && ! $wp_query->is_singular() );
+
+       /*
+        * Check the queried object for the existence of posts if it is not a feed for an archive,
+        * search result, or main comments. By checking for the absense of posts we can prevent rendering the feed
+        * templates at invalid endpoints. e.g.) /wp-content/plugins/feed/
+        */
+       if ( ! $wp_query->have_posts() && ! ( $wp_query->is_archive() || $wp_query->is_search() || $is_main_comments_feed ) ) {
+               wp_die( __( 'ERROR: This is not a valid feed.' ), '', array( 'response' => 404 ) );
+       }
+
        $feed = get_query_var( 'feed' );
 
        // Remove the pad, if present.
@@ -1411,7 +1415,12 @@ function is_blog_installed() {
                wp_load_translations_early();
 
                // Die with a DB error.
-               $wpdb->error = sprintf( __( 'One or more database tables are unavailable. The database may need to be <a href="%s">repaired</a>.' ), 'maint/repair.php?referrer=is_blog_installed' );
+               $wpdb->error = sprintf(
+                       /* translators: %s: database repair URL */
+                       __( 'One or more database tables are unavailable. The database may need to be <a href="%s">repaired</a>.' ),
+                       'maint/repair.php?referrer=is_blog_installed'
+               );
+
                dead_db();
        }
 
@@ -1895,7 +1904,11 @@ function wp_upload_dir( $time = null, $create_dir = true, $refresh_cache = false
                                        $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 ) );
+                               $uploads['error'] = sprintf(
+                                       /* translators: %s: directory path */
+                                       __( 'Unable to create directory %s. Is its parent directory writable by the server?' ),
+                                       esc_html( $error_path )
+                               );
                        }
 
                        $tested_paths[ $path ] = $uploads['error'];
@@ -2034,13 +2047,16 @@ function wp_unique_filename( $dir, $filename, $unique_filename_callback = null )
        $filename = sanitize_file_name($filename);
 
        // Separate the filename into a name and extension.
-       $info = pathinfo($filename);
-       $ext = !empty($info['extension']) ? '.' . $info['extension'] : '';
-       $name = basename($filename, $ext);
+       $ext = pathinfo( $filename, PATHINFO_EXTENSION );
+       $name = pathinfo( $filename, PATHINFO_BASENAME );
+       if ( $ext ) {
+               $ext = '.' . $ext;
+       }
 
        // Edge case: if file is named '.ext', treat as an empty name.
-       if ( $name === $ext )
+       if ( $name === $ext ) {
                $name = '';
+       }
 
        /*
         * Increment the file number until we have a unique file to save in $dir.
@@ -2154,7 +2170,11 @@ function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
                else
                        $error_path = basename( $upload['basedir'] ) . $upload['subdir'];
 
-               $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
+               $message = sprintf(
+                       /* translators: %s: directory path */
+                       __( 'Unable to create directory %s. Is its parent directory writable by the server?' ),
+                       $error_path
+               );
                return array( 'error' => $message );
        }
 
@@ -2234,7 +2254,7 @@ function wp_check_filetype( $filename, $mimes = null ) {
  * If it's determined that the extension does not match the file's real type,
  * then the "proper_filename" value will be set with a proper filename and extension.
  *
- * Currently this function only supports validating images known to getimagesize().
+ * Currently this function only supports renaming images validated via wp_get_image_mime().
  *
  * @since 3.0.0
  *
@@ -2258,14 +2278,15 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
                return compact( 'ext', 'type', 'proper_filename' );
        }
 
-       // We're able to validate images using GD
-       if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) {
+       // Validate image types.
+       if ( $type && 0 === strpos( $type, 'image/' ) ) {
 
                // Attempt to figure out what type of image it actually is
-               $imgstats = @getimagesize( $file );
+               $real_mime = wp_get_image_mime( $file );
 
-               // 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 ) {
+               if ( ! $real_mime ) {
+                       $type = $ext = false;
+               } elseif ( $real_mime != $type ) {
                        /**
                         * Filters the list mapping image mime types to their respective extensions.
                         *
@@ -2282,10 +2303,10 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
                        ) );
 
                        // Replace whatever is after the last period in the filename with the correct extension
-                       if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) {
+                       if ( ! empty( $mime_to_ext[ $real_mime ] ) ) {
                                $filename_parts = explode( '.', $filename );
                                array_pop( $filename_parts );
-                               $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ];
+                               $filename_parts[] = $mime_to_ext[ $real_mime ];
                                $new_filename = implode( '.', $filename_parts );
 
                                if ( $new_filename != $filename ) {
@@ -2295,8 +2316,20 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
                                $wp_filetype = wp_check_filetype( $new_filename, $mimes );
                                $ext = $wp_filetype['ext'];
                                $type = $wp_filetype['type'];
+                       } else {
+                               $type = $ext = false;
                        }
                }
+       } elseif ( function_exists( 'finfo_file' ) ) {
+               // Use finfo_file if available to validate non-image files.
+               $finfo = finfo_open( FILEINFO_MIME_TYPE );
+               $real_mime = finfo_file( $finfo, $file );
+               finfo_close( $finfo );
+
+               // If the extension does not match the file's real type, return false.
+               if ( $real_mime !== $type ) {
+                       $type = $ext = false;
+               }
        }
 
        /**
@@ -2314,6 +2347,38 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
        return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
 }
 
+/**
+ * Returns the real mime type of an image file.
+ *
+ * This depends on exif_imagetype() or getimagesize() to determine real mime types.
+ *
+ * @since 4.7.1
+ *
+ * @param string $file Full path to the file.
+ * @return string|false The actual mime type or false if the type cannot be determined.
+ */
+function wp_get_image_mime( $file ) {
+       /*
+        * Use exif_imagetype() to check the mimetype if available or fall back to
+        * getimagesize() if exif isn't avaialbe. If either function throws an Exception
+        * we assume the file could not be validated.
+        */
+       try {
+               if ( is_callable( 'exif_imagetype' ) ) {
+                       $mime = image_type_to_mime_type( exif_imagetype( $file ) );
+               } elseif ( function_exists( 'getimagesize' ) ) {
+                       $imagesize = getimagesize( $file );
+                       $mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
+               } else {
+                       $mime = false;
+               }
+       } catch ( Exception $e ) {
+               $mime = false;
+       }
+
+       return $mime;
+}
+
 /**
  * Retrieve list of mime types and file extensions.
  *
@@ -2513,13 +2578,27 @@ function get_allowed_mime_types( $user = null ) {
  */
 function wp_nonce_ays( $action ) {
        if ( 'log-out' == $action ) {
-               $html = sprintf( __( 'You are attempting to log out of %s' ), get_bloginfo( 'name' ) ) . '</p><p>';
+               $html = sprintf(
+                       /* translators: %s: site name */
+                       __( 'You are attempting to log out of %s' ),
+                       get_bloginfo( 'name' )
+               );
+               $html .= '</p><p>';
                $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
-               $html .= sprintf( __( "Do you really want to <a href='%s'>log out</a>?"), wp_logout_url( $redirect_to ) );
+               $html .= sprintf(
+                       /* translators: %s: logout URL */
+                       __( 'Do you really want to <a href="%s">log out</a>?' ),
+                       wp_logout_url( $redirect_to )
+               );
        } else {
                $html = __( 'Are you sure you want to do this?' );
-               if ( wp_get_referer() )
-                       $html .= "</p><p><a href='" . esc_url( remove_query_arg( 'updated', wp_get_referer() ) ) . "'>" . __( 'Please try again.' ) . "</a>";
+               if ( wp_get_referer() ) {
+                       $html .= '</p><p>';
+                       $html .= sprintf( '<a href="%s">%s</a>',
+                               esc_url( remove_query_arg( 'updated', wp_get_referer() ) ),
+                               __( 'Please try again.' )
+                       );
+               }
        }
 
        wp_die( $html, __( 'WordPress Failure Notice' ), 403 );
@@ -2542,7 +2621,8 @@ function wp_nonce_ays( $action ) {
  *              an integer to be used as the response code.
  *
  * @param string|WP_Error  $message Optional. Error message. If this is a WP_Error object,
- *                                  the error's messages are used. Default empty.
+ *                                  and not an Ajax or XML-RPC request, 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.
  *                                  If `$title` is an integer, then it is treated as the response
@@ -2551,7 +2631,7 @@ function wp_nonce_ays( $action ) {
  *     Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
  *     as the response code. Default empty array.
  *
- *     @type int    $response       The HTTP response code. Default 500.
+ *     @type int    $response       The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
  *     @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'.
@@ -2567,7 +2647,7 @@ function wp_die( $message = '', $title = '', $args = array() ) {
                $title = '';
        }
 
-       if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
+       if ( wp_doing_ajax() ) {
                /**
                 * Filters the callback for killing WordPress execution for Ajax requests.
                 *
@@ -2608,9 +2688,9 @@ function wp_die( $message = '', $title = '', $args = array() ) {
  * @since 3.0.0
  * @access private
  *
- * @param string       $message Error message.
- * @param string       $title   Optional. Error title. Default empty.
- * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
+ * @param string|WP_Error $message Error message or WP_Error object.
+ * @param string          $title   Optional. Error title. Default empty.
+ * @param string|array    $args    Optional. Arguments to control behavior. Default empty array.
  */
 function _default_wp_die_handler( $message, $title = '', $args = array() ) {
        $defaults = array( 'response' => 500 );
@@ -2835,9 +2915,20 @@ function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
  * @since 3.4.0
  * @access private
  *
- * @param string $message Optional. Response to print. Default empty.
+ * @param string       $message Error message.
+ * @param string       $title   Optional. Error title (unused). Default empty.
+ * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
  */
-function _ajax_wp_die_handler( $message = '' ) {
+function _ajax_wp_die_handler( $message, $title = '', $args = array() ) {
+       $defaults = array(
+               'response' => 200,
+       );
+       $r = wp_parse_args( $args, $defaults );
+
+       if ( ! headers_sent() && null !== $r['response'] ) {
+               status_header( $r['response'] );
+       }
+
        if ( is_scalar( $message ) )
                die( (string) $message );
        die( '0' );
@@ -3054,33 +3145,44 @@ function _wp_json_prepare_data( $data ) {
  * Send a JSON response back to an Ajax request.
  *
  * @since 3.5.0
+ * @since 4.7.0 The `$status_code` parameter was added.
  *
- * @param mixed $response Variable (usually an array or object) to encode as JSON,
- *                        then print and die.
+ * @param mixed $response    Variable (usually an array or object) to encode as JSON,
+ *                           then print and die.
+ * @param int   $status_code The HTTP status code to output.
  */
-function wp_send_json( $response ) {
+function wp_send_json( $response, $status_code = null ) {
        @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
+       if ( null !== $status_code ) {
+               status_header( $status_code );
+       }
        echo wp_json_encode( $response );
-       if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
-               wp_die();
-       else
+
+       if ( wp_doing_ajax() ) {
+               wp_die( '', '', array(
+                       'response' => null,
+               ) );
+       } else {
                die;
+       }
 }
 
 /**
  * Send a JSON response back to an Ajax request, indicating success.
  *
  * @since 3.5.0
+ * @since 4.7.0 The `$status_code` parameter was added.
  *
- * @param mixed $data Data to encode as JSON, then print and die.
+ * @param mixed $data        Data to encode as JSON, then print and die.
+ * @param int   $status_code The HTTP status code to output.
  */
-function wp_send_json_success( $data = null ) {
+function wp_send_json_success( $data = null, $status_code = null ) {
        $response = array( 'success' => true );
 
        if ( isset( $data ) )
                $response['data'] = $data;
 
-       wp_send_json( $response );
+       wp_send_json( $response, $status_code );
 }
 
 /**
@@ -3093,10 +3195,12 @@ function wp_send_json_success( $data = null ) {
  *
  * @since 3.5.0
  * @since 4.1.0 The `$data` parameter is now processed if a WP_Error object is passed in.
+ * @since 4.7.0 The `$status_code` parameter was added.
  *
- * @param mixed $data Data to encode as JSON, then print and die.
+ * @param mixed $data        Data to encode as JSON, then print and die.
+ * @param int   $status_code The HTTP status code to output.
  */
-function wp_send_json_error( $data = null ) {
+function wp_send_json_error( $data = null, $status_code = null ) {
        $response = array( 'success' => false );
 
        if ( isset( $data ) ) {
@@ -3114,7 +3218,7 @@ function wp_send_json_error( $data = null ) {
                }
        }
 
-       wp_send_json( $response );
+       wp_send_json( $response, $status_code );
 }
 
 /**
@@ -3134,7 +3238,7 @@ function wp_check_jsonp_callback( $callback ) {
                return false;
        }
 
-       $jsonp_callback = preg_replace( '/[^\w\.]/', '', $callback, -1, $illegal_char_count );
+       preg_replace( '/[^\w\.]/', '', $callback, -1, $illegal_char_count );
 
        return 0 === $illegal_char_count;
 }
@@ -3181,6 +3285,16 @@ function _config_wp_siteurl( $url = '' ) {
        return $url;
 }
 
+/**
+ * Delete the fresh site option.
+ *
+ * @since 4.7.0
+ * @access private
+ */
+function _delete_option_fresh_site() {
+       update_option( 'fresh_site', 0 );
+}
+
 /**
  * Set the localized direction for MCE plugin.
  *
@@ -3190,28 +3304,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';
+               $mce_init['directionality'] = 'rtl';
+               $mce_init['rtl_ui'] = true;
 
-               if ( ! empty( $input['plugins'] ) && strpos( $input['plugins'], 'directionality' ) === false ) {
-                       $input['plugins'] .= ',directionality';
+               if ( ! empty( $mce_init['plugins'] ) && strpos( $mce_init['plugins'], 'directionality' ) === false ) {
+                       $mce_init['plugins'] .= ',directionality';
                }
 
-               if ( ! empty( $input['toolbar1'] ) && ! preg_match( '/\bltr\b/', $input['toolbar1'] ) ) {
-                       $input['toolbar1'] .= ',ltr';
+               if ( ! empty( $mce_init['toolbar1'] ) && ! preg_match( '/\bltr\b/', $mce_init['toolbar1'] ) ) {
+                       $mce_init['toolbar1'] .= ',ltr';
                }
        }
 
-       return $input;
+       return $mce_init;
 }
 
 
@@ -3294,6 +3409,18 @@ function smilies_init() {
                );
        }
 
+       /**
+        * Filters all the smilies.
+        *
+        * This filter must be added before `smilies_init` is run, as
+        * it is normally only run once to setup the smilies regex.
+        *
+        * @since 4.7.0
+        *
+        * @param array $wpsmiliestrans List of the smilies.
+        */
+       $wpsmiliestrans = apply_filters('smilies', $wpsmiliestrans);
+
        if (count($wpsmiliestrans) == 0) {
                return;
        }
@@ -3340,9 +3467,10 @@ function smilies_init() {
  * to be merged into another array.
  *
  * @since 2.2.0
+ * @since 2.3.0 `$args` can now also be an object.
  *
- * @param string|array $args     Value to merge with $defaults
- * @param array        $defaults Optional. Array that serves as the defaults. Default empty.
+ * @param string|array|object $args     Value to merge with $defaults.
+ * @param array               $defaults Optional. Array that serves as the defaults. Default empty.
  * @return array Merged user defined values with defaults.
  */
 function wp_parse_args( $args, $defaults = '' ) {
@@ -3373,6 +3501,26 @@ function wp_parse_id_list( $list ) {
        return array_unique(array_map('absint', $list));
 }
 
+/**
+ * Clean up an array, comma- or space-separated list of slugs.
+ *
+ * @since 4.7.0
+ *
+ * @param  array|string $list List of slugs.
+ * @return array Sanitized array of slugs.
+ */
+function wp_parse_slug_list( $list ) {
+       if ( ! is_array( $list ) ) {
+               $list = preg_split( '/[\s,]+/', $list );
+       }
+
+       foreach ( $list as $key => $value ) {
+               $list[ $key ] = sanitize_title( $value );
+       }
+
+       return array_unique( $list );
+}
+
 /**
  * Extract a slice of an array, given a list of keys.
  *
@@ -3413,6 +3561,7 @@ function wp_is_numeric_array( $data ) {
  * Filters a list of objects, based on a set of key => value arguments.
  *
  * @since 3.0.0
+ * @since 4.7.0 Uses WP_List_Util class.
  *
  * @param array       $list     An array of objects to filter
  * @param array       $args     Optional. An array of key => value arguments to match
@@ -3426,21 +3575,26 @@ function wp_is_numeric_array( $data ) {
  * @return array A list of objects or object fields.
  */
 function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
-       if ( ! is_array( $list ) )
+       if ( ! is_array( $list ) ) {
                return array();
+       }
 
-       $list = wp_list_filter( $list, $args, $operator );
+       $util = new WP_List_Util( $list );
 
-       if ( $field )
-               $list = wp_list_pluck( $list, $field );
+       $util->filter( $args, $operator );
 
-       return $list;
+       if ( $field ) {
+               $util->pluck( $field );
+       }
+
+       return $util->get_output();
 }
 
 /**
  * Filters a list of objects, based on a set of key => value arguments.
  *
  * @since 3.1.0
+ * @since 4.7.0 Uses WP_List_Util class.
  *
  * @param array  $list     An array of objects to filter.
  * @param array  $args     Optional. An array of key => value arguments to match
@@ -3452,33 +3606,12 @@ function wp_filter_object_list( $list, $args = array(), $operator = 'and', $fiel
  * @return array Array of found values.
  */
 function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
-       if ( ! is_array( $list ) )
+       if ( ! is_array( $list ) ) {
                return array();
-
-       if ( empty( $args ) )
-               return $list;
-
-       $operator = strtoupper( $operator );
-       $count = count( $args );
-       $filtered = array();
-
-       foreach ( $list as $key => $obj ) {
-               $to_match = (array) $obj;
-
-               $matched = 0;
-               foreach ( $args as $m_key => $m_value ) {
-                       if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] )
-                               $matched++;
-               }
-
-               if ( ( 'AND' == $operator && $matched == $count )
-                 || ( 'OR' == $operator && $matched > 0 )
-                 || ( 'NOT' == $operator && 0 == $matched ) ) {
-                       $filtered[$key] = $obj;
-               }
        }
 
-       return $filtered;
+       $util = new WP_List_Util( $list );
+       return $util->filter( $args, $operator );
 }
 
 /**
@@ -3489,6 +3622,7 @@ function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
  *
  * @since 3.1.0
  * @since 4.0.0 $index_key parameter added.
+ * @since 4.7.0 Uses WP_List_Util class.
  *
  * @param array      $list      List of objects or arrays
  * @param int|string $field     Field from the object to place instead of the entire object
@@ -3499,43 +3633,30 @@ function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
  *               `$list` will be preserved in the results.
  */
 function wp_list_pluck( $list, $field, $index_key = null ) {
-       if ( ! $index_key ) {
-               /*
-                * This is simple. Could at some point wrap array_column()
-                * if we knew we had an array of arrays.
-                */
-               foreach ( $list as $key => $value ) {
-                       if ( is_object( $value ) ) {
-                               $list[ $key ] = $value->$field;
-                       } else {
-                               $list[ $key ] = $value[ $field ];
-                       }
-               }
-               return $list;
-       }
+       $util = new WP_List_Util( $list );
+       return $util->pluck( $field, $index_key );
+}
 
-       /*
-        * When index_key is not set for a particular item, push the value
-        * to the end of the stack. This is how array_column() behaves.
-        */
-       $newlist = array();
-       foreach ( $list as $value ) {
-               if ( is_object( $value ) ) {
-                       if ( isset( $value->$index_key ) ) {
-                               $newlist[ $value->$index_key ] = $value->$field;
-                       } else {
-                               $newlist[] = $value->$field;
-                       }
-               } else {
-                       if ( isset( $value[ $index_key ] ) ) {
-                               $newlist[ $value[ $index_key ] ] = $value[ $field ];
-                       } else {
-                               $newlist[] = $value[ $field ];
-                       }
-               }
+/**
+ * Sorts a list of objects, based on one or more orderby arguments.
+ *
+ * @since 4.7.0
+ *
+ * @param array        $list          An array of objects to filter.
+ * @param string|array $orderby       Optional. Either the field name to order by or an array
+ *                                    of multiple orderby fields as $orderby => $order.
+ * @param string       $order         Optional. Either 'ASC' or 'DESC'. Only used if $orderby
+ *                                    is a string.
+ * @param bool         $preserve_keys Optional. Whether to preserve keys. Default false.
+ * @return array The sorted array.
+ */
+function wp_list_sort( $list, $orderby = array(), $order = 'ASC', $preserve_keys = false ) {
+       if ( ! is_array( $list ) ) {
+               return array();
        }
 
-       return $newlist;
+       $util = new WP_List_Util( $list );
+       return $util->sort( $orderby, $order, $preserve_keys );
 }
 
 /**
@@ -3702,15 +3823,19 @@ function _deprecated_function( $function, $version, $replacement = null ) {
         */
        if ( WP_DEBUG && apply_filters( 'deprecated_function_trigger_error', true ) ) {
                if ( function_exists( '__' ) ) {
-                       if ( ! is_null( $replacement ) )
+                       if ( ! is_null( $replacement ) ) {
+                               /* translators: 1: PHP function name, 2: version number, 3: alternative function name */
                                trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) );
-                       else
+                       } else {
+                               /* translators: 1: PHP function name, 2: version number */
                                trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
+                       }
                } else {
-                       if ( ! is_null( $replacement ) )
+                       if ( ! is_null( $replacement ) ) {
                                trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $function, $version, $replacement ) );
-                       else
+                       } else {
                                trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
+                       }
                }
        }
 }
@@ -3826,15 +3951,19 @@ function _deprecated_file( $file, $version, $replacement = null, $message = '' )
        if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
                $message = empty( $message ) ? '' : ' ' . $message;
                if ( function_exists( '__' ) ) {
-                       if ( ! is_null( $replacement ) )
+                       if ( ! is_null( $replacement ) ) {
+                               /* translators: 1: PHP file name, 2: version number, 3: alternative file name */
                                trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $file, $version, $replacement ) . $message );
-                       else
+                       } else {
+                               /* translators: 1: PHP file name, 2: version number */
                                trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $file, $version ) . $message );
+                       }
                } else {
-                       if ( ! is_null( $replacement ) )
+                       if ( ! is_null( $replacement ) ) {
                                trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $file, $version, $replacement ) . $message );
-                       else
+                       } else {
                                trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $file, $version ) . $message );
+                       }
                }
        }
 }
@@ -3886,15 +4015,19 @@ function _deprecated_argument( $function, $version, $message = null ) {
         */
        if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
                if ( function_exists( '__' ) ) {
-                       if ( ! is_null( $message ) )
+                       if ( ! is_null( $message ) ) {
+                               /* translators: 1: PHP function name, 2: version number, 3: optional message regarding the change */
                                trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s'), $function, $version, $message ) );
-                       else
+                       } else {
+                               /* translators: 1: PHP function name, 2: version number */
                                trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
+                       }
                } else {
-                       if ( ! is_null( $message ) )
+                       if ( ! is_null( $message ) ) {
                                trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s', $function, $version, $message ) );
-                       else
+                       } else {
                                trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
+                       }
                }
        }
 }
@@ -3942,8 +4075,10 @@ function _deprecated_hook( $hook, $version, $replacement = null, $message = null
        if ( WP_DEBUG && apply_filters( 'deprecated_hook_trigger_error', true ) ) {
                $message = empty( $message ) ? '' : ' ' . $message;
                if ( ! is_null( $replacement ) ) {
+                       /* translators: 1: WordPress hook name, 2: version number, 3: alternative hook name */
                        trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ), $hook, $version, $replacement ) . $message );
                } else {
+                       /* translators: 1: WordPress hook name, 2: version number */
                        trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ), $hook, $version ) . $message );
                }
        }
@@ -3987,14 +4122,24 @@ 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 );
+                       if ( is_null( $version ) ) {
+                               $version = '';
+                       } else {
+                               /* translators: %s: version number */
+                               $version = sprintf( __( '(This message was added in version %s.)' ), $version );
+                       }
                        /* translators: %s: Codex URL */
                        $message .= ' ' . sprintf( __( 'Please see <a href="%s">Debugging in WordPress</a> for more information.' ),
                                __( 'https://codex.wordpress.org/Debugging_in_WordPress' )
                        );
+                       /* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message, 3: Version information message */
                        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 );
+                       if ( is_null( $version ) ) {
+                               $version = '';
+                       } else {
+                               $version = sprintf( '(This message was added in version %s.)', $version );
+                       }
                        $message .= sprintf( ' Please see <a href="%s">Debugging in WordPress</a> for more information.',
                                'https://codex.wordpress.org/Debugging_in_WordPress'
                        );
@@ -4237,23 +4382,18 @@ 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.
  * @return bool True if $site_id is the main site of the network, or if not
  *              running Multisite.
  */
 function is_main_site( $site_id = null ) {
-       // This is the current network's information; 'site' is old terminology.
-       global $current_site;
-
        if ( ! is_multisite() )
                return true;
 
        if ( ! $site_id )
                $site_id = get_current_blog_id();
 
-       return (int) $site_id === (int) $current_site->blog_id;
+       return (int) $site_id === (int) get_network()->site_id;
 }
 
 /**
@@ -4269,10 +4409,8 @@ function is_main_network( $network_id = null ) {
                return true;
        }
 
-       $current_network_id = (int) get_current_site()->id;
-
        if ( null === $network_id ) {
-               $network_id = $current_network_id;
+               $network_id = get_current_network_id();
        }
 
        $network_id = (int) $network_id;
@@ -4285,31 +4423,23 @@ function is_main_network( $network_id = null ) {
  *
  * @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;
        }
 
-       $current_site = get_current_site();
+       $current_network = get_network();
 
        if ( defined( 'PRIMARY_NETWORK_ID' ) ) {
                $main_network_id = PRIMARY_NETWORK_ID;
-       } elseif ( isset( $current_site->id ) && 1 === (int) $current_site->id ) {
+       } elseif ( isset( $current_network->id ) && 1 === (int) $current_network->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' );
-
-               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' );
-               }
+               $_networks = get_networks( array( 'fields' => 'ids', 'number' => 1 ) );
+               $main_network_id = array_shift( $_networks );
        }
 
        /**
@@ -4431,21 +4561,25 @@ function _wp_timezone_choice_usort_callback( $a, $b ) {
  * Gives a nicely-formatted list of timezone strings.
  *
  * @since 2.9.0
+ * @since 4.7.0 Added the `$locale` parameter.
  *
  * @staticvar bool $mo_loaded
+ * @staticvar string $locale_loaded
  *
  * @param string $selected_zone Selected timezone.
+ * @param string $locale        Optional. Locale to load the timezones in. Default current site locale.
  * @return string
  */
-function wp_timezone_choice( $selected_zone ) {
-       static $mo_loaded = false;
+function wp_timezone_choice( $selected_zone, $locale = null ) {
+       static $mo_loaded = false, $locale_loaded = null;
 
        $continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');
 
-       // Load translations for continents and cities
-       if ( !$mo_loaded ) {
-               $locale = get_locale();
-               $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
+       // Load translations for continents and cities.
+       if ( ! $mo_loaded || $locale !== $locale_loaded ) {
+               $locale_loaded = $locale ? $locale : get_locale();
+               $mofile = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
+               unload_textdomain( 'continents-cities' );
                load_textdomain( 'continents-cities', $mofile );
                $mo_loaded = true;
        }
@@ -4889,6 +5023,7 @@ function send_frame_options_header() {
  *
  * @since 3.3.0
  * @since 4.3.0 Added 'webcal' to the protocols array.
+ * @since 4.7.0 Added 'urn' to the protocols array.
  *
  * @see wp_kses()
  * @see esc_url()
@@ -4897,13 +5032,13 @@ function send_frame_options_header() {
  *
  * @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'.
+ *               'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'.
  */
 function wp_allowed_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', 'webcal' );
+               $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal', 'urn' );
 
                /**
                 * Filters the list of protocols allowed in HTML attributes.
@@ -5192,13 +5327,15 @@ function get_tag_regex( $tag ) {
  * @return string The canonical form of the charset.
  */
 function _canonical_charset( $charset ) {
-       if ( 'UTF-8' === $charset || 'utf-8' === $charset || 'utf8' === $charset ||
-               'UTF8' === $charset )
+       if ( 'utf-8' === strtolower( $charset ) || 'utf8' === strtolower( $charset) ) {
+
                return 'UTF-8';
+       }
+
+       if ( 'iso-8859-1' === strtolower( $charset ) || 'iso8859-1' === strtolower( $charset ) ) {
 
-       if ( 'ISO-8859-1' === $charset || 'iso-8859-1' === $charset ||
-               'iso8859-1' === $charset || 'ISO8859-1' === $charset )
                return 'ISO-8859-1';
+       }
 
        return $charset;
 }
@@ -5463,3 +5600,40 @@ function wp_raise_memory_limit( $context = 'admin' ) {
 
        return false;
 }
+
+/**
+ * Generate a random UUID (version 4).
+ *
+ * @since 4.7.0
+ *
+ * @return string UUID.
+ */
+function wp_generate_uuid4() {
+       return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
+               mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
+               mt_rand( 0, 0xffff ),
+               mt_rand( 0, 0x0fff ) | 0x4000,
+               mt_rand( 0, 0x3fff ) | 0x8000,
+               mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
+       );
+}
+
+/**
+ * Get last changed date for the specified cache group.
+ *
+ * @since 4.7.0
+ *
+ * @param $group Where the cache contents are grouped.
+ *
+ * @return string $last_changed UNIX timestamp with microseconds representing when the group was last changed.
+ */
+function wp_cache_get_last_changed( $group ) {
+       $last_changed = wp_cache_get( 'last_changed', $group );
+
+       if ( ! $last_changed ) {
+               $last_changed = microtime();
+               wp_cache_set( 'last_changed', $last_changed, $group );
+       }
+
+       return $last_changed;
+}