: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @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 )";
* Finds 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. Default empty array.
* @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 );
* Uses 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 ) );
* Sends a HTTP header to limit rendering of pages to same origin iframes.
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
function send_frame_options_header() {
header( 'X-Frame-Options: SAMEORIGIN' );
* Retrieves 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 ) );
* Returns a comma-separated string or array 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 you want a comma separated string instead of
* the 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 ) );
* Retrieves IDs that are not already present in the cache.
* @since 6.1.0 This function is no longer marked as "private".
* @param int[] $object_ids Array of IDs.
* @param string $cache_group The cache group to check against.
* @return int[] Array of IDs not present in the cache.
function _get_non_cached_ids( $object_ids, $cache_group ) {
$object_ids = array_filter( $object_ids, '_validate_cache_id' );
$object_ids = array_unique( array_map( 'intval', $object_ids ), SORT_NUMERIC );
if ( empty( $object_ids ) ) {
$non_cached_ids = array();
$cache_values = wp_cache_get_multiple( $object_ids, $cache_group );
foreach ( $cache_values as $id => $value ) {
if ( false === $value ) {
$non_cached_ids[] = (int) $id;
* Checks whether the given cache ID is either an integer or an integer-like string.
* Both `16` and `"16"` are considered valid, other numeric types and numeric strings
* (`16.3` and `"16.3"`) are considered invalid.
* @param mixed $object_id The cache ID to validate.
* @return bool Whether the given $object_id is a valid cache ID.
function _validate_cache_id( $object_id ) {
* filter_var() could be used here, but the `filter` PHP extension
* is considered optional and may not be available.
if ( is_int( $object_id )
|| ( is_string( $object_id ) && (string) (int) $object_id === $object_id ) ) {
/* translators: %s: The type of the given object ID. */
$message = sprintf( __( 'Object ID must be an integer, %s given.' ), gettype( $object_id ) );
_doing_it_wrong( '_get_non_cached_ids', $message, '6.3.0' );
* Tests 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() ) {
$ua = $_SERVER['HTTP_USER_AGENT'];
if ( str_contains( $ua, 'iPhone' )
|| str_contains( $ua, 'iPad' )
|| str_contains( $ua, 'iPod' ) ) {
return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
* Tests if a given path is a stream URL
* @param string $path The resource path or URL.
* @return bool True if the path is a stream URL.
function wp_is_stream( $path ) {
$scheme_separator = strpos( $path, '://' );
if ( false === $scheme_separator ) {
$stream = substr( $path, 0, $scheme_separator );
return in_array( $stream, stream_get_wrappers(), true );
* Tests if the supplied date is valid for the Gregorian calendar.
* @link https://www.php.net/manual/en/function.checkdate.php
* @param int $month Month number.
* @param int $day Day number.
* @param int $year Year number.
* @param string $source_date The date to filter.
* @return bool True if valid date, false if not valid date.
function wp_checkdate( $month, $day, $year, $source_date ) {
* Filters whether the given date is valid for the Gregorian calendar.
* @param bool $checkdate Whether the given date is valid.
* @param string $source_date Date to check.
return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date );
* Loads the auth check for monitoring whether the user is still logged in.
* 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 {@see 'wp_auth_check_load'} can be used
* for fine-grained control.
function wp_auth_check_load() {
if ( ! is_admin() && ! is_user_logged_in() ) {
if ( defined( 'IFRAME_REQUEST' ) ) {
$screen = get_current_screen();
$hidden = array( 'update', 'update-network', 'update-core', 'update-core-network', 'upgrade', 'upgrade-network', 'network' );
$show = ! in_array( $screen->id, $hidden, true );
* Filters whether to load the authentication check.
* Returning a falsey value from the filter will effectively short-circuit
* loading the authentication check.
* @param bool $show Whether to load the authentication check.
* @param WP_Screen $screen The current screen object.
if ( apply_filters( 'wp_auth_check_load', $show, $screen ) ) {
wp_enqueue_style( 'wp-auth-check' );
wp_enqueue_script( 'wp-auth-check' );
add_action( 'admin_print_footer_scripts', 'wp_auth_check_html', 5 );
add_action( 'wp_print_footer_scripts', 'wp_auth_check_html', 5 );
* Outputs the HTML that shows the wp-login dialog when the user is no longer logged in.
function wp_auth_check_html() {
$login_url = wp_login_url();
$current_domain = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
$same_domain = str_starts_with( $login_url, $current_domain );
* Filters whether the authentication check originated at the same domain.
* @param bool $same_domain Whether the authentication check originated at the same domain.
$same_domain = apply_filters( 'wp_auth_check_same_domain', $same_domain );
$wrap_class = $same_domain ? 'hidden' : 'hidden fallback';
<div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
<div id="wp-auth-check-bg"></div>
<button type="button" class="wp-auth-check-close button-link"><span class="screen-reader-text">
/* translators: Hidden accessibility text. */
$login_src = add_query_arg(
'wp_lang' => get_user_locale(),
<div id="wp-auth-check-form" class="loading" data-src="<?php echo esc_url( $login_src ); ?>"></div>
<div class="wp-auth-fallback">
<p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e( 'Session expired' ); ?></b></p>
<p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e( 'Please log in again.' ); ?></a>
<?php _e( 'The login page will open in a new tab. After logging in you can close it and return to this page.' ); ?></p>
* Checks whether a user is still logged in, for the heartbeat.
* Send a result that shows a log-in box if the user is no longer logged in,
* or if their cookie is within the grace period.
* @global int $login_grace_period
* @param array $response The Heartbeat response.
* @return array 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'] );
* Returns RegEx body to liberally match an opening HTML tag.
* Matches an opening HTML tag that:
* 2. Has no body but has a closing tag of the same name or
* 3. Contains a body and a closing tag of the same name
* Note: this RegEx does not balance inner tags and does not attempt
* @param string $tag An HTML tag name. Example: 'video'.
* @return string Tag RegEx.
function get_tag_regex( $tag ) {
return sprintf( '<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)', tag_escape( $tag ) );
* Indicates if a given slug for a character set represents the UTF-8
* text encoding. If not provided, examines the current blog's charset.
* A charset is considered to represent UTF-8 if it is a case-insensitive
* match of "UTF-8" with or without the hyphen.
* true === is_utf8_charset( 'UTF-8' );
* true === is_utf8_charset( 'utf8' );
* false === is_utf8_charset( 'latin1' );
* false === is_utf8_charset( 'UTF 8' );
* false === is_utf8_charset( [ 'charset' => 'utf-8' ] );
* // Without a given charset, it depends on the site option "blog_charset".
* $is_utf8 = is_utf8_charset();
* @since 6.6.1 A wrapper for _is_utf8_charset