: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
for ( $i = 0; $i < $stop; $i++ ) {
$content = $textarr[ $i ];
// If we're in an ignore block, wait until we find its closing tag.
if ( '' === $ignore_block_element && preg_match( '/^<(' . $tags_to_ignore . ')[^>]*>/', $content, $matches ) ) {
$ignore_block_element = $matches[1];
// If it's not a tag and not in ignore block.
if ( '' === $ignore_block_element && strlen( $content ) > 0 && '<' !== $content[0] ) {
$content = preg_replace_callback( $wp_smiliessearch, 'translate_smiley', $content );
// Did we exit ignore block?
if ( '' !== $ignore_block_element && '</' . $ignore_block_element . '>' === $content ) {
$ignore_block_element = '';
* Verifies that an email is valid.
* Does not grok i18n domains. Not RFC compliant.
* @param string $email Email address to verify.
* @param bool $deprecated Deprecated.
* @return string|false Valid email address on success, false on failure.
function is_email( $email, $deprecated = false ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '3.0.0' );
// Test for the minimum length the email can be.
if ( strlen( $email ) < 6 ) {
* Filters whether an email address is valid.
* This filter is evaluated under several different contexts, such as 'email_too_short',
* 'email_no_at', 'local_invalid_chars', 'domain_period_sequence', 'domain_period_limits',
* 'domain_no_periods', 'sub_hyphen_limits', 'sub_invalid_chars', or no specific context.
* @param string|false $is_email The email address if successfully passed the is_email() checks, false otherwise.
* @param string $email The email address being checked.
* @param string $context Context under which the email was tested.
return apply_filters( 'is_email', false, $email, 'email_too_short' );
// Test for an @ character after the first position.
if ( strpos( $email, '@', 1 ) === false ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'is_email', false, $email, 'email_no_at' );
// Split out the local and domain parts.
list( $local, $domain ) = explode( '@', $email, 2 );
* Test for invalid characters.
if ( ! preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'is_email', false, $email, 'local_invalid_chars' );
* Test for sequences of periods.
if ( preg_match( '/\.{2,}/', $domain ) ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'is_email', false, $email, 'domain_period_sequence' );
// Test for leading and trailing periods and whitespace.
if ( trim( $domain, " \t\n\r\0\x0B." ) !== $domain ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'is_email', false, $email, 'domain_period_limits' );
// Split the domain into subs.
$subs = explode( '.', $domain );
// Assume the domain will have at least two subs.
if ( 2 > count( $subs ) ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'is_email', false, $email, 'domain_no_periods' );
// Loop through each sub.
foreach ( $subs as $sub ) {
// Test for leading and trailing hyphens and whitespace.
if ( trim( $sub, " \t\n\r\0\x0B-" ) !== $sub ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
// Test for invalid characters.
if ( ! preg_match( '/^[a-z0-9-]+$/i', $sub ) ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'is_email', false, $email, 'sub_invalid_chars' );
// Congratulations, your email made it!
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'is_email', $email, $email, null );
* Converts to ASCII from email subjects.
* @param string $subject Subject line.
* @return string Converted string to ASCII.
function wp_iso_descrambler( $subject ) {
/* this may only work with iso-8859-1, I'm afraid */
if ( ! preg_match( '#\=\?(.+)\?Q\?(.+)\?\=#i', $subject, $matches ) ) {
$subject = str_replace( '_', ' ', $matches[2] );
return preg_replace_callback( '#\=([0-9a-f]{2})#i', '_wp_iso_convert', $subject );
* Helper function to convert hex encoded chars to ASCII.
* @param array $matches The preg_replace_callback matches array.
* @return string Converted chars.
function _wp_iso_convert( $matches ) {
return chr( hexdec( strtolower( $matches[1] ) ) );
* Given a date in the timezone of the site, returns that date in UTC.
* Requires and returns a date in the Y-m-d H:i:s format.
* Return format can be overridden using the $format parameter.
* @param string $date_string The date to be converted, in the timezone of the site.
* @param string $format The format string for the returned date. Default 'Y-m-d H:i:s'.
* @return string Formatted version of the date, in UTC.
function get_gmt_from_date( $date_string, $format = 'Y-m-d H:i:s' ) {
$datetime = date_create( $date_string, wp_timezone() );
if ( false === $datetime ) {
return gmdate( $format, 0 );
return $datetime->setTimezone( new DateTimeZone( 'UTC' ) )->format( $format );
* Given a date in UTC or GMT timezone, returns that date in the timezone of the site.
* Requires a date in the Y-m-d H:i:s format.
* Default return format of 'Y-m-d H:i:s' can be overridden using the `$format` parameter.
* @param string $date_string The date to be converted, in UTC or GMT timezone.
* @param string $format The format string for the returned date. Default 'Y-m-d H:i:s'.
* @return string Formatted version of the date, in the site's timezone.
function get_date_from_gmt( $date_string, $format = 'Y-m-d H:i:s' ) {
$datetime = date_create( $date_string, new DateTimeZone( 'UTC' ) );
if ( false === $datetime ) {
return gmdate( $format, 0 );
return $datetime->setTimezone( wp_timezone() )->format( $format );
* Given an ISO 8601 timezone, returns its UTC offset in seconds.
* @param string $timezone Either 'Z' for 0 offset or '±hhmm'.
* @return int|float The offset in seconds.
function iso8601_timezone_to_offset( $timezone ) {
// $timezone is either 'Z' or '[+|-]hhmm'.
if ( 'Z' === $timezone ) {
$sign = ( str_starts_with( $timezone, '+' ) ) ? 1 : -1;
$hours = (int) substr( $timezone, 1, 2 );
$minutes = (int) substr( $timezone, 3, 4 ) / 60;
$offset = $sign * HOUR_IN_SECONDS * ( $hours + $minutes );
* Given an ISO 8601 (Ymd\TH:i:sO) date, returns a MySQL DateTime (Y-m-d H:i:s) format used by post_date[_gmt].
* @param string $date_string Date and time in ISO 8601 format {@link https://en.wikipedia.org/wiki/ISO_8601}.
* @param string $timezone Optional. If set to 'gmt' returns the result in UTC. Default 'user'.
* @return string|false The date and time in MySQL DateTime format - Y-m-d H:i:s, or false on failure.
function iso8601_to_datetime( $date_string, $timezone = 'user' ) {
$timezone = strtolower( $timezone );
$wp_timezone = wp_timezone();
$datetime = date_create( $date_string, $wp_timezone ); // Timezone is ignored if input has one.
if ( false === $datetime ) {
if ( 'gmt' === $timezone ) {
return $datetime->setTimezone( new DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' );
if ( 'user' === $timezone ) {
return $datetime->setTimezone( $wp_timezone )->format( 'Y-m-d H:i:s' );
* Strips out all characters that are not allowable in an email.
* @param string $email Email address to filter.
* @return string Filtered email address.
function sanitize_email( $email ) {
// Test for the minimum length the email can be.
if ( strlen( $email ) < 6 ) {
* Filters a sanitized email address.
* This filter is evaluated under several contexts, including 'email_too_short',
* 'email_no_at', 'local_invalid_chars', 'domain_period_sequence', 'domain_period_limits',
* 'domain_no_periods', 'domain_no_valid_subs', or no context.
* @param string $sanitized_email The sanitized email address.
* @param string $email The email address, as provided to sanitize_email().
* @param string|null $message A message to pass to the user. null if email is sanitized.
return apply_filters( 'sanitize_email', '', $email, 'email_too_short' );
// Test for an @ character after the first position.
if ( strpos( $email, '@', 1 ) === false ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'sanitize_email', '', $email, 'email_no_at' );
// Split out the local and domain parts.
list( $local, $domain ) = explode( '@', $email, 2 );
* Test for invalid characters.
$local = preg_replace( '/[^a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]/', '', $local );
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'sanitize_email', '', $email, 'local_invalid_chars' );
* Test for sequences of periods.
$domain = preg_replace( '/\.{2,}/', '', $domain );
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'sanitize_email', '', $email, 'domain_period_sequence' );
// Test for leading and trailing periods and whitespace.
$domain = trim( $domain, " \t\n\r\0\x0B." );
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'sanitize_email', '', $email, 'domain_period_limits' );
// Split the domain into subs.
$subs = explode( '.', $domain );
// Assume the domain will have at least two subs.
if ( 2 > count( $subs ) ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'sanitize_email', '', $email, 'domain_no_periods' );
// Create an array that will contain valid subs.
// Loop through each sub.
foreach ( $subs as $sub ) {
// Test for leading and trailing hyphens.
$sub = trim( $sub, " \t\n\r\0\x0B-" );
// Test for invalid characters.
$sub = preg_replace( '/[^a-z0-9-]+/i', '', $sub );
// If there's anything left, add it to the valid subs.
// If there aren't 2 or more valid subs.
if ( 2 > count( $new_subs ) ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'sanitize_email', '', $email, 'domain_no_valid_subs' );
// Join valid subs into the new domain.
$domain = implode( '.', $new_subs );
// Put the email back together.
$sanitized_email = $local . '@' . $domain;
// Congratulations, your email made it!
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'sanitize_email', $sanitized_email, $email, null );
* Determines the difference between two timestamps.
* The difference is returned in a human-readable format such as "1 hour",
* @since 5.3.0 Added support for showing a difference in seconds.
* @param int $from Unix timestamp from which the difference begins.
* @param int $to Optional. Unix timestamp to end the time difference. Default becomes time() if not set.
* @return string Human-readable time difference.
function human_time_diff( $from, $to = 0 ) {
$diff = (int) abs( $to - $from );
if ( $diff < MINUTE_IN_SECONDS ) {
/* translators: Time difference between two dates, in seconds. %s: Number of seconds. */
$since = sprintf( _n( '%s second', '%s seconds', $secs ), $secs );
} elseif ( $diff < HOUR_IN_SECONDS && $diff >= MINUTE_IN_SECONDS ) {
$mins = round( $diff / MINUTE_IN_SECONDS );
/* translators: Time difference between two dates, in minutes (min=minute). %s: Number of minutes. */
$since = sprintf( _n( '%s min', '%s mins', $mins ), $mins );
} elseif ( $diff < DAY_IN_SECONDS && $diff >= HOUR_IN_SECONDS ) {
$hours = round( $diff / HOUR_IN_SECONDS );
/* translators: Time difference between two dates, in hours. %s: Number of hours. */
$since = sprintf( _n( '%s hour', '%s hours', $hours ), $hours );
} elseif ( $diff < WEEK_IN_SECONDS && $diff >= DAY_IN_SECONDS ) {
$days = round( $diff / DAY_IN_SECONDS );
/* translators: Time difference between two dates, in days. %s: Number of days. */
$since = sprintf( _n( '%s day', '%s days', $days ), $days );
} elseif ( $diff < MONTH_IN_SECONDS && $diff >= WEEK_IN_SECONDS ) {
$weeks = round( $diff / WEEK_IN_SECONDS );
/* translators: Time difference between two dates, in weeks. %s: Number of weeks. */
$since = sprintf( _n( '%s week', '%s weeks', $weeks ), $weeks );
} elseif ( $diff < YEAR_IN_SECONDS && $diff >= MONTH_IN_SECONDS ) {
$months = round( $diff / MONTH_IN_SECONDS );
/* translators: Time difference between two dates, in months. %s: Number of months. */
$since = sprintf( _n( '%s month', '%s months', $months ), $months );
} elseif ( $diff >= YEAR_IN_SECONDS ) {
$years = round( $diff / YEAR_IN_SECONDS );
/* translators: Time difference between two dates, in years. %s: Number of years. */
$since = sprintf( _n( '%s year', '%s years', $years ), $years );
* Filters the human-readable difference between two timestamps.
* @param string $since The difference in human-readable text.
* @param int $diff The difference in seconds.
* @param int $from Unix timestamp from which the difference begins.
* @param int $to Unix timestamp to end the time difference.
return apply_filters( 'human_time_diff', $since, $diff, $from, $to );
* Generates an excerpt from the content, if needed.
* Returns a maximum of 55 words with an ellipsis appended if necessary.
* The 55-word limit can be modified by plugins/themes using the {@see 'excerpt_length'} filter
* The ' […]' string can be modified by plugins/themes using the {@see 'excerpt_more'} filter
* @since 5.2.0 Added the `$post` parameter.
* @since 6.3.0 Removes footnotes markup from the excerpt content.
* @param string $text Optional. The excerpt. If set to empty, an excerpt is generated.
* @param WP_Post|object|int $post Optional. WP_Post instance or Post ID/object. Default null.
* @return string The excerpt.
function wp_trim_excerpt( $text = '', $post = null ) {
if ( '' === trim( $text ) ) {
$post = get_post( $post );
$text = get_the_content( '', false, $post );
$text = strip_shortcodes( $text );
$text = excerpt_remove_blocks( $text );
$text = excerpt_remove_footnotes( $text );
* Temporarily unhook wp_filter_content_tags() since any tags
* within the excerpt are stripped out. Modifying the tags here
* is wasteful and can lead to bugs in the image counting logic.
$filter_image_removed = remove_filter( 'the_content', 'wp_filter_content_tags', 12 );
* Temporarily unhook do_blocks() since excerpt_remove_blocks( $text )
* handles block rendering needed for excerpt.
$filter_block_removed = remove_filter( 'the_content', 'do_blocks', 9 );
/** This filter is documented in wp-includes/post-template.php */
$text = apply_filters( 'the_content', $text );
$text = str_replace( ']]>', ']]>', $text );
// Restore the original filter if removed.
if ( $filter_block_removed ) {
add_filter( 'the_content', 'do_blocks', 9 );
* Only restore the filter callback if it was removed above. The logic
* to unhook and restore only applies on the default priority of 10,
* which is generally used for the filter callback in WordPress core.
if ( $filter_image_removed ) {
add_filter( 'the_content', 'wp_filter_content_tags', 12 );
/* translators: Maximum number of words used in a post excerpt. */
$excerpt_length = (int) _x( '55', 'excerpt_length' );