) { $text = wp_encode_emoji( $text ); /** This filter is documented in wp-includes/formatting.php */ $cdn_url = apply_filters( 'emoji_url', 'https://s.w.org/images/core/emoji/2.2.1/72x72/' ); /** This filter is documented in wp-includes/formatting.php */ $ext = apply_filters( 'emoji_ext', '.png' ); $output = ''; /* * HTML loop taken from smiley function, which was taken from texturize function. * It'll never be consolidated. * * First, capture the tags as well as in between. */ $textarr = preg_split( '/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); $stop = count( $textarr ); // Ignore processing of specific tags. $tags_to_ignore = 'code|pre|style|script|textarea'; $ignore_block_element = ''; 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] ) { $matches = array(); if ( preg_match_all( '/(DZ(e[6-9a-f]|f[0-9a-f]);){2}/', $content, $matches ) ) { if ( ! empty( $matches[0] ) ) { foreach ( $matches[0] as $flag ) { $chars = str_replace( array( '&#x', ';'), '', $flag ); list( $char1, $char2 ) = str_split( $chars, 5 ); $entity = sprintf( '%s', $cdn_url . $char1 . '-' . $char2 . $ext, html_entity_decode( $flag ) ); $content = str_replace( $flag, $entity, $content ); } } } // Loosely match the Emoji Unicode range. $regex = '/(&#x[2-3][0-9a-f]{3};|[1-6][0-9a-f]{2};)/'; $matches = array(); if ( preg_match_all( $regex, $content, $matches ) ) { if ( ! empty( $matches[1] ) ) { foreach ( $matches[1] as $emoji ) { $char = str_replace( array( '&#x', ';'), '', $emoji ); $entity = sprintf( '%s', $cdn_url . $char . $ext, html_entity_decode( $emoji ) ); $content = str_replace( $emoji, $entity, $content ); } } } } // Did we exit ignore block. if ( '' != $ignore_block_element && '' == $content ) { $ignore_block_element = ''; } $output .= $content; } return $output; } /** * Convert emoji in emails into static images. * * @since 4.2.0 * * @param array $mail The email data array. * @return array The email data array, with emoji in the message staticized. */ function wp_staticize_emoji_for_email( $mail ) { if ( ! isset( $mail['message'] ) ) { return $mail; } /* * We can only transform the emoji into images if it's a text/html email. * To do that, here's a cut down version of the same process that happens * in wp_mail() - get the Content-Type from the headers, if there is one, * then pass it through the wp_mail_content_type filter, in case a plugin * is handling changing the Content-Type. */ $headers = array(); if ( isset( $mail['headers'] ) ) { if ( is_array( $mail['headers'] ) ) { $headers = $mail['headers']; } else { $headers = explode( "\n", str_replace( "\r\n", "\n", $mail['headers'] ) ); } } foreach ( $headers as $header ) { if ( strpos($header, ':') === false ) { continue; } // Explode them out. list( $name, $content ) = explode( ':', trim( $header ), 2 ); // Cleanup crew. $name = trim( $name ); $content = trim( $content ); if ( 'content-type' === strtolower( $name ) ) { if ( strpos( $content, ';' ) !== false ) { list( $type, $charset ) = explode( ';', $content ); $content_type = trim( $type ); } else { $content_type = trim( $content ); } break; } } // Set Content-Type if we don't have a content-type from the input headers. if ( ! isset( $content_type ) ) { $content_type = 'text/plain'; } /** This filter is documented in wp-includes/pluggable.php */ $content_type = apply_filters( 'wp_mail_content_type', $content_type ); if ( 'text/html' === $content_type ) { $mail['message'] = wp_staticize_emoji( $mail['message'] ); } return $mail; } /** * Shorten a URL, to be used as link text. * * @since 1.2.0 * @since 4.4.0 Moved to wp-includes/formatting.php from wp-admin/includes/misc.php and added $length param. * * @param string $url URL to shorten. * @param int $length Optional. Maximum length of the shortened URL. Default 35 characters. * @return string Shortened URL. */ function url_shorten( $url, $length = 35 ) { $stripped = str_replace( array( 'https://', 'http://', 'www.' ), '', $url ); $short_url = untrailingslashit( $stripped ); if ( strlen( $short_url ) > $length ) { $short_url = substr( $short_url, 0, $length - 3 ) . '…'; } return $short_url; } /** * Sanitizes a hex color. * * Returns either '', a 3 or 6 digit hex color (with #), or nothing. * For sanitizing values without a #, see sanitize_hex_color_no_hash(). * * @since 3.4.0 * * @param string $color * @return string|void */ function sanitize_hex_color( $color ) { if ( '' === $color ) { return ''; } // 3 or 6 hex digits, or the empty string. if ( preg_match('|^#([A-Fa-f0-9]{3}){1,2}$|', $color ) ) { return $color; } } /** * Sanitizes a hex color without a hash. Use sanitize_hex_color() when possible. * * Saving hex colors without a hash puts the burden of adding the hash on the * UI, which makes it difficult to use or upgrade to other color types such as * rgba, hsl, rgb, and html color names. * * Returns either '', a 3 or 6 digit hex color (without a #), or null. * * @since 3.4.0 * * @param string $color * @return string|null */ function sanitize_hex_color_no_hash( $color ) { $color = ltrim( $color, '#' ); if ( '' === $color ) { return ''; } return sanitize_hex_color( '#' . $color ) ? $color : null; } /** * Ensures that any hex color is properly hashed. * Otherwise, returns value untouched. * * This method should only be necessary if using sanitize_hex_color_no_hash(). * * @since 3.4.0 * * @param string $color * @return string */ function maybe_hash_hex_color( $color ) { if ( $unhashed = sanitize_hex_color_no_hash( $color ) ) { return '#' . $unhashed; } return $color; }