foreach ( $offset_range as $offset ) {
$offset_name = '+' . $offset;
$offset_name = (string) $offset;
$offset_value = $offset_name;
$offset_name = str_replace( array( '.25', '.5', '.75' ), array( ':15', ':30', ':45' ), $offset_name );
$offset_name = 'UTC' . $offset_name;
$offset_value = 'UTC' . $offset_value;
if ( $offset_value === $selected_zone ) {
$selected = 'selected="selected" ';
$structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . '</option>';
$structure[] = '</optgroup>';
return implode( "\n", $structure );
* Strip close comment and close php tags from file headers used by WP.
* @see https://core.trac.wordpress.org/ticket/8497
* @param string $str Header comment to clean up.
function _cleanup_header_comment( $str ) {
return trim( preg_replace( '/\s*(?:\*\/|\?>).*/', '', $str ) );
* 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).
* @global wpdb $wpdb WordPress database abstraction object.
function wp_scheduled_delete() {
$delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
$posts_to_delete = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < %d", $delete_timestamp ), ARRAY_A );
foreach ( (array) $posts_to_delete as $post ) {
$post_id = (int) $post['post_id'];
$del_post = get_post( $post_id );
if ( ! $del_post || 'trash' !== $del_post->post_status ) {
delete_post_meta( $post_id, '_wp_trash_meta_status' );
delete_post_meta( $post_id, '_wp_trash_meta_time' );
wp_delete_post( $post_id );
$comments_to_delete = $wpdb->get_results( $wpdb->prepare( "SELECT comment_id FROM $wpdb->commentmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < %d", $delete_timestamp ), ARRAY_A );
foreach ( (array) $comments_to_delete as $comment ) {
$comment_id = (int) $comment['comment_id'];
$del_comment = get_comment( $comment_id );
if ( ! $del_comment || 'trash' !== $del_comment->comment_approved ) {
delete_comment_meta( $comment_id, '_wp_trash_meta_time' );
delete_comment_meta( $comment_id, '_wp_trash_meta_status' );
wp_delete_comment( $del_comment );
* Retrieve metadata from a file.
* Searches for metadata in the first 8 KB of a file, such as a plugin or theme.
* Each piece of metadata must be on its own line. Fields can not span multiple
* lines, the value will get cut at the end of the first line.
* If the file data is not within that first 8 KB, then the author should correct
* their plugin file and move the data headers to the top.
* @link https://codex.wordpress.org/File_Header
* @param string $file Absolute path to the file.
* @param array $default_headers List of headers, in the format `array( 'HeaderKey' => 'Header Name' )`.
* @param string $context Optional. If specified adds filter hook {@see 'extra_$context_headers'}.
* @return string[] Array of file header values keyed by header name.
function get_file_data( $file, $default_headers, $context = '' ) {
// We don't need to write to the file, so just open for reading.
$fp = fopen( $file, 'r' );
// Pull only the first 8 KB of the file in.
$file_data = fread( $fp, 8 * KB_IN_BYTES );
// PHP will close file handle, but we are good citizens.
// Make sure we catch CR-only line endings.
$file_data = str_replace( "\r", "\n", $file_data );
* Filters extra file headers by context.
* The dynamic portion of the hook name, `$context`, refers to
* the context where extra headers might be loaded.
* @param array $extra_context_headers Empty array by default.
$extra_headers = $context ? apply_filters( "extra_{$context}_headers", array() ) : array();
$extra_headers = array_combine( $extra_headers, $extra_headers ); // Keys equal values.
$all_headers = array_merge( $extra_headers, (array) $default_headers );
$all_headers = $default_headers;
foreach ( $all_headers as $field => $regex ) {
if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] ) {
$all_headers[ $field ] = _cleanup_header_comment( $match[1] );
$all_headers[ $field ] = '';
* Useful for returning true to filters easily.
function __return_true() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
* Useful for returning false to filters easily.
function __return_false() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
* Useful for returning 0 to filters easily.
function __return_zero() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
* Returns an empty array.
* Useful for returning an empty array to filters easily.
* @return array Empty array.
function __return_empty_array() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
* Useful for returning null to filters easily.
* @return null Null value.
function __return_null() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
* Returns an empty string.
* Useful for returning an empty string to filters easily.
* @return string Empty string.
function __return_empty_string() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
* Send a HTTP header to disable content type sniffing in browsers which support it.
* @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' );
* Return a MySQL expression for selecting the week number based on the start_of_week option.
* @param string $column Database column.
* @return string SQL clause.
function _wp_mysql_week( $column ) {
$start_of_week = (int) get_option( 'start_of_week' );
switch ( $start_of_week ) {
return "WEEK( $column, 1 )";
return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
return "WEEK( $column, 0 )";
* Find hierarchy loops using a callback function that maps object IDs to parent IDs.
* @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
* @param array $callback_args Optional. Additional arguments to send to $callback.
* @return array IDs of all members of loop.
function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
$override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args );
if ( ! $arbitrary_loop_member ) {
return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
* Use the "The Tortoise and the Hare" algorithm to detect loops.
* For every step of the algorithm, the hare takes two steps and the tortoise one.
* If the hare ever laps the tortoise, there must be a loop.
* @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.
* @param array $callback_args Optional. Additional arguments to send to $callback. Default empty array.
* @param bool $_return_loop Optional. Return loop members or just detect presence of loop? Only set
* to true if you already know the given $start is part of a loop (otherwise
* the returned array might include branches). Default false.
* @return mixed Scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if
function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
$evanescent_hare = $start;
// Set evanescent_hare to one past hare.
// Increment hare two steps.
( $evanescent_hare = isset( $override[ $hare ] ) ? $override[ $hare ] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
( $hare = isset( $override[ $evanescent_hare ] ) ? $override[ $evanescent_hare ] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
$return[ $tortoise ] = true;
$return[ $evanescent_hare ] = true;
// Tortoise got lapped - must be a loop.
if ( $tortoise == $evanescent_hare || $tortoise == $hare ) {
return $_return_loop ? $return : $tortoise;
// Increment tortoise by one step.
$tortoise = isset( $override[ $tortoise ] ) ? $override[ $tortoise ] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
* Send a HTTP header to limit rendering of pages to same origin iframes.
* @see https://developer.mozilla.org/en/the_x-frame-options_response_header
function send_frame_options_header() {
header( 'X-Frame-Options: SAMEORIGIN' );
* Retrieve a list of protocols to allow in HTML attributes.
* @since 4.3.0 Added 'webcal' to the protocols array.
* @since 4.7.0 Added 'urn' to the protocols array.
* @since 5.3.0 Added 'sms' to the protocols array.
* @since 5.6.0 Added 'irc6' and 'ircs' to the protocols array.
* @return string[] Array of allowed protocols. Defaults to an array containing 'http', 'https',
* 'ftp', 'ftps', 'mailto', 'news', 'irc', 'irc6', 'ircs', 'gopher', 'nntp', 'feed',
* 'telnet', 'mms', 'rtsp', 'sms', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'.
* This covers all common link protocols, except for 'javascript' which should not
* be allowed for untrusted users.
function wp_allowed_protocols() {
static $protocols = array();
if ( empty( $protocols ) ) {
$protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'irc6', 'ircs', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'sms', 'svn', 'tel', 'fax', 'xmpp', 'webcal', 'urn' );
if ( ! did_action( 'wp_loaded' ) ) {
* Filters the list of protocols allowed in HTML attributes.
* @param string[] $protocols Array of allowed protocols e.g. 'http', 'ftp', 'tel', and more.
$protocols = array_unique( (array) apply_filters( 'kses_allowed_protocols', $protocols ) );
* Return a comma-separated string of functions that have been called to get
* to the current point in code.
* @see https://core.trac.wordpress.org/ticket/19589
* @param string $ignore_class Optional. A class to ignore all function calls within - useful
* when you want to just give info about the callee. Default null.
* @param int $skip_frames Optional. A number of stack frames to skip - useful for unwinding
* back to the source of the issue. Default 0.
* @param bool $pretty Optional. Whether or not you want a comma separated string or raw
* array returned. Default true.
* @return string|array Either a string containing a reversed comma separated trace or an array
function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
$trace = debug_backtrace( false );
$check_class = ! is_null( $ignore_class );
$skip_frames++; // Skip this function.
if ( ! isset( $truncate_paths ) ) {
wp_normalize_path( WP_CONTENT_DIR ),
wp_normalize_path( ABSPATH ),
foreach ( $trace as $call ) {
if ( $skip_frames > 0 ) {
} elseif ( isset( $call['class'] ) ) {
if ( $check_class && $ignore_class == $call['class'] ) {
continue; // Filter out calls.
$caller[] = "{$call['class']}{$call['type']}{$call['function']}";
if ( in_array( $call['function'], array( 'do_action', 'apply_filters', 'do_action_ref_array', 'apply_filters_ref_array' ), true ) ) {
$caller[] = "{$call['function']}('{$call['args'][0]}')";
} elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ), true ) ) {
$filename = isset( $call['args'][0] ) ? $call['args'][0] : '';
$caller[] = $call['function'] . "('" . str_replace( $truncate_paths, '', wp_normalize_path( $filename ) ) . "')";
$caller[] = $call['function'];
return implode( ', ', array_reverse( $caller ) );
* Retrieve IDs that are not already present in the cache.
* @param int[] $object_ids Array of IDs.
* @param string $cache_key The cache bucket to check against.
* @return int[] Array of IDs not present in the cache.
function _get_non_cached_ids( $object_ids, $cache_key ) {
$non_cached_ids = array();
$cache_values = wp_cache_get_multiple( $object_ids, $cache_key );
foreach ( $cache_values as $id => $value ) {
$non_cached_ids[] = (int) $id;
* Test if the current device has the capability to upload files.
* @return bool Whether the device is able to upload files.
function _device_can_upload() {
if ( ! wp_is_mobile() ) {