$ua = $_SERVER['HTTP_USER_AGENT'];
if ( strpos( $ua, 'iPhone' ) !== false
|| strpos( $ua, 'iPad' ) !== false
|| strpos( $ua, 'iPod' ) !== false ) {
return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
* Test 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 );
* Test 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 );
* Load 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 );
* Output 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 = ( strpos( $login_url, $current_domain ) === 0 );
* 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"><?php _e( 'Close dialog' ); ?></span></button>
$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>
* Check 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'] );
* Return 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 ) );
* Retrieve a canonical form of the provided charset appropriate for passing to PHP
* functions such as htmlspecialchars() and charset HTML attributes.
* @see https://core.trac.wordpress.org/ticket/23688
* @param string $charset A charset name.
* @return string The canonical form of the charset.
function _canonical_charset( $charset ) {
if ( 'utf-8' === strtolower( $charset ) || 'utf8' === strtolower( $charset ) ) {
if ( 'iso-8859-1' === strtolower( $charset ) || 'iso8859-1' === strtolower( $charset ) ) {
* Set the mbstring internal encoding to a binary safe encoding when func_overload
* When mbstring.func_overload is in use for multi-byte encodings, the results from
* strlen() and similar functions respect the utf8 characters, causing binary data
* to return incorrect lengths.
* This function overrides the mbstring encoding to a binary-safe encoding, and
* resets it to the users expected encoding afterwards through the
* `reset_mbstring_encoding` function.
* It is safe to recursively call this function, however each
* `mbstring_binary_safe_encoding()` call must be followed up with an equal number
* of `reset_mbstring_encoding()` calls.
* @see reset_mbstring_encoding()
* @param bool $reset Optional. Whether to reset the encoding back to a previously-set encoding.
function mbstring_binary_safe_encoding( $reset = false ) {
static $encodings = array();
static $overloaded = null;
if ( is_null( $overloaded ) ) {
$overloaded = function_exists( 'mb_internal_encoding' ) && ( ini_get( 'mbstring.func_overload' ) & 2 ); // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated
if ( false === $overloaded ) {
$encoding = mb_internal_encoding();
array_push( $encodings, $encoding );
mb_internal_encoding( 'ISO-8859-1' );
if ( $reset && $encodings ) {
$encoding = array_pop( $encodings );
mb_internal_encoding( $encoding );
* Reset the mbstring internal encoding to a users previously set encoding.
* @see mbstring_binary_safe_encoding()
function reset_mbstring_encoding() {
mbstring_binary_safe_encoding( true );
* Filter/validate a variable as a boolean.
* Alternative to `filter_var( $var, FILTER_VALIDATE_BOOLEAN )`.
* @param mixed $var Boolean value to validate.
* @return bool Whether the value is validated.
function wp_validate_boolean( $var ) {
if ( is_string( $var ) && 'false' === strtolower( $var ) ) {
* @param string $file The path to the file to delete.
function wp_delete_file( $file ) {
* Filters the path of the file to delete.
* @param string $file Path to the file to delete.
$delete = apply_filters( 'wp_delete_file', $file );
if ( ! empty( $delete ) ) {
* Deletes a file if its path is within the given directory.
* @param string $file Absolute path to the file to delete.
* @param string $directory Absolute path to a directory.
* @return bool True on success, false on failure.
function wp_delete_file_from_directory( $file, $directory ) {
if ( wp_is_stream( $file ) ) {
$real_directory = $directory;
$real_file = realpath( wp_normalize_path( $file ) );
$real_directory = realpath( wp_normalize_path( $directory ) );
if ( false !== $real_file ) {
$real_file = wp_normalize_path( $real_file );
if ( false !== $real_directory ) {
$real_directory = wp_normalize_path( $real_directory );
if ( false === $real_file || false === $real_directory || strpos( $real_file, trailingslashit( $real_directory ) ) !== 0 ) {
* 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.
* @global WP_Post $post Global post object.
function wp_post_preview_js() {
if ( ! is_preview() || empty( $post ) ) {
// Has to match the window name used in post_submit_meta_box().
$name = 'wp-preview-' . (int) $post->ID;
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 );
* Parses and formats a MySQL datetime (Y-m-d H:i:s) for ISO8601 (Y-m-d\TH:i:s).
* Explicitly strips timezones, as datetimes are not saved with any timezone
* information. Including any information on the offset could be misleading.
* Despite historical function name, the output does not conform to RFC3339 format,
* which must contain timezone.
* @param string $date_string Date string to parse and format.
* @return string Date formatted for ISO8601 without time zone.
function mysql_to_rfc3339( $date_string ) {
return mysql2date( 'Y-m-d\TH:i:s', $date_string, false );
* Attempts to raise the PHP memory limit for memory intensive processes.
* Only allows raising the existing limit and prevents lowering it.
* @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 int|string|false 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' ) ) {
$current_limit = ini_get( 'memory_limit' );
$current_limit_int = wp_convert_hr_to_bytes( $current_limit );
if ( -1 === $current_limit_int ) {
$wp_max_limit = WP_MAX_MEMORY_LIMIT;
$wp_max_limit_int = wp_convert_hr_to_bytes( $wp_max_limit );
$filtered_limit = $wp_max_limit;
* 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
* @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 );
* Filters the memory limit allocated for image manipulation.
* @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 );
* 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.
* @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 );