--- a/wp/wp-includes/formatting.php Tue Oct 22 16:11:46 2019 +0200
+++ b/wp/wp-includes/formatting.php Tue Dec 15 13:49:49 2020 +0100
@@ -8,7 +8,10 @@
*/
/**
- * Replaces common plain text characters into formatted entities
+ * Replaces common plain text characters with formatted entities.
+ *
+ * Returns given text with transformations of quotes into smart quotes, apostrophes,
+ * dashes, ellipses, the trademark symbol, and the multiplication symbol.
*
* As an example,
*
@@ -18,35 +21,18 @@
*
* ’cause today’s effort makes it worth tomorrow’s “holiday” …
*
- * Code within certain html blocks are skipped.
+ * Code within certain HTML blocks are skipped.
*
* Do not use this function before the {@see 'init'} action hook; everything will break.
*
* @since 0.71
*
- * @global array $wp_cockneyreplace Array of formatted entities for certain common phrases
+ * @global array $wp_cockneyreplace Array of formatted entities for certain common phrases.
* @global array $shortcode_tags
- * @staticvar array $static_characters
- * @staticvar array $static_replacements
- * @staticvar array $dynamic_characters
- * @staticvar array $dynamic_replacements
- * @staticvar array $default_no_texturize_tags
- * @staticvar array $default_no_texturize_shortcodes
- * @staticvar bool $run_texturize
- * @staticvar string $apos
- * @staticvar string $prime
- * @staticvar string $double_prime
- * @staticvar string $opening_quote
- * @staticvar string $closing_quote
- * @staticvar string $opening_single_quote
- * @staticvar string $closing_single_quote
- * @staticvar string $open_q_flag
- * @staticvar string $open_sq_flag
- * @staticvar string $apos_flag
- *
- * @param string $text The text to be formatted
+ *
+ * @param string $text The text to be formatted.
* @param bool $reset Set to true for unit testing. Translated patterns will reset.
- * @return string The string replaced with html entities
+ * @return string The string replaced with HTML entities.
*/
function wptexturize( $text, $reset = false ) {
global $wp_cockneyreplace, $shortcode_tags;
@@ -78,8 +64,8 @@
/**
* Filters whether to skip running wptexturize().
*
- * Passing false to the filter will effectively short-circuit wptexturize().
- * returning the original text passed to the function instead.
+ * Returning false from the filter will effectively short-circuit wptexturize()
+ * and return the original text passed to the function instead.
*
* The filter runs only once, the first time wptexturize() is called.
*
@@ -94,39 +80,40 @@
return $text;
}
- /* translators: opening curly double quote */
+ /* translators: Opening curly double quote. */
$opening_quote = _x( '“', 'opening curly double quote' );
- /* translators: closing curly double quote */
+ /* translators: Closing curly double quote. */
$closing_quote = _x( '”', 'closing curly double quote' );
- /* translators: apostrophe, for example in 'cause or can't */
+ /* translators: Apostrophe, for example in 'cause or can't. */
$apos = _x( '’', 'apostrophe' );
- /* translators: prime, for example in 9' (nine feet) */
+ /* translators: Prime, for example in 9' (nine feet). */
$prime = _x( '′', 'prime' );
- /* translators: double prime, for example in 9" (nine inches) */
+ /* translators: Double prime, for example in 9" (nine inches). */
$double_prime = _x( '″', 'double prime' );
- /* translators: opening curly single quote */
+ /* translators: Opening curly single quote. */
$opening_single_quote = _x( '‘', 'opening curly single quote' );
- /* translators: closing curly single quote */
+ /* translators: Closing curly single quote. */
$closing_single_quote = _x( '’', 'closing curly single quote' );
- /* translators: en dash */
+ /* translators: En dash. */
$en_dash = _x( '–', 'en dash' );
- /* translators: em dash */
+ /* translators: Em dash. */
$em_dash = _x( '—', 'em dash' );
$default_no_texturize_tags = array( 'pre', 'code', 'kbd', 'style', 'script', 'tt' );
$default_no_texturize_shortcodes = array( 'code' );
- // if a plugin has provided an autocorrect array, use it
+ // If a plugin has provided an autocorrect array, use it.
if ( isset( $wp_cockneyreplace ) ) {
$cockney = array_keys( $wp_cockneyreplace );
$cockneyreplace = array_values( $wp_cockneyreplace );
} else {
- /* translators: This is a comma-separated list of words that defy the syntax of quotations in normal use,
- * for example... 'We do not have enough words yet' ... is a typical quoted phrase. But when we write
+ /*
+ * translators: This is a comma-separated list of words that defy the syntax of quotations in normal use,
+ * for example... 'We do not have enough words yet'... is a typical quoted phrase. But when we write
* lines of code 'til we have enough of 'em, then we need to insert apostrophes instead of quotes.
*/
$cockney = explode(
@@ -177,7 +164,7 @@
$dynamic['/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/'] = $apos_flag;
}
- // Quoted Numbers like '0.42'
+ // Quoted numbers like '0.42'.
if ( "'" !== $opening_single_quote && "'" !== $closing_single_quote ) {
$dynamic[ '/(?<=\A|' . $spaces . ')\'(\d[.,\d]*)\'/' ] = $open_sq_flag . '$1' . $closing_single_quote;
}
@@ -187,7 +174,7 @@
$dynamic[ '/(?<=\A|[([{"\-]|<|' . $spaces . ')\'/' ] = $open_sq_flag;
}
- // Apostrophe in a word. No spaces, double apostrophes, or other punctuation.
+ // Apostrophe in a word. No spaces, double apostrophes, or other punctuation.
if ( "'" !== $apos ) {
$dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;!?"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos_flag;
}
@@ -196,7 +183,7 @@
$dynamic_replacements['apos'] = array_values( $dynamic );
$dynamic = array();
- // Quoted Numbers like "42"
+ // Quoted numbers like "42".
if ( '"' !== $opening_quote && '"' !== $closing_quote ) {
$dynamic[ '/(?<=\A|' . $spaces . ')"(\d[.,\d]*)"/' ] = $open_q_flag . '$1' . $closing_quote;
}
@@ -210,7 +197,7 @@
$dynamic_replacements['quote'] = array_values( $dynamic );
$dynamic = array();
- // Dashes and spaces
+ // Dashes and spaces.
$dynamic['/---/'] = $em_dash;
$dynamic[ '/(?<=^|' . $spaces . ')--(?=$|' . $spaces . ')/' ] = $em_dash;
$dynamic['/(?<!xn)--/'] = $en_dash;
@@ -220,13 +207,13 @@
$dynamic_replacements['dash'] = array_values( $dynamic );
}
- // Must do this every time in case plugins use these filters in a context sensitive manner
+ // Must do this every time in case plugins use these filters in a context sensitive manner.
/**
* Filters the list of HTML elements not to texturize.
*
* @since 2.8.0
*
- * @param array $default_no_texturize_tags An array of HTML element names.
+ * @param string[] $default_no_texturize_tags An array of HTML element names.
*/
$no_texturize_tags = apply_filters( 'no_texturize_tags', $default_no_texturize_tags );
/**
@@ -234,7 +221,7 @@
*
* @since 2.8.0
*
- * @param array $default_no_texturize_shortcodes An array of shortcode names.
+ * @param string[] $default_no_texturize_shortcodes An array of shortcode names.
*/
$no_texturize_shortcodes = apply_filters( 'no_texturize_shortcodes', $default_no_texturize_shortcodes );
@@ -267,7 +254,7 @@
_wptexturize_pushpop_element( $curl, $no_texturize_tags_stack, $no_texturize_tags );
}
} elseif ( '' === trim( $curl ) ) {
- // This is a newline between delimiters. Performance improves when we check this.
+ // This is a newline between delimiters. Performance improves when we check this.
continue;
} elseif ( '[' === $first && $found_shortcodes && 1 === preg_match( '/^' . $shortcode_regex . '$/', $curl ) ) {
@@ -281,7 +268,7 @@
continue;
}
} elseif ( empty( $no_texturize_shortcodes_stack ) && empty( $no_texturize_tags_stack ) ) {
- // This is neither a delimiter, nor is this content inside of no_texturize pairs. Do texturize.
+ // This is neither a delimiter, nor is this content inside of no_texturize pairs. Do texturize.
$curl = str_replace( $static_characters, $static_replacements, $curl );
@@ -300,7 +287,7 @@
$curl = preg_replace( $dynamic_characters['dash'], $dynamic_replacements['dash'], $curl );
}
- // 9x9 (times), but never 0x9999
+ // 9x9 (times), but never 0x9999.
if ( 1 === preg_match( '/(?<=\d)x\d/', $curl ) ) {
// Searching for a digit is 10 times more expensive than for the x, so we avoid doing this one!
$curl = preg_replace( '/\b(\d(?(?<=0)[\d\.,]+|[\d\.,]*))x(\d[\d\.,]*)\b/', '$1×$2', $curl );
@@ -344,7 +331,7 @@
} elseif ( 0 !== $key && 0 === substr_count( $sentence, $close_quote ) ) {
$sentence = preg_replace( $quote_pattern, $flag, $sentence, -1, $count );
if ( $count > 1 ) {
- // This sentence appears to have multiple closing quotes. Attempt Vulcan logic.
+ // This sentence appears to have multiple closing quotes. Attempt Vulcan logic.
$sentence = preg_replace( $flag_no_digit, $close_quote, $sentence, -1, $count2 );
if ( 0 === $count2 ) {
// Try looking for a quote followed by a period.
@@ -368,14 +355,14 @@
$sentence = str_replace( $flag, $close_quote, $sentence );
$sentence = preg_replace( $prime_pattern, $prime, $sentence );
} else {
- // No closing quotes found. Just run primes pattern.
+ // No closing quotes found. Just run primes pattern.
$sentence = preg_replace( $prime_pattern, $prime, $sentence );
}
} else {
$sentence = preg_replace( $prime_pattern, $prime, $sentence );
$sentence = preg_replace( $quote_pattern, $close_quote, $sentence );
}
- if ( '"' == $needle && false !== strpos( $sentence, '"' ) ) {
+ if ( '"' === $needle && false !== strpos( $sentence, '"' ) ) {
$sentence = str_replace( '"', $close_quote, $sentence );
}
}
@@ -393,16 +380,16 @@
* @since 2.9.0
* @access private
*
- * @param string $text Text to check. Must be a tag like `<html>` or `[shortcode]`.
- * @param array $stack List of open tag elements.
- * @param array $disabled_elements The tag names to match against. Spaces are not allowed in tag names.
+ * @param string $text Text to check. Must be a tag like `<html>` or `[shortcode]`.
+ * @param string[] $stack Array of open tag elements.
+ * @param string[] $disabled_elements Array of tag names to match against. Spaces are not allowed in tag names.
*/
function _wptexturize_pushpop_element( $text, &$stack, $disabled_elements ) {
// Is it an opening tag or closing tag?
if ( isset( $text[1] ) && '/' !== $text[1] ) {
$opening_tag = true;
$name_offset = 1;
- } elseif ( 0 == count( $stack ) ) {
+ } elseif ( 0 === count( $stack ) ) {
// Stack is empty. Just stop.
return;
} else {
@@ -420,14 +407,14 @@
$tag = substr( $text, $name_offset, $space );
// Handle disabled tags.
- if ( in_array( $tag, $disabled_elements ) ) {
+ if ( in_array( $tag, $disabled_elements, true ) ) {
if ( $opening_tag ) {
/*
* This disables texturize until we find a closing tag of our type
- * (e.g. <pre>) even if there was invalid nesting before that
+ * (e.g. <pre>) even if there was invalid nesting before that.
*
* Example: in the case <pre>sadsadasd</code>"baba"</pre>
- * "baba" won't be texturize
+ * "baba" won't be texturized.
*/
array_push( $stack, $tag );
@@ -438,17 +425,18 @@
}
/**
- * Replaces double line-breaks with paragraph elements.
+ * Replaces double line breaks with paragraph elements.
*
* A group of regex replaces used to identify text formatted with newlines and
- * replace double line-breaks with HTML paragraph tags. The remaining line-breaks
+ * replace double line breaks with HTML paragraph tags. The remaining line breaks
* after conversion become <<br />> tags, unless $br is set to '0' or 'false'.
*
* @since 0.71
*
* @param string $pee The text which has to be formatted.
- * @param bool $br Optional. If set, this will convert all remaining line-breaks
- * after paragraphing. Default true.
+ * @param bool $br Optional. If set, this will convert all remaining line breaks
+ * after paragraphing. Line breaks within `<script>`, `<style>`,
+ * and `<svg>` tags are not affected. Default true.
* @return string Text which has been converted into correct paragraph tags.
*/
function wpautop( $pee, $br = true ) {
@@ -474,8 +462,8 @@
foreach ( $pee_parts as $pee_part ) {
$start = strpos( $pee_part, '<pre' );
- // Malformed html?
- if ( $start === false ) {
+ // Malformed HTML?
+ if ( false === $start ) {
$pee .= $pee_part;
continue;
}
@@ -489,7 +477,7 @@
$pee .= $last_pee;
}
- // Change multiple <br>s into two line breaks, which will turn into paragraphs.
+ // Change multiple <br>'s into two line breaks, which will turn into paragraphs.
$pee = preg_replace( '|<br\s*/?>\s*<br\s*/?>|', "\n\n", $pee );
$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)';
@@ -500,6 +488,9 @@
// Add a double line break below block-level closing tags.
$pee = preg_replace( '!(</' . $allblocks . '>)!', "$1\n\n", $pee );
+ // Add a double line break after hr tags, which are self closing.
+ $pee = preg_replace( '!(<hr\s*?/?>)!', "$1\n\n", $pee );
+
// Standardize newline characters to "\n".
$pee = str_replace( array( "\r\n", "\r" ), "\n", $pee );
@@ -577,7 +568,7 @@
// Optionally insert line breaks.
if ( $br ) {
// Replace newlines that shouldn't be touched with a placeholder.
- $pee = preg_replace_callback( '/<(script|style).*?<\/\\1>/s', '_autop_newline_preservation_helper', $pee );
+ $pee = preg_replace_callback( '/<(script|style|svg).*?<\/\\1>/s', '_autop_newline_preservation_helper', $pee );
// Normalize <br>
$pee = str_replace( array( '<br>', '<br/>' ), '<br />', $pee );
@@ -615,7 +606,7 @@
* @since 4.2.4
*
* @param string $input The text which has to be formatted.
- * @return array The formatted text.
+ * @return string[] Array of the formatted text.
*/
function wp_html_split( $input ) {
return preg_split( get_html_split_regex(), $input, -1, PREG_SPLIT_DELIM_CAPTURE );
@@ -626,8 +617,6 @@
*
* @since 4.4.0
*
- * @staticvar string $regex
- *
* @return string The regular expression
*/
function get_html_split_regex() {
@@ -669,7 +658,7 @@
. '<' // Find start of element.
. '(?' // Conditional expression follows.
. $escaped // Find end of escaped element.
- . '|' // ... else ...
+ . '|' // ...else...
. '[^>]*>?' // Find end of normal element.
. ')'
. ')/';
@@ -687,9 +676,7 @@
* @internal This function will be removed in 4.5.0 per Shortcode API Roadmap.
* @since 4.4.0
*
- * @staticvar string $html_regex
- *
- * @param string $shortcode_regex The result from _get_wptexturize_shortcode_regex(). Optional.
+ * @param string $shortcode_regex The result from _get_wptexturize_shortcode_regex(). Optional.
* @return string The regular expression
*/
function _get_wptexturize_split_regex( $shortcode_regex = '' ) {
@@ -729,10 +716,9 @@
*
* @access private
* @ignore
- * @internal This function will be removed in 4.5.0 per Shortcode API Roadmap.
* @since 4.4.0
*
- * @param array $tagnames List of shortcodes to find.
+ * @param string[] $tagnames Array of shortcodes to find.
* @return string The regular expression
*/
function _get_wptexturize_shortcode_regex( $tagnames ) {
@@ -740,8 +726,8 @@
$tagregexp = "(?:$tagregexp)(?=[\\s\\]\\/])"; // Excerpt of get_shortcode_regex().
// phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation
$regex =
- '\[' // Find start of shortcode.
- . '[\/\[]?' // Shortcodes may begin with [/ or [[
+ '\[' // Find start of shortcode.
+ . '[\/\[]?' // Shortcodes may begin with [/ or [[.
. $tagregexp // Only match registered shortcodes, because performance.
. '(?:'
. '[^\[\]<>]+' // Shortcodes do not contain other shortcodes. Quantifier critical.
@@ -749,7 +735,7 @@
. '<[^\[\]>]*>' // HTML elements permitted. Prevents matching ] before >.
. ')*+' // Possessive critical.
. '\]' // Find end of shortcode.
- . '\]?'; // Shortcodes may end with ]]
+ . '\]?'; // Shortcodes may end with ]].
// phpcs:enable
return $regex;
@@ -760,8 +746,8 @@
*
* @since 4.2.3
*
- * @param string $haystack The text which has to be formatted.
- * @param array $replace_pairs In the form array('from' => 'to', ...).
+ * @param string $haystack The text which has to be formatted.
+ * @param array $replace_pairs In the form array('from' => 'to', ...).
* @return string The formatted text.
*/
function wp_replace_in_html_tags( $haystack, $replace_pairs ) {
@@ -841,37 +827,37 @@
$tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags ) ) );
$spaces = wp_spaces_regexp();
- // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation
+ // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound,WordPress.WhiteSpace.PrecisionAlignment.Found -- don't remove regex indentation
$pattern =
'/'
- . '<p>' // Opening paragraph
- . '(?:' . $spaces . ')*+' // Optional leading whitespace
- . '(' // 1: The shortcode
- . '\\[' // Opening bracket
- . "($tagregexp)" // 2: Shortcode name
- . '(?![\\w-])' // Not followed by word character or hyphen
- // Unroll the loop: Inside the opening shortcode tag
- . '[^\\]\\/]*' // Not a closing bracket or forward slash
+ . '<p>' // Opening paragraph.
+ . '(?:' . $spaces . ')*+' // Optional leading whitespace.
+ . '(' // 1: The shortcode.
+ . '\\[' // Opening bracket.
+ . "($tagregexp)" // 2: Shortcode name.
+ . '(?![\\w-])' // Not followed by word character or hyphen.
+ // Unroll the loop: Inside the opening shortcode tag.
+ . '[^\\]\\/]*' // Not a closing bracket or forward slash.
. '(?:'
- . '\\/(?!\\])' // A forward slash not followed by a closing bracket
- . '[^\\]\\/]*' // Not a closing bracket or forward slash
+ . '\\/(?!\\])' // A forward slash not followed by a closing bracket.
+ . '[^\\]\\/]*' // Not a closing bracket or forward slash.
. ')*?'
. '(?:'
- . '\\/\\]' // Self closing tag and closing bracket
+ . '\\/\\]' // Self closing tag and closing bracket.
. '|'
- . '\\]' // Closing bracket
- . '(?:' // Unroll the loop: Optionally, anything between the opening and closing shortcode tags
- . '[^\\[]*+' // Not an opening bracket
+ . '\\]' // Closing bracket.
+ . '(?:' // Unroll the loop: Optionally, anything between the opening and closing shortcode tags.
+ . '[^\\[]*+' // Not an opening bracket.
. '(?:'
- . '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag
- . '[^\\[]*+' // Not an opening bracket
+ . '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag.
+ . '[^\\[]*+' // Not an opening bracket.
. ')*+'
- . '\\[\\/\\2\\]' // Closing shortcode tag
+ . '\\[\\/\\2\\]' // Closing shortcode tag.
. ')?'
. ')'
. ')'
- . '(?:' . $spaces . ')*+' // optional trailing whitespace
- . '<\\/p>' // closing paragraph
+ . '(?:' . $spaces . ')*+' // Optional trailing whitespace.
+ . '<\\/p>' // Closing paragraph.
. '/';
// phpcs:enable
@@ -909,7 +895,7 @@
} elseif ( ( $c & 0xFE ) == 0xFC ) {
$n = 5; // 1111110b
} else {
- return false; // Does not match any model
+ return false; // Does not match any model.
}
for ( $j = 0; $j < $n; $j++ ) { // n bytes matching 10bbbbbb follow ?
if ( ( ++$i == $length ) || ( ( ord( $str[ $i ] ) & 0xC0 ) != 0x80 ) ) {
@@ -929,18 +915,20 @@
* ", or ENT_QUOTES to do both. Default is ENT_NOQUOTES where no quotes are encoded.
*
* @since 1.2.2
+ * @since 5.5.0 `$quote_style` also accepts `ENT_XML1`.
* @access private
*
- * @staticvar string $_charset
- *
- * @param string $string The text which is to be encoded.
- * @param int|string $quote_style Optional. Converts double quotes if set to ENT_COMPAT,
- * both single and double if set to ENT_QUOTES or none if set to ENT_NOQUOTES.
- * Also compatible with old values; converting single quotes if set to 'single',
- * double if set to 'double' or both if otherwise set.
- * Default is ENT_NOQUOTES.
- * @param string $charset Optional. The character encoding of the string. Default is false.
- * @param bool $double_encode Optional. Whether to encode existing html entities. Default is false.
+ * @param string $string The text which is to be encoded.
+ * @param int|string $quote_style Optional. Converts double quotes if set to ENT_COMPAT,
+ * both single and double if set to ENT_QUOTES or none if set to ENT_NOQUOTES.
+ * Converts single and double quotes, as well as converting HTML
+ * named entities (that are not also XML named entities) to their
+ * code points if set to ENT_XML1. Also compatible with old values;
+ * converting single quotes if set to 'single',
+ * double if set to 'double' or both if otherwise set.
+ * Default is ENT_NOQUOTES.
+ * @param false|string $charset Optional. The character encoding of the string. Default false.
+ * @param bool $double_encode Optional. Whether to encode existing HTML entities. Default false.
* @return string The encoded text with HTML entities.
*/
function _wp_specialchars( $string, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false ) {
@@ -950,19 +938,21 @@
return '';
}
- // Don't bother if there are no specialchars - saves some processing
+ // Don't bother if there are no specialchars - saves some processing.
if ( ! preg_match( '/[&<>"\']/', $string ) ) {
return $string;
}
- // Account for the previous behaviour of the function when the $quote_style is not an accepted value
+ // Account for the previous behaviour of the function when the $quote_style is not an accepted value.
if ( empty( $quote_style ) ) {
$quote_style = ENT_NOQUOTES;
- } elseif ( ! in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) {
+ } elseif ( ENT_XML1 === $quote_style ) {
+ $quote_style = ENT_QUOTES | ENT_XML1;
+ } elseif ( ! in_array( $quote_style, array( ENT_NOQUOTES, ENT_COMPAT, ENT_QUOTES, 'single', 'double' ), true ) ) {
$quote_style = ENT_QUOTES;
}
- // Store the site charset as a static to avoid multiple calls to wp_load_alloptions()
+ // Store the site charset as a static to avoid multiple calls to wp_load_alloptions().
if ( ! $charset ) {
static $_charset = null;
if ( ! isset( $_charset ) ) {
@@ -972,26 +962,26 @@
$charset = $_charset;
}
- if ( in_array( $charset, array( 'utf8', 'utf-8', 'UTF8' ) ) ) {
+ if ( in_array( $charset, array( 'utf8', 'utf-8', 'UTF8' ), true ) ) {
$charset = 'UTF-8';
}
$_quote_style = $quote_style;
- if ( $quote_style === 'double' ) {
+ if ( 'double' === $quote_style ) {
$quote_style = ENT_COMPAT;
$_quote_style = ENT_COMPAT;
- } elseif ( $quote_style === 'single' ) {
+ } elseif ( 'single' === $quote_style ) {
$quote_style = ENT_NOQUOTES;
}
if ( ! $double_encode ) {
// Guarantee every &entity; is valid, convert &garbage; into &garbage;
// This is required for PHP < 5.4.0 because ENT_HTML401 flag is unavailable.
- $string = wp_kses_normalize_entities( $string );
- }
-
- $string = @htmlspecialchars( $string, $quote_style, $charset, $double_encode );
+ $string = wp_kses_normalize_entities( $string, ( $quote_style & ENT_XML1 ) ? 'xml' : 'html' );
+ }
+
+ $string = htmlspecialchars( $string, $quote_style, $charset, $double_encode );
// Back-compat.
if ( 'single' === $_quote_style ) {
@@ -1028,19 +1018,19 @@
return '';
}
- // Don't bother if there are no entities - saves a lot of processing
+ // Don't bother if there are no entities - saves a lot of processing.
if ( strpos( $string, '&' ) === false ) {
return $string;
}
- // Match the previous behaviour of _wp_specialchars() when the $quote_style is not an accepted value
+ // Match the previous behaviour of _wp_specialchars() when the $quote_style is not an accepted value.
if ( empty( $quote_style ) ) {
$quote_style = ENT_NOQUOTES;
} elseif ( ! in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) {
$quote_style = ENT_QUOTES;
}
- // More complete than get_html_translation_table( HTML_SPECIALCHARS )
+ // More complete than get_html_translation_table( HTML_SPECIALCHARS ).
$single = array(
''' => '\'',
''' => '\'',
@@ -1074,24 +1064,24 @@
'/�*26;/i' => '&',
);
- if ( $quote_style === ENT_QUOTES ) {
+ if ( ENT_QUOTES === $quote_style ) {
$translation = array_merge( $single, $double, $others );
$translation_preg = array_merge( $single_preg, $double_preg, $others_preg );
- } elseif ( $quote_style === ENT_COMPAT || $quote_style === 'double' ) {
+ } elseif ( ENT_COMPAT === $quote_style || 'double' === $quote_style ) {
$translation = array_merge( $double, $others );
$translation_preg = array_merge( $double_preg, $others_preg );
- } elseif ( $quote_style === 'single' ) {
+ } elseif ( 'single' === $quote_style ) {
$translation = array_merge( $single, $others );
$translation_preg = array_merge( $single_preg, $others_preg );
- } elseif ( $quote_style === ENT_NOQUOTES ) {
+ } elseif ( ENT_NOQUOTES === $quote_style ) {
$translation = $others;
$translation_preg = $others_preg;
}
- // Remove zero padding on numeric entities
+ // Remove zero padding on numeric entities.
$string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string );
- // Replace characters according to translation table
+ // Replace characters according to translation table.
return strtr( $string, $translation );
}
@@ -1100,11 +1090,8 @@
*
* @since 2.8.0
*
- * @staticvar bool $is_utf8
- * @staticvar bool $utf8_pcre
- *
- * @param string $string The text which is to be checked.
- * @param bool $strip Optional. Whether to attempt to strip out invalid UTF8. Default is false.
+ * @param string $string The text which is to be checked.
+ * @param bool $strip Optional. Whether to attempt to strip out invalid UTF8. Default false.
* @return string The checked text.
*/
function wp_check_invalid_utf8( $string, $strip = false ) {
@@ -1114,31 +1101,32 @@
return '';
}
- // Store the site charset as a static to avoid multiple calls to get_option()
+ // Store the site charset as a static to avoid multiple calls to get_option().
static $is_utf8 = null;
if ( ! isset( $is_utf8 ) ) {
- $is_utf8 = in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) );
+ $is_utf8 = in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ), true );
}
if ( ! $is_utf8 ) {
return $string;
}
- // Check for support for utf8 in the installed PCRE library once and store the result in a static
+ // Check for support for utf8 in the installed PCRE library once and store the result in a static.
static $utf8_pcre = null;
if ( ! isset( $utf8_pcre ) ) {
+ // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
$utf8_pcre = @preg_match( '/^./u', 'a' );
}
- // We can't demand utf8 in the PCRE installation, so just return the string in those cases
+ // We can't demand utf8 in the PCRE installation, so just return the string in those cases.
if ( ! $utf8_pcre ) {
return $string;
}
- // preg_match fails when it encounters invalid UTF8 in $string
+ // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- preg_match fails when it encounters invalid UTF8 in $string.
if ( 1 === @preg_match( '/^./us', $string ) ) {
return $string;
}
- // Attempt to strip the bad chars if requested (not recommended)
+ // Attempt to strip the bad chars if requested (not recommended).
if ( $strip && function_exists( 'iconv' ) ) {
return iconv( 'utf-8', 'utf-8', $string );
}
@@ -1600,7 +1588,7 @@
if ( seems_utf8( $string ) ) {
$chars = array(
- // Decompositions for Latin-1 Supplement
+ // Decompositions for Latin-1 Supplement.
'ª' => 'a',
'º' => 'o',
'À' => 'A',
@@ -1665,7 +1653,7 @@
'þ' => 'th',
'ÿ' => 'y',
'Ø' => 'O',
- // Decompositions for Latin Extended-A
+ // Decompositions for Latin Extended-A.
'Ā' => 'A',
'ā' => 'a',
'Ă' => 'A',
@@ -1794,22 +1782,22 @@
'Ž' => 'Z',
'ž' => 'z',
'ſ' => 's',
- // Decompositions for Latin Extended-B
+ // Decompositions for Latin Extended-B.
'Ș' => 'S',
'ș' => 's',
'Ț' => 'T',
'ț' => 't',
- // Euro Sign
+ // Euro sign.
'€' => 'E',
- // GBP (Pound) Sign
+ // GBP (Pound) sign.
'£' => '',
- // Vowels with diacritic (Vietnamese)
- // unmarked
+ // Vowels with diacritic (Vietnamese).
+ // Unmarked.
'Ơ' => 'O',
'ơ' => 'o',
'Ư' => 'U',
'ư' => 'u',
- // grave accent
+ // Grave accent.
'Ầ' => 'A',
'ầ' => 'a',
'Ằ' => 'A',
@@ -1824,7 +1812,7 @@
'ừ' => 'u',
'Ỳ' => 'Y',
'ỳ' => 'y',
- // hook
+ // Hook.
'Ả' => 'A',
'ả' => 'a',
'Ẩ' => 'A',
@@ -1849,7 +1837,7 @@
'ử' => 'u',
'Ỷ' => 'Y',
'ỷ' => 'y',
- // tilde
+ // Tilde.
'Ẫ' => 'A',
'ẫ' => 'a',
'Ẵ' => 'A',
@@ -1866,7 +1854,7 @@
'ữ' => 'u',
'Ỹ' => 'Y',
'ỹ' => 'y',
- // acute accent
+ // Acute accent.
'Ấ' => 'A',
'ấ' => 'a',
'Ắ' => 'A',
@@ -1879,7 +1867,7 @@
'ớ' => 'o',
'Ứ' => 'U',
'ứ' => 'u',
- // dot below
+ // Dot below.
'Ạ' => 'A',
'ạ' => 'a',
'Ậ' => 'A',
@@ -1904,15 +1892,15 @@
'ự' => 'u',
'Ỵ' => 'Y',
'ỵ' => 'y',
- // Vowels with diacritic (Chinese, Hanyu Pinyin)
+ // Vowels with diacritic (Chinese, Hanyu Pinyin).
'ɑ' => 'a',
- // macron
+ // Macron.
'Ǖ' => 'U',
'ǖ' => 'u',
- // acute accent
+ // Acute accent.
'Ǘ' => 'U',
'ǘ' => 'u',
- // caron
+ // Caron.
'Ǎ' => 'A',
'ǎ' => 'a',
'Ǐ' => 'I',
@@ -1923,15 +1911,15 @@
'ǔ' => 'u',
'Ǚ' => 'U',
'ǚ' => 'u',
- // grave accent
+ // Grave accent.
'Ǜ' => 'U',
'ǜ' => 'u',
);
- // Used for locale-specific rules
+ // Used for locale-specific rules.
$locale = get_locale();
- if ( 'de_DE' == $locale || 'de_DE_formal' == $locale || 'de_CH' == $locale || 'de_CH_informal' == $locale ) {
+ if ( in_array( $locale, array( 'de_DE', 'de_DE_formal', 'de_CH', 'de_CH_informal' ), true ) ) {
$chars['Ä'] = 'Ae';
$chars['ä'] = 'ae';
$chars['Ö'] = 'Oe';
@@ -1956,7 +1944,7 @@
$string = strtr( $string, $chars );
} else {
$chars = array();
- // Assume ISO-8859-1 if not UTF-8
+ // Assume ISO-8859-1 if not UTF-8.
$chars['in'] = "\x80\x83\x8a\x8e\x9a\x9e"
. "\x9f\xa2\xa5\xb5\xc0\xc1\xc2"
. "\xc3\xc4\xc5\xc7\xc8\xc9\xca"
@@ -1992,26 +1980,46 @@
*
* @since 2.1.0
*
- * @param string $filename The filename to be sanitized
- * @return string The sanitized filename
+ * @param string $filename The filename to be sanitized.
+ * @return string The sanitized filename.
*/
function sanitize_file_name( $filename ) {
- $filename_raw = $filename;
- $special_chars = array( '?', '[', ']', '/', '\\', '=', '<', '>', ':', ';', ',', "'", '"', '&', '$', '#', '*', '(', ')', '|', '~', '`', '!', '{', '}', '%', '+', chr( 0 ) );
+ $filename_raw = $filename;
+ $filename = remove_accents( $filename );
+
+ $special_chars = array( '?', '[', ']', '/', '\\', '=', '<', '>', ':', ';', ',', "'", '"', '&', '$', '#', '*', '(', ')', '|', '~', '`', '!', '{', '}', '%', '+', '’', '«', '»', '”', '“', chr( 0 ) );
+
+ // Check for support for utf8 in the installed PCRE library once and store the result in a static.
+ static $utf8_pcre = null;
+ if ( ! isset( $utf8_pcre ) ) {
+ // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
+ $utf8_pcre = @preg_match( '/^./u', 'a' );
+ }
+
+ if ( ! seems_utf8( $filename ) ) {
+ $_ext = pathinfo( $filename, PATHINFO_EXTENSION );
+ $_name = pathinfo( $filename, PATHINFO_FILENAME );
+ $filename = sanitize_title_with_dashes( $_name ) . '.' . $_ext;
+ }
+
+ if ( $utf8_pcre ) {
+ $filename = preg_replace( "#\x{00a0}#siu", ' ', $filename );
+ }
+
/**
* Filters the list of characters to remove from a filename.
*
* @since 2.8.0
*
- * @param array $special_chars Characters to remove.
- * @param string $filename_raw Filename as it was passed into sanitize_file_name().
+ * @param string[] $special_chars Array of characters to remove.
+ * @param string $filename_raw The original filename to be sanitized.
*/
$special_chars = apply_filters( 'sanitize_file_name_chars', $special_chars, $filename_raw );
- $filename = preg_replace( "#\x{00a0}#siu", ' ', $filename );
- $filename = str_replace( $special_chars, '', $filename );
- $filename = str_replace( array( '%20', '+' ), '-', $filename );
- $filename = preg_replace( '/[\r\n\t -]+/', '-', $filename );
- $filename = trim( $filename, '.-_' );
+
+ $filename = str_replace( $special_chars, '', $filename );
+ $filename = str_replace( array( '%20', '+' ), '-', $filename );
+ $filename = preg_replace( '/[\r\n\t -]+/', '-', $filename );
+ $filename = trim( $filename, '.-_' );
if ( false === strpos( $filename, '.' ) ) {
$mime_types = wp_get_mime_types();
@@ -2021,10 +2029,10 @@
}
}
- // Split the filename into a base and extension[s]
+ // Split the filename into a base and extension[s].
$parts = explode( '.', $filename );
- // Return if only one extension
+ // Return if only one extension.
if ( count( $parts ) <= 2 ) {
/**
* Filters a sanitized filename string.
@@ -2037,14 +2045,14 @@
return apply_filters( 'sanitize_file_name', $filename, $filename_raw );
}
- // Process multiple extensions
+ // Process multiple extensions.
$filename = array_shift( $parts );
$extension = array_pop( $parts );
$mimes = get_allowed_mime_types();
/*
* Loop over any intermediate extensions. Postfix them with a trailing underscore
- * if they are a 2 - 5 character long alpha string not in the extension whitelist.
+ * if they are a 2 - 5 character long alpha string not in the allowed extension list.
*/
foreach ( (array) $parts as $part ) {
$filename .= '.' . $part;
@@ -2063,7 +2071,9 @@
}
}
}
+
$filename .= '.' . $extension;
+
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'sanitize_file_name', $filename, $filename_raw );
}
@@ -2079,16 +2089,18 @@
* @since 2.0.0
*
* @param string $username The username to be sanitized.
- * @param bool $strict If set limits $username to specific characters. Default false.
+ * @param bool $strict Optional. If set limits $username to specific characters.
+ * Default false.
* @return string The sanitized username, after passing through filters.
*/
function sanitize_user( $username, $strict = false ) {
$raw_username = $username;
$username = wp_strip_all_tags( $username );
$username = remove_accents( $username );
- // Kill octets
+ // Kill octets.
$username = preg_replace( '|%([a-fA-F0-9][a-fA-F0-9])|', '', $username );
- $username = preg_replace( '/&.+?;/', '', $username ); // Kill entities
+ // Kill entities.
+ $username = preg_replace( '/&.+?;/', '', $username );
// If strict, reduce to ASCII for max portability.
if ( $strict ) {
@@ -2096,7 +2108,7 @@
}
$username = trim( $username );
- // Consolidate contiguous whitespace
+ // Consolidate contiguous whitespace.
$username = preg_replace( '|\s+|', ' ', $username );
/**
@@ -2106,7 +2118,7 @@
*
* @param string $username Sanitized username.
* @param string $raw_username The username prior to sanitization.
- * @param bool $strict Whether to limit the sanitization to specific characters. Default false.
+ * @param bool $strict Whether to limit the sanitization to specific characters.
*/
return apply_filters( 'sanitize_user', $username, $raw_username, $strict );
}
@@ -2114,7 +2126,8 @@
/**
* Sanitizes a string key.
*
- * Keys are used as internal identifiers. Lowercase alphanumeric characters, dashes and underscores are allowed.
+ * Keys are used as internal identifiers. Lowercase alphanumeric characters,
+ * dashes, and underscores are allowed.
*
* @since 3.0.0
*
@@ -2138,23 +2151,26 @@
}
/**
- * Sanitizes a title, or returns a fallback title.
- *
- * Specifically, HTML and PHP tags are stripped. Further actions can be added
- * via the plugin API. If $title is empty and $fallback_title is set, the latter
- * will be used.
+ * Sanitizes a string into a slug, which can be used in URLs or HTML attributes.
+ *
+ * By default, converts accent characters to ASCII characters and further
+ * limits the output to alphanumeric characters, underscore (_) and dash (-)
+ * through the {@see 'sanitize_title'} filter.
+ *
+ * If `$title` is empty and `$fallback_title` is set, the latter will be used.
*
* @since 1.0.0
*
* @param string $title The string to be sanitized.
- * @param string $fallback_title Optional. A title to use if $title is empty.
- * @param string $context Optional. The operation for which the string is sanitized
+ * @param string $fallback_title Optional. A title to use if $title is empty. Default empty.
+ * @param string $context Optional. The operation for which the string is sanitized.
+ * Default 'save'.
* @return string The sanitized string.
*/
function sanitize_title( $title, $fallback_title = '', $context = 'save' ) {
$raw_title = $title;
- if ( 'save' == $context ) {
+ if ( 'save' === $context ) {
$title = remove_accents( $title );
}
@@ -2199,8 +2215,9 @@
* @since 1.2.0
*
* @param string $title The title to be sanitized.
- * @param string $raw_title Optional. Not used.
+ * @param string $raw_title Optional. Not used. Default empty.
* @param string $context Optional. The operation for which the string is sanitized.
+ * Default 'display'.
* @return string The sanitized title.
*/
function sanitize_title_with_dashes( $title, $raw_title = '', $context = 'display' ) {
@@ -2221,28 +2238,28 @@
$title = strtolower( $title );
- if ( 'save' == $context ) {
- // Convert nbsp, ndash and mdash to hyphens
+ if ( 'save' === $context ) {
+ // Convert  , &ndash, and &mdash to hyphens.
$title = str_replace( array( '%c2%a0', '%e2%80%93', '%e2%80%94' ), '-', $title );
- // Convert nbsp, ndash and mdash HTML entities to hyphens
+ // Convert  , &ndash, and &mdash HTML entities to hyphens.
$title = str_replace( array( ' ', ' ', '–', '–', '—', '—' ), '-', $title );
- // Convert forward slash to hyphen
+ // Convert forward slash to hyphen.
$title = str_replace( '/', '-', $title );
- // Strip these characters entirely
+ // Strip these characters entirely.
$title = str_replace(
array(
- // soft hyphens
+ // Soft hyphens.
'%c2%ad',
- // iexcl and iquest
+ // ¡ and ¿.
'%c2%a1',
'%c2%bf',
- // angle quotes
+ // Angle quotes.
'%c2%ab',
'%c2%bb',
'%e2%80%b9',
'%e2%80%ba',
- // curly quotes
+ // Curly quotes.
'%e2%80%98',
'%e2%80%99',
'%e2%80%9c',
@@ -2251,18 +2268,20 @@
'%e2%80%9b',
'%e2%80%9e',
'%e2%80%9f',
- // copy, reg, deg, hellip and trade
+ // Bullet.
+ '%e2%80%a2',
+ // ©, ®, °, &hellip, and &trade.
'%c2%a9',
'%c2%ae',
'%c2%b0',
'%e2%80%a6',
'%e2%84%a2',
- // acute accents
+ // Acute accents.
'%c2%b4',
'%cb%8a',
'%cc%81',
'%cd%81',
- // grave accent, macron, caron
+ // Grave accent, macron, caron.
'%cc%80',
'%cc%84',
'%cc%8c',
@@ -2271,11 +2290,12 @@
$title
);
- // Convert times to x
+ // Convert × to 'x'.
$title = str_replace( '%c3%97', 'x', $title );
}
- $title = preg_replace( '/&.+?;/', '', $title ); // kill entities
+ // Kill entities.
+ $title = preg_replace( '/&.+?;/', '', $title );
$title = str_replace( '.', '-', $title );
$title = preg_replace( '/[^%a-z0-9 _-]/', '', $title );
@@ -2322,13 +2342,13 @@
* @return string The sanitized value
*/
function sanitize_html_class( $class, $fallback = '' ) {
- //Strip out any % encoded octets
+ // Strip out any %-encoded octets.
$sanitized = preg_replace( '|%[a-fA-F0-9][a-fA-F0-9]|', '', $class );
- //Limit to A-Z,a-z,0-9,_,-
+ // Limit to A-Z, a-z, 0-9, '_', '-'.
$sanitized = preg_replace( '/[^A-Za-z0-9_-]/', '', $sanitized );
- if ( '' == $sanitized && $fallback ) {
+ if ( '' === $sanitized && $fallback ) {
return sanitize_html_class( $fallback );
}
/**
@@ -2374,10 +2394,10 @@
*/
function convert_invalid_entities( $content ) {
$wp_htmltranswinuni = array(
- '€' => '€', // the Euro sign
+ '€' => '€', // The Euro sign.
'' => '',
- '‚' => '‚', // these are Windows CP1252 specific characters
- 'ƒ' => 'ƒ', // they would look weird on non-Windows browsers
+ '‚' => '‚', // These are Windows CP1252 specific characters.
+ 'ƒ' => 'ƒ', // They would look weird on non-Windows browsers.
'„' => '„',
'…' => '…',
'†' => '†',
@@ -2424,8 +2444,8 @@
* @param bool $force If true, forces balancing, ignoring the value of the option. Default false.
* @return string Balanced text
*/
-function balanceTags( $text, $force = false ) {
- if ( $force || get_option( 'use_balanceTags' ) == 1 ) {
+function balanceTags( $text, $force = false ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
+ if ( $force || (int) get_option( 'use_balanceTags' ) === 1 ) {
return force_balance_tags( $text );
} else {
return $text;
@@ -2436,6 +2456,7 @@
* Balances tags of string using a modified stack.
*
* @since 2.0.4
+ * @since 5.3.0 Improve accuracy and add support for custom element tags.
*
* @author Leonard Lin <leonard@acm.org>
* @license GPL
@@ -2455,42 +2476,84 @@
$stacksize = 0;
$tagqueue = '';
$newtext = '';
- // Known single-entity/self-closing tags
+ // Known single-entity/self-closing tags.
$single_tags = array( 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'source' );
- // Tags that can be immediately nested within themselves
+ // Tags that can be immediately nested within themselves.
$nestable_tags = array( 'blockquote', 'div', 'object', 'q', 'span' );
- // WP bug fix for comments - in case you REALLY meant to type '< !--'
+ // WP bug fix for comments - in case you REALLY meant to type '< !--'.
$text = str_replace( '< !--', '< !--', $text );
- // WP bug fix for LOVE <3 (and other situations with '<' before a number)
+ // WP bug fix for LOVE <3 (and other situations with '<' before a number).
$text = preg_replace( '#<([0-9]{1})#', '<$1', $text );
- while ( preg_match( '/<(\/?[\w:]*)\s*([^>]*)>/', $text, $regex ) ) {
+ /**
+ * Matches supported tags.
+ *
+ * To get the pattern as a string without the comments paste into a PHP
+ * REPL like `php -a`.
+ *
+ * @see https://html.spec.whatwg.org/#elements-2
+ * @see https://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name
+ *
+ * @example
+ * ~# php -a
+ * php > $s = [paste copied contents of expression below including parentheses];
+ * php > echo $s;
+ */
+ $tag_pattern = (
+ '#<' . // Start with an opening bracket.
+ '(/?)' . // Group 1 - If it's a closing tag it'll have a leading slash.
+ '(' . // Group 2 - Tag name.
+ // Custom element tags have more lenient rules than HTML tag names.
+ '(?:[a-z](?:[a-z0-9._]*)-(?:[a-z0-9._-]+)+)' .
+ '|' .
+ // Traditional tag rules approximate HTML tag names.
+ '(?:[\w:]+)' .
+ ')' .
+ '(?:' .
+ // We either immediately close the tag with its '>' and have nothing here.
+ '\s*' .
+ '(/?)' . // Group 3 - "attributes" for empty tag.
+ '|' .
+ // Or we must start with space characters to separate the tag name from the attributes (or whitespace).
+ '(\s+)' . // Group 4 - Pre-attribute whitespace.
+ '([^>]*)' . // Group 5 - Attributes.
+ ')' .
+ '>#' // End with a closing bracket.
+ );
+
+ while ( preg_match( $tag_pattern, $text, $regex ) ) {
+ $full_match = $regex[0];
+ $has_leading_slash = ! empty( $regex[1] );
+ $tag_name = $regex[2];
+ $tag = strtolower( $tag_name );
+ $is_single_tag = in_array( $tag, $single_tags, true );
+ $pre_attribute_ws = isset( $regex[4] ) ? $regex[4] : '';
+ $attributes = trim( isset( $regex[5] ) ? $regex[5] : $regex[3] );
+ $has_self_closer = '/' === substr( $attributes, -1 );
+
$newtext .= $tagqueue;
- $i = strpos( $text, $regex[0] );
- $l = strlen( $regex[0] );
-
- // clear the shifter
+ $i = strpos( $text, $full_match );
+ $l = strlen( $full_match );
+
+ // Clear the shifter.
$tagqueue = '';
- // Pop or Push
- if ( isset( $regex[1][0] ) && '/' == $regex[1][0] ) { // End Tag
- $tag = strtolower( substr( $regex[1], 1 ) );
- // if too many closing tags
+ if ( $has_leading_slash ) { // End tag.
+ // If too many closing tags.
if ( $stacksize <= 0 ) {
$tag = '';
- // or close to be safe $tag = '/' . $tag;
-
- // if stacktop value = tag close value then pop
- } elseif ( $tagstack[ $stacksize - 1 ] == $tag ) { // found closing tag
- $tag = '</' . $tag . '>'; // Close Tag
- // Pop
+ // Or close to be safe $tag = '/' . $tag.
+
+ // If stacktop value = tag close value, then pop.
+ } elseif ( $tagstack[ $stacksize - 1 ] === $tag ) { // Found closing tag.
+ $tag = '</' . $tag . '>'; // Close tag.
array_pop( $tagstack );
$stacksize--;
- } else { // closing tag not at top, search for it
+ } else { // Closing tag not at top, search for it.
for ( $j = $stacksize - 1; $j >= 0; $j-- ) {
- if ( $tagstack[ $j ] == $tag ) {
- // add tag to tagqueue
+ if ( $tagstack[ $j ] === $tag ) {
+ // Add tag to tagqueue.
for ( $k = $stacksize - 1; $k >= $j; $k-- ) {
$tagqueue .= '</' . array_pop( $tagstack ) . '>';
$stacksize--;
@@ -2500,39 +2563,33 @@
}
$tag = '';
}
- } else { // Begin Tag
- $tag = strtolower( $regex[1] );
-
- // Tag Cleaning
-
- // If it's an empty tag "< >", do nothing
- if ( '' == $tag ) {
- // do nothing
- } elseif ( substr( $regex[2], -1 ) == '/' ) { // ElseIf it presents itself as a self-closing tag...
- // ...but it isn't a known single-entity self-closing tag, then don't let it be treated as such and
- // immediately close it with a closing tag (the tag will encapsulate no text as a result)
- if ( ! in_array( $tag, $single_tags ) ) {
- $regex[2] = trim( substr( $regex[2], 0, -1 ) ) . "></$tag";
+ } else { // Begin tag.
+ if ( $has_self_closer ) { // If it presents itself as a self-closing tag...
+ // ...but it isn't a known single-entity self-closing tag, then don't let it be treated as such
+ // and immediately close it with a closing tag (the tag will encapsulate no text as a result).
+ if ( ! $is_single_tag ) {
+ $attributes = trim( substr( $attributes, 0, -1 ) ) . "></$tag";
}
- } elseif ( in_array( $tag, $single_tags ) ) { // ElseIf it's a known single-entity tag but it doesn't close itself, do so
- $regex[2] .= '/';
- } else { // Else it's not a single-entity tag
- // If the top of the stack is the same as the tag we want to push, close previous tag
- if ( $stacksize > 0 && ! in_array( $tag, $nestable_tags ) && $tagstack[ $stacksize - 1 ] == $tag ) {
+ } elseif ( $is_single_tag ) { // Else if it's a known single-entity tag but it doesn't close itself, do so.
+ $pre_attribute_ws = ' ';
+ $attributes .= '/';
+ } else { // It's not a single-entity tag.
+ // If the top of the stack is the same as the tag we want to push, close previous tag.
+ if ( $stacksize > 0 && ! in_array( $tag, $nestable_tags, true ) && $tagstack[ $stacksize - 1 ] === $tag ) {
$tagqueue = '</' . array_pop( $tagstack ) . '>';
$stacksize--;
}
$stacksize = array_push( $tagstack, $tag );
}
- // Attributes
- $attributes = $regex[2];
- if ( ! empty( $attributes ) && $attributes[0] != '>' ) {
- $attributes = ' ' . $attributes;
+ // Attributes.
+ if ( $has_self_closer && $is_single_tag ) {
+ // We need some space - avoid <br/> and prefer <br />.
+ $pre_attribute_ws = ' ';
}
- $tag = '<' . $tag . $attributes . '>';
- //If already queuing a close tag, then put this tag on, too
+ $tag = '<' . $tag . $pre_attribute_ws . $attributes . '>';
+ // If already queuing a close tag, then put this tag on too.
if ( ! empty( $tagqueue ) ) {
$tagqueue .= $tag;
$tag = '';
@@ -2542,18 +2599,17 @@
$text = substr( $text, $i + $l );
}
- // Clear Tag Queue
+ // Clear tag queue.
$newtext .= $tagqueue;
- // Add Remaining text
+ // Add remaining text.
$newtext .= $text;
- // Empty Stack
while ( $x = array_pop( $tagstack ) ) {
- $newtext .= '</' . $x . '>'; // Add remaining tags to close
- }
-
- // WP fix for the bug with HTML comments
+ $newtext .= '</' . $x . '>'; // Add remaining tags to close.
+ }
+
+ // WP fix for the bug with HTML comments.
$newtext = str_replace( '< !--', '<!--', $newtext );
$newtext = str_replace( '< !--', '< !--', $newtext );
@@ -2664,7 +2720,7 @@
* Adds slashes to escape strings.
*
* Slashes will first be removed if magic_quotes_gpc is set, see {@link
- * https://secure.php.net/magic_quotes} for more details.
+ * https://www.php.net/magic_quotes} for more details.
*
* @since 0.71
*
@@ -2672,10 +2728,6 @@
* @return string Returns a string escaped with slashes.
*/
function addslashes_gpc( $gpc ) {
- if ( get_magic_quotes_gpc() ) {
- $gpc = stripslashes( $gpc );
- }
-
return wp_slash( $gpc );
}
@@ -2697,7 +2749,7 @@
* @since 4.4.0
*
* @param mixed $value The array or string to be stripped.
- * @return mixed $value The stripped value.
+ * @return mixed The stripped value.
*/
function stripslashes_from_strings_only( $value ) {
return is_string( $value ) ? stripslashes( $value ) : $value;
@@ -2709,7 +2761,7 @@
* @since 2.2.0
*
* @param mixed $value The array or string to be encoded.
- * @return mixed $value The encoded value.
+ * @return mixed The encoded value.
*/
function urlencode_deep( $value ) {
return map_deep( $value, 'urlencode' );
@@ -2721,7 +2773,7 @@
* @since 3.4.0
*
* @param mixed $value The array or string to be encoded.
- * @return mixed $value The encoded value.
+ * @return mixed The encoded value.
*/
function rawurlencode_deep( $value ) {
return map_deep( $value, 'rawurlencode' );
@@ -2733,7 +2785,7 @@
* @since 4.4.0
*
* @param mixed $value The array or string to be decoded.
- * @return mixed $value The decoded value.
+ * @return mixed The decoded value.
*/
function urldecode_deep( $value ) {
return map_deep( $value, 'urldecode' );
@@ -2752,11 +2804,11 @@
$email_no_spam_address = '';
for ( $i = 0, $len = strlen( $email_address ); $i < $len; $i++ ) {
$j = rand( 0, 1 + $hex_encoding );
- if ( $j == 0 ) {
+ if ( 0 == $j ) {
$email_no_spam_address .= '&#' . ord( $email_address[ $i ] ) . ';';
- } elseif ( $j == 1 ) {
+ } elseif ( 1 == $j ) {
$email_no_spam_address .= $email_address[ $i ];
- } elseif ( $j == 2 ) {
+ } elseif ( 2 == $j ) {
$email_no_spam_address .= '%' . zeroise( dechex( ord( $email_address[ $i ] ) ), 2 );
}
}
@@ -2778,16 +2830,16 @@
function _make_url_clickable_cb( $matches ) {
$url = $matches[2];
- if ( ')' == $matches[3] && strpos( $url, '(' ) ) {
- // If the trailing character is a closing parethesis, and the URL has an opening parenthesis in it, add the closing parenthesis to the URL.
- // Then we can let the parenthesis balancer do its thing below.
+ if ( ')' === $matches[3] && strpos( $url, '(' ) ) {
+ // If the trailing character is a closing parethesis, and the URL has an opening parenthesis in it,
+ // add the closing parenthesis to the URL. Then we can let the parenthesis balancer do its thing below.
$url .= $matches[3];
$suffix = '';
} else {
$suffix = $matches[3];
}
- // Include parentheses in the URL only if paired
+ // Include parentheses in the URL only if paired.
while ( substr_count( $url, '(' ) < substr_count( $url, ')' ) ) {
$suffix = strrchr( $url, ')' ) . $suffix;
$url = substr( $url, 0, strrpos( $url, ')' ) );
@@ -2798,7 +2850,24 @@
return $matches[0];
}
- return $matches[1] . "<a href=\"$url\" rel=\"nofollow\">$url</a>" . $suffix;
+ if ( 'comment_text' === current_filter() ) {
+ $rel = 'nofollow ugc';
+ } else {
+ $rel = 'nofollow';
+ }
+
+ /**
+ * Filters the rel value that is added to URL matches converted to links.
+ *
+ * @since 5.3.0
+ *
+ * @param string $rel The rel value.
+ * @param string $url The matched URL being converted to a link tag.
+ */
+ $rel = apply_filters( 'make_clickable_rel', $rel, $url );
+ $rel = esc_attr( $rel );
+
+ return $matches[1] . "<a href=\"$url\" rel=\"$rel\">$url</a>" . $suffix;
}
/**
@@ -2817,9 +2886,10 @@
$dest = $matches[2];
$dest = 'http://' . $dest;
- // removed trailing [.,;:)] from URL
- if ( in_array( substr( $dest, -1 ), array( '.', ',', ';', ':', ')' ) ) === true ) {
- $ret = substr( $dest, -1 );
+ // Removed trailing [.,;:)] from URL.
+ $last_char = substr( $dest, -1 );
+ if ( in_array( $last_char, array( '.', ',', ';', ':', ')' ), true ) === true ) {
+ $ret = $last_char;
$dest = substr( $dest, 0, strlen( $dest ) - 1 );
}
@@ -2828,7 +2898,17 @@
return $matches[0];
}
- return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>$ret";
+ if ( 'comment_text' === current_filter() ) {
+ $rel = 'nofollow ugc';
+ } else {
+ $rel = 'nofollow';
+ }
+
+ /** This filter is documented in wp-includes/formatting.php */
+ $rel = apply_filters( 'make_clickable_rel', $rel, $dest );
+ $rel = esc_attr( $rel );
+
+ return $matches[1] . "<a href=\"$dest\" rel=\"$rel\">$dest</a>$ret";
}
/**
@@ -2860,8 +2940,8 @@
*/
function make_clickable( $text ) {
$r = '';
- $textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
- $nested_code_pre = 0; // Keep track of how many levels link is nested inside <pre> or <code>
+ $textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // Split out HTML tags.
+ $nested_code_pre = 0; // Keep track of how many levels link is nested inside <pre> or <code>.
foreach ( $textarr as $piece ) {
if ( preg_match( '|^<code[\s>]|i', $piece ) || preg_match( '|^<pre[\s>]|i', $piece ) || preg_match( '|^<script[\s>]|i', $piece ) || preg_match( '|^<style[\s>]|i', $piece ) ) {
@@ -2870,15 +2950,15 @@
$nested_code_pre--;
}
- if ( $nested_code_pre || empty( $piece ) || ( $piece[0] === '<' && ! preg_match( '|^<\s*[\w]{1,20}+://|', $piece ) ) ) {
+ if ( $nested_code_pre || empty( $piece ) || ( '<' === $piece[0] && ! preg_match( '|^<\s*[\w]{1,20}+://|', $piece ) ) ) {
$r .= $piece;
continue;
}
- // Long strings might contain expensive edge cases ...
+ // Long strings might contain expensive edge cases...
if ( 10000 < strlen( $piece ) ) {
- // ... break it up
- foreach ( _split_str_by_whitespace( $piece, 2100 ) as $chunk ) { // 2100: Extra room for scheme and leading and trailing paretheses
+ // ...break it up.
+ foreach ( _split_str_by_whitespace( $piece, 2100 ) as $chunk ) { // 2100: Extra room for scheme and leading and trailing paretheses.
if ( 2101 < strlen( $chunk ) ) {
$r .= $chunk; // Too big, no whitespace: bail.
} else {
@@ -2886,22 +2966,23 @@
}
}
} else {
- $ret = " $piece "; // Pad with whitespace to simplify the regexes
+ $ret = " $piece "; // Pad with whitespace to simplify the regexes.
$url_clickable = '~
- ([\\s(<.,;:!?]) # 1: Leading whitespace, or punctuation
- ( # 2: URL
- [\\w]{1,20}+:// # Scheme and hier-part prefix
- (?=\S{1,2000}\s) # Limit to URLs less than about 2000 characters long
- [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+ # Non-punctuation URL character
- (?: # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character
- [\'.,;:!?)] # Punctuation URL character
- [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character
+ ([\\s(<.,;:!?]) # 1: Leading whitespace, or punctuation.
+ ( # 2: URL.
+ [\\w]{1,20}+:// # Scheme and hier-part prefix.
+ (?=\S{1,2000}\s) # Limit to URLs less than about 2000 characters long.
+ [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+ # Non-punctuation URL character.
+ (?: # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character.
+ [\'.,;:!?)] # Punctuation URL character.
+ [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character.
)*
)
- (\)?) # 3: Trailing closing parenthesis (for parethesis balancing post processing)
- ~xS'; // The regex is a non-anchored pattern and does not have a single fixed starting character.
- // Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times.
+ (\)?) # 3: Trailing closing parenthesis (for parethesis balancing post processing).
+ ~xS';
+ // The regex is a non-anchored pattern and does not have a single fixed starting character.
+ // Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times.
$ret = preg_replace_callback( $url_clickable, '_make_url_clickable_cb', $ret );
@@ -2913,7 +2994,7 @@
}
}
- // Cleanup of accidental links within links
+ // Cleanup of accidental links within links.
return preg_replace( '#(<a([ \r\n\t]+[^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', '$1$3</a>', $r );
}
@@ -2929,14 +3010,14 @@
*
* _split_str_by_whitespace( "1234 67890 1234 67890a cd 1234 890 123456789 1234567890a 45678 1 3 5 7 90 ", 10 ) ==
* array (
- * 0 => '1234 67890 ', // 11 characters: Perfect split
- * 1 => '1234 ', // 5 characters: '1234 67890a' was too long
- * 2 => '67890a cd ', // 10 characters: '67890a cd 1234' was too long
- * 3 => '1234 890 ', // 11 characters: Perfect split
- * 4 => '123456789 ', // 10 characters: '123456789 1234567890a' was too long
- * 5 => '1234567890a ', // 12 characters: Too long, but no inner whitespace on which to split
- * 6 => ' 45678 ', // 11 characters: Perfect split
- * 7 => '1 3 5 7 90 ', // 11 characters: End of $string
+ * 0 => '1234 67890 ', // 11 characters: Perfect split.
+ * 1 => '1234 ', // 5 characters: '1234 67890a' was too long.
+ * 2 => '67890a cd ', // 10 characters: '67890a cd 1234' was too long.
+ * 3 => '1234 890 ', // 11 characters: Perfect split.
+ * 4 => '123456789 ', // 10 characters: '123456789 1234567890a' was too long.
+ * 5 => '1234567890a ', // 12 characters: Too long, but no inner whitespace on which to split.
+ * 6 => ' 45678 ', // 11 characters: Perfect split.
+ * 7 => '1 3 5 7 90 ', // 11 characters: End of $string.
* );
*
* @since 3.4.0
@@ -2974,35 +3055,19 @@
}
/**
- * Adds rel nofollow string to all HTML A elements in content.
- *
- * @since 1.5.0
- *
- * @param string $text Content that may contain HTML A elements.
- * @return string Converted content.
+ * Callback to add a rel attribute to HTML A element.
+ *
+ * Will remove already existing string before adding to prevent invalidating (X)HTML.
+ *
+ * @since 5.3.0
+ *
+ * @param array $matches Single match.
+ * @param string $rel The rel attribute to add.
+ * @return string HTML A element with the added rel attribute.
*/
-function wp_rel_nofollow( $text ) {
- // This is a pre save filter, so text is already escaped.
- $text = stripslashes( $text );
- $text = preg_replace_callback( '|<a (.+?)>|i', 'wp_rel_nofollow_callback', $text );
- return wp_slash( $text );
-}
-
-/**
- * Callback to add rel=nofollow string to HTML A element.
- *
- * Will remove already existing rel="nofollow" and rel='nofollow' from the
- * string to prevent from invalidating (X)HTML.
- *
- * @since 2.3.0
- *
- * @param array $matches Single Match
- * @return string HTML A Element with rel nofollow.
- */
-function wp_rel_nofollow_callback( $matches ) {
+function wp_rel_callback( $matches, $rel ) {
$text = $matches[1];
$atts = wp_kses_hair( $matches[1], wp_allowed_protocols() );
- $rel = 'nofollow';
if ( ! empty( $atts['href'] ) ) {
if ( in_array( strtolower( wp_parse_url( $atts['href']['value'], PHP_URL_SCHEME ) ), array( 'http', 'https' ), true ) ) {
@@ -3013,11 +3078,10 @@
}
if ( ! empty( $atts['rel'] ) ) {
- $parts = array_map( 'trim', explode( ' ', $atts['rel']['value'] ) );
- if ( false === array_search( 'nofollow', $parts ) ) {
- $parts[] = 'nofollow';
- }
- $rel = implode( ' ', $parts );
+ $parts = array_map( 'trim', explode( ' ', $atts['rel']['value'] ) );
+ $rel_array = array_map( 'trim', explode( ' ', $rel ) );
+ $parts = array_unique( array_merge( $parts, $rel_array ) );
+ $rel = implode( ' ', $parts );
unset( $atts['rel'] );
$html = '';
@@ -3034,6 +3098,61 @@
}
/**
+ * Adds `rel="nofollow"` string to all HTML A elements in content.
+ *
+ * @since 1.5.0
+ *
+ * @param string $text Content that may contain HTML A elements.
+ * @return string Converted content.
+ */
+function wp_rel_nofollow( $text ) {
+ // This is a pre-save filter, so text is already escaped.
+ $text = stripslashes( $text );
+ $text = preg_replace_callback(
+ '|<a (.+?)>|i',
+ function( $matches ) {
+ return wp_rel_callback( $matches, 'nofollow' );
+ },
+ $text
+ );
+ return wp_slash( $text );
+}
+
+/**
+ * Callback to add `rel="nofollow"` string to HTML A element.
+ *
+ * @since 2.3.0
+ * @deprecated 5.3.0 Use wp_rel_callback()
+ *
+ * @param array $matches Single match.
+ * @return string HTML A Element with `rel="nofollow"`.
+ */
+function wp_rel_nofollow_callback( $matches ) {
+ return wp_rel_callback( $matches, 'nofollow' );
+}
+
+/**
+ * Adds `rel="nofollow ugc"` string to all HTML A elements in content.
+ *
+ * @since 5.3.0
+ *
+ * @param string $text Content that may contain HTML A elements.
+ * @return string Converted content.
+ */
+function wp_rel_ugc( $text ) {
+ // This is a pre-save filter, so text is already escaped.
+ $text = stripslashes( $text );
+ $text = preg_replace_callback(
+ '|<a (.+?)>|i',
+ function( $matches ) {
+ return wp_rel_callback( $matches, 'nofollow ugc' );
+ },
+ $text
+ );
+ return wp_slash( $text );
+}
+
+/**
* Adds rel noreferrer and noopener to all HTML A elements that have a target.
*
* @since 5.1.0
@@ -3043,8 +3162,26 @@
*/
function wp_targeted_link_rel( $text ) {
// Don't run (more expensive) regex if no links with targets.
- if ( stripos( $text, 'target' ) !== false && stripos( $text, '<a ' ) !== false ) {
- $text = preg_replace_callback( '|<a\s([^>]*target\s*=[^>]*)>|i', 'wp_targeted_link_rel_callback', $text );
+ if ( stripos( $text, 'target' ) === false || stripos( $text, '<a ' ) === false || is_serialized( $text ) ) {
+ return $text;
+ }
+
+ $script_and_style_regex = '/<(script|style).*?<\/\\1>/si';
+
+ preg_match_all( $script_and_style_regex, $text, $matches );
+ $extra_parts = $matches[0];
+ $html_parts = preg_split( $script_and_style_regex, $text );
+
+ foreach ( $html_parts as &$part ) {
+ $part = preg_replace_callback( '|<a\s([^>]*target\s*=[^>]*)>|i', 'wp_targeted_link_rel_callback', $part );
+ }
+
+ $text = '';
+ for ( $i = 0; $i < count( $html_parts ); $i++ ) {
+ $text .= $html_parts[ $i ];
+ if ( isset( $extra_parts[ $i ] ) ) {
+ $text .= $extra_parts[ $i ];
+ }
}
return $text;
@@ -3062,48 +3199,43 @@
* @return string HTML A Element with rel noreferrer noopener in addition to any existing values
*/
function wp_targeted_link_rel_callback( $matches ) {
- $link_html = $matches[1];
- $rel_match = array();
+ $link_html = $matches[1];
+ $original_link_html = $link_html;
+
+ // Consider the HTML escaped if there are no unescaped quotes.
+ $is_escaped = ! preg_match( '/(^|[^\\\\])[\'"]/', $link_html );
+ if ( $is_escaped ) {
+ // Replace only the quotes so that they are parsable by wp_kses_hair(), leave the rest as is.
+ $link_html = preg_replace( '/\\\\([\'"])/', '$1', $link_html );
+ }
+
+ $atts = wp_kses_hair( $link_html, wp_allowed_protocols() );
/**
* Filters the rel values that are added to links with `target` attribute.
*
* @since 5.1.0
*
- * @param string The rel values.
+ * @param string $rel The rel values.
* @param string $link_html The matched content of the link tag including all HTML attributes.
*/
$rel = apply_filters( 'wp_targeted_link_rel', 'noopener noreferrer', $link_html );
- // Avoid additional regex if the filter removes rel values.
- if ( ! $rel ) {
- return "<a $link_html>";
- }
-
- // Value with delimiters, spaces around are optional.
- $attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\\1|i';
- preg_match( $attr_regex, $link_html, $rel_match );
-
- if ( empty( $rel_match[0] ) ) {
- // No delimiters, try with a single value and spaces, because `rel = va"lue` is totally fine...
- $attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
- preg_match( $attr_regex, $link_html, $rel_match );
- }
-
- if ( ! empty( $rel_match[0] ) ) {
- $parts = preg_split( '|\s+|', strtolower( $rel_match[2] ) );
- $parts = array_map( 'esc_attr', $parts );
- $needed = explode( ' ', $rel );
- $parts = array_unique( array_merge( $parts, $needed ) );
- $delimiter = trim( $rel_match[1] ) ? $rel_match[1] : '"';
- $rel = 'rel=' . $delimiter . trim( implode( ' ', $parts ) ) . $delimiter;
- $link_html = str_replace( $rel_match[0], $rel, $link_html );
- } elseif ( preg_match( '|target\s*=\s*?\\\\"|', $link_html ) ) {
- $link_html .= " rel=\\\"$rel\\\"";
- } elseif ( preg_match( '#(target|href)\s*=\s*?\'#', $link_html ) ) {
- $link_html .= " rel='$rel'";
- } else {
- $link_html .= " rel=\"$rel\"";
+ // Return early if no rel values to be added or if no actual target attribute.
+ if ( ! $rel || ! isset( $atts['target'] ) ) {
+ return "<a $original_link_html>";
+ }
+
+ if ( isset( $atts['rel'] ) ) {
+ $all_parts = preg_split( '/\s/', "{$atts['rel']['value']} $rel", -1, PREG_SPLIT_NO_EMPTY );
+ $rel = implode( ' ', array_unique( $all_parts ) );
+ }
+
+ $atts['rel']['whole'] = 'rel="' . esc_attr( $rel ) . '"';
+ $link_html = join( ' ', array_column( $atts, 'whole' ) );
+
+ if ( $is_escaped ) {
+ $link_html = preg_replace( '/[\'"]/', '\\\\$0', $link_html );
}
return "<a $link_html>";
@@ -3185,7 +3317,7 @@
$image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
// Don't convert smilies that aren't images - they're probably emoji.
- if ( ! in_array( $ext, $image_exts ) ) {
+ if ( ! in_array( $ext, $image_exts, true ) ) {
return $img;
}
@@ -3220,36 +3352,36 @@
global $wp_smiliessearch;
$output = '';
if ( get_option( 'use_smilies' ) && ! empty( $wp_smiliessearch ) ) {
- // HTML loop taken from texturize function, could possible be consolidated
- $textarr = preg_split( '/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // capture the tags as well as in between
- $stop = count( $textarr );// loop stuff
-
- // Ignore proessing of specific tags
+ // HTML loop taken from texturize function, could possible be consolidated.
+ $textarr = preg_split( '/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // Capture the tags as well as in between.
+ $stop = count( $textarr ); // Loop stuff.
+
+ // Ignore proessing 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 ) ) {
+ // 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] ) {
+ // 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 ) {
+ // Did we exit ignore block?
+ if ( '' !== $ignore_block_element && '</' . $ignore_block_element . '>' === $content ) {
$ignore_block_element = '';
}
$output .= $content;
}
} else {
- // return default text.
+ // Return default text.
$output = $text;
}
return $output;
@@ -3264,14 +3396,14 @@
*
* @param string $email Email address to verify.
* @param bool $deprecated Deprecated.
- * @return string|bool Either false or the valid email address.
+ * @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
+ // Test for the minimum length the email can be.
if ( strlen( $email ) < 6 ) {
/**
* Filters whether an email address is valid.
@@ -3282,67 +3414,67 @@
*
* @since 2.8.0
*
- * @param bool $is_email Whether the email address has passed the is_email() checks. Default false.
- * @param string $email The email address being checked.
- * @param string $context Context under which the email was tested.
+ * @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
+ // 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
+ // Split out the local and domain parts.
list( $local, $domain ) = explode( '@', $email, 2 );
// LOCAL PART
- // Test for invalid characters
+ // 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' );
}
// DOMAIN PART
- // Test for sequences of periods
+ // 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
+ // 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
+ // Split the domain into subs.
$subs = explode( '.', $domain );
- // Assume the domain will have at least two subs
+ // 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
+ // Loop through each sub.
foreach ( $subs as $sub ) {
- // Test for leading and trailing hyphens and whitespace
+ // 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
+ // 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!
+ // Congratulations, your email made it!
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'is_email', $email, $email, null );
}
@@ -3379,77 +3511,51 @@
}
/**
- * Returns a date in the GMT equivalent.
- *
- * Requires and returns a date in the Y-m-d H:i:s format. If there is a
- * timezone_string available, the date is assumed to be in that timezone,
- * otherwise it simply subtracts the value of the 'gmt_offset' option. Return
- * format can be overridden using the $format parameter.
+ * 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.
*
* @since 1.2.0
*
- * @param string $string The date to be converted.
- * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
- * @return string GMT version of the date provided.
+ * @param string $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( $string, $format = 'Y-m-d H:i:s' ) {
- $tz = get_option( 'timezone_string' );
- if ( $tz ) {
- $datetime = date_create( $string, new DateTimeZone( $tz ) );
- if ( ! $datetime ) {
- return gmdate( $format, 0 );
- }
- $datetime->setTimezone( new DateTimeZone( 'UTC' ) );
- $string_gmt = $datetime->format( $format );
- } else {
- if ( ! preg_match( '#([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})#', $string, $matches ) ) {
- $datetime = strtotime( $string );
- if ( false === $datetime ) {
- return gmdate( $format, 0 );
- }
- return gmdate( $format, $datetime );
- }
- $string_time = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
- $string_gmt = gmdate( $format, $string_time - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
- }
- return $string_gmt;
+ $datetime = date_create( $string, wp_timezone() );
+
+ if ( false === $datetime ) {
+ return gmdate( $format, 0 );
+ }
+
+ return $datetime->setTimezone( new DateTimeZone( 'UTC' ) )->format( $format );
}
/**
- * Converts a GMT date into the correct format for the blog.
- *
- * Requires and returns a date in the Y-m-d H:i:s format. If there is a
- * timezone_string available, the returned date is in that timezone, otherwise
- * it simply adds the value of gmt_offset. Return format can be overridden
- * using the $format parameter
+ * Given a date in UTC or GMT timezone, returns that date in the timezone of the site.
+ *
+ * Requires and returns a date in the Y-m-d H:i:s format.
+ * Return format can be overridden using the $format parameter.
*
* @since 1.2.0
*
- * @param string $string The date to be converted.
- * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
- * @return string Formatted date relative to the timezone / GMT offset.
+ * @param string $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( $string, $format = 'Y-m-d H:i:s' ) {
- $tz = get_option( 'timezone_string' );
- if ( $tz ) {
- $datetime = date_create( $string, new DateTimeZone( 'UTC' ) );
- if ( ! $datetime ) {
- return date( $format, 0 );
- }
- $datetime->setTimezone( new DateTimeZone( $tz ) );
- $string_localtime = $datetime->format( $format );
- } else {
- if ( ! preg_match( '#([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})#', $string, $matches ) ) {
- return date( $format, 0 );
- }
- $string_time = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
- $string_localtime = gmdate( $format, $string_time + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
- }
- return $string_localtime;
+ $datetime = date_create( $string, new DateTimeZone( 'UTC' ) );
+
+ if ( false === $datetime ) {
+ return gmdate( $format, 0 );
+ }
+
+ return $datetime->setTimezone( wp_timezone() )->format( $format );
}
/**
- * Computes an offset in seconds from an iso8601 timezone.
+ * Given an ISO 8601 timezone, returns its UTC offset in seconds.
*
* @since 1.5.0
*
@@ -3457,11 +3563,11 @@
* @return int|float The offset in seconds.
*/
function iso8601_timezone_to_offset( $timezone ) {
- // $timezone is either 'Z' or '[+|-]hhmm'
- if ( $timezone == 'Z' ) {
+ // $timezone is either 'Z' or '[+|-]hhmm'.
+ if ( 'Z' === $timezone ) {
$offset = 0;
} else {
- $sign = ( substr( $timezone, 0, 1 ) == '+' ) ? 1 : -1;
+ $sign = ( '+' === substr( $timezone, 0, 1 ) ) ? 1 : -1;
$hours = intval( substr( $timezone, 1, 2 ) );
$minutes = intval( substr( $timezone, 3, 4 ) ) / 60;
$offset = $sign * HOUR_IN_SECONDS * ( $hours + $minutes );
@@ -3470,35 +3576,32 @@
}
/**
- * Converts an iso8601 date to MySQL DateTime format used by post_date[_gmt].
+ * 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].
*
* @since 1.5.0
*
* @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 time minus gmt_offset. Default is 'user'.
- * @return string The date and time in MySQL DateTime format - Y-m-d H:i:s.
+ * @param string $timezone Optional. If set to 'gmt' returns the result in UTC. Default 'user'.
+ * @return string|bool 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 );
-
- if ( $timezone == 'gmt' ) {
-
- preg_match( '#([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(Z|[\+|\-][0-9]{2,4}){0,1}#', $date_string, $date_bits );
-
- if ( ! empty( $date_bits[7] ) ) { // we have a timezone, so let's compute an offset
- $offset = iso8601_timezone_to_offset( $date_bits[7] );
- } else { // we don't have a timezone, so we assume user local timezone (not server's!)
- $offset = HOUR_IN_SECONDS * get_option( 'gmt_offset' );
- }
-
- $timestamp = gmmktime( $date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1] );
- $timestamp -= $offset;
-
- return gmdate( 'Y-m-d H:i:s', $timestamp );
-
- } elseif ( $timezone == 'user' ) {
- return preg_replace( '#([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(Z|[\+|\-][0-9]{2,4}){0,1}#', '$1-$2-$3 $4:$5:$6', $date_string );
- }
+ $timezone = strtolower( $timezone );
+ $wp_timezone = wp_timezone();
+ $datetime = date_create( $date_string, $wp_timezone ); // Timezone is ignored if input has one.
+
+ if ( false === $datetime ) {
+ return false;
+ }
+
+ 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' );
+ }
+
+ return false;
}
/**
@@ -3510,7 +3613,7 @@
* @return string Filtered email address.
*/
function sanitize_email( $email ) {
- // Test for the minimum length the email can be
+ // Test for the minimum length the email can be.
if ( strlen( $email ) < 6 ) {
/**
* Filters a sanitized email address.
@@ -3528,17 +3631,17 @@
return apply_filters( 'sanitize_email', '', $email, 'email_too_short' );
}
- // Test for an @ character after the first position
+ // 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
+ // Split out the local and domain parts.
list( $local, $domain ) = explode( '@', $email, 2 );
// LOCAL PART
- // Test for invalid characters
+ // Test for invalid characters.
$local = preg_replace( '/[^a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]/', '', $local );
if ( '' === $local ) {
/** This filter is documented in wp-includes/formatting.php */
@@ -3546,59 +3649,59 @@
}
// DOMAIN PART
- // Test for sequences of periods
+ // Test for sequences of periods.
$domain = preg_replace( '/\.{2,}/', '', $domain );
if ( '' === $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
+ // Test for leading and trailing periods and whitespace.
$domain = trim( $domain, " \t\n\r\0\x0B." );
if ( '' === $domain ) {
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'sanitize_email', '', $email, 'domain_period_limits' );
}
- // Split the domain into subs
+ // Split the domain into subs.
$subs = explode( '.', $domain );
- // Assume the domain will have at least two subs
+ // 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
+ // Create an array that will contain valid subs.
$new_subs = array();
- // Loop through each sub
+ // Loop through each sub.
foreach ( $subs as $sub ) {
- // Test for leading and trailing hyphens
+ // Test for leading and trailing hyphens.
$sub = trim( $sub, " \t\n\r\0\x0B-" );
- // Test for invalid characters
+ // 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's anything left, add it to the valid subs.
if ( '' !== $sub ) {
$new_subs[] = $sub;
}
}
- // If there aren't 2 or more 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
+ // Join valid subs into the new domain.
$domain = join( '.', $new_subs );
- // Put the email back together
+ // Put the email back together.
$sanitized_email = $local . '@' . $domain;
- // Congratulations your email made it!
+ // Congratulations, your email made it!
/** This filter is documented in wp-includes/formatting.php */
return apply_filters( 'sanitize_email', $sanitized_email, $email, null );
}
@@ -3610,59 +3713,67 @@
* "5 mins", "2 days".
*
* @since 1.5.0
+ * @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 = '' ) {
+function human_time_diff( $from, $to = 0 ) {
if ( empty( $to ) ) {
$to = time();
}
$diff = (int) abs( $to - $from );
- if ( $diff < HOUR_IN_SECONDS ) {
+ if ( $diff < MINUTE_IN_SECONDS ) {
+ $secs = $diff;
+ if ( $secs <= 1 ) {
+ $secs = 1;
+ }
+ /* 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 );
if ( $mins <= 1 ) {
$mins = 1;
}
- /* translators: Time difference between two dates, in minutes (min=minute). %s: Number of minutes */
+ /* 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 );
if ( $hours <= 1 ) {
$hours = 1;
}
- /* translators: Time difference between two dates, in hours. %s: Number of hours */
+ /* 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 );
if ( $days <= 1 ) {
$days = 1;
}
- /* translators: Time difference between two dates, in days. %s: Number of days */
+ /* 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 );
if ( $weeks <= 1 ) {
$weeks = 1;
}
- /* translators: Time difference between two dates, in weeks. %s: Number of weeks */
+ /* 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 );
if ( $months <= 1 ) {
$months = 1;
}
- /* translators: Time difference between two dates, in months. %s: Number of months */
+ /* 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 );
if ( $years <= 1 ) {
$years = 1;
}
- /* translators: Time difference between two dates, in years. %s: Number of years */
+ /* translators: Time difference between two dates, in years. %s: Number of years. */
$since = sprintf( _n( '%s year', '%s years', $years ), $years );
}
@@ -3682,9 +3793,7 @@
/**
* Generates an excerpt from the content, if needed.
*
- * The excerpt word amount will be 55 words and if the amount is greater than
- * that, then the string ' […]' will be appended to the excerpt. If the string
- * is less than 55 words, then the content will be returned as is.
+ * 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
@@ -3693,12 +3802,13 @@
* @since 5.2.0 Added the `$post` parameter.
*
* @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 is null.
+ * @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 ) {
$raw_excerpt = $text;
- if ( '' == $text ) {
+
+ if ( '' === trim( $text ) ) {
$post = get_post( $post );
$text = get_the_content( '', false, $post );
@@ -3709,14 +3819,18 @@
$text = apply_filters( 'the_content', $text );
$text = str_replace( ']]>', ']]>', $text );
+ /* translators: Maximum number of words used in a post excerpt. */
+ $excerpt_length = intval( _x( '55', 'excerpt_length' ) );
+
/**
- * Filters the number of words in an excerpt.
+ * Filters the maximum number of words in a post excerpt.
*
* @since 2.7.0
*
- * @param int $number The number of words. Default 55.
+ * @param int $number The maximum number of words. Default 55.
*/
- $excerpt_length = apply_filters( 'excerpt_length', 55 );
+ $excerpt_length = (int) apply_filters( 'excerpt_length', $excerpt_length );
+
/**
* Filters the string in the "more" link displayed after a trimmed excerpt.
*
@@ -3727,6 +3841,7 @@
$excerpt_more = apply_filters( 'excerpt_more', ' ' . '[…]' );
$text = wp_trim_words( $text, $excerpt_length, $excerpt_more );
}
+
/**
* Filters the trimmed excerpt string.
*
@@ -3759,6 +3874,7 @@
$original_text = $text;
$text = wp_strip_all_tags( $text );
+ $num_words = (int) $num_words;
/*
* translators: If your word count is based on single characters (e.g. East Asian characters),
@@ -3813,8 +3929,8 @@
*
* @since 3.3.0
*
- * @param null $converted_text The text to be converted. Default null.
- * @param string $text The text prior to entity conversion.
+ * @param string|null $converted_text The text to be converted. Default null.
+ * @param string $text The text prior to entity conversion.
*/
$filtered = apply_filters( 'pre_ent2ncr', null, $text );
if ( null !== $filtered ) {
@@ -4177,20 +4293,20 @@
*
* @since 2.8.0
*
- * @param string $url The URL to be cleaned.
- * @param array $protocols Optional. An array of acceptable protocols.
- * Defaults to return value of wp_allowed_protocols()
- * @param string $_context Private. Use esc_url_raw() for database usage.
- * @return string The cleaned $url after the {@see 'clean_url'} filter is applied.
+ * @param string $url The URL to be cleaned.
+ * @param string[] $protocols Optional. An array of acceptable protocols.
+ * Defaults to return value of wp_allowed_protocols().
+ * @param string $_context Private. Use esc_url_raw() for database usage.
+ * @return string The cleaned URL after the {@see 'clean_url'} filter is applied.
*/
function esc_url( $url, $protocols = null, $_context = 'display' ) {
$original_url = $url;
- if ( '' == $url ) {
+ if ( '' === $url ) {
return $url;
}
- $url = str_replace( ' ', '%20', $url );
+ $url = str_replace( ' ', '%20', ltrim( $url ) );
$url = preg_replace( '|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url );
if ( '' === $url ) {
@@ -4203,17 +4319,18 @@
}
$url = str_replace( ';//', '://', $url );
- /* If the URL doesn't appear to contain a scheme, we
- * presume it needs http:// prepended (unless a relative
- * link starting with /, # or ? or a php file).
+ /*
+ * If the URL doesn't appear to contain a scheme, we presume
+ * it needs http:// prepended (unless it's a relative link
+ * starting with /, # or ?, or a PHP file).
*/
- if ( strpos( $url, ':' ) === false && ! in_array( $url[0], array( '/', '#', '?' ) ) &&
+ if ( strpos( $url, ':' ) === false && ! in_array( $url[0], array( '/', '#', '?' ), true ) &&
! preg_match( '/^[a-z0-9-]+?\.php/i', $url ) ) {
$url = 'http://' . $url;
}
// Replace ampersands and single quotes only when displaying.
- if ( 'display' == $_context ) {
+ if ( 'display' === $_context ) {
$url = wp_kses_normalize_entities( $url );
$url = str_replace( '&', '&', $url );
$url = str_replace( "'", ''', $url );
@@ -4285,8 +4402,9 @@
*
* @since 2.8.0
*
- * @param string $url The URL to be cleaned.
- * @param array $protocols An array of acceptable protocols.
+ * @param string $url The URL to be cleaned.
+ * @param string[] $protocols Optional. An array of acceptable protocols.
+ * Defaults to return value of wp_allowed_protocols().
* @return string The cleaned URL.
*/
function esc_url_raw( $url, $protocols = null ) {
@@ -4296,7 +4414,7 @@
/**
* Convert entities, while preserving already-encoded entities.
*
- * @link https://secure.php.net/htmlentities Borrowed from the PHP Manual user notes.
+ * @link https://www.php.net/htmlentities Borrowed from the PHP Manual user notes.
*
* @since 1.2.2
*
@@ -4413,6 +4531,63 @@
}
/**
+ * Escaping for XML blocks.
+ *
+ * @since 5.5.0
+ *
+ * @param string $text Text to escape.
+ * @return string Escaped text.
+ */
+function esc_xml( $text ) {
+ $safe_text = wp_check_invalid_utf8( $text );
+
+ $cdata_regex = '\<\!\[CDATA\[.*?\]\]\>';
+ $regex = <<<EOF
+/
+ (?=.*?{$cdata_regex}) # lookahead that will match anything followed by a CDATA Section
+ (?<non_cdata_followed_by_cdata>(.*?)) # the "anything" matched by the lookahead
+ (?<cdata>({$cdata_regex})) # the CDATA Section matched by the lookahead
+
+| # alternative
+
+ (?<non_cdata>(.*)) # non-CDATA Section
+/sx
+EOF;
+
+ $safe_text = (string) preg_replace_callback(
+ $regex,
+ static function( $matches ) {
+ if ( ! $matches[0] ) {
+ return '';
+ }
+
+ if ( ! empty( $matches['non_cdata'] ) ) {
+ // escape HTML entities in the non-CDATA Section.
+ return _wp_specialchars( $matches['non_cdata'], ENT_XML1 );
+ }
+
+ // Return the CDATA Section unchanged, escape HTML entities in the rest.
+ return _wp_specialchars( $matches['non_cdata_followed_by_cdata'], ENT_XML1 ) . $matches['cdata'];
+ },
+ $safe_text
+ );
+
+ /**
+ * Filters a string cleaned and escaped for output in XML.
+ *
+ * Text passed to esc_xml() is stripped of invalid or special characters
+ * before output. HTML named character references are converted to their
+ * equivalent code points.
+ *
+ * @since 5.5.0
+ *
+ * @param string $safe_text The text after it has been escaped.
+ * @param string $text The text prior to being escaped.
+ */
+ return apply_filters( 'esc_xml', $safe_text, $text );
+}
+
+/**
* Escape an HTML tag name.
*
* @since 2.5.0
@@ -4521,8 +4696,8 @@
case 'default_ping_status':
case 'default_comment_status':
- // Options that if not there have 0 value but need to be something like "closed"
- if ( $value == '0' || $value == '' ) {
+ // Options that if not there have 0 value but need to be something like "closed".
+ if ( '0' == $value || '' === $value ) {
$value = 'closed';
}
break;
@@ -4542,7 +4717,7 @@
break;
case 'blog_charset':
- $value = preg_replace( '/[^a-zA-Z0-9_-]/', '', $value ); // strips slashes
+ $value = preg_replace( '/[^a-zA-Z0-9_-]/', '', $value ); // Strips slashes.
break;
case 'blog_public':
@@ -4577,7 +4752,7 @@
break;
case 'gmt_offset':
- $value = preg_replace( '/[^0-9:.-]/', '', $value ); // strips slashes
+ $value = preg_replace( '/[^0-9:.-]/', '', $value ); // Strips slashes.
break;
case 'siteurl':
@@ -4611,7 +4786,7 @@
if ( ! is_multisite() && defined( 'WPLANG' ) && '' !== WPLANG && 'en_US' !== WPLANG ) {
$allowed[] = WPLANG;
}
- if ( ! in_array( $value, $allowed ) && ! empty( $value ) ) {
+ if ( ! in_array( $value, $allowed, true ) && ! empty( $value ) ) {
$value = get_option( $option );
}
break;
@@ -4659,7 +4834,7 @@
case 'timezone_string':
$allowed_zones = timezone_identifiers_list();
- if ( ! in_array( $value, $allowed_zones ) && ! empty( $value ) ) {
+ if ( ! in_array( $value, $allowed_zones, true ) && ! empty( $value ) ) {
$error = __( 'The timezone you have entered is not valid. Please select a valid timezone.' );
}
break;
@@ -4677,9 +4852,9 @@
if ( 'permalink_structure' === $option && '' !== $value && ! preg_match( '/%[^\/%]+%/', $value ) ) {
$error = sprintf(
- /* translators: %s: Codex URL */
+ /* translators: %s: Documentation URL. */
__( 'A structure tag is required when using custom permalinks. <a href="%s">Learn more</a>' ),
- __( 'https://codex.wordpress.org/Using_Permalinks#Choosing_your_permalink_structure' )
+ __( 'https://wordpress.org/support/article/using-permalinks/#choosing-your-permalink-structure' )
);
}
break;
@@ -4691,7 +4866,7 @@
break;
case 'moderation_keys':
- case 'blacklist_keys':
+ case 'disallowed_keys':
$value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
if ( is_wp_error( $value ) ) {
$error = $value->get_error_message();
@@ -4755,9 +4930,6 @@
/**
* Parses a string into variables to be stored in an array.
*
- * Uses {@link https://secure.php.net/parse_str parse_str()} and stripslashes if
- * {@link https://secure.php.net/magic_quotes magic_quotes_gpc} is on.
- *
* @since 2.2.1
*
* @param string $string The string to be parsed.
@@ -4765,9 +4937,7 @@
*/
function wp_parse_str( $string, &$array ) {
parse_str( $string, $array );
- if ( get_magic_quotes_gpc() ) {
- $array = stripslashes_deep( $array );
- }
+
/**
* Filters the array of variables derived from a parsed string.
*
@@ -4808,51 +4978,79 @@
}
/**
+ * Remove non-allowable HTML from parsed block attribute values when filtering
+ * in the post context.
+ *
+ * @since 5.3.1
+ *
+ * @param string $string Content to be run through KSES.
+ * @param array[]|string $allowed_html An array of allowed HTML elements
+ * and attributes, or a context name
+ * such as 'post'.
+ * @param string[] $allowed_protocols Array of allowed URL protocols.
+ * @return string Filtered text to run through KSES.
+ */
+function wp_pre_kses_block_attributes( $string, $allowed_html, $allowed_protocols ) {
+ /*
+ * `filter_block_content` is expected to call `wp_kses`. Temporarily remove
+ * the filter to avoid recursion.
+ */
+ remove_filter( 'pre_kses', 'wp_pre_kses_block_attributes', 10 );
+ $string = filter_block_content( $string, $allowed_html, $allowed_protocols );
+ add_filter( 'pre_kses', 'wp_pre_kses_block_attributes', 10, 3 );
+
+ return $string;
+}
+
+/**
* WordPress implementation of PHP sprintf() with filters.
*
* @since 2.5.0
- * @link https://secure.php.net/sprintf
- *
- * @param string $pattern The string which formatted args are inserted.
- * @param mixed $args ,... Arguments to be formatted into the $pattern string.
+ * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
+ * by adding it to the function signature.
+ *
+ * @link https://www.php.net/sprintf
+ *
+ * @param string $pattern The string which formatted args are inserted.
+ * @param mixed ...$args Arguments to be formatted into the $pattern string.
* @return string The formatted string.
*/
-function wp_sprintf( $pattern ) {
- $args = func_get_args();
+function wp_sprintf( $pattern, ...$args ) {
$len = strlen( $pattern );
$start = 0;
$result = '';
$arg_index = 0;
while ( $len > $start ) {
- // Last character: append and break
+ // Last character: append and break.
if ( strlen( $pattern ) - 1 == $start ) {
$result .= substr( $pattern, -1 );
break;
}
- // Literal %: append and continue
- if ( substr( $pattern, $start, 2 ) == '%%' ) {
+ // Literal %: append and continue.
+ if ( '%%' === substr( $pattern, $start, 2 ) ) {
$start += 2;
$result .= '%';
continue;
}
- // Get fragment before next %
+ // Get fragment before next %.
$end = strpos( $pattern, '%', $start + 1 );
if ( false === $end ) {
$end = $len;
}
$fragment = substr( $pattern, $start, $end - $start );
- // Fragment has a specifier
- if ( $pattern[ $start ] == '%' ) {
- // Find numbered arguments or take the next one in order
+ // Fragment has a specifier.
+ if ( '%' === $pattern[ $start ] ) {
+ // Find numbered arguments or take the next one in order.
if ( preg_match( '/^%(\d+)\$/', $fragment, $matches ) ) {
- $arg = isset( $args[ $matches[1] ] ) ? $args[ $matches[1] ] : '';
+ $index = $matches[1] - 1; // 0-based array vs 1-based sprintf() arguments.
+ $arg = isset( $args[ $index ] ) ? $args[ $index ] : '';
$fragment = str_replace( "%{$matches[1]}$", '%', $fragment );
} else {
+ $arg = isset( $args[ $arg_index ] ) ? $args[ $arg_index ] : '';
++$arg_index;
- $arg = isset( $args[ $arg_index ] ) ? $args[ $arg_index ] : '';
}
/**
@@ -4873,10 +5071,11 @@
}
}
- // Append to result and move to next fragment
+ // Append to result and move to next fragment.
$result .= $fragment;
$start = $end;
}
+
return $result;
}
@@ -4894,12 +5093,12 @@
* @return string Localized list items and rest of the content.
*/
function wp_sprintf_l( $pattern, $args ) {
- // Not a match
- if ( substr( $pattern, 0, 2 ) != '%l' ) {
+ // Not a match.
+ if ( '%l' !== substr( $pattern, 0, 2 ) ) {
return $pattern;
}
- // Nothing to work with
+ // Nothing to work with.
if ( empty( $args ) ) {
return '';
}
@@ -4918,11 +5117,11 @@
$l = apply_filters(
'wp_sprintf_l',
array(
- /* translators: used to join items in a list with more than 2 items */
+ /* translators: Used to join items in a list with more than 2 items. */
'between' => sprintf( __( '%1$s, %2$s' ), '', '' ),
- /* translators: used to join last two items in a list with more than 2 times */
+ /* translators: Used to join last two items in a list with more than 2 times. */
'between_last_two' => sprintf( __( '%1$s, and %2$s' ), '', '' ),
- /* translators: used to join items in a list with only 2 items */
+ /* translators: Used to join items in a list with only 2 items. */
'between_only_two' => sprintf( __( '%1$s and %2$s' ), '', '' ),
)
);
@@ -4932,7 +5131,8 @@
if ( count( $args ) == 1 ) {
$result .= $l['between_only_two'] . array_shift( $args );
}
- // Loop when more than two args
+
+ // Loop when more than two args.
$i = count( $args );
while ( $i ) {
$arg = array_shift( $args );
@@ -4943,11 +5143,12 @@
$result .= $l['between'] . $arg;
}
}
+
return $result . substr( $pattern, 2 );
}
/**
- * Safely extracts not more than the first $count characters from html string.
+ * Safely extracts not more than the first $count characters from HTML string.
*
* UTF-8, tags and entities safe prefix extraction. Entities inside will *NOT*
* be counted as one character. For example & will be counted as 4, < as
@@ -4964,13 +5165,16 @@
if ( null === $more ) {
$more = '';
}
+
$str = wp_strip_all_tags( $str, true );
$excerpt = mb_substr( $str, 0, $count );
- // remove part of an entity at the end
+
+ // Remove part of an entity at the end.
$excerpt = preg_replace( '/&[^;\s]{0,6}$/', '', $excerpt );
if ( $str != $excerpt ) {
$excerpt = trim( $excerpt ) . $more;
}
+
return $excerpt;
}
@@ -5009,9 +5213,9 @@
*/
function _links_add_base( $m ) {
global $_links_add_base;
- //1 = attribute name 2 = quotation mark 3 = URL
+ // 1 = attribute name 2 = quotation mark 3 = URL.
return $m[1] . '=' . $m[2] .
- ( preg_match( '#^(\w{1,20}):#', $m[3], $protocol ) && in_array( $protocol[1], wp_allowed_protocols() ) ?
+ ( preg_match( '#^(\w{1,20}):#', $m[3], $protocol ) && in_array( $protocol[1], wp_allowed_protocols(), true ) ?
$m[3] :
WP_Http::make_absolute_url( $m[3], $_links_add_base )
)
@@ -5030,9 +5234,9 @@
*
* @global string $_links_add_target
*
- * @param string $content String to search for links in.
- * @param string $target The Target to add to the links.
- * @param array $tags An array of tags to apply to.
+ * @param string $content String to search for links in.
+ * @param string $target The Target to add to the links.
+ * @param string[] $tags An array of tags to apply to.
* @return string The processed content.
*/
function links_add_target( $content, $target = '_blank', $tags = array( 'a' ) ) {
@@ -5165,8 +5369,8 @@
* @since 4.7.0
* @access private
*
- * @param string $str String to sanitize.
- * @param bool $keep_newlines optional Whether to keep newlines. Default: false.
+ * @param string $str String to sanitize.
+ * @param bool $keep_newlines Optional. Whether to keep newlines. Default: false.
* @return string Sanitized string.
*/
function _sanitize_text_fields( $str, $keep_newlines = false ) {
@@ -5183,8 +5387,8 @@
// This will strip extra whitespace for us.
$filtered = wp_strip_all_tags( $filtered, false );
- // Use html entities in a special case to make sure no later
- // newline stripping stage could lead to a functional tag
+ // Use HTML entities in a special case to make sure no later
+ // newline stripping stage could lead to a functional tag.
$filtered = str_replace( "<\n", "<\n", $filtered );
}
@@ -5228,18 +5432,16 @@
*
* @since 3.0.0
*
- * @staticvar string|false $dblq
- *
* @param string $text The text to be modified.
* @return string The modified text.
*/
function capital_P_dangit( $text ) {
- // Simple replacement for titles
+ // Simple replacement for titles.
$current_filter = current_filter();
if ( 'the_title' === $current_filter || 'wp_title' === $current_filter ) {
return str_replace( 'Wordpress', 'WordPress', $text );
}
- // Still here? Use the more judicious replacement
+ // Still here? Use the more judicious replacement.
static $dblq = false;
if ( false === $dblq ) {
$dblq = _x( '“', 'opening curly double quote' );
@@ -5305,27 +5507,24 @@
}
/**
- * Add slashes to a string or array of strings.
+ * Add slashes to a string or array of strings, in a recursive manner.
*
* This should be used when preparing data for core API that expects slashed data.
* This should not be used to escape data going directly into an SQL query.
*
* @since 3.6.0
- *
- * @param string|array $value String or array of strings to slash.
- * @return string|array Slashed $value
+ * @since 5.5.0 Non-string values are left untouched.
+ *
+ * @param string|string[] $value String or array of strings to slash.
+ * @return string|string[] Slashed $value.
*/
function wp_slash( $value ) {
if ( is_array( $value ) ) {
- foreach ( $value as $k => $v ) {
- if ( is_array( $v ) ) {
- $value[ $k ] = wp_slash( $v );
- } else {
- $value[ $k ] = addslashes( $v );
- }
- }
- } else {
- $value = addslashes( $value );
+ $value = array_map( 'wp_slash', $value );
+ }
+
+ if ( is_string( $value ) ) {
+ return addslashes( $value );
}
return $value;
@@ -5339,14 +5538,41 @@
*
* @since 3.6.0
*
- * @param string|array $value String or array of strings to unslash.
- * @return string|array Unslashed $value
+ * @param string|string[] $value String or array of strings to unslash.
+ * @return string|string[] Unslashed $value
*/
function wp_unslash( $value ) {
return stripslashes_deep( $value );
}
/**
+ * Adds slashes to only string values in an array of values.
+ *
+ * This should be used when preparing data for core APIs that expect slashed data.
+ * This should not be used to escape data going directly into an SQL query.
+ *
+ * @since 5.3.0
+ *
+ * @param mixed $value Scalar or array of scalars.
+ * @return mixed Slashes $value
+ */
+function wp_slash_strings_only( $value ) {
+ return map_deep( $value, 'addslashes_strings_only' );
+}
+
+/**
+ * Adds slashes only if the provided value is a string.
+ *
+ * @since 5.3.0
+ *
+ * @param mixed $value
+ * @return mixed
+ */
+function addslashes_strings_only( $value ) {
+ return is_string( $value ) ? addslashes( $value ) : $value;
+}
+
+/**
* Extract and return the first URL from passed content.
*
* @since 3.6.0
@@ -5370,13 +5596,11 @@
* Returns the regexp for common whitespace characters.
*
* By default, spaces include new lines, tabs, nbsp entities, and the UTF-8 nbsp.
- * This is designed to replace the PCRE \s sequence. In ticket #22692, that
+ * This is designed to replace the PCRE \s sequence. In ticket #22692, that
* sequence was found to be unreliable due to random inclusion of the A0 byte.
*
* @since 4.0.0
*
- * @staticvar string $spaces
- *
* @return string The spaces regexp.
*/
function wp_spaces_regexp() {
@@ -5405,8 +5629,6 @@
* Print the important emoji-related styles.
*
* @since 4.2.0
- *
- * @staticvar bool $printed
*/
function print_emoji_styles() {
static $printed = false;
@@ -5416,8 +5638,10 @@
}
$printed = true;
+
+ $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
?>
-<style type="text/css">
+<style<?php echo $type_attr; ?>>
img.wp-smiley,
img.emoji {
display: inline !important;
@@ -5438,7 +5662,6 @@
* Print the inline Emoji detection script if it is not already printed.
*
* @since 4.2.0
- * @staticvar bool $printed
*/
function print_emoji_detection_script() {
static $printed = false;
@@ -5453,7 +5676,7 @@
}
/**
- * Prints inline Emoji dection script
+ * Prints inline Emoji detection script.
*
* @ignore
* @since 4.6.0
@@ -5466,16 +5689,16 @@
*
* @since 4.2.0
*
- * @param string The emoji base URL for png images.
+ * @param string $url The emoji base URL for png images.
*/
- 'baseUrl' => apply_filters( 'emoji_url', 'https://s.w.org/images/core/emoji/12.0.0-1/72x72/' ),
+ 'baseUrl' => apply_filters( 'emoji_url', 'https://s.w.org/images/core/emoji/13.0.0/72x72/' ),
/**
* Filters the extension of the emoji png files.
*
* @since 4.2.0
*
- * @param string The emoji extension for png files. Default .png.
+ * @param string $extension The emoji extension for png files. Default .png.
*/
'ext' => apply_filters( 'emoji_ext', '.png' ),
@@ -5484,21 +5707,22 @@
*
* @since 4.6.0
*
- * @param string The emoji base URL for svg images.
+ * @param string $url The emoji base URL for svg images.
*/
- 'svgUrl' => apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/12.0.0-1/svg/' ),
+ 'svgUrl' => apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/13.0.0/svg/' ),
/**
* Filters the extension of the emoji SVG files.
*
* @since 4.6.0
*
- * @param string The emoji extension for svg files. Default .svg.
+ * @param string $extension The emoji extension for svg files. Default .svg.
*/
'svgExt' => apply_filters( 'emoji_svg_ext', '.svg' ),
);
- $version = 'ver=' . get_bloginfo( 'version' );
+ $version = 'ver=' . get_bloginfo( 'version' );
+ $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/javascript"';
if ( SCRIPT_DEBUG ) {
$settings['source'] = array(
@@ -5509,7 +5733,7 @@
);
?>
- <script type="text/javascript">
+ <script<?php echo $type_attr; ?>>
window._wpemojiSettings = <?php echo wp_json_encode( $settings ); ?>;
<?php readfile( ABSPATH . WPINC . '/js/wp-emoji-loader.js' ); ?>
</script>
@@ -5522,7 +5746,7 @@
/*
* If you're looking at a src version of this file, you'll see an "include"
- * statement below. This is used by the `grunt build` process to directly
+ * statement below. This is used by the `npm run build` process to directly
* include a minified version of wp-emoji-loader.js, instead of using the
* readfile() method from above.
*
@@ -5531,9 +5755,9 @@
* and edit wp-emoji-loader.js directly.
*/
?>
- <script type="text/javascript">
+ <script<?php echo $type_attr; ?>>
window._wpemojiSettings = <?php echo wp_json_encode( $settings ); ?>;
- !function(a,b,c){function d(a,b){var c=String.fromCharCode;l.clearRect(0,0,k.width,k.height),l.fillText(c.apply(this,a),0,0);var d=k.toDataURL();l.clearRect(0,0,k.width,k.height),l.fillText(c.apply(this,b),0,0);var e=k.toDataURL();return d===e}function e(a){var b;if(!l||!l.fillText)return!1;switch(l.textBaseline="top",l.font="600 32px Arial",a){case"flag":return!(b=d([55356,56826,55356,56819],[55356,56826,8203,55356,56819]))&&(b=d([55356,57332,56128,56423,56128,56418,56128,56421,56128,56430,56128,56423,56128,56447],[55356,57332,8203,56128,56423,8203,56128,56418,8203,56128,56421,8203,56128,56430,8203,56128,56423,8203,56128,56447]),!b);case"emoji":return b=d([55357,56424,55356,57342,8205,55358,56605,8205,55357,56424,55356,57340],[55357,56424,55356,57342,8203,55358,56605,8203,55357,56424,55356,57340]),!b}return!1}function f(a){var c=b.createElement("script");c.src=a,c.defer=c.type="text/javascript",b.getElementsByTagName("head")[0].appendChild(c)}var g,h,i,j,k=b.createElement("canvas"),l=k.getContext&&k.getContext("2d");for(j=Array("flag","emoji"),c.supports={everything:!0,everythingExceptFlag:!0},i=0;i<j.length;i++)c.supports[j[i]]=e(j[i]),c.supports.everything=c.supports.everything&&c.supports[j[i]],"flag"!==j[i]&&(c.supports.everythingExceptFlag=c.supports.everythingExceptFlag&&c.supports[j[i]]);c.supports.everythingExceptFlag=c.supports.everythingExceptFlag&&!c.supports.flag,c.DOMReady=!1,c.readyCallback=function(){c.DOMReady=!0},c.supports.everything||(h=function(){c.readyCallback()},b.addEventListener?(b.addEventListener("DOMContentLoaded",h,!1),a.addEventListener("load",h,!1)):(a.attachEvent("onload",h),b.attachEvent("onreadystatechange",function(){"complete"===b.readyState&&c.readyCallback()})),g=c.source||{},g.concatemoji?f(g.concatemoji):g.wpemoji&&g.twemoji&&(f(g.twemoji),f(g.wpemoji)))}(window,document,window._wpemojiSettings);
+ !function(e,a,t){var r,n,o,i,p=a.createElement("canvas"),s=p.getContext&&p.getContext("2d");function c(e,t){var a=String.fromCharCode;s.clearRect(0,0,p.width,p.height),s.fillText(a.apply(this,e),0,0);var r=p.toDataURL();return s.clearRect(0,0,p.width,p.height),s.fillText(a.apply(this,t),0,0),r===p.toDataURL()}function l(e){if(!s||!s.fillText)return!1;switch(s.textBaseline="top",s.font="600 32px Arial",e){case"flag":return!c([127987,65039,8205,9895,65039],[127987,65039,8203,9895,65039])&&(!c([55356,56826,55356,56819],[55356,56826,8203,55356,56819])&&!c([55356,57332,56128,56423,56128,56418,56128,56421,56128,56430,56128,56423,56128,56447],[55356,57332,8203,56128,56423,8203,56128,56418,8203,56128,56421,8203,56128,56430,8203,56128,56423,8203,56128,56447]));case"emoji":return!c([55357,56424,8205,55356,57212],[55357,56424,8203,55356,57212])}return!1}function d(e){var t=a.createElement("script");t.src=e,t.defer=t.type="text/javascript",a.getElementsByTagName("head")[0].appendChild(t)}for(i=Array("flag","emoji"),t.supports={everything:!0,everythingExceptFlag:!0},o=0;o<i.length;o++)t.supports[i[o]]=l(i[o]),t.supports.everything=t.supports.everything&&t.supports[i[o]],"flag"!==i[o]&&(t.supports.everythingExceptFlag=t.supports.everythingExceptFlag&&t.supports[i[o]]);t.supports.everythingExceptFlag=t.supports.everythingExceptFlag&&!t.supports.flag,t.DOMReady=!1,t.readyCallback=function(){t.DOMReady=!0},t.supports.everything||(n=function(){t.readyCallback()},a.addEventListener?(a.addEventListener("DOMContentLoaded",n,!1),e.addEventListener("load",n,!1)):(e.attachEvent("onload",n),a.attachEvent("onreadystatechange",function(){"complete"===a.readyState&&t.readyCallback()})),(r=t.source||{}).concatemoji?d(r.concatemoji):r.wpemoji&&r.twemoji&&(d(r.twemoji),d(r.wpemoji)))}(window,document,window._wpemojiSettings);
</script>
<?php
}
@@ -5550,15 +5774,10 @@
* @return string The encoded content.
*/
function wp_encode_emoji( $content ) {
- $emoji = _wp_emoji_list( 'partials' );
- $compat = version_compare( phpversion(), '5.4', '<' );
+ $emoji = _wp_emoji_list( 'partials' );
foreach ( $emoji as $emojum ) {
- if ( $compat ) {
- $emoji_char = html_entity_decode( $emojum, ENT_COMPAT, 'UTF-8' );
- } else {
- $emoji_char = html_entity_decode( $emojum );
- }
+ $emoji_char = html_entity_decode( $emojum );
if ( false !== strpos( $content, $emoji_char ) ) {
$content = preg_replace( "/$emoji_char/", $emojum, $content );
}
@@ -5594,14 +5813,9 @@
// Quickly narrow down the list of emoji that might be in the text and need replacing.
$possible_emoji = array();
- $compat = version_compare( phpversion(), '5.4', '<' );
foreach ( $emoji as $emojum ) {
if ( false !== strpos( $text, $emojum ) ) {
- if ( $compat ) {
- $possible_emoji[ $emojum ] = html_entity_decode( $emojum, ENT_COMPAT, 'UTF-8' );
- } else {
- $possible_emoji[ $emojum ] = html_entity_decode( $emojum );
- }
+ $possible_emoji[ $emojum ] = html_entity_decode( $emojum );
}
}
@@ -5610,7 +5824,7 @@
}
/** This filter is documented in wp-includes/formatting.php */
- $cdn_url = apply_filters( 'emoji_url', 'https://s.w.org/images/core/emoji/12.0.0-1/72x72/' );
+ $cdn_url = apply_filters( 'emoji_url', 'https://s.w.org/images/core/emoji/13.0.0/72x72/' );
/** This filter is documented in wp-includes/formatting.php */
$ext = apply_filters( 'emoji_ext', '.png' );
@@ -5633,12 +5847,12 @@
$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 ) ) {
+ 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] && false !== strpos( $content, '&#x' ) ) {
+ if ( '' === $ignore_block_element && strlen( $content ) > 0 && '<' !== $content[0] && false !== strpos( $content, '&#x' ) ) {
foreach ( $possible_emoji as $emojum => $emoji_char ) {
if ( false === strpos( $content, $emojum ) ) {
continue;
@@ -5653,15 +5867,15 @@
}
}
- // Did we exit ignore block.
- if ( '' != $ignore_block_element && '</' . $ignore_block_element . '>' == $content ) {
+ // Did we exit ignore block?
+ if ( '' !== $ignore_block_element && '</' . $ignore_block_element . '>' === $content ) {
$ignore_block_element = '';
}
$output .= $content;
}
- // Finally, remove any stray U+FE0F characters
+ // Finally, remove any stray U+FE0F characters.
$output = str_replace( '️', '', $output );
return $output;
@@ -5738,7 +5952,7 @@
* Returns arrays of emoji data.
*
* These arrays are automatically built from the regex in twemoji.js - if they need to be updated,
- * you should update the regex there, then run the `grunt precommit:emoji` job.
+ * you should update the regex there, then run the `npm run grunt precommit:emoji` job.
*
* @since 4.9.0
* @access private
@@ -5750,8 +5964,8 @@
// Do not remove the START/END comments - they're used to find where to insert the arrays.
// START: emoji arrays
- $entities = array( '👨‍❤️‍💋‍👨', '👩‍❤️‍💋‍👩', '👩‍❤️‍💋‍👨', '🏴󠁧󠁢󠁥󠁮󠁧󠁿', '🏴󠁧󠁢󠁳󠁣󠁴󠁿', '🏴󠁧󠁢󠁷󠁬󠁳󠁿', '🧑🏿‍🤝‍🧑🏻', '🧑🏾‍🤝‍🧑🏾', '🧑🏾‍🤝‍🧑🏽', '🧑🏾‍🤝‍🧑🏼', '🧑🏾‍🤝‍🧑🏻', '🧑🏽‍🤝‍🧑🏽', '🧑🏽‍🤝‍🧑🏼', '🧑🏽‍🤝‍🧑🏻', '🧑🏼‍🤝‍🧑🏼', '🧑🏼‍🤝‍🧑🏻', '🧑🏻‍🤝‍🧑🏻', '👩🏾‍🤝‍👩🏽', '🧑🏿‍🤝‍🧑🏿', '🧑🏿‍🤝‍🧑🏾', '👨🏼‍🤝‍👨🏻', '🧑🏿‍🤝‍🧑🏽', '🧑🏿‍🤝‍🧑🏼', '👩🏻‍🤝‍👨🏼', '👩🏻‍🤝‍👨🏽', '👩🏻‍🤝‍👨🏾', '👩🏻‍🤝‍👨🏿', '👨🏿‍🤝‍👨🏾', '👨🏿‍🤝‍👨🏽', '👨🏿‍🤝‍👨🏼', '👨🏿‍🤝‍👨🏻', '👩🏼‍🤝‍👨🏻', '👩🏼‍🤝‍👨🏽', '👨🏽‍🤝‍👨🏻', '👨🏽‍🤝‍👨🏼', '👩🏿‍🤝‍👩🏾', '👩🏿‍🤝‍👩🏽', '👩🏿‍🤝‍👩🏼', '👩🏿‍🤝‍👩🏻', '👩🏿‍🤝‍👨🏾', '👩🏿‍🤝‍👨🏽', '👩🏿‍🤝‍👨🏼', '👩🏿‍🤝‍👨🏻', '👩🏼‍🤝‍👨🏾', '👩🏾‍🤝‍👩🏼', '👩🏾‍🤝‍👩🏻', '👩🏾‍🤝‍👨🏿', '👩🏾‍🤝‍👨🏽', '👩🏾‍🤝‍👨🏼', '👨🏾‍🤝‍👨🏻', '👨🏾‍🤝‍👨🏼', '👨🏾‍🤝‍👨🏽', '👩🏾‍🤝‍👨🏻', '👩🏽‍🤝‍👩🏼', '👩🏽‍🤝‍👩🏻', '👩🏽‍🤝‍👨🏿', '👩🏽‍🤝‍👨🏾', '👩🏽‍🤝‍👨🏼', '👩🏽‍🤝‍👨🏻', '👩🏼‍🤝‍👩🏻', '👩🏼‍🤝‍👨🏿', '👨‍👨‍👧‍👦', '👩‍👩‍👧‍👦', '👩‍👩‍👧‍👧', '👨‍👨‍👦‍👦', '👩‍👩‍👦‍👦', '👨‍👨‍👧‍👧', '👨‍👩‍👦‍👦', '👨‍👩‍👧‍👦', '👨‍👩‍👧‍👧', '👨‍❤️‍👨', '👩‍❤️‍👨', '👩‍❤️‍👩', '👩‍👦‍👦', '👩‍👩‍👦', '👨‍👨‍👦', '👩‍👧‍👦', '👩‍👧‍👧', '👨‍👨‍👧', '👩‍👩‍👧', '👨‍👩‍👦', '🧑‍🤝‍🧑', '👨‍👦‍👦', '👨‍👩‍👧', '👨‍👧‍👦', '👨‍👧‍👧', '🧗🏽‍♀️', '🧗🏼‍♂️', '🧗🏼‍♀️', '🧗🏻‍♂️', '🧗🏻‍♀️', '👷🏿‍♀️', '💆🏻‍♀️', '🧖🏿‍♂️', '🧖🏿‍♀️', '🧖🏾‍♂️', '🧖🏾‍♀️', '🧖🏽‍♂️', '🧖🏽‍♀️', '🧖🏼‍♂️', '🧖🏼‍♀️', '🧖🏻‍♂️', '🧖🏻‍♀️', '💁🏿‍♀️', '💁🏾‍♂️', '💁🏾‍♀️', '💁🏽‍♂️', '💁🏽‍♀️', '💁🏼‍♂️', '💁🏼‍♀️', '💂🏻‍♀️', '🧝🏿‍♂️', '🧝🏿‍♀️', '🧝🏾‍♂️', '🧝🏾‍♀️', '🧝🏽‍♂️', '🧝🏽‍♀️', '🧝🏼‍♂️', '🧝🏼‍♀️', '👷🏾‍♂️', '👷🏾‍♀️', '🧏🏿‍♂️', '🧏🏿‍♀️', '🧏🏾‍♂️', '🧏🏾‍♀️', '🧏🏽‍♂️', '🧏🏽‍♀️', '🧏🏼‍♂️', '🧏🏼‍♀️', '🧏🏻‍♂️', '🧏🏻‍♀️', '💆🏻‍♂️', '👷🏽‍♂️', '🧎🏿‍♂️', '🧎🏿‍♀️', '🧎🏾‍♂️', '🧎🏾‍♀️', '🧎🏽‍♂️', '🧎🏽‍♀️', '🧎🏼‍♂️', '🧎🏼‍♀️', '🧎🏻‍♂️', '🧎🏻‍♀️', '👷🏽‍♀️', '💆🏼‍♀️', '🧍🏿‍♂️', '🧍🏿‍♀️', '🧍🏾‍♂️', '🧍🏾‍♀️', '🧍🏽‍♂️', '🧍🏽‍♀️', '🧍🏼‍♂️', '🧍🏼‍♀️', '🧍🏻‍♂️', '🧍🏻‍♀️', '👷🏼‍♂️', '👷🏼‍♀️', '🦹🏿‍♂️', '🦹🏿‍♀️', '🦹🏾‍♂️', '🦹🏾‍♀️', '🦹🏽‍♂️', '🦹🏽‍♀️', '🦹🏼‍♂️', '🦹🏼‍♀️', '🦹🏻‍♂️', '🦹🏻‍♀️', '💆🏼‍♂️', '👷🏻‍♂️', '🦸🏿‍♂️', '🦸🏿‍♀️', '🦸🏾‍♂️', '🦸🏾‍♀️', '🦸🏽‍♂️', '🦸🏽‍♀️', '🦸🏼‍♂️', '🦸🏼‍♀️', '🦸🏻‍♂️', '🦸🏻‍♀️', '👷🏻‍♀️', '💆🏽‍♀️', '🤾🏿‍♂️', '🤾🏿‍♀️', '🤾🏾‍♂️', '🤾🏾‍♀️', '🤾🏽‍♂️', '🤾🏽‍♀️', '🤾🏼‍♂️', '🤾🏼‍♀️', '🤾🏻‍♂️', '🤾🏻‍♀️', '💆🏽‍♂️', '💆🏾‍♀️', '🤽🏿‍♂️', '🤽🏿‍♀️', '🤽🏾‍♂️', '🤽🏾‍♀️', '🤽🏽‍♂️', '🤽🏽‍♀️', '🤽🏼‍♂️', '🤽🏼‍♀️', '🤽🏻‍♂️', '🤽🏻‍♀️', '💆🏾‍♂️', '💆🏿‍♀️', '💆🏿‍♂️', '💇🏻‍♀️', '🤹🏿‍♂️', '🤹🏿‍♀️', '🤹🏾‍♂️', '🤹🏾‍♀️', '🤹🏽‍♂️', '🤹🏽‍♀️', '🤹🏼‍♂️', '🤹🏼‍♀️', '🤹🏻‍♂️', '🤹🏻‍♀️', '💇🏻‍♂️', '💇🏼‍♀️', '🤸🏿‍♂️', '🤸🏿‍♀️', '🤸🏾‍♂️', '🤸🏾‍♀️', '🤸🏽‍♂️', '🤸🏽‍♀️', '🤸🏼‍♂️', '🤸🏼‍♀️', '🤸🏻‍♂️', '🤸🏻‍♀️', '💇🏼‍♂️', '💇🏽‍♀️', '🤷🏿‍♂️', '🤷🏿‍♀️', '🤷🏾‍♂️', '🤷🏾‍♀️', '🤷🏽‍♂️', '🤷🏽‍♀️', '🤷🏼‍♂️', '🤷🏼‍♀️', '🤷🏻‍♂️', '🤷🏻‍♀️', '💇🏽‍♂️', '💇🏾‍♀️', '🤵🏿‍♂️', '🤵🏿‍♀️', '🤵🏾‍♂️', '🤵🏾‍♀️', '🤵🏽‍♂️', '🤵🏽‍♀️', '🤵🏼‍♂️', '🤵🏼‍♀️', '🤵🏻‍♂️', '🤵🏻‍♀️', '💇🏾‍♂️', '👳🏿‍♂️', '🤦🏿‍♂️', '🤦🏿‍♀️', '🤦🏾‍♂️', '🏃🏻‍♀️', '🏃🏻‍♂️', '🤦🏾‍♀️', '🏃🏼‍♀️', '🏃🏼‍♂️', '🤦🏽‍♂️', '🏃🏽‍♀️', '🏃🏽‍♂️', '🤦🏽‍♀️', '🏃🏾‍♀️', '🏃🏾‍♂️', '🤦🏼‍♂️', '🏃🏿‍♀️', '🏃🏿‍♂️', '🤦🏼‍♀️', '👳🏿‍♀️', '💇🏿‍♀️', '🏄🏻‍♀️', '🏄🏻‍♂️', '🤦🏻‍♂️', '🏄🏼‍♀️', '🏄🏼‍♂️', '🤦🏻‍♀️', '🏄🏽‍♀️', '🏄🏽‍♂️', '💁🏿‍♂️', '🏄🏾‍♀️', '🏄🏾‍♂️', '👳🏾‍♀️', '🏄🏿‍♀️', '🏄🏿‍♂️', '🚶🏿‍♂️', '💇🏿‍♂️', '👳🏽‍♂️', '🚶🏿‍♀️', '🚶🏾‍♂️', '🚶🏾‍♀️', '🚶🏽‍♂️', '🚶🏽‍♀️', '🏊🏻‍♀️', '🏊🏻‍♂️', '🚶🏼‍♂️', '🏊🏼‍♀️', '🏊🏼‍♂️', '🚶🏼‍♀️', '🏊🏽‍♀️', '🏊🏽‍♂️', '🚶🏻‍♂️', '🏊🏾‍♀️', '🏊🏾‍♂️', '🚶🏻‍♀️', '🏊🏿‍♀️', '🏊🏿‍♂️', '👳🏽‍♀️', '👳🏼‍♂️', '👳🏼‍♀️', '🏋🏻‍♀️', '🏋🏻‍♂️', '👳🏻‍♂️', '🏋🏼‍♀️', '🏋🏼‍♂️', '🚵🏿‍♂️', '🏋🏽‍♀️', '🏋🏽‍♂️', '🚵🏿‍♀️', '🏋🏾‍♀️', '🏋🏾‍♂️', '🚵🏾‍♂️', '🏋🏿‍♀️', '🏋🏿‍♂️', '🚵🏾‍♀️', '🏌🏻‍♀️', '🏌🏻‍♂️', '🚵🏽‍♂️', '🏌🏼‍♀️', '🏌🏼‍♂️', '🚵🏽‍♀️', '🏌🏽‍♀️', '🏌🏽‍♂️', '🚵🏼‍♂️', '🏌🏾‍♀️', '🏌🏾‍♂️', '🚵🏼‍♀️', '🏌🏿‍♀️', '🏌🏿‍♂️', '🚵🏻‍♂️', '👳🏻‍♀️', '🕴🏻‍♀️', '🧝🏻‍♂️', '🧝🏻‍♀️', '💁🏻‍♂️', '🚵🏻‍♀️', '🕴🏻‍♂️', '🕴🏼‍♀️', '🚴🏿‍♂️', '🚴🏿‍♀️', '🚴🏾‍♂️', '🚴🏾‍♀️', '🚴🏽‍♂️', '🚴🏽‍♀️', '🚴🏼‍♂️', '🚴🏼‍♀️', '🚴🏻‍♂️', '🚴🏻‍♀️', '🕴🏼‍♂️', '🕴🏽‍♀️', '🚣🏿‍♂️', '🚣🏿‍♀️', '🚣🏾‍♂️', '🚣🏾‍♀️', '🚣🏽‍♂️', '🚣🏽‍♀️', '🚣🏼‍♂️', '🚣🏼‍♀️', '🚣🏻‍♂️', '🚣🏻‍♀️', '🕴🏽‍♂️', '👱🏿‍♂️', '🙎🏿‍♂️', '🙎🏿‍♀️', '🙎🏾‍♂️', '🙎🏾‍♀️', '🙎🏽‍♂️', '🙎🏽‍♀️', '🙎🏼‍♂️', '🙎🏼‍♀️', '🙎🏻‍♂️', '🙎🏻‍♀️', '👱🏿‍♀️', '🕴🏾‍♀️', '🙍🏿‍♂️', '🙍🏿‍♀️', '🙍🏾‍♂️', '🙍🏾‍♀️', '🙍🏽‍♂️', '🙍🏽‍♀️', '🙍🏼‍♂️', '🙍🏼‍♀️', '🙍🏻‍♂️', '🙍🏻‍♀️', '👱🏾‍♂️', '👱🏾‍♀️', '🙋🏿‍♂️', '🙋🏿‍♀️', '🙋🏾‍♂️', '🙋🏾‍♀️', '🙋🏽‍♂️', '🙋🏽‍♀️', '🙋🏼‍♂️', '🙋🏼‍♀️', '🙋🏻‍♂️', '🙋🏻‍♀️', '🕴🏾‍♂️', '👱🏽‍♂️', '🙇🏿‍♂️', '🙇🏿‍♀️', '🙇🏾‍♂️', '🙇🏾‍♀️', '🙇🏽‍♂️', '🙇🏽‍♀️', '🙇🏼‍♂️', '🙇🏼‍♀️', '🙇🏻‍♂️', '🙇🏻‍♀️', '👱🏽‍♀️', '🕴🏿‍♀️', '👱🏼‍♂️', '👱🏼‍♀️', '🕴🏿‍♂️', '👱🏻‍♂️', '👱🏻‍♀️', '🕵🏻‍♀️', '🕵🏻‍♂️', '🕵🏼‍♀️', '🕵🏼‍♂️', '👮🏿‍♂️', '👮🏿‍♀️', '🕵🏽‍♀️', '👮🏾‍♂️', '👮🏾‍♀️', '🕵🏽‍♂️', '👮🏽‍♂️', '👮🏽‍♀️', '👨🏻‍⚕️', '👨🏻‍⚖️', '👨🏻‍✈️', '🙆🏿‍♂️', '🕵🏾‍♀️', '👮🏼‍♂️', '👮🏼‍♀️', '🕵🏾‍♂️', '👮🏻‍♂️', '👮🏻‍♀️', '🕵🏿‍♀️', '🕵🏿‍♂️', '🙅🏻‍♀️', '🙅🏻‍♂️', '🙅🏼‍♀️', '💁🏻‍♀️', '🙅🏼‍♂️', '🙅🏽‍♀️', '🙅🏽‍♂️', '🙅🏾‍♀️', '🙅🏾‍♂️', '🙅🏿‍♀️', '🙅🏿‍♂️', '👨🏼‍⚕️', '👨🏼‍⚖️', '👨🏼‍✈️', '🙆🏿‍♀️', '🧜🏿‍♂️', '🧜🏿‍♀️', '🧜🏾‍♂️', '🧜🏾‍♀️', '🧜🏽‍♂️', '🧜🏽‍♀️', '🧜🏼‍♂️', '🧜🏼‍♀️', '🧜🏻‍♂️', '🧜🏻‍♀️', '💂🏻‍♂️', '💂🏼‍♀️', '👩🏿‍✈️', '🧛🏿‍♂️', '🧛🏿‍♀️', '👩🏿‍⚖️', '👩🏿‍⚕️', '🧛🏾‍♂️', '🧛🏾‍♀️', '🧛🏽‍♂️', '🧛🏽‍♀️', '🧛🏼‍♂️', '👨🏽‍⚕️', '👨🏽‍⚖️', '👨🏽‍✈️', '🙆🏾‍♂️', '🧛🏼‍♀️', '🧛🏻‍♂️', '🧛🏻‍♀️', '🙆🏻‍♀️', '👩🏾‍✈️', '👩🏾‍⚖️', '👩🏾‍⚕️', '💂🏼‍♂️', '💂🏽‍♀️', '🧚🏿‍♂️', '🧚🏿‍♀️', '🧚🏾‍♂️', '🧚🏾‍♀️', '🧚🏽‍♂️', '🧚🏽‍♀️', '🧚🏼‍♂️', '🧚🏼‍♀️', '🙆🏻‍♂️', '👩🏽‍✈️', '👩🏽‍⚖️', '👩🏽‍⚕️', '🧚🏻‍♂️', '🧚🏻‍♀️', '👨🏾‍⚕️', '👨🏾‍⚖️', '👨🏾‍✈️', '🙆🏾‍♀️', '💂🏽‍♂️', '💂🏾‍♀️', '🧙🏿‍♂️', '🧙🏿‍♀️', '🙆🏼‍♀️', '👩🏼‍✈️', '👩🏼‍⚖️', '👩🏼‍⚕️', '🧙🏾‍♂️', '🧙🏾‍♀️', '🧙🏽‍♂️', '🧙🏽‍♀️', '🧙🏼‍♂️', '🧙🏼‍♀️', '🧙🏻‍♂️', '🧙🏻‍♀️', '💂🏾‍♂️', '🙆🏼‍♂️', '👩🏻‍✈️', '👩🏻‍⚖️', '👩🏻‍⚕️', '💂🏿‍♀️', '🧘🏿‍♂️', '🧘🏿‍♀️', '👨🏿‍⚕️', '👨🏿‍⚖️', '👨🏿‍✈️', '🙆🏽‍♂️', '🧘🏾‍♂️', '🧘🏾‍♀️', '🧘🏽‍♂️', '🧘🏽‍♀️', '🧘🏼‍♂️', '🧘🏼‍♀️', '🧘🏻‍♂️', '🧘🏻‍♀️', '💂🏿‍♂️', '👷🏿‍♂️', '🧗🏿‍♂️', '🧗🏿‍♀️', '🧗🏾‍♂️', '🙆🏽‍♀️', '🧗🏾‍♀️', '🧗🏽‍♂️', '👳🏾‍♂️', '⛹🏼‍♂️', '🕴️‍♀️', '🕴️‍♂️', '⛹🏾‍♂️', '⛹🏿‍♀️', '⛹🏿‍♂️', '⛹🏼‍♀️', '🏌️‍♀️', '🏌️‍♂️', '⛹🏽‍♀️', '⛹🏻‍♂️', '🕵️‍♀️', '🕵️‍♂️', '⛹🏻‍♀️', '⛹🏽‍♂️', '⛹🏾‍♀️', '🏋️‍♀️', '🏋️‍♂️', '⛹️‍♀️', '⛹️‍♂️', '👨🏽‍🚒', '👩🏻‍🍳', '👩🏻‍🎓', '👩🏻‍🎤', '👩🏻‍🎨', '👩🏻‍🏫', '👩🏻‍🏭', '👩🏻‍💻', '👩🏻‍💼', '👩🏻‍🔧', '👩🏻‍🔬', '👩🏻‍🚀', '👩🏻‍🚒', '👨🏻‍🏫', '👨🏿‍🦽', '👨🏿‍🦼', '👨🏿‍🦳', '👩🏻‍🦯', '👩🏻‍🦰', '👩🏻‍🦱', '👩🏻‍🦲', '👩🏻‍🦳', '👩🏻‍🦼', '👩🏻‍🦽', '👨🏿‍🦲', '👨🏿‍🦱', '👨🏿‍🦰', '👨🏿‍🦯', '👩🏼‍🌾', '👩🏼‍🍳', '👩🏼‍🎓', '👩🏼‍🎤', '👩🏼‍🎨', '👩🏼‍🏫', '👩🏼‍🏭', '👩🏼‍💻', '👩🏼‍💼', '👩🏼‍🔧', '👩🏼‍🔬', '👩🏼‍🚀', '👩🏼‍🚒', '👨🏿‍🚒', '👨🏿‍🚀', '👨🏿‍🔬', '👨🏿‍🔧', '👨🏿‍💼', '👩🏼‍🦯', '👩🏼‍🦰', '👩🏼‍🦱', '👩🏼‍🦲', '👩🏼‍🦳', '👩🏼‍🦼', '👩🏼‍🦽', '👨🏿‍💻', '👨🏿‍🏭', '👨🏿‍🏫', '👨🏿‍🎨', '👩🏽‍🌾', '👩🏽‍🍳', '👩🏽‍🎓', '👩🏽‍🎤', '👩🏽‍🎨', '👩🏽‍🏫', '👩🏽‍🏭', '👩🏽‍💻', '👩🏽‍💼', '👩🏽‍🔧', '👩🏽‍🔬', '👩🏽‍🚀', '👩🏽‍🚒', '👨🏿‍🎤', '👨🏿‍🎓', '👨🏿‍🍳', '👨🏿‍🌾', '👨🏾‍🦽', '👨🏾‍🦼', '👩🏽‍🦯', '👩🏽‍🦰', '👩🏽‍🦱', '👩🏽‍🦲', '👩🏽‍🦳', '👩🏽‍🦼', '👩🏽‍🦽', '👨🏾‍🦳', '👨🏾‍🦲', '👨🏾‍🦱', '👨🏾‍🦰', '👩🏾‍🌾', '👩🏾‍🍳', '👩🏾‍🎓', '👩🏾‍🎤', '👩🏾‍🎨', '👩🏾‍🏫', '👩🏾‍🏭', '👩🏾‍💻', '👩🏾‍💼', '👩🏾‍🔧', '👩🏾‍🔬', '👩🏾‍🚀', '👩🏾‍🚒', '👨🏾‍🦯', '👨🏾‍🚒', '👨🏾‍🚀', '👨🏾‍🔬', '👨🏾‍🔧', '👨🏾‍💼', '👨🏾‍💻', '👩🏾‍🦯', '👩🏾‍🦰', '👩🏾‍🦱', '👩🏾‍🦲', '👩🏾‍🦳', '👩🏾‍🦼', '👩🏾‍🦽', '👨🏾‍🏭', '👨🏾‍🏫', '👨🏾‍🎨', '👨🏾‍🎤', '👩🏿‍🌾', '👩🏿‍🍳', '👩🏿‍🎓', '👩🏿‍🎤', '👩🏿‍🎨', '👩🏿‍🏫', '👩🏿‍🏭', '👩🏿‍💻', '👩🏿‍💼', '👩🏿‍🔧', '👩🏿‍🔬', '👩🏿‍🚀', '👩🏿‍🚒', '👨🏾‍🎓', '👨🏾‍🍳', '👨🏾‍🌾', '👨🏽‍🦽', '👨🏽‍🦼', '👨🏽‍🦳', '👨🏽‍🦲', '👨🏽‍🦱', '👩🏿‍🦯', '👩🏿‍🦰', '👩🏿‍🦱', '👩🏿‍🦲', '👩🏿‍🦳', '👩🏿‍🦼', '👩🏿‍🦽', '👨🏽‍🦰', '👨🏽‍🦯', '👩🏻‍🌾', '👨🏻‍🌾', '👨🏽‍🚀', '👨🏽‍🔬', '👨🏽‍🔧', '👨🏽‍💼', '👨🏽‍💻', '👨🏽‍🏭', '👨🏽‍🏫', '👨🏽‍🎨', '👨🏻‍🍳', '👨🏻‍🎓', '👨🏻‍🎤', '👨🏽‍🎤', '👨🏽‍🎓', '👨🏽‍🍳', '👨🏽‍🌾', '👨🏻‍🎨', '👨🏼‍🦽', '👨🏼‍🦼', '👨🏼‍🦳', '👨🏼‍🦲', '👨🏼‍🦱', '👨🏼‍🦰', '👨🏼‍🦯', '👨🏼‍🚒', '👨🏼‍🚀', '👨🏼‍🔬', '👨🏼‍🔧', '👨🏼‍💼', '👨🏼‍💻', '👨🏼‍🏭', '👨🏼‍🏫', '👨🏼‍🎨', '👨🏼‍🎤', '👨🏼‍🎓', '👨🏼‍🍳', '👨🏼‍🌾', '👨🏻‍🦽', '👨🏻‍🦼', '👨🏻‍🦳', '👨🏻‍🦲', '👨🏻‍🦱', '👨🏻‍🦰', '👨🏻‍🦯', '👨🏻‍🚒', '👨🏻‍🚀', '👨🏻‍🏭', '👨🏻‍💻', '👨🏻‍💼', '👨🏻‍🔧', '👨🏻‍🔬', '🏳️‍🌈', '🤹‍♀️', '👮‍♂️', '👮‍♀️', '🙅‍♀️', '👩‍✈️', '👩‍⚖️', '👩‍⚕️', '🙅‍♂️', '🙆‍♀️', '🙆‍♂️', '🙇‍♀️', '🙇‍♂️', '🙋‍♀️', '🙋‍♂️', '🙍‍♀️', '🙍‍♂️', '🙎‍♀️', '🙎‍♂️', '👱‍♀️', '👱‍♂️', '🚣‍♀️', '🚣‍♂️', '🚴‍♀️', '🚴‍♂️', '🏴‍☠️', '👯‍♂️', '🚵‍♀️', '💇‍♂️', '🏊‍♂️', '🏊‍♀️', '💇‍♀️', '🚵‍♂️', '🏄‍♂️', '🏄‍♀️', '🚶‍♀️', '🚶‍♂️', '🏃‍♂️', '🏃‍♀️', '🤦‍♀️', '🤦‍♂️', '👳‍♀️', '👳‍♂️', '🤵‍♀️', '🤵‍♂️', '🤷‍♀️', '🤷‍♂️', '🤸‍♀️', '🤸‍♂️', '👯‍♀️', '💆‍♂️', '💆‍♀️', '🤹‍♂️', '🤼‍♀️', '🤼‍♂️', '🤽‍♀️', '🤽‍♂️', '🤾‍♀️', '🤾‍♂️', '🦸‍♀️', '🦸‍♂️', '🦹‍♀️', '🦹‍♂️', '🧍‍♀️', '🧍‍♂️', '🧎‍♀️', '🧎‍♂️', '🧏‍♀️', '🧏‍♂️', '🧖‍♀️', '🧖‍♂️', '🧗‍♀️', '💂‍♂️', '👷‍♀️', '👷‍♂️', '💂‍♀️', '🧗‍♂️', '🧘‍♀️', '🧘‍♂️', '🧙‍♀️', '🧙‍♂️', '🧚‍♀️', '🧚‍♂️', '🧛‍♀️', '🧛‍♂️', '🧜‍♀️', '🧜‍♂️', '🧝‍♀️', '🧝‍♂️', '🧞‍♀️', '💁‍♂️', '🧞‍♂️', '🧟‍♀️', '💁‍♀️', '🧟‍♂️', '👨‍⚖️', '👨‍⚕️', '👨‍✈️', '👨‍🦳', '👨‍🦼', '👨‍🦽', '👨‍👧', '👨‍🌾', '👨‍🍳', '👨‍🎓', '👨‍🎤', '👨‍🎨', '👨‍🏫', '👨‍🏭', '🐕‍🦺', '👨‍👦', '👁‍🗨', '👩‍🌾', '👩‍🍳', '👩‍🎓', '👩‍🎤', '👩‍🎨', '👩‍🏫', '👩‍🏭', '👨‍💻', '👩‍👦', '👨‍💼', '👨‍🔧', '👩‍👧', '👨‍🔬', '👨‍🚀', '👨‍🚒', '👨‍🦯', '👨‍🦰', '👩‍💻', '👩‍💼', '👩‍🔧', '👩‍🔬', '👩‍🚀', '👩‍🚒', '👩‍🦯', '👩‍🦰', '👩‍🦱', '👩‍🦲', '👩‍🦳', '👩‍🦼', '👩‍🦽', '👨‍🦱', '👨‍🦲', '🎅🏽', '💁🏾', '💁🏽', '💁🏼', '💁🏻', '👼🏿', '💂🏻', '👼🏾', '👼🏽', '💂🏼', '👼🏼', '👼🏻', '💂🏽', '👸🏿', '👸🏾', '💂🏾', '👸🏽', '👸🏼', '💂🏿', '👸🏻', '👷🏿', '💃🏻', '💃🏼', '💃🏽', '💃🏾', '💃🏿', '💅🏻', '💅🏼', '💅🏽', '💅🏾', '💅🏿', '👷🏾', '👷🏽', '💆🏻', '👷🏼', '👷🏻', '💆🏼', '👶🏿', '👶🏾', '💆🏽', '👶🏽', '👶🏼', '💆🏾', '👶🏻', '👵🏿', '💆🏿', '👵🏾', '👵🏽', '👵🏼', '👵🏻', '💇🏻', '👴🏿', '👴🏾', '💇🏼', '👴🏽', '👴🏼', '💇🏽', '👴🏻', '👳🏿', '💇🏾', '👳🏾', '👳🏽', '💇🏿', '👳🏼', '👳🏻', '💪🏻', '💪🏼', '💪🏽', '💪🏾', '💪🏿', '👲🏿', '👲🏾', '🕴🏻', '👲🏽', '👲🏼', '🕴🏼', '👲🏻', '👱🏿', '🕴🏽', '👱🏾', '👱🏽', '🕴🏾', '👱🏼', '👱🏻', '🕴🏿', '👰🏿', '👰🏾', '👰🏽', '👰🏼', '🕵🏻', '👰🏻', '👮🏿', '🕵🏼', '👮🏾', '👮🏽', '🕵🏽', '👮🏼', '👮🏻', '🕵🏾', '👭🏿', '👭🏾', '🕵🏿', '👭🏽', '👭🏼', '🕺🏻', '🕺🏼', '🕺🏽', '🕺🏾', '🕺🏿', '🖐🏻', '🖐🏼', '🖐🏽', '🖐🏾', '🖐🏿', '🖕🏻', '🖕🏼', '🖕🏽', '🖕🏾', '🖕🏿', '🖖🏻', '🖖🏼', '🖖🏽', '🖖🏾', '🖖🏿', '👭🏻', '👬🏿', '🙅🏻', '👬🏾', '👬🏽', '🙅🏼', '👬🏼', '👬🏻', '🙅🏽', '👫🏿', '👫🏾', '🙅🏾', '👫🏽', '👫🏼', '🙅🏿', '👫🏻', '👩🏿', '👩🏾', '👩🏽', '🙆🏻', '👩🏼', '👩🏻', '🙆🏼', '🇦🇨', '👨🏿', '🙆🏽', '👨🏾', '👨🏽', '🙆🏾', '👨🏼', '👨🏻', '🙆🏿', '👧🏿', '👧🏾', '👧🏽', '👧🏼', '🙇🏻', '👧🏻', '👦🏿', '🙇🏼', '👦🏾', '👦🏽', '🙇🏽', '👦🏼', '👦🏻', '🙇🏾', '👐🏿', '👐🏾', '🙇🏿', '👐🏽', '👐🏼', '👐🏻', '👏🏿', '🙋🏻', '👏🏾', '👏🏽', '🙋🏼', '👏🏼', '👏🏻', '🙋🏽', '👎🏿', '👎🏾', '🙋🏾', '👎🏽', '👎🏼', '🙋🏿', '👎🏻', '👍🏿', '🙌🏻', '🙌🏼', '🙌🏽', '🙌🏾', '🙌🏿', '👍🏾', '👍🏽', '🙍🏻', '👍🏼', '👍🏻', '🙍🏼', '👌🏿', '👌🏾', '🙍🏽', '👌🏽', '👌🏼', '🙍🏾', '👌🏻', '👋🏿', '🙍🏿', '👋🏾', '👋🏽', '👋🏼', '👋🏻', '🙎🏻', '👊🏿', '👊🏾', '🙎🏼', '👊🏽', '👊🏼', '🙎🏽', '👊🏻', '👉🏿', '🙎🏾', '👉🏾', '👉🏽', '🙎🏿', '👉🏼', '👉🏻', '🙏🏻', '🙏🏼', '🙏🏽', '🙏🏾', '🙏🏿', '👈🏿', '👈🏾', '🚣🏻', '👈🏽', '👈🏼', '🚣🏼', '👈🏻', '👇🏿', '🚣🏽', '👇🏾', '👇🏽', '🚣🏾', '👇🏼', '👇🏻', '🚣🏿', '👆🏿', '👆🏾', '👆🏽', '👆🏼', '🚴🏻', '👆🏻', '👃🏿', '🚴🏼', '👃🏾', '👃🏽', '🚴🏽', '👃🏼', '👃🏻', '🚴🏾', '👂🏿', '👂🏾', '🚴🏿', '👂🏽', '👂🏼', '👂🏻', '🏌🏿', '🚵🏻', '🏌🏾', '🏌🏽', '🚵🏼', '🏌🏼', '🏌🏻', '🚵🏽', '🏋🏿', '🏋🏾', '🚵🏾', '🏋🏽', '🏋🏼', '🚵🏿', '🏋🏻', '🏊🏿', '🏊🏾', '🏊🏽', '🚶🏻', '🏊🏼', '🏊🏻', '🚶🏼', '🏇🏿', '🏇🏾', '🚶🏽', '🏇🏽', '🏇🏼', '🚶🏾', '🏇🏻', '🏄🏿', '🚶🏿', '🏄🏾', '🏄🏽', '🛀🏻', '🛀🏼', '🛀🏽', '🛀🏾', '🛀🏿', '🛌🏻', '🛌🏼', '🛌🏽', '🛌🏾', '🛌🏿', '🤏🏻', '🤏🏼', '🤏🏽', '🤏🏾', '🤏🏿', '🤘🏻', '🤘🏼', '🤘🏽', '🤘🏾', '🤘🏿', '🤙🏻', '🤙🏼', '🤙🏽', '🤙🏾', '🤙🏿', '🤚🏻', '🤚🏼', '🤚🏽', '🤚🏾', '🤚🏿', '🤛🏻', '🤛🏼', '🤛🏽', '🤛🏾', '🤛🏿', '🤜🏻', '🤜🏼', '🤜🏽', '🤜🏾', '🤜🏿', '🤞🏻', '🤞🏼', '🤞🏽', '🤞🏾', '🤞🏿', '🤟🏻', '🤟🏼', '🤟🏽', '🤟🏾', '🤟🏿', '🏄🏼', '🏄🏻', '🤦🏻', '🏃🏿', '🏃🏾', '🤦🏼', '🏃🏽', '🏃🏼', '🤦🏽', '🏃🏻', '🏂🏿', '🤦🏾', '🏂🏾', '🏂🏽', '🤦🏿', '🏂🏼', '🏂🏻', '🤰🏻', '🤰🏼', '🤰🏽', '🤰🏾', '🤰🏿', '🤱🏻', '🤱🏼', '🤱🏽', '🤱🏾', '🤱🏿', '🤲🏻', '🤲🏼', '🤲🏽', '🤲🏾', '🤲🏿', '🤳🏻', '🤳🏼', '🤳🏽', '🤳🏾', '🤳🏿', '🤴🏻', '🤴🏼', '🤴🏽', '🤴🏾', '🤴🏿', '🎅🏿', '🎅🏾', '🤵🏻', '💁🏿', '🎅🏼', '🤵🏼', '🎅🏻', '🇿🇼', '🤵🏽', '🇿🇲', '🇿🇦', '🤵🏾', '🇾🇹', '🇾🇪', '🤵🏿', '🇽🇰', '🇼🇸', '🤶🏻', '🤶🏼', '🤶🏽', '🤶🏾', '🤶🏿', '🇼🇫', '🇻🇺', '🤷🏻', '🇻🇳', '🇻🇮', '🤷🏼', '🇻🇬', '🇻🇪', '🤷🏽', '🇻🇨', '🇻🇦', '🤷🏾', '🇺🇿', '🇺🇾', '🤷🏿', '🇺🇸', '🇺🇳', '🇺🇲', '🇺🇬', '🤸🏻', '🇺🇦', '🇹🇿', '🤸🏼', '🇹🇼', '🇹🇻', '🤸🏽', '🇹🇹', '🇹🇷', '🤸🏾', '🇹🇴', '🇹🇳', '🤸🏿', '🇹🇲', '🇹🇱', '🇹🇰', '🇹🇯', '🤹🏻', '🇹🇭', '🇹🇬', '🤹🏼', '🇹🇫', '🇹🇩', '🤹🏽', '🇹🇨', '🇹🇦', '🤹🏾', '🇸🇿', '🇸🇾', '🤹🏿', '🇸🇽', '🇸🇻', '🇸🇹', '🇸🇸', '🇸🇷', '🇸🇴', '🤽🏻', '🇸🇳', '🇸🇲', '🤽🏼', '🇸🇱', '🇸🇰', '🤽🏽', '🇸🇯', '🇸🇮', '🤽🏾', '🇸🇭', '🇸🇬', '🤽🏿', '🇸🇪', '🇸🇩', '🇸🇨', '🇸🇧', '🤾🏻', '🇸🇦', '🇷🇼', '🤾🏼', '🇷🇺', '🇷🇸', '🤾🏽', '🇷🇴', '🇷🇪', '🤾🏾', '🇶🇦', '🇵🇾', '🤾🏿', '🇵🇼', '🇵🇹', '🦵🏻', '🦵🏼', '🦵🏽', '🦵🏾', '🦵🏿', '🦶🏻', '🦶🏼', '🦶🏽', '🦶🏾', '🦶🏿', '🇵🇸', '🇵🇷', '🦸🏻', '🇵🇳', '🇵🇲', '🦸🏼', '🇵🇱', '🇵🇰', '🦸🏽', '🇵🇭', '🇵🇬', '🦸🏾', '🇵🇫', '🇵🇪', '🦸🏿', '🇵🇦', '🇴🇲', '🇳🇿', '🇳🇺', '🦹🏻', '🇳🇷', '🇳🇵', '🦹🏼', '🇳🇴', '🇳🇱', '🦹🏽', '🇳🇮', '🇳🇬', '🦹🏾', '🇳🇫', '🇳🇪', '🦹🏿', '🇳🇨', '🇳🇦', '🦻🏻', '🦻🏼', '🦻🏽', '🦻🏾', '🦻🏿', '🇲🇿', '🇲🇾', '🧍🏻', '🇲🇽', '🇲🇼', '🧍🏼', '🇲🇻', '🇲🇺', '🧍🏽', '🇲🇹', '🇲🇸', '🧍🏾', '🇲🇷', '🇲🇶', '🧍🏿', '🇲🇵', '🇲🇴', '🇲🇳', '🇲🇲', '🧎🏻', '🇲🇱', '🇲🇰', '🧎🏼', '🇲🇭', '🇲🇬', '🧎🏽', '🇲🇫', '🇲🇪', '🧎🏾', '🇲🇩', '🇲🇨', '🧎🏿', '🇲🇦', '🇱🇾', '🇱🇻', '🇱🇺', '🧏🏻', '🇱🇹', '🇱🇸', '🧏🏼', '🇱🇷', '🇱🇰', '🧏🏽', '🇱🇮', '🇱🇨', '🧏🏾', '🇱🇧', '🇱🇦', '🧏🏿', '🇰🇿', '🇰🇾', '🇰🇼', '🧑🏻', '🇰🇷', '🇰🇵', '🧑🏼', '🇰🇳', '🇰🇲', '🇰🇮', '🧑🏽', '🇰🇭', '🇰🇬', '🇰🇪', '🇯🇵', '🧑🏾', '🇯🇴', '🇯🇲', '🇯🇪', '🇮🇹', '🇮🇸', '🧑🏿', '🇮🇷', '🧒🏻', '🧒🏼', '🧒🏽', '🧒🏾', '🧒🏿', '🧓🏻', '🧓🏼', '🧓🏽', '🧓🏾', '🧓🏿', '🧔🏻', '🧔🏼', '🧔🏽', '🧔🏾', '🧔🏿', '🧕🏻', '🧕🏼', '🧕🏽', '🧕🏾', '🧕🏿', '🇮🇶', '🇮🇴', '🧖🏻', '🇮🇳', '🇮🇲', '🧖🏼', '🇮🇱', '🇮🇪', '🧖🏽', '🇮🇩', '🇮🇨', '🧖🏾', '🇭🇺', '🇭🇹', '🧖🏿', '🇭🇷', '🇭🇳', '🇭🇲', '🇭🇰', '🧗🏻', '🇬🇾', '🇬🇼', '🧗🏼', '🇬🇺', '🇬🇹', '🧗🏽', '🇬🇸', '🇬🇷', '🧗🏾', '🇬🇶', '🇬🇵', '🧗🏿', '🇬🇳', '🇬🇲', '🇬🇱', '🇬🇮', '🧘🏻', '🇬🇭', '🇬🇬', '🧘🏼', '🇬🇫', '🇬🇪', '🧘🏽', '🇬🇩', '🇬🇧', '🧘🏾', '🇬🇦', '🇫🇷', '🧘🏿', '🇫🇴', '🇫🇲', '🇫🇰', '🇫🇯', '🧙🏻', '🇫🇮', '🇪🇺', '🧙🏼', '🇪🇹', '🇪🇸', '🧙🏽', '🇪🇷', '🇪🇭', '🧙🏾', '🇪🇬', '🇪🇪', '🧙🏿', '🇪🇨', '🇪🇦', '🇩🇿', '🇩🇴', '🧚🏻', '🇩🇲', '🇩🇰', '🧚🏼', '🇩🇯', '🇩🇬', '🧚🏽', '🇩🇪', '🇨🇿', '🧚🏾', '🇨🇾', '🇨🇽', '🧚🏿', '🇨🇼', '🇨🇻', '🇨🇺', '🇨🇷', '🧛🏻', '🇨🇵', '🇨🇴', '🧛🏼', '🇨🇳', '🇨🇲', '🧛🏽', '🇨🇱', '🇨🇰', '🧛🏾', '🇨🇮', '🇨🇭', '🧛🏿', '🇨🇬', '🇨🇫', '🇨🇩', '🇨🇨', '🧜🏻', '🇨🇦', '🇧🇿', '🧜🏼', '🇧🇾', '🇧🇼', '🧜🏽', '🇧🇻', '🇧🇹', '🧜🏾', '🇧🇸', '🇧🇷', '🧜🏿', '🇧🇶', '🇧🇴', '🇧🇳', '🇧🇲', '🧝🏻', '🇧🇱', '🇧🇯', '🧝🏼', '🇧🇮', '🇧🇭', '🧝🏽', '🇧🇬', '🇧🇫', '🧝🏾', '🇧🇪', '🇧🇩', '🧝🏿', '🇧🇧', '🇧🇦', '🇦🇿', '🇦🇽', '🇦🇼', '🇦🇺', '🇦🇹', '🇦🇸', '🇦🇷', '🇦🇶', '🇦🇴', '🇦🇲', '🇦🇱', '🇦🇮', '🇦🇬', '🇦🇫', '🇦🇪', '🇦🇩', '✍🏿', '⛹🏻', '✍🏾', '✍🏽', '✍🏼', '✍🏻', '✌🏿', '✌🏾', '✌🏽', '✌🏼', '✌🏻', '✋🏿', '✋🏾', '✋🏽', '✋🏼', '✋🏻', '✊🏿', '✊🏾', '✊🏽', '✊🏼', '✊🏻', '⛷🏽', '⛷🏾', '⛹🏿', '☝🏿', '☝🏾', '⛹🏾', '☝🏽', '☝🏼', '⛹🏽', '☝🏻', '⛷🏿', '⛹🏼', '⛷🏻', '⛷🏼', '4⃣', '#⃣', '0⃣', '1⃣', '2⃣', '3⃣', '*⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '🏌', '😛', '😜', '😝', '😞', '😟', '😠', '😡', '😢', '😣', '😤', '😥', '😦', '😧', '😨', '😩', '😪', '😫', '😬', '😭', '😮', '😯', '😰', '😱', '😲', '😳', '😴', '😵', '😶', '😷', '😸', '😹', '😺', '😻', '😼', '😽', '😾', '😿', '🙀', '🙁', '🙂', '🙃', '🙄', '🏮', '🏯', '🏰', '🌭', '🏳', '🌮', '🌯', '🌰', '🌱', '🏴', '🏵', '🏷', '🏸', '🏹', '🏺', '🏻', '🏼', '🙅', '🏽', '🏾', '🏿', '🐀', '🐁', '🐂', '🐃', '🐄', '🐅', '🐆', '🐇', '🐈', '🐉', '🐊', '🐋', '🐌', '🐍', '🙆', '🐎', '🐏', '🐐', '🐑', '🐒', '🐓', '🐔', '🌲', '🐕', '🐖', '🐗', '🐘', '🐙', '🐚', '🐛', '🐜', '🐝', '🙇', '🙈', '🙉', '🙊', '🐞', '🐟', '🐠', '🐡', '🐢', '🐣', '🐤', '🐥', '🐦', '🐧', '🐨', '🐩', '🐪', '🐫', '🐬', '🐭', '🐮', '🙋', '🐯', '🐰', '🐱', '🐲', '🐳', '🙌', '🐴', '🐵', '🐶', '🐷', '🐸', '🐹', '🐺', '🐻', '🐼', '🐽', '🐾', '🐿', '👀', '🌳', '👁', '🌴', '🌵', '🙍', '🌶', '🌷', '🌸', '👂', '🌹', '🌺', '🌻', '🌼', '🌽', '👃', '👄', '👅', '🌾', '🌿', '🍀', '🍁', '🍂', '🙎', '👆', '🍃', '🍄', '🍅', '🍆', '🙏', '🚀', '🚁', '🚂', '🚃', '🚄', '🚅', '🚆', '🚇', '🚈', '🚉', '🚊', '🚋', '🚌', '🚍', '🚎', '🚏', '🚐', '🚑', '🚒', '🚓', '🚔', '🚕', '🚖', '🚗', '🚘', '🚙', '🚚', '🚛', '🚜', '🚝', '🚞', '🚟', '🚠', '🚡', '🚢', '🍇', '👇', '🍈', '🍉', '🍊', '🍋', '🍌', '👈', '🍍', '🍎', '🍏', '🍐', '🍑', '👉', '🍒', '🍓', '🍔', '🚣', '🚤', '🚥', '🚦', '🚧', '🚨', '🚩', '🚪', '🚫', '🚬', '🚭', '🚮', '🚯', '🚰', '🚱', '🚲', '🚳', '🍕', '🍖', '👊', '🍗', '🍘', '🍙', '🍚', '🍛', '👋', '🍜', '🍝', '🍞', '🍟', '🍠', '👌', '🍡', '🍢', '🚴', '🍣', '🍤', '🍥', '👍', '🍦', '👩', '👪', '🍧', '🍨', '🍩', '🍪', '👎', '👫', '🍫', '🍬', '🍭', '🍮', '🚵', '🍯', '👬', '👏', '🍰', '🍱', '🍲', '🍳', '👭', '🍴', '👐', '👑', '👒', '👓', '👔', '👕', '👖', '👗', '🚶', '🚷', '🚸', '🚹', '🚺', '🚻', '🚼', '🚽', '🚾', '🚿', '👘', '👙', '👚', '👛', '👜', '🛀', '🛁', '🛂', '🛃', '🛄', '🛅', '🛋', '👝', '👞', '👟', '👮', '👠', '🛌', '🛍', '🛎', '🛏', '🛐', '🛑', '🛒', '🛕', '🛠', '🛡', '🛢', '🛣', '🛤', '🛥', '🛩', '🛫', '🛬', '🛰', '🛳', '🛴', '🛵', '🛶', '🛷', '🛸', '🛹', '🛺', '🟠', '🟡', '🟢', '🟣', '🟤', '🟥', '🟦', '🟧', '🟨', '🟩', '🟪', '🟫', '🤍', '🤎', '👡', '👯', '👢', '👣', '👤', '🤏', '🤐', '🤑', '🤒', '🤓', '🤔', '🤕', '🤖', '🤗', '👥', '🍵', '👰', '🍶', '🍷', '🤘', '🍸', '🍹', '👦', '🍺', '🍻', '🤙', '🍼', '🍽', '🍾', '👧', '🍿', '🤚', '🎀', '🎁', '🎂', '🎃', '🎄', '🤛', '👱', '🇵', '🅾', '🇶', '🇲', '🤜', '🤝', '🅿', '👲', '🎅', '🎆', '🎇', '🤞', '🎈', '🎉', '🎊', '🎋', '🎌', '🤟', '🤠', '🤡', '🤢', '🤣', '🤤', '🤥', '🎍', '🎎', '🎏', '🎐', '🎑', '🎒', '🎓', '🎖', '🎗', '👳', '🎙', '🎚', '🎛', '🎞', '🎟', '👴', '🎠', '🤦', '🤧', '🤨', '🤩', '🤪', '🤫', '🤬', '🤭', '🤮', '🤯', '🎡', '🎢', '🎣', '🎤', '👵', '🤰', '🎥', '🎦', '🎧', '🎨', '🎩', '🤱', '👶', '🎪', '🎫', '🎬', '🎭', '🤲', '🎮', '🎯', '🎰', '🎱', '🎲', '🤳', '🎳', '🎴', '🎵', '🎶', '🎷', '🤴', '🎸', '🎹', '🎺', '👷', '🎻', '🎼', '🎽', '🎾', '🎿', '👸', '👹', '👺', '👻', '🏀', '🏁', '🇧', '🇮', '🤵', '🇪', '👼', '👽', '👾', '👿', '🤶', '💀', '🇷', '🇱', '🏂', '🆎', '🆑', '🇨', '🇹', '🇯', '🆒', '🇬', '🆓', '🇳', '🆔', '🇴', '🇺', '🇫', '🤷', '🆕', '💁', '🆖', '🆗', '🇭', '🏃', '🆘', '🇩', '🇻', '🇰', '🆙', '🇼', '🆚', '🇽', '🇸', '🀄', '🇾', '🤸', '🇦', '🅰', '💂', '🅱', '🇿', '🈁', '🈂', '🏄', '💃', '💄', '🏅', '🏆', '🈚', '🈯', '🈲', '💅', '🈳', '🤹', '🤺', '🈴', '🏇', '🤼', '🏈', '🏉', '🈵', '🈶', '🈷', '🈸', '🈹', '🈺', '🉐', '🉑', '🌀', '🌁', '🌂', '🌃', '💆', '🌄', '🌅', '🤽', '🌆', '🌇', '🌈', '🏊', '🌉', '🌊', '🌋', '🌌', '🌍', '🌎', '🌏', '🌐', '🌑', '🌒', '🌓', '💇', '💈', '🤾', '🤿', '🥀', '🥁', '🥂', '🥃', '🥄', '🥅', '🥇', '🥈', '🥉', '🥊', '🥋', '🥌', '🥍', '🥎', '🥏', '🥐', '🥑', '🥒', '🥓', '🥔', '🥕', '🥖', '🥗', '🥘', '🥙', '🥚', '🥛', '🥜', '🥝', '🥞', '🥟', '🥠', '🥡', '🥢', '🥣', '🥤', '🥥', '🥦', '🥧', '🥨', '🥩', '🥪', '🥫', '🥬', '🥭', '🥮', '🥯', '🥰', '🥱', '🥳', '🥴', '🥵', '🥶', '🥺', '🥻', '🥼', '🥽', '🥾', '🥿', '🦀', '🦁', '🦂', '🦃', '🦄', '🦅', '🦆', '🦇', '🦈', '🦉', '🦊', '🦋', '🦌', '🦍', '🦎', '🦏', '🦐', '🦑', '🦒', '🦓', '🦔', '🦕', '🦖', '🦗', '🦘', '🦙', '🦚', '🦛', '🦜', '🦝', '🦞', '🦟', '🦠', '🦡', '🦢', '🦥', '🦦', '🦧', '🦨', '🦩', '🦪', '🦮', '🦯', '🦰', '🦱', '🦲', '🦳', '🦴', '💉', '💊', '💋', '💌', '💍', '🦵', '💎', '💏', '💐', '💑', '💒', '🦶', '🦷', '💓', '💔', '💕', '💖', '💗', '💘', '💙', '💚', '💛', '💜', '💝', '💞', '💟', '💠', '💡', '💢', '💣', '🦸', '💤', '💥', '💦', '💧', '💨', '💩', '🌔', '🌕', '🌖', '🌗', '🌘', '💪', '💫', '💬', '💭', '💮', '💯', '🦹', '🦺', '💰', '💱', '💲', '💳', '💴', '🦻', '🦼', '🦽', '🦾', '🦿', '🧀', '🧁', '🧂', '🧃', '🧄', '🧅', '🧆', '🧇', '🧈', '🧉', '🧊', '💵', '💶', '💷', '💸', '💹', '💺', '💻', '💼', '💽', '💾', '💿', '📀', '📁', '📂', '📃', '📄', '📅', '🧍', '📆', '📇', '📈', '📉', '📊', '📋', '📌', '📍', '📎', '📏', '📐', '📑', '📒', '📓', '📔', '📕', '📖', '🧎', '📗', '📘', '📙', '📚', '📛', '📜', '📝', '📞', '📟', '📠', '📡', '📢', '📣', '📤', '📥', '📦', '📧', '🧏', '🧐', '📨', '📩', '📪', '📫', '📬', '📭', '📮', '📯', '📰', '📱', '📲', '📳', '📴', '📵', '📶', '📷', '📸', '📹', '📺', '📻', '📼', '🧑', '📽', '📿', '🔀', '🔁', '🔂', '🧒', '🔃', '🔄', '🔅', '🔆', '🔇', '🧓', '🔈', '🔉', '🔊', '🔋', '🔌', '🧔', '🔍', '🔎', '🔏', '🔐', '🔑', '🧕', '🔒', '🔓', '🔔', '🔕', '🔖', '🔗', '🔘', '🔙', '🔚', '🔛', '🔜', '🔝', '🔞', '🔟', '🔠', '🔡', '🔢', '🧖', '🔣', '🔤', '🔥', '🔦', '🔧', '🔨', '🔩', '🔪', '🔫', '🔬', '🔭', '🔮', '🔯', '🔰', '🔱', '🔲', '🔳', '🧗', '🔴', '🔵', '🔶', '🔷', '🔸', '🔹', '🔺', '🔻', '🔼', '🔽', '🕉', '🕊', '🕋', '🕌', '🕍', '🕎', '🕐', '🧘', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛', '🕜', '🕝', '🕞', '🕟', '🕠', '🕡', '🧙', '🕢', '🕣', '🕤', '🕥', '🕦', '🕧', '🕯', '🕰', '🕳', '🌙', '🏋', '🌚', '🌛', '🌜', '🌝', '🌞', '🌟', '🧚', '🌠', '🌡', '🌤', '🌥', '🌦', '🌧', '🌨', '🌩', '🌪', '🕴', '👨', '🌫', '🌬', '🃏', '🏍', '🏎', '🏏', '🧛', '🏐', '🏑', '🏒', '🏓', '🏔', '🏕', '🏖', '🏗', '🏘', '🏙', '🕵', '🕶', '🕷', '🕸', '🕹', '🏚', '🏛', '🧜', '🏜', '🏝', '🏞', '🕺', '🖇', '🖊', '🖋', '🖌', '🖍', '🏟', '🏠', '🏡', '🏢', '🏣', '🖐', '🏤', '🏥', '🧝', '🏦', '🏧', '🧞', '🏨', '🖕', '🧟', '🧠', '🧡', '🧢', '🧣', '🧤', '🧥', '🧦', '🧧', '🧨', '🧩', '🧪', '🧫', '🧬', '🧭', '🧮', '🧯', '🧰', '🧱', '🧲', '🧳', '🧴', '🧵', '🧶', '🧷', '🧸', '🧹', '🧺', '🧻', '🧼', '🧽', '🧾', '🧿', '🩰', '🩱', '🩲', '🩳', '🩸', '🩹', '🩺', '🪀', '🪁', '🪂', '🪐', '🪑', '🪒', '🪓', '🪔', '🪕', '🏩', '🏪', '🏫', '🏬', '🏭', '🖖', '🖤', '🖥', '🖨', '🖱', '🖲', '🖼', '🗂', '🗃', '🗄', '🗑', '🗒', '🗓', '🗜', '🗝', '🗞', '🗡', '🗣', '🗨', '🗯', '🗳', '🗺', '🗻', '🗼', '🗽', '🗾', '🗿', '😀', '😁', '😂', '😃', '😄', '😅', '😆', '😇', '😈', '😉', '😊', '😋', '😌', '😍', '😎', '😏', '😐', '😑', '😒', '😓', '😔', '😕', '😖', '😗', '😘', '😙', '😚', '▫', '☦', '☮', '☯', '☸', '☹', '☺', '♀', '♂', '♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '♟', '♠', '♣', '♥', '♦', '♨', '♻', '♾', '♿', '⚒', '⚓', '⚔', '⚕', '⚖', '⚗', '⚙', '⚛', '⚜', '⚠', '⚡', '⚪', '⚫', '⚰', '⚱', '⚽', '⚾', '⛄', '⛅', '⛈', '⛎', '⛏', '⛑', '⛓', '⛔', '⛩', '⛪', '⛰', '⛱', '⛲', '⛳', '⛴', '⛵', '☣', '☢', '☠', '☝', '☘', '⛷', '⛸', '☕', '☔', '☑', '☎', '☄', '☃', '☂', '☁', '☀', '◾', '◽', '◼', '◻', '◀', '▶', '☪', '▪', '⛹', '⛺', '⛽', '✂', '✅', '✈', '✉', 'Ⓜ', '⏺', '⏹', '⏸', '⏳', '✊', '⏲', '⏱', '⏰', '⏯', '⏮', '✋', '⏭', '⏬', '⏫', '⏪', '⏩', '✌', '⏏', '⌨', '⌛', '⌚', '↪', '✍', '✏', '✒', '✔', '✖', '✝', '✡', '✨', '✳', '✴', '❄', '❇', '❌', '❎', '❓', '❔', '❕', '❗', '❣', '❤', '➕', '➖', '➗', '➡', '➰', '➿', '⤴', '⤵', '↩', '⬅', '⬆', '⬇', '⬛', '⬜', '⭐', '⭕', '↙', '〰', '〽', '↘', '↗', '㊗', '㊙', '↖', '↕', '↔', 'ℹ', '™', '⁉', '‼', '' );
- $partials = array( '🀄', '🃏', '🅰', '🅱', '🅾', '🅿', '🆎', '🆑', '🆒', '🆓', '🆔', '🆕', '🆖', '🆗', '🆘', '🆙', '🆚', '🇦', '🇨', '🇩', '🇪', '🇫', '🇬', '🇮', '🇱', '🇲', '🇴', '🇶', '🇷', '🇸', '🇹', '🇺', '🇼', '🇽', '🇿', '🇧', '🇭', '🇯', '🇳', '🇻', '🇾', '🇰', '🇵', '🈁', '🈂', '🈚', '🈯', '🈲', '🈳', '🈴', '🈵', '🈶', '🈷', '🈸', '🈹', '🈺', '🉐', '🉑', '🌀', '🌁', '🌂', '🌃', '🌄', '🌅', '🌆', '🌇', '🌈', '🌉', '🌊', '🌋', '🌌', '🌍', '🌎', '🌏', '🌐', '🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘', '🌙', '🌚', '🌛', '🌜', '🌝', '🌞', '🌟', '🌠', '🌡', '🌤', '🌥', '🌦', '🌧', '🌨', '🌩', '🌪', '🌫', '🌬', '🌭', '🌮', '🌯', '🌰', '🌱', '🌲', '🌳', '🌴', '🌵', '🌶', '🌷', '🌸', '🌹', '🌺', '🌻', '🌼', '🌽', '🌾', '🌿', '🍀', '🍁', '🍂', '🍃', '🍄', '🍅', '🍆', '🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🍎', '🍏', '🍐', '🍑', '🍒', '🍓', '🍔', '🍕', '🍖', '🍗', '🍘', '🍙', '🍚', '🍛', '🍜', '🍝', '🍞', '🍟', '🍠', '🍡', '🍢', '🍣', '🍤', '🍥', '🍦', '🍧', '🍨', '🍩', '🍪', '🍫', '🍬', '🍭', '🍮', '🍯', '🍰', '🍱', '🍲', '🍳', '🍴', '🍵', '🍶', '🍷', '🍸', '🍹', '🍺', '🍻', '🍼', '🍽', '🍾', '🍿', '🎀', '🎁', '🎂', '🎃', '🎄', '🎅', '🏻', '🏼', '🏽', '🏾', '🏿', '🎆', '🎇', '🎈', '🎉', '🎊', '🎋', '🎌', '🎍', '🎎', '🎏', '🎐', '🎑', '🎒', '🎓', '🎖', '🎗', '🎙', '🎚', '🎛', '🎞', '🎟', '🎠', '🎡', '🎢', '🎣', '🎤', '🎥', '🎦', '🎧', '🎨', '🎩', '🎪', '🎫', '🎬', '🎭', '🎮', '🎯', '🎰', '🎱', '🎲', '🎳', '🎴', '🎵', '🎶', '🎷', '🎸', '🎹', '🎺', '🎻', '🎼', '🎽', '🎾', '🎿', '🏀', '🏁', '🏂', '🏃', '‍', '♀', '️', '♂', '🏄', '🏅', '🏆', '🏇', '🏈', '🏉', '🏊', '🏋', '🏌', '🏍', '🏎', '🏏', '🏐', '🏑', '🏒', '🏓', '🏔', '🏕', '🏖', '🏗', '🏘', '🏙', '🏚', '🏛', '🏜', '🏝', '🏞', '🏟', '🏠', '🏡', '🏢', '🏣', '🏤', '🏥', '🏦', '🏧', '🏨', '🏩', '🏪', '🏫', '🏬', '🏭', '🏮', '🏯', '🏰', '🏳', '🏴', '☠', '󠁧', '󠁢', '󠁥', '󠁮', '󠁿', '󠁳', '󠁣', '󠁴', '󠁷', '󠁬', '🏵', '🏷', '🏸', '🏹', '🏺', '🐀', '🐁', '🐂', '🐃', '🐄', '🐅', '🐆', '🐇', '🐈', '🐉', '🐊', '🐋', '🐌', '🐍', '🐎', '🐏', '🐐', '🐑', '🐒', '🐓', '🐔', '🐕', '🦺', '🐖', '🐗', '🐘', '🐙', '🐚', '🐛', '🐜', '🐝', '🐞', '🐟', '🐠', '🐡', '🐢', '🐣', '🐤', '🐥', '🐦', '🐧', '🐨', '🐩', '🐪', '🐫', '🐬', '🐭', '🐮', '🐯', '🐰', '🐱', '🐲', '🐳', '🐴', '🐵', '🐶', '🐷', '🐸', '🐹', '🐺', '🐻', '🐼', '🐽', '🐾', '🐿', '👀', '👁', '🗨', '👂', '👃', '👄', '👅', '👆', '👇', '👈', '👉', '👊', '👋', '👌', '👍', '👎', '👏', '👐', '👑', '👒', '👓', '👔', '👕', '👖', '👗', '👘', '👙', '👚', '👛', '👜', '👝', '👞', '👟', '👠', '👡', '👢', '👣', '👤', '👥', '👦', '👧', '👨', '💻', '💼', '🔧', '🔬', '🚀', '🚒', '🦯', '🦰', '🦱', '🦲', '🦳', '🦼', '🦽', '⚕', '⚖', '✈', '🤝', '👩', '❤', '💋', '👪', '👫', '👬', '👭', '👮', '👯', '👰', '👱', '👲', '👳', '👴', '👵', '👶', '👷', '👸', '👹', '👺', '👻', '👼', '👽', '👾', '👿', '💀', '💁', '💂', '💃', '💄', '💅', '💆', '💇', '💈', '💉', '💊', '💌', '💍', '💎', '💏', '💐', '💑', '💒', '💓', '💔', '💕', '💖', '💗', '💘', '💙', '💚', '💛', '💜', '💝', '💞', '💟', '💠', '💡', '💢', '💣', '💤', '💥', '💦', '💧', '💨', '💩', '💪', '💫', '💬', '💭', '💮', '💯', '💰', '💱', '💲', '💳', '💴', '💵', '💶', '💷', '💸', '💹', '💺', '💽', '💾', '💿', '📀', '📁', '📂', '📃', '📄', '📅', '📆', '📇', '📈', '📉', '📊', '📋', '📌', '📍', '📎', '📏', '📐', '📑', '📒', '📓', '📔', '📕', '📖', '📗', '📘', '📙', '📚', '📛', '📜', '📝', '📞', '📟', '📠', '📡', '📢', '📣', '📤', '📥', '📦', '📧', '📨', '📩', '📪', '📫', '📬', '📭', '📮', '📯', '📰', '📱', '📲', '📳', '📴', '📵', '📶', '📷', '📸', '📹', '📺', '📻', '📼', '📽', '📿', '🔀', '🔁', '🔂', '🔃', '🔄', '🔅', '🔆', '🔇', '🔈', '🔉', '🔊', '🔋', '🔌', '🔍', '🔎', '🔏', '🔐', '🔑', '🔒', '🔓', '🔔', '🔕', '🔖', '🔗', '🔘', '🔙', '🔚', '🔛', '🔜', '🔝', '🔞', '🔟', '🔠', '🔡', '🔢', '🔣', '🔤', '🔥', '🔦', '🔨', '🔩', '🔪', '🔫', '🔭', '🔮', '🔯', '🔰', '🔱', '🔲', '🔳', '🔴', '🔵', '🔶', '🔷', '🔸', '🔹', '🔺', '🔻', '🔼', '🔽', '🕉', '🕊', '🕋', '🕌', '🕍', '🕎', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛', '🕜', '🕝', '🕞', '🕟', '🕠', '🕡', '🕢', '🕣', '🕤', '🕥', '🕦', '🕧', '🕯', '🕰', '🕳', '🕴', '🕵', '🕶', '🕷', '🕸', '🕹', '🕺', '🖇', '🖊', '🖋', '🖌', '🖍', '🖐', '🖕', '🖖', '🖤', '🖥', '🖨', '🖱', '🖲', '🖼', '🗂', '🗃', '🗄', '🗑', '🗒', '🗓', '🗜', '🗝', '🗞', '🗡', '🗣', '🗯', '🗳', '🗺', '🗻', '🗼', '🗽', '🗾', '🗿', '😀', '😁', '😂', '😃', '😄', '😅', '😆', '😇', '😈', '😉', '😊', '😋', '😌', '😍', '😎', '😏', '😐', '😑', '😒', '😓', '😔', '😕', '😖', '😗', '😘', '😙', '😚', '😛', '😜', '😝', '😞', '😟', '😠', '😡', '😢', '😣', '😤', '😥', '😦', '😧', '😨', '😩', '😪', '😫', '😬', '😭', '😮', '😯', '😰', '😱', '😲', '😳', '😴', '😵', '😶', '😷', '😸', '😹', '😺', '😻', '😼', '😽', '😾', '😿', '🙀', '🙁', '🙂', '🙃', '🙄', '🙅', '🙆', '🙇', '🙈', '🙉', '🙊', '🙋', '🙌', '🙍', '🙎', '🙏', '🚁', '🚂', '🚃', '🚄', '🚅', '🚆', '🚇', '🚈', '🚉', '🚊', '🚋', '🚌', '🚍', '🚎', '🚏', '🚐', '🚑', '🚓', '🚔', '🚕', '🚖', '🚗', '🚘', '🚙', '🚚', '🚛', '🚜', '🚝', '🚞', '🚟', '🚠', '🚡', '🚢', '🚣', '🚤', '🚥', '🚦', '🚧', '🚨', '🚩', '🚪', '🚫', '🚬', '🚭', '🚮', '🚯', '🚰', '🚱', '🚲', '🚳', '🚴', '🚵', '🚶', '🚷', '🚸', '🚹', '🚺', '🚻', '🚼', '🚽', '🚾', '🚿', '🛀', '🛁', '🛂', '🛃', '🛄', '🛅', '🛋', '🛌', '🛍', '🛎', '🛏', '🛐', '🛑', '🛒', '🛕', '🛠', '🛡', '🛢', '🛣', '🛤', '🛥', '🛩', '🛫', '🛬', '🛰', '🛳', '🛴', '🛵', '🛶', '🛷', '🛸', '🛹', '🛺', '🟠', '🟡', '🟢', '🟣', '🟤', '🟥', '🟦', '🟧', '🟨', '🟩', '🟪', '🟫', '🤍', '🤎', '🤏', '🤐', '🤑', '🤒', '🤓', '🤔', '🤕', '🤖', '🤗', '🤘', '🤙', '🤚', '🤛', '🤜', '🤞', '🤟', '🤠', '🤡', '🤢', '🤣', '🤤', '🤥', '🤦', '🤧', '🤨', '🤩', '🤪', '🤫', '🤬', '🤭', '🤮', '🤯', '🤰', '🤱', '🤲', '🤳', '🤴', '🤵', '🤶', '🤷', '🤸', '🤹', '🤺', '🤼', '🤽', '🤾', '🤿', '🥀', '🥁', '🥂', '🥃', '🥄', '🥅', '🥇', '🥈', '🥉', '🥊', '🥋', '🥌', '🥍', '🥎', '🥏', '🥐', '🥑', '🥒', '🥓', '🥔', '🥕', '🥖', '🥗', '🥘', '🥙', '🥚', '🥛', '🥜', '🥝', '🥞', '🥟', '🥠', '🥡', '🥢', '🥣', '🥤', '🥥', '🥦', '🥧', '🥨', '🥩', '🥪', '🥫', '🥬', '🥭', '🥮', '🥯', '🥰', '🥱', '🥳', '🥴', '🥵', '🥶', '🥺', '🥻', '🥼', '🥽', '🥾', '🥿', '🦀', '🦁', '🦂', '🦃', '🦄', '🦅', '🦆', '🦇', '🦈', '🦉', '🦊', '🦋', '🦌', '🦍', '🦎', '🦏', '🦐', '🦑', '🦒', '🦓', '🦔', '🦕', '🦖', '🦗', '🦘', '🦙', '🦚', '🦛', '🦜', '🦝', '🦞', '🦟', '🦠', '🦡', '🦢', '🦥', '🦦', '🦧', '🦨', '🦩', '🦪', '🦮', '🦴', '🦵', '🦶', '🦷', '🦸', '🦹', '🦻', '🦾', '🦿', '🧀', '🧁', '🧂', '🧃', '🧄', '🧅', '🧆', '🧇', '🧈', '🧉', '🧊', '🧍', '🧎', '🧏', '🧐', '🧑', '🧒', '🧓', '🧔', '🧕', '🧖', '🧗', '🧘', '🧙', '🧚', '🧛', '🧜', '🧝', '🧞', '🧟', '🧠', '🧡', '🧢', '🧣', '🧤', '🧥', '🧦', '🧧', '🧨', '🧩', '🧪', '🧫', '🧬', '🧭', '🧮', '🧯', '🧰', '🧱', '🧲', '🧳', '🧴', '🧵', '🧶', '🧷', '🧸', '🧹', '🧺', '🧻', '🧼', '🧽', '🧾', '🧿', '🩰', '🩱', '🩲', '🩳', '🩸', '🩹', '🩺', '🪀', '🪁', '🪂', '🪐', '🪑', '🪒', '🪓', '🪔', '🪕', '‼', '⁉', '™', 'ℹ', '↔', '↕', '↖', '↗', '↘', '↙', '↩', '↪', '⃣', '⌚', '⌛', '⌨', '⏏', '⏩', '⏪', '⏫', '⏬', '⏭', '⏮', '⏯', '⏰', '⏱', '⏲', '⏳', '⏸', '⏹', '⏺', 'Ⓜ', '▪', '▫', '▶', '◀', '◻', '◼', '◽', '◾', '☀', '☁', '☂', '☃', '☄', '☎', '☑', '☔', '☕', '☘', '☝', '☢', '☣', '☦', '☪', '☮', '☯', '☸', '☹', '☺', '♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '♟', '♠', '♣', '♥', '♦', '♨', '♻', '♾', '♿', '⚒', '⚓', '⚔', '⚗', '⚙', '⚛', '⚜', '⚠', '⚡', '⚪', '⚫', '⚰', '⚱', '⚽', '⚾', '⛄', '⛅', '⛈', '⛎', '⛏', '⛑', '⛓', '⛔', '⛩', '⛪', '⛰', '⛱', '⛲', '⛳', '⛴', '⛵', '⛷', '⛸', '⛹', '⛺', '⛽', '✂', '✅', '✉', '✊', '✋', '✌', '✍', '✏', '✒', '✔', '✖', '✝', '✡', '✨', '✳', '✴', '❄', '❇', '❌', '❎', '❓', '❔', '❕', '❗', '❣', '➕', '➖', '➗', '➡', '➰', '➿', '⤴', '⤵', '⬅', '⬆', '⬇', '⬛', '⬜', '⭐', '⭕', '〰', '〽', '㊗', '㊙', '' );
+ $entities = array( '👨‍❤️‍💋‍👨', '👩‍❤️‍💋‍👨', '👩‍❤️‍💋‍👩', '🏴󠁧󠁢󠁥󠁮󠁧󠁿', '🏴󠁧󠁢󠁳󠁣󠁴󠁿', '🏴󠁧󠁢󠁷󠁬󠁳󠁿', '👨🏻‍🤝‍👨🏼', '👨🏻‍🤝‍👨🏽', '👨🏻‍🤝‍👨🏾', '👨🏻‍🤝‍👨🏿', '👨🏼‍🤝‍👨🏻', '👨🏼‍🤝‍👨🏽', '👨🏼‍🤝‍👨🏾', '👨🏼‍🤝‍👨🏿', '👨🏽‍🤝‍👨🏻', '👨🏽‍🤝‍👨🏼', '👨🏽‍🤝‍👨🏾', '👨🏽‍🤝‍👨🏿', '👨🏾‍🤝‍👨🏻', '👨🏾‍🤝‍👨🏼', '👨🏾‍🤝‍👨🏽', '👨🏾‍🤝‍👨🏿', '👨🏿‍🤝‍👨🏻', '👨🏿‍🤝‍👨🏼', '👨🏿‍🤝‍👨🏽', '👨🏿‍🤝‍👨🏾', '👩🏻‍🤝‍👨🏼', '👩🏻‍🤝‍👨🏽', '👩🏻‍🤝‍👨🏾', '👩🏻‍🤝‍👨🏿', '👩🏻‍🤝‍👩🏼', '👩🏻‍🤝‍👩🏽', '👩🏻‍🤝‍👩🏾', '👩🏻‍🤝‍👩🏿', '👩🏼‍🤝‍👨🏻', '👩🏼‍🤝‍👨🏽', '👩🏼‍🤝‍👨🏾', '👩🏼‍🤝‍👨🏿', '👩🏼‍🤝‍👩🏻', '👩🏼‍🤝‍👩🏽', '👩🏼‍🤝‍👩🏾', '👩🏼‍🤝‍👩🏿', '👩🏽‍🤝‍👨🏻', '👩🏽‍🤝‍👨🏼', '👩🏽‍🤝‍👨🏾', '👩🏽‍🤝‍👨🏿', '👩🏽‍🤝‍👩🏻', '👩🏽‍🤝‍👩🏼', '👩🏽‍🤝‍👩🏾', '👩🏽‍🤝‍👩🏿', '👩🏾‍🤝‍👨🏻', '👩🏾‍🤝‍👨🏼', '👩🏾‍🤝‍👨🏽', '👩🏾‍🤝‍👨🏿', '👩🏾‍🤝‍👩🏻', '👩🏾‍🤝‍👩🏼', '👩🏾‍🤝‍👩🏽', '👩🏾‍🤝‍👩🏿', '👩🏿‍🤝‍👨🏻', '👩🏿‍🤝‍👨🏼', '👩🏿‍🤝‍👨🏽', '👩🏿‍🤝‍👨🏾', '👩🏿‍🤝‍👩🏻', '👩🏿‍🤝‍👩🏼', '👩🏿‍🤝‍👩🏽', '👩🏿‍🤝‍👩🏾', '🧑🏻‍🤝‍🧑🏻', '🧑🏻‍🤝‍🧑🏼', '🧑🏻‍🤝‍🧑🏽', '🧑🏻‍🤝‍🧑🏾', '🧑🏻‍🤝‍🧑🏿', '🧑🏼‍🤝‍🧑🏻', '🧑🏼‍🤝‍🧑🏼', '🧑🏼‍🤝‍🧑🏽', '🧑🏼‍🤝‍🧑🏾', '🧑🏼‍🤝‍🧑🏿', '🧑🏽‍🤝‍🧑🏻', '🧑🏽‍🤝‍🧑🏼', '🧑🏽‍🤝‍🧑🏽', '🧑🏽‍🤝‍🧑🏾', '🧑🏽‍🤝‍🧑🏿', '🧑🏾‍🤝‍🧑🏻', '🧑🏾‍🤝‍🧑🏼', '🧑🏾‍🤝‍🧑🏽', '🧑🏾‍🤝‍🧑🏾', '🧑🏾‍🤝‍🧑🏿', '🧑🏿‍🤝‍🧑🏻', '🧑🏿‍🤝‍🧑🏼', '🧑🏿‍🤝‍🧑🏽', '🧑🏿‍🤝‍🧑🏾', '🧑🏿‍🤝‍🧑🏿', '👨‍👨‍👦‍👦', '👨‍👨‍👧‍👦', '👨‍👨‍👧‍👧', '👨‍👩‍👦‍👦', '👨‍👩‍👧‍👦', '👨‍👩‍👧‍👧', '👩‍👩‍👦‍👦', '👩‍👩‍👧‍👦', '👩‍👩‍👧‍👧', '👨‍❤️‍👨', '👩‍❤️‍👨', '👩‍❤️‍👩', '👨‍👦‍👦', '👨‍👧‍👦', '👨‍👧‍👧', '👨‍👨‍👦', '👨‍👨‍👧', '👨‍👩‍👦', '👨‍👩‍👧', '👩‍👦‍👦', '👩‍👧‍👦', '👩‍👧‍👧', '👩‍👩‍👦', '👩‍👩‍👧', '🧑‍🤝‍🧑', '🏃🏻‍♀️', '🏃🏻‍♂️', '🏃🏼‍♀️', '🏃🏼‍♂️', '🏃🏽‍♀️', '🏃🏽‍♂️', '🏃🏾‍♀️', '🏃🏾‍♂️', '🏃🏿‍♀️', '🏃🏿‍♂️', '🏄🏻‍♀️', '🏄🏻‍♂️', '🏄🏼‍♀️', '🏄🏼‍♂️', '🏄🏽‍♀️', '🏄🏽‍♂️', '🏄🏾‍♀️', '🏄🏾‍♂️', '🏄🏿‍♀️', '🏄🏿‍♂️', '🏊🏻‍♀️', '🏊🏻‍♂️', '🏊🏼‍♀️', '🏊🏼‍♂️', '🏊🏽‍♀️', '🏊🏽‍♂️', '🏊🏾‍♀️', '🏊🏾‍♂️', '🏊🏿‍♀️', '🏊🏿‍♂️', '🏋🏻‍♀️', '🏋🏻‍♂️', '🏋🏼‍♀️', '🏋🏼‍♂️', '🏋🏽‍♀️', '🏋🏽‍♂️', '🏋🏾‍♀️', '🏋🏾‍♂️', '🏋🏿‍♀️', '🏋🏿‍♂️', '🏌🏻‍♀️', '🏌🏻‍♂️', '🏌🏼‍♀️', '🏌🏼‍♂️', '🏌🏽‍♀️', '🏌🏽‍♂️', '🏌🏾‍♀️', '🏌🏾‍♂️', '🏌🏿‍♀️', '🏌🏿‍♂️', '👨🏻‍⚕️', '👨🏻‍⚖️', '👨🏻‍✈️', '👨🏼‍⚕️', '👨🏼‍⚖️', '👨🏼‍✈️', '👨🏽‍⚕️', '👨🏽‍⚖️', '👨🏽‍✈️', '👨🏾‍⚕️', '👨🏾‍⚖️', '👨🏾‍✈️', '👨🏿‍⚕️', '👨🏿‍⚖️', '👨🏿‍✈️', '👩🏻‍⚕️', '👩🏻‍⚖️', '👩🏻‍✈️', '👩🏼‍⚕️', '👩🏼‍⚖️', '👩🏼‍✈️', '👩🏽‍⚕️', '👩🏽‍⚖️', '👩🏽‍✈️', '👩🏾‍⚕️', '👩🏾‍⚖️', '👩🏾‍✈️', '👩🏿‍⚕️', '👩🏿‍⚖️', '👩🏿‍✈️', '👮🏻‍♀️', '👮🏻‍♂️', '👮🏼‍♀️', '👮🏼‍♂️', '👮🏽‍♀️', '👮🏽‍♂️', '👮🏾‍♀️', '👮🏾‍♂️', '👮🏿‍♀️', '👮🏿‍♂️', '👰🏻‍♀️', '👰🏻‍♂️', '👰🏼‍♀️', '👰🏼‍♂️', '👰🏽‍♀️', '👰🏽‍♂️', '👰🏾‍♀️', '👰🏾‍♂️', '👰🏿‍♀️', '👰🏿‍♂️', '👱🏻‍♀️', '👱🏻‍♂️', '👱🏼‍♀️', '👱🏼‍♂️', '👱🏽‍♀️', '👱🏽‍♂️', '👱🏾‍♀️', '👱🏾‍♂️', '👱🏿‍♀️', '👱🏿‍♂️', '👳🏻‍♀️', '👳🏻‍♂️', '👳🏼‍♀️', '👳🏼‍♂️', '👳🏽‍♀️', '👳🏽‍♂️', '👳🏾‍♀️', '👳🏾‍♂️', '👳🏿‍♀️', '👳🏿‍♂️', '👷🏻‍♀️', '👷🏻‍♂️', '👷🏼‍♀️', '👷🏼‍♂️', '👷🏽‍♀️', '👷🏽‍♂️', '👷🏾‍♀️', '👷🏾‍♂️', '👷🏿‍♀️', '👷🏿‍♂️', '💁🏻‍♀️', '💁🏻‍♂️', '💁🏼‍♀️', '💁🏼‍♂️', '💁🏽‍♀️', '💁🏽‍♂️', '💁🏾‍♀️', '💁🏾‍♂️', '💁🏿‍♀️', '💁🏿‍♂️', '💂🏻‍♀️', '💂🏻‍♂️', '💂🏼‍♀️', '💂🏼‍♂️', '💂🏽‍♀️', '💂🏽‍♂️', '💂🏾‍♀️', '💂🏾‍♂️', '💂🏿‍♀️', '💂🏿‍♂️', '💆🏻‍♀️', '💆🏻‍♂️', '💆🏼‍♀️', '💆🏼‍♂️', '💆🏽‍♀️', '💆🏽‍♂️', '💆🏾‍♀️', '💆🏾‍♂️', '💆🏿‍♀️', '💆🏿‍♂️', '💇🏻‍♀️', '💇🏻‍♂️', '💇🏼‍♀️', '💇🏼‍♂️', '💇🏽‍♀️', '💇🏽‍♂️', '💇🏾‍♀️', '💇🏾‍♂️', '💇🏿‍♀️', '💇🏿‍♂️', '🕴🏻‍♀️', '🕴🏻‍♂️', '🕴🏼‍♀️', '🕴🏼‍♂️', '🕴🏽‍♀️', '🕴🏽‍♂️', '🕴🏾‍♀️', '🕴🏾‍♂️', '🕴🏿‍♀️', '🕴🏿‍♂️', '🕵🏻‍♀️', '🕵🏻‍♂️', '🕵🏼‍♀️', '🕵🏼‍♂️', '🕵🏽‍♀️', '🕵🏽‍♂️', '🕵🏾‍♀️', '🕵🏾‍♂️', '🕵🏿‍♀️', '🕵🏿‍♂️', '🙅🏻‍♀️', '🙅🏻‍♂️', '🙅🏼‍♀️', '🙅🏼‍♂️', '🙅🏽‍♀️', '🙅🏽‍♂️', '🙅🏾‍♀️', '🙅🏾‍♂️', '🙅🏿‍♀️', '🙅🏿‍♂️', '🙆🏻‍♀️', '🙆🏻‍♂️', '🙆🏼‍♀️', '🙆🏼‍♂️', '🙆🏽‍♀️', '🙆🏽‍♂️', '🙆🏾‍♀️', '🙆🏾‍♂️', '🙆🏿‍♀️', '🙆🏿‍♂️', '🙇🏻‍♀️', '🙇🏻‍♂️', '🙇🏼‍♀️', '🙇🏼‍♂️', '🙇🏽‍♀️', '🙇🏽‍♂️', '🙇🏾‍♀️', '🙇🏾‍♂️', '🙇🏿‍♀️', '🙇🏿‍♂️', '🙋🏻‍♀️', '🙋🏻‍♂️', '🙋🏼‍♀️', '🙋🏼‍♂️', '🙋🏽‍♀️', '🙋🏽‍♂️', '🙋🏾‍♀️', '🙋🏾‍♂️', '🙋🏿‍♀️', '🙋🏿‍♂️', '🙍🏻‍♀️', '🙍🏻‍♂️', '🙍🏼‍♀️', '🙍🏼‍♂️', '🙍🏽‍♀️', '🙍🏽‍♂️', '🙍🏾‍♀️', '🙍🏾‍♂️', '🙍🏿‍♀️', '🙍🏿‍♂️', '🙎🏻‍♀️', '🙎🏻‍♂️', '🙎🏼‍♀️', '🙎🏼‍♂️', '🙎🏽‍♀️', '🙎🏽‍♂️', '🙎🏾‍♀️', '🙎🏾‍♂️', '🙎🏿‍♀️', '🙎🏿‍♂️', '🚣🏻‍♀️', '🚣🏻‍♂️', '🚣🏼‍♀️', '🚣🏼‍♂️', '🚣🏽‍♀️', '🚣🏽‍♂️', '🚣🏾‍♀️', '🚣🏾‍♂️', '🚣🏿‍♀️', '🚣🏿‍♂️', '🚴🏻‍♀️', '🚴🏻‍♂️', '🚴🏼‍♀️', '🚴🏼‍♂️', '🚴🏽‍♀️', '🚴🏽‍♂️', '🚴🏾‍♀️', '🚴🏾‍♂️', '🚴🏿‍♀️', '🚴🏿‍♂️', '🚵🏻‍♀️', '🚵🏻‍♂️', '🚵🏼‍♀️', '🚵🏼‍♂️', '🚵🏽‍♀️', '🚵🏽‍♂️', '🚵🏾‍♀️', '🚵🏾‍♂️', '🚵🏿‍♀️', '🚵🏿‍♂️', '🚶🏻‍♀️', '🚶🏻‍♂️', '🚶🏼‍♀️', '🚶🏼‍♂️', '🚶🏽‍♀️', '🚶🏽‍♂️', '🚶🏾‍♀️', '🚶🏾‍♂️', '🚶🏿‍♀️', '🚶🏿‍♂️', '🤦🏻‍♀️', '🤦🏻‍♂️', '🤦🏼‍♀️', '🤦🏼‍♂️', '🤦🏽‍♀️', '🤦🏽‍♂️', '🤦🏾‍♀️', '🤦🏾‍♂️', '🤦🏿‍♀️', '🤦🏿‍♂️', '🤵🏻‍♀️', '🤵🏻‍♂️', '🤵🏼‍♀️', '🤵🏼‍♂️', '🤵🏽‍♀️', '🤵🏽‍♂️', '🤵🏾‍♀️', '🤵🏾‍♂️', '🤵🏿‍♀️', '🤵🏿‍♂️', '🤷🏻‍♀️', '🤷🏻‍♂️', '🤷🏼‍♀️', '🤷🏼‍♂️', '🤷🏽‍♀️', '🤷🏽‍♂️', '🤷🏾‍♀️', '🤷🏾‍♂️', '🤷🏿‍♀️', '🤷🏿‍♂️', '🤸🏻‍♀️', '🤸🏻‍♂️', '🤸🏼‍♀️', '🤸🏼‍♂️', '🤸🏽‍♀️', '🤸🏽‍♂️', '🤸🏾‍♀️', '🤸🏾‍♂️', '🤸🏿‍♀️', '🤸🏿‍♂️', '🤹🏻‍♀️', '🤹🏻‍♂️', '🤹🏼‍♀️', '🤹🏼‍♂️', '🤹🏽‍♀️', '🤹🏽‍♂️', '🤹🏾‍♀️', '🤹🏾‍♂️', '🤹🏿‍♀️', '🤹🏿‍♂️', '🤽🏻‍♀️', '🤽🏻‍♂️', '🤽🏼‍♀️', '🤽🏼‍♂️', '🤽🏽‍♀️', '🤽🏽‍♂️', '🤽🏾‍♀️', '🤽🏾‍♂️', '🤽🏿‍♀️', '🤽🏿‍♂️', '🤾🏻‍♀️', '🤾🏻‍♂️', '🤾🏼‍♀️', '🤾🏼‍♂️', '🤾🏽‍♀️', '🤾🏽‍♂️', '🤾🏾‍♀️', '🤾🏾‍♂️', '🤾🏿‍♀️', '🤾🏿‍♂️', '🦸🏻‍♀️', '🦸🏻‍♂️', '🦸🏼‍♀️', '🦸🏼‍♂️', '🦸🏽‍♀️', '🦸🏽‍♂️', '🦸🏾‍♀️', '🦸🏾‍♂️', '🦸🏿‍♀️', '🦸🏿‍♂️', '🦹🏻‍♀️', '🦹🏻‍♂️', '🦹🏼‍♀️', '🦹🏼‍♂️', '🦹🏽‍♀️', '🦹🏽‍♂️', '🦹🏾‍♀️', '🦹🏾‍♂️', '🦹🏿‍♀️', '🦹🏿‍♂️', '🧍🏻‍♀️', '🧍🏻‍♂️', '🧍🏼‍♀️', '🧍🏼‍♂️', '🧍🏽‍♀️', '🧍🏽‍♂️', '🧍🏾‍♀️', '🧍🏾‍♂️', '🧍🏿‍♀️', '🧍🏿‍♂️', '🧎🏻‍♀️', '🧎🏻‍♂️', '🧎🏼‍♀️', '🧎🏼‍♂️', '🧎🏽‍♀️', '🧎🏽‍♂️', '🧎🏾‍♀️', '🧎🏾‍♂️', '🧎🏿‍♀️', '🧎🏿‍♂️', '🧏🏻‍♀️', '🧏🏻‍♂️', '🧏🏼‍♀️', '🧏🏼‍♂️', '🧏🏽‍♀️', '🧏🏽‍♂️', '🧏🏾‍♀️', '🧏🏾‍♂️', '🧏🏿‍♀️', '🧏🏿‍♂️', '🧑🏻‍⚕️', '🧑🏻‍⚖️', '🧑🏻‍✈️', '🧑🏼‍⚕️', '🧑🏼‍⚖️', '🧑🏼‍✈️', '🧑🏽‍⚕️', '🧑🏽‍⚖️', '🧑🏽‍✈️', '🧑🏾‍⚕️', '🧑🏾‍⚖️', '🧑🏾‍✈️', '🧑🏿‍⚕️', '🧑🏿‍⚖️', '🧑🏿‍✈️', '🧖🏻‍♀️', '🧖🏻‍♂️', '🧖🏼‍♀️', '🧖🏼‍♂️', '🧖🏽‍♀️', '🧖🏽‍♂️', '🧖🏾‍♀️', '🧖🏾‍♂️', '🧖🏿‍♀️', '🧖🏿‍♂️', '🧗🏻‍♀️', '🧗🏻‍♂️', '🧗🏼‍♀️', '🧗🏼‍♂️', '🧗🏽‍♀️', '🧗🏽‍♂️', '🧗🏾‍♀️', '🧗🏾‍♂️', '🧗🏿‍♀️', '🧗🏿‍♂️', '🧘🏻‍♀️', '🧘🏻‍♂️', '🧘🏼‍♀️', '🧘🏼‍♂️', '🧘🏽‍♀️', '🧘🏽‍♂️', '🧘🏾‍♀️', '🧘🏾‍♂️', '🧘🏿‍♀️', '🧘🏿‍♂️', '🧙🏻‍♀️', '🧙🏻‍♂️', '🧙🏼‍♀️', '🧙🏼‍♂️', '🧙🏽‍♀️', '🧙🏽‍♂️', '🧙🏾‍♀️', '🧙🏾‍♂️', '🧙🏿‍♀️', '🧙🏿‍♂️', '🧚🏻‍♀️', '🧚🏻‍♂️', '🧚🏼‍♀️', '🧚🏼‍♂️', '🧚🏽‍♀️', '🧚🏽‍♂️', '🧚🏾‍♀️', '🧚🏾‍♂️', '🧚🏿‍♀️', '🧚🏿‍♂️', '🧛🏻‍♀️', '🧛🏻‍♂️', '🧛🏼‍♀️', '🧛🏼‍♂️', '🧛🏽‍♀️', '🧛🏽‍♂️', '🧛🏾‍♀️', '🧛🏾‍♂️', '🧛🏿‍♀️', '🧛🏿‍♂️', '🧜🏻‍♀️', '🧜🏻‍♂️', '🧜🏼‍♀️', '🧜🏼‍♂️', '🧜🏽‍♀️', '🧜🏽‍♂️', '🧜🏾‍♀️', '🧜🏾‍♂️', '🧜🏿‍♀️', '🧜🏿‍♂️', '🧝🏻‍♀️', '🧝🏻‍♂️', '🧝🏼‍♀️', '🧝🏼‍♂️', '🧝🏽‍♀️', '🧝🏽‍♂️', '🧝🏾‍♀️', '🧝🏾‍♂️', '🧝🏿‍♀️', '🧝🏿‍♂️', '🏋️‍♀️', '🏋️‍♂️', '🏌️‍♀️', '🏌️‍♂️', '🏳️‍⚧️', '🕴️‍♀️', '🕴️‍♂️', '🕵️‍♀️', '🕵️‍♂️', '⛹🏻‍♀️', '⛹🏻‍♂️', '⛹🏼‍♀️', '⛹🏼‍♂️', '⛹🏽‍♀️', '⛹🏽‍♂️', '⛹🏾‍♀️', '⛹🏾‍♂️', '⛹🏿‍♀️', '⛹🏿‍♂️', '⛹️‍♀️', '⛹️‍♂️', '👨🏻‍🌾', '👨🏻‍🍳', '👨🏻‍🍼', '👨🏻‍🎄', '👨🏻‍🎓', '👨🏻‍🎤', '👨🏻‍🎨', '👨🏻‍🏫', '👨🏻‍🏭', '👨🏻‍💻', '👨🏻‍💼', '👨🏻‍🔧', '👨🏻‍🔬', '👨🏻‍🚀', '👨🏻‍🚒', '👨🏻‍🦯', '👨🏻‍🦰', '👨🏻‍🦱', '👨🏻‍🦲', '👨🏻‍🦳', '👨🏻‍🦼', '👨🏻‍🦽', '👨🏼‍🌾', '👨🏼‍🍳', '👨🏼‍🍼', '👨🏼‍🎄', '👨🏼‍🎓', '👨🏼‍🎤', '👨🏼‍🎨', '👨🏼‍🏫', '👨🏼‍🏭', '👨🏼‍💻', '👨🏼‍💼', '👨🏼‍🔧', '👨🏼‍🔬', '👨🏼‍🚀', '👨🏼‍🚒', '👨🏼‍🦯', '👨🏼‍🦰', '👨🏼‍🦱', '👨🏼‍🦲', '👨🏼‍🦳', '👨🏼‍🦼', '👨🏼‍🦽', '👨🏽‍🌾', '👨🏽‍🍳', '👨🏽‍🍼', '👨🏽‍🎄', '👨🏽‍🎓', '👨🏽‍🎤', '👨🏽‍🎨', '👨🏽‍🏫', '👨🏽‍🏭', '👨🏽‍💻', '👨🏽‍💼', '👨🏽‍🔧', '👨🏽‍🔬', '👨🏽‍🚀', '👨🏽‍🚒', '👨🏽‍🦯', '👨🏽‍🦰', '👨🏽‍🦱', '👨🏽‍🦲', '👨🏽‍🦳', '👨🏽‍🦼', '👨🏽‍🦽', '👨🏾‍🌾', '👨🏾‍🍳', '👨🏾‍🍼', '👨🏾‍🎄', '👨🏾‍🎓', '👨🏾‍🎤', '👨🏾‍🎨', '👨🏾‍🏫', '👨🏾‍🏭', '👨🏾‍💻', '👨🏾‍💼', '👨🏾‍🔧', '👨🏾‍🔬', '👨🏾‍🚀', '👨🏾‍🚒', '👨🏾‍🦯', '👨🏾‍🦰', '👨🏾‍🦱', '👨🏾‍🦲', '👨🏾‍🦳', '👨🏾‍🦼', '👨🏾‍🦽', '👨🏿‍🌾', '👨🏿‍🍳', '👨🏿‍🍼', '👨🏿‍🎄', '👨🏿‍🎓', '👨🏿‍🎤', '👨🏿‍🎨', '👨🏿‍🏫', '👨🏿‍🏭', '👨🏿‍💻', '👨🏿‍💼', '👨🏿‍🔧', '👨🏿‍🔬', '👨🏿‍🚀', '👨🏿‍🚒', '👨🏿‍🦯', '👨🏿‍🦰', '👨🏿‍🦱', '👨🏿‍🦲', '👨🏿‍🦳', '👨🏿‍🦼', '👨🏿‍🦽', '👩🏻‍🌾', '👩🏻‍🍳', '👩🏻‍🍼', '👩🏻‍🎄', '👩🏻‍🎓', '👩🏻‍🎤', '👩🏻‍🎨', '👩🏻‍🏫', '👩🏻‍🏭', '👩🏻‍💻', '👩🏻‍💼', '👩🏻‍🔧', '👩🏻‍🔬', '👩🏻‍🚀', '👩🏻‍🚒', '👩🏻‍🦯', '👩🏻‍🦰', '👩🏻‍🦱', '👩🏻‍🦲', '👩🏻‍🦳', '👩🏻‍🦼', '👩🏻‍🦽', '👩🏼‍🌾', '👩🏼‍🍳', '👩🏼‍🍼', '👩🏼‍🎄', '👩🏼‍🎓', '👩🏼‍🎤', '👩🏼‍🎨', '👩🏼‍🏫', '👩🏼‍🏭', '👩🏼‍💻', '👩🏼‍💼', '👩🏼‍🔧', '👩🏼‍🔬', '👩🏼‍🚀', '👩🏼‍🚒', '👩🏼‍🦯', '👩🏼‍🦰', '👩🏼‍🦱', '👩🏼‍🦲', '👩🏼‍🦳', '👩🏼‍🦼', '👩🏼‍🦽', '👩🏽‍🌾', '👩🏽‍🍳', '👩🏽‍🍼', '👩🏽‍🎄', '👩🏽‍🎓', '👩🏽‍🎤', '👩🏽‍🎨', '👩🏽‍🏫', '👩🏽‍🏭', '👩🏽‍💻', '👩🏽‍💼', '👩🏽‍🔧', '👩🏽‍🔬', '👩🏽‍🚀', '👩🏽‍🚒', '👩🏽‍🦯', '👩🏽‍🦰', '👩🏽‍🦱', '👩🏽‍🦲', '👩🏽‍🦳', '👩🏽‍🦼', '👩🏽‍🦽', '👩🏾‍🌾', '👩🏾‍🍳', '👩🏾‍🍼', '👩🏾‍🎄', '👩🏾‍🎓', '👩🏾‍🎤', '👩🏾‍🎨', '👩🏾‍🏫', '👩🏾‍🏭', '👩🏾‍💻', '👩🏾‍💼', '👩🏾‍🔧', '👩🏾‍🔬', '👩🏾‍🚀', '👩🏾‍🚒', '👩🏾‍🦯', '👩🏾‍🦰', '👩🏾‍🦱', '👩🏾‍🦲', '👩🏾‍🦳', '👩🏾‍🦼', '👩🏾‍🦽', '👩🏿‍🌾', '👩🏿‍🍳', '👩🏿‍🍼', '👩🏿‍🎄', '👩🏿‍🎓', '👩🏿‍🎤', '👩🏿‍🎨', '👩🏿‍🏫', '👩🏿‍🏭', '👩🏿‍💻', '👩🏿‍💼', '👩🏿‍🔧', '👩🏿‍🔬', '👩🏿‍🚀', '👩🏿‍🚒', '👩🏿‍🦯', '👩🏿‍🦰', '👩🏿‍🦱', '👩🏿‍🦲', '👩🏿‍🦳', '👩🏿‍🦼', '👩🏿‍🦽', '🧑🏻‍🌾', '🧑🏻‍🍳', '🧑🏻‍🍼', '🧑🏻‍🎄', '🧑🏻‍🎓', '🧑🏻‍🎤', '🧑🏻‍🎨', '🧑🏻‍🏫', '🧑🏻‍🏭', '🧑🏻‍💻', '🧑🏻‍💼', '🧑🏻‍🔧', '🧑🏻‍🔬', '🧑🏻‍🚀', '🧑🏻‍🚒', '🧑🏻‍🦯', '🧑🏻‍🦰', '🧑🏻‍🦱', '🧑🏻‍🦲', '🧑🏻‍🦳', '🧑🏻‍🦼', '🧑🏻‍🦽', '🧑🏼‍🌾', '🧑🏼‍🍳', '🧑🏼‍🍼', '🧑🏼‍🎄', '🧑🏼‍🎓', '🧑🏼‍🎤', '🧑🏼‍🎨', '🧑🏼‍🏫', '🧑🏼‍🏭', '🧑🏼‍💻', '🧑🏼‍💼', '🧑🏼‍🔧', '🧑🏼‍🔬', '🧑🏼‍🚀', '🧑🏼‍🚒', '🧑🏼‍🦯', '🧑🏼‍🦰', '🧑🏼‍🦱', '🧑🏼‍🦲', '🧑🏼‍🦳', '🧑🏼‍🦼', '🧑🏼‍🦽', '🧑🏽‍🌾', '🧑🏽‍🍳', '🧑🏽‍🍼', '🧑🏽‍🎄', '🧑🏽‍🎓', '🧑🏽‍🎤', '🧑🏽‍🎨', '🧑🏽‍🏫', '🧑🏽‍🏭', '🧑🏽‍💻', '🧑🏽‍💼', '🧑🏽‍🔧', '🧑🏽‍🔬', '🧑🏽‍🚀', '🧑🏽‍🚒', '🧑🏽‍🦯', '🧑🏽‍🦰', '🧑🏽‍🦱', '🧑🏽‍🦲', '🧑🏽‍🦳', '🧑🏽‍🦼', '🧑🏽‍🦽', '🧑🏾‍🌾', '🧑🏾‍🍳', '🧑🏾‍🍼', '🧑🏾‍🎄', '🧑🏾‍🎓', '🧑🏾‍🎤', '🧑🏾‍🎨', '🧑🏾‍🏫', '🧑🏾‍🏭', '🧑🏾‍💻', '🧑🏾‍💼', '🧑🏾‍🔧', '🧑🏾‍🔬', '🧑🏾‍🚀', '🧑🏾‍🚒', '🧑🏾‍🦯', '🧑🏾‍🦰', '🧑🏾‍🦱', '🧑🏾‍🦲', '🧑🏾‍🦳', '🧑🏾‍🦼', '🧑🏾‍🦽', '🧑🏿‍🌾', '🧑🏿‍🍳', '🧑🏿‍🍼', '🧑🏿‍🎄', '🧑🏿‍🎓', '🧑🏿‍🎤', '🧑🏿‍🎨', '🧑🏿‍🏫', '🧑🏿‍🏭', '🧑🏿‍💻', '🧑🏿‍💼', '🧑🏿‍🔧', '🧑🏿‍🔬', '🧑🏿‍🚀', '🧑🏿‍🚒', '🧑🏿‍🦯', '🧑🏿‍🦰', '🧑🏿‍🦱', '🧑🏿‍🦲', '🧑🏿‍🦳', '🧑🏿‍🦼', '🧑🏿‍🦽', '🏳️‍🌈', '🏃‍♀️', '🏃‍♂️', '🏄‍♀️', '🏄‍♂️', '🏊‍♀️', '🏊‍♂️', '🏴‍☠️', '🐻‍❄️', '👨‍⚕️', '👨‍⚖️', '👨‍✈️', '👩‍⚕️', '👩‍⚖️', '👩‍✈️', '👮‍♀️', '👮‍♂️', '👯‍♀️', '👯‍♂️', '👰‍♀️', '👰‍♂️', '👱‍♀️', '👱‍♂️', '👳‍♀️', '👳‍♂️', '👷‍♀️', '👷‍♂️', '💁‍♀️', '💁‍♂️', '💂‍♀️', '💂‍♂️', '💆‍♀️', '💆‍♂️', '💇‍♀️', '💇‍♂️', '🙅‍♀️', '🙅‍♂️', '🙆‍♀️', '🙆‍♂️', '🙇‍♀️', '🙇‍♂️', '🙋‍♀️', '🙋‍♂️', '🙍‍♀️', '🙍‍♂️', '🙎‍♀️', '🙎‍♂️', '🚣‍♀️', '🚣‍♂️', '🚴‍♀️', '🚴‍♂️', '🚵‍♀️', '🚵‍♂️', '🚶‍♀️', '🚶‍♂️', '🤦‍♀️', '🤦‍♂️', '🤵‍♀️', '🤵‍♂️', '🤷‍♀️', '🤷‍♂️', '🤸‍♀️', '🤸‍♂️', '🤹‍♀️', '🤹‍♂️', '🤼‍♀️', '🤼‍♂️', '🤽‍♀️', '🤽‍♂️', '🤾‍♀️', '🤾‍♂️', '🦸‍♀️', '🦸‍♂️', '🦹‍♀️', '🦹‍♂️', '🧍‍♀️', '🧍‍♂️', '🧎‍♀️', '🧎‍♂️', '🧏‍♀️', '🧏‍♂️', '🧑‍⚕️', '🧑‍⚖️', '🧑‍✈️', '🧖‍♀️', '🧖‍♂️', '🧗‍♀️', '🧗‍♂️', '🧘‍♀️', '🧘‍♂️', '🧙‍♀️', '🧙‍♂️', '🧚‍♀️', '🧚‍♂️', '🧛‍♀️', '🧛‍♂️', '🧜‍♀️', '🧜‍♂️', '🧝‍♀️', '🧝‍♂️', '🧞‍♀️', '🧞‍♂️', '🧟‍♀️', '🧟‍♂️', '🐕‍🦺', '👁‍🗨', '👨‍🌾', '👨‍🍳', '👨‍🍼', '👨‍🎄', '👨‍🎓', '👨‍🎤', '👨‍🎨', '👨‍🏫', '👨‍🏭', '👨‍👦', '👨‍👧', '👨‍💻', '👨‍💼', '👨‍🔧', '👨‍🔬', '👨‍🚀', '👨‍🚒', '👨‍🦯', '👨‍🦰', '👨‍🦱', '👨‍🦲', '👨‍🦳', '👨‍🦼', '👨‍🦽', '👩‍🌾', '👩‍🍳', '👩‍🍼', '👩‍🎄', '👩‍🎓', '👩‍🎤', '👩‍🎨', '👩‍🏫', '👩‍🏭', '👩‍👦', '👩‍👧', '👩‍💻', '👩‍💼', '👩‍🔧', '👩‍🔬', '👩‍🚀', '👩‍🚒', '👩‍🦯', '👩‍🦰', '👩‍🦱', '👩‍🦲', '👩‍🦳', '👩‍🦼', '👩‍🦽', '🧑‍🌾', '🧑‍🍳', '🧑‍🍼', '🧑‍🎄', '🧑‍🎓', '🧑‍🎤', '🧑‍🎨', '🧑‍🏫', '🧑‍🏭', '🧑‍💻', '🧑‍💼', '🧑‍🔧', '🧑‍🔬', '🧑‍🚀', '🧑‍🚒', '🧑‍🦯', '🧑‍🦰', '🧑‍🦱', '🧑‍🦲', '🧑‍🦳', '🧑‍🦼', '🧑‍🦽', '🐈‍⬛', '🇦🇨', '🇦🇩', '🇦🇪', '🇦🇫', '🇦🇬', '🇦🇮', '🇦🇱', '🇦🇲', '🇦🇴', '🇦🇶', '🇦🇷', '🇦🇸', '🇦🇹', '🇦🇺', '🇦🇼', '🇦🇽', '🇦🇿', '🇧🇦', '🇧🇧', '🇧🇩', '🇧🇪', '🇧🇫', '🇧🇬', '🇧🇭', '🇧🇮', '🇧🇯', '🇧🇱', '🇧🇲', '🇧🇳', '🇧🇴', '🇧🇶', '🇧🇷', '🇧🇸', '🇧🇹', '🇧🇻', '🇧🇼', '🇧🇾', '🇧🇿', '🇨🇦', '🇨🇨', '🇨🇩', '🇨🇫', '🇨🇬', '🇨🇭', '🇨🇮', '🇨🇰', '🇨🇱', '🇨🇲', '🇨🇳', '🇨🇴', '🇨🇵', '🇨🇷', '🇨🇺', '🇨🇻', '🇨🇼', '🇨🇽', '🇨🇾', '🇨🇿', '🇩🇪', '🇩🇬', '🇩🇯', '🇩🇰', '🇩🇲', '🇩🇴', '🇩🇿', '🇪🇦', '🇪🇨', '🇪🇪', '🇪🇬', '🇪🇭', '🇪🇷', '🇪🇸', '🇪🇹', '🇪🇺', '🇫🇮', '🇫🇯', '🇫🇰', '🇫🇲', '🇫🇴', '🇫🇷', '🇬🇦', '🇬🇧', '🇬🇩', '🇬🇪', '🇬🇫', '🇬🇬', '🇬🇭', '🇬🇮', '🇬🇱', '🇬🇲', '🇬🇳', '🇬🇵', '🇬🇶', '🇬🇷', '🇬🇸', '🇬🇹', '🇬🇺', '🇬🇼', '🇬🇾', '🇭🇰', '🇭🇲', '🇭🇳', '🇭🇷', '🇭🇹', '🇭🇺', '🇮🇨', '🇮🇩', '🇮🇪', '🇮🇱', '🇮🇲', '🇮🇳', '🇮🇴', '🇮🇶', '🇮🇷', '🇮🇸', '🇮🇹', '🇯🇪', '🇯🇲', '🇯🇴', '🇯🇵', '🇰🇪', '🇰🇬', '🇰🇭', '🇰🇮', '🇰🇲', '🇰🇳', '🇰🇵', '🇰🇷', '🇰🇼', '🇰🇾', '🇰🇿', '🇱🇦', '🇱🇧', '🇱🇨', '🇱🇮', '🇱🇰', '🇱🇷', '🇱🇸', '🇱🇹', '🇱🇺', '🇱🇻', '🇱🇾', '🇲🇦', '🇲🇨', '🇲🇩', '🇲🇪', '🇲🇫', '🇲🇬', '🇲🇭', '🇲🇰', '🇲🇱', '🇲🇲', '🇲🇳', '🇲🇴', '🇲🇵', '🇲🇶', '🇲🇷', '🇲🇸', '🇲🇹', '🇲🇺', '🇲🇻', '🇲🇼', '🇲🇽', '🇲🇾', '🇲🇿', '🇳🇦', '🇳🇨', '🇳🇪', '🇳🇫', '🇳🇬', '🇳🇮', '🇳🇱', '🇳🇴', '🇳🇵', '🇳🇷', '🇳🇺', '🇳🇿', '🇴🇲', '🇵🇦', '🇵🇪', '🇵🇫', '🇵🇬', '🇵🇭', '🇵🇰', '🇵🇱', '🇵🇲', '🇵🇳', '🇵🇷', '🇵🇸', '🇵🇹', '🇵🇼', '🇵🇾', '🇶🇦', '🇷🇪', '🇷🇴', '🇷🇸', '🇷🇺', '🇷🇼', '🇸🇦', '🇸🇧', '🇸🇨', '🇸🇩', '🇸🇪', '🇸🇬', '🇸🇭', '🇸🇮', '🇸🇯', '🇸🇰', '🇸🇱', '🇸🇲', '🇸🇳', '🇸🇴', '🇸🇷', '🇸🇸', '🇸🇹', '🇸🇻', '🇸🇽', '🇸🇾', '🇸🇿', '🇹🇦', '🇹🇨', '🇹🇩', '🇹🇫', '🇹🇬', '🇹🇭', '🇹🇯', '🇹🇰', '🇹🇱', '🇹🇲', '🇹🇳', '🇹🇴', '🇹🇷', '🇹🇹', '🇹🇻', '🇹🇼', '🇹🇿', '🇺🇦', '🇺🇬', '🇺🇲', '🇺🇳', '🇺🇸', '🇺🇾', '🇺🇿', '🇻🇦', '🇻🇨', '🇻🇪', '🇻🇬', '🇻🇮', '🇻🇳', '🇻🇺', '🇼🇫', '🇼🇸', '🇽🇰', '🇾🇪', '🇾🇹', '🇿🇦', '🇿🇲', '🇿🇼', '🎅🏻', '🎅🏼', '🎅🏽', '🎅🏾', '🎅🏿', '🏂🏻', '🏂🏼', '🏂🏽', '🏂🏾', '🏂🏿', '🏃🏻', '🏃🏼', '🏃🏽', '🏃🏾', '🏃🏿', '🏄🏻', '🏄🏼', '🏄🏽', '🏄🏾', '🏄🏿', '🏇🏻', '🏇🏼', '🏇🏽', '🏇🏾', '🏇🏿', '🏊🏻', '🏊🏼', '🏊🏽', '🏊🏾', '🏊🏿', '🏋🏻', '🏋🏼', '🏋🏽', '🏋🏾', '🏋🏿', '🏌🏻', '🏌🏼', '🏌🏽', '🏌🏾', '🏌🏿', '👂🏻', '👂🏼', '👂🏽', '👂🏾', '👂🏿', '👃🏻', '👃🏼', '👃🏽', '👃🏾', '👃🏿', '👆🏻', '👆🏼', '👆🏽', '👆🏾', '👆🏿', '👇🏻', '👇🏼', '👇🏽', '👇🏾', '👇🏿', '👈🏻', '👈🏼', '👈🏽', '👈🏾', '👈🏿', '👉🏻', '👉🏼', '👉🏽', '👉🏾', '👉🏿', '👊🏻', '👊🏼', '👊🏽', '👊🏾', '👊🏿', '👋🏻', '👋🏼', '👋🏽', '👋🏾', '👋🏿', '👌🏻', '👌🏼', '👌🏽', '👌🏾', '👌🏿', '👍🏻', '👍🏼', '👍🏽', '👍🏾', '👍🏿', '👎🏻', '👎🏼', '👎🏽', '👎🏾', '👎🏿', '👏🏻', '👏🏼', '👏🏽', '👏🏾', '👏🏿', '👐🏻', '👐🏼', '👐🏽', '👐🏾', '👐🏿', '👦🏻', '👦🏼', '👦🏽', '👦🏾', '👦🏿', '👧🏻', '👧🏼', '👧🏽', '👧🏾', '👧🏿', '👨🏻', '👨🏼', '👨🏽', '👨🏾', '👨🏿', '👩🏻', '👩🏼', '👩🏽', '👩🏾', '👩🏿', '👫🏻', '👫🏼', '👫🏽', '👫🏾', '👫🏿', '👬🏻', '👬🏼', '👬🏽', '👬🏾', '👬🏿', '👭🏻', '👭🏼', '👭🏽', '👭🏾', '👭🏿', '👮🏻', '👮🏼', '👮🏽', '👮🏾', '👮🏿', '👰🏻', '👰🏼', '👰🏽', '👰🏾', '👰🏿', '👱🏻', '👱🏼', '👱🏽', '👱🏾', '👱🏿', '👲🏻', '👲🏼', '👲🏽', '👲🏾', '👲🏿', '👳🏻', '👳🏼', '👳🏽', '👳🏾', '👳🏿', '👴🏻', '👴🏼', '👴🏽', '👴🏾', '👴🏿', '👵🏻', '👵🏼', '👵🏽', '👵🏾', '👵🏿', '👶🏻', '👶🏼', '👶🏽', '👶🏾', '👶🏿', '👷🏻', '👷🏼', '👷🏽', '👷🏾', '👷🏿', '👸🏻', '👸🏼', '👸🏽', '👸🏾', '👸🏿', '👼🏻', '👼🏼', '👼🏽', '👼🏾', '👼🏿', '💁🏻', '💁🏼', '💁🏽', '💁🏾', '💁🏿', '💂🏻', '💂🏼', '💂🏽', '💂🏾', '💂🏿', '💃🏻', '💃🏼', '💃🏽', '💃🏾', '💃🏿', '💅🏻', '💅🏼', '💅🏽', '💅🏾', '💅🏿', '💆🏻', '💆🏼', '💆🏽', '💆🏾', '💆🏿', '💇🏻', '💇🏼', '💇🏽', '💇🏾', '💇🏿', '💪🏻', '💪🏼', '💪🏽', '💪🏾', '💪🏿', '🕴🏻', '🕴🏼', '🕴🏽', '🕴🏾', '🕴🏿', '🕵🏻', '🕵🏼', '🕵🏽', '🕵🏾', '🕵🏿', '🕺🏻', '🕺🏼', '🕺🏽', '🕺🏾', '🕺🏿', '🖐🏻', '🖐🏼', '🖐🏽', '🖐🏾', '🖐🏿', '🖕🏻', '🖕🏼', '🖕🏽', '🖕🏾', '🖕🏿', '🖖🏻', '🖖🏼', '🖖🏽', '🖖🏾', '🖖🏿', '🙅🏻', '🙅🏼', '🙅🏽', '🙅🏾', '🙅🏿', '🙆🏻', '🙆🏼', '🙆🏽', '🙆🏾', '🙆🏿', '🙇🏻', '🙇🏼', '🙇🏽', '🙇🏾', '🙇🏿', '🙋🏻', '🙋🏼', '🙋🏽', '🙋🏾', '🙋🏿', '🙌🏻', '🙌🏼', '🙌🏽', '🙌🏾', '🙌🏿', '🙍🏻', '🙍🏼', '🙍🏽', '🙍🏾', '🙍🏿', '🙎🏻', '🙎🏼', '🙎🏽', '🙎🏾', '🙎🏿', '🙏🏻', '🙏🏼', '🙏🏽', '🙏🏾', '🙏🏿', '🚣🏻', '🚣🏼', '🚣🏽', '🚣🏾', '🚣🏿', '🚴🏻', '🚴🏼', '🚴🏽', '🚴🏾', '🚴🏿', '🚵🏻', '🚵🏼', '🚵🏽', '🚵🏾', '🚵🏿', '🚶🏻', '🚶🏼', '🚶🏽', '🚶🏾', '🚶🏿', '🛀🏻', '🛀🏼', '🛀🏽', '🛀🏾', '🛀🏿', '🛌🏻', '🛌🏼', '🛌🏽', '🛌🏾', '🛌🏿', '🤌🏻', '🤌🏼', '🤌🏽', '🤌🏾', '🤌🏿', '🤏🏻', '🤏🏼', '🤏🏽', '🤏🏾', '🤏🏿', '🤘🏻', '🤘🏼', '🤘🏽', '🤘🏾', '🤘🏿', '🤙🏻', '🤙🏼', '🤙🏽', '🤙🏾', '🤙🏿', '🤚🏻', '🤚🏼', '🤚🏽', '🤚🏾', '🤚🏿', '🤛🏻', '🤛🏼', '🤛🏽', '🤛🏾', '🤛🏿', '🤜🏻', '🤜🏼', '🤜🏽', '🤜🏾', '🤜🏿', '🤞🏻', '🤞🏼', '🤞🏽', '🤞🏾', '🤞🏿', '🤟🏻', '🤟🏼', '🤟🏽', '🤟🏾', '🤟🏿', '🤦🏻', '🤦🏼', '🤦🏽', '🤦🏾', '🤦🏿', '🤰🏻', '🤰🏼', '🤰🏽', '🤰🏾', '🤰🏿', '🤱🏻', '🤱🏼', '🤱🏽', '🤱🏾', '🤱🏿', '🤲🏻', '🤲🏼', '🤲🏽', '🤲🏾', '🤲🏿', '🤳🏻', '🤳🏼', '🤳🏽', '🤳🏾', '🤳🏿', '🤴🏻', '🤴🏼', '🤴🏽', '🤴🏾', '🤴🏿', '🤵🏻', '🤵🏼', '🤵🏽', '🤵🏾', '🤵🏿', '🤶🏻', '🤶🏼', '🤶🏽', '🤶🏾', '🤶🏿', '🤷🏻', '🤷🏼', '🤷🏽', '🤷🏾', '🤷🏿', '🤸🏻', '🤸🏼', '🤸🏽', '🤸🏾', '🤸🏿', '🤹🏻', '🤹🏼', '🤹🏽', '🤹🏾', '🤹🏿', '🤽🏻', '🤽🏼', '🤽🏽', '🤽🏾', '🤽🏿', '🤾🏻', '🤾🏼', '🤾🏽', '🤾🏾', '🤾🏿', '🥷🏻', '🥷🏼', '🥷🏽', '🥷🏾', '🥷🏿', '🦵🏻', '🦵🏼', '🦵🏽', '🦵🏾', '🦵🏿', '🦶🏻', '🦶🏼', '🦶🏽', '🦶🏾', '🦶🏿', '🦸🏻', '🦸🏼', '🦸🏽', '🦸🏾', '🦸🏿', '🦹🏻', '🦹🏼', '🦹🏽', '🦹🏾', '🦹🏿', '🦻🏻', '🦻🏼', '🦻🏽', '🦻🏾', '🦻🏿', '🧍🏻', '🧍🏼', '🧍🏽', '🧍🏾', '🧍🏿', '🧎🏻', '🧎🏼', '🧎🏽', '🧎🏾', '🧎🏿', '🧏🏻', '🧏🏼', '🧏🏽', '🧏🏾', '🧏🏿', '🧑🏻', '🧑🏼', '🧑🏽', '🧑🏾', '🧑🏿', '🧒🏻', '🧒🏼', '🧒🏽', '🧒🏾', '🧒🏿', '🧓🏻', '🧓🏼', '🧓🏽', '🧓🏾', '🧓🏿', '🧔🏻', '🧔🏼', '🧔🏽', '🧔🏾', '🧔🏿', '🧕🏻', '🧕🏼', '🧕🏽', '🧕🏾', '🧕🏿', '🧖🏻', '🧖🏼', '🧖🏽', '🧖🏾', '🧖🏿', '🧗🏻', '🧗🏼', '🧗🏽', '🧗🏾', '🧗🏿', '🧘🏻', '🧘🏼', '🧘🏽', '🧘🏾', '🧘🏿', '🧙🏻', '🧙🏼', '🧙🏽', '🧙🏾', '🧙🏿', '🧚🏻', '🧚🏼', '🧚🏽', '🧚🏾', '🧚🏿', '🧛🏻', '🧛🏼', '🧛🏽', '🧛🏾', '🧛🏿', '🧜🏻', '🧜🏼', '🧜🏽', '🧜🏾', '🧜🏿', '🧝🏻', '🧝🏼', '🧝🏽', '🧝🏾', '🧝🏿', '☝🏻', '☝🏼', '☝🏽', '☝🏾', '☝🏿', '⛷🏻', '⛷🏼', '⛷🏽', '⛷🏾', '⛷🏿', '⛹🏻', '⛹🏼', '⛹🏽', '⛹🏾', '⛹🏿', '✊🏻', '✊🏼', '✊🏽', '✊🏾', '✊🏿', '✋🏻', '✋🏼', '✋🏽', '✋🏾', '✋🏿', '✌🏻', '✌🏼', '✌🏽', '✌🏾', '✌🏿', '✍🏻', '✍🏼', '✍🏽', '✍🏾', '✍🏿', '#⃣', '*⃣', '0⃣', '1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '🀄', '🃏', '🅰', '🅱', '🅾', '🅿', '🆎', '🆑', '🆒', '🆓', '🆔', '🆕', '🆖', '🆗', '🆘', '🆙', '🆚', '🇦', '🇧', '🇨', '🇩', '🇪', '🇫', '🇬', '🇭', '🇮', '🇯', '🇰', '🇱', '🇲', '🇳', '🇴', '🇵', '🇶', '🇷', '🇸', '🇹', '🇺', '🇻', '🇼', '🇽', '🇾', '🇿', '🈁', '🈂', '🈚', '🈯', '🈲', '🈳', '🈴', '🈵', '🈶', '🈷', '🈸', '🈹', '🈺', '🉐', '🉑', '🌀', '🌁', '🌂', '🌃', '🌄', '🌅', '🌆', '🌇', '🌈', '🌉', '🌊', '🌋', '🌌', '🌍', '🌎', '🌏', '🌐', '🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘', '🌙', '🌚', '🌛', '🌜', '🌝', '🌞', '🌟', '🌠', '🌡', '🌤', '🌥', '🌦', '🌧', '🌨', '🌩', '🌪', '🌫', '🌬', '🌭', '🌮', '🌯', '🌰', '🌱', '🌲', '🌳', '🌴', '🌵', '🌶', '🌷', '🌸', '🌹', '🌺', '🌻', '🌼', '🌽', '🌾', '🌿', '🍀', '🍁', '🍂', '🍃', '🍄', '🍅', '🍆', '🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🍎', '🍏', '🍐', '🍑', '🍒', '🍓', '🍔', '🍕', '🍖', '🍗', '🍘', '🍙', '🍚', '🍛', '🍜', '🍝', '🍞', '🍟', '🍠', '🍡', '🍢', '🍣', '🍤', '🍥', '🍦', '🍧', '🍨', '🍩', '🍪', '🍫', '🍬', '🍭', '🍮', '🍯', '🍰', '🍱', '🍲', '🍳', '🍴', '🍵', '🍶', '🍷', '🍸', '🍹', '🍺', '🍻', '🍼', '🍽', '🍾', '🍿', '🎀', '🎁', '🎂', '🎃', '🎄', '🎅', '🎆', '🎇', '🎈', '🎉', '🎊', '🎋', '🎌', '🎍', '🎎', '🎏', '🎐', '🎑', '🎒', '🎓', '🎖', '🎗', '🎙', '🎚', '🎛', '🎞', '🎟', '🎠', '🎡', '🎢', '🎣', '🎤', '🎥', '🎦', '🎧', '🎨', '🎩', '🎪', '🎫', '🎬', '🎭', '🎮', '🎯', '🎰', '🎱', '🎲', '🎳', '🎴', '🎵', '🎶', '🎷', '🎸', '🎹', '🎺', '🎻', '🎼', '🎽', '🎾', '🎿', '🏀', '🏁', '🏂', '🏃', '🏄', '🏅', '🏆', '🏇', '🏈', '🏉', '🏊', '🏋', '🏌', '🏍', '🏎', '🏏', '🏐', '🏑', '🏒', '🏓', '🏔', '🏕', '🏖', '🏗', '🏘', '🏙', '🏚', '🏛', '🏜', '🏝', '🏞', '🏟', '🏠', '🏡', '🏢', '🏣', '🏤', '🏥', '🏦', '🏧', '🏨', '🏩', '🏪', '🏫', '🏬', '🏭', '🏮', '🏯', '🏰', '🏳', '🏴', '🏵', '🏷', '🏸', '🏹', '🏺', '🏻', '🏼', '🏽', '🏾', '🏿', '🐀', '🐁', '🐂', '🐃', '🐄', '🐅', '🐆', '🐇', '🐈', '🐉', '🐊', '🐋', '🐌', '🐍', '🐎', '🐏', '🐐', '🐑', '🐒', '🐓', '🐔', '🐕', '🐖', '🐗', '🐘', '🐙', '🐚', '🐛', '🐜', '🐝', '🐞', '🐟', '🐠', '🐡', '🐢', '🐣', '🐤', '🐥', '🐦', '🐧', '🐨', '🐩', '🐪', '🐫', '🐬', '🐭', '🐮', '🐯', '🐰', '🐱', '🐲', '🐳', '🐴', '🐵', '🐶', '🐷', '🐸', '🐹', '🐺', '🐻', '🐼', '🐽', '🐾', '🐿', '👀', '👁', '👂', '👃', '👄', '👅', '👆', '👇', '👈', '👉', '👊', '👋', '👌', '👍', '👎', '👏', '👐', '👑', '👒', '👓', '👔', '👕', '👖', '👗', '👘', '👙', '👚', '👛', '👜', '👝', '👞', '👟', '👠', '👡', '👢', '👣', '👤', '👥', '👦', '👧', '👨', '👩', '👪', '👫', '👬', '👭', '👮', '👯', '👰', '👱', '👲', '👳', '👴', '👵', '👶', '👷', '👸', '👹', '👺', '👻', '👼', '👽', '👾', '👿', '💀', '💁', '💂', '💃', '💄', '💅', '💆', '💇', '💈', '💉', '💊', '💋', '💌', '💍', '💎', '💏', '💐', '💑', '💒', '💓', '💔', '💕', '💖', '💗', '💘', '💙', '💚', '💛', '💜', '💝', '💞', '💟', '💠', '💡', '💢', '💣', '💤', '💥', '💦', '💧', '💨', '💩', '💪', '💫', '💬', '💭', '💮', '💯', '💰', '💱', '💲', '💳', '💴', '💵', '💶', '💷', '💸', '💹', '💺', '💻', '💼', '💽', '💾', '💿', '📀', '📁', '📂', '📃', '📄', '📅', '📆', '📇', '📈', '📉', '📊', '📋', '📌', '📍', '📎', '📏', '📐', '📑', '📒', '📓', '📔', '📕', '📖', '📗', '📘', '📙', '📚', '📛', '📜', '📝', '📞', '📟', '📠', '📡', '📢', '📣', '📤', '📥', '📦', '📧', '📨', '📩', '📪', '📫', '📬', '📭', '📮', '📯', '📰', '📱', '📲', '📳', '📴', '📵', '📶', '📷', '📸', '📹', '📺', '📻', '📼', '📽', '📿', '🔀', '🔁', '🔂', '🔃', '🔄', '🔅', '🔆', '🔇', '🔈', '🔉', '🔊', '🔋', '🔌', '🔍', '🔎', '🔏', '🔐', '🔑', '🔒', '🔓', '🔔', '🔕', '🔖', '🔗', '🔘', '🔙', '🔚', '🔛', '🔜', '🔝', '🔞', '🔟', '🔠', '🔡', '🔢', '🔣', '🔤', '🔥', '🔦', '🔧', '🔨', '🔩', '🔪', '🔫', '🔬', '🔭', '🔮', '🔯', '🔰', '🔱', '🔲', '🔳', '🔴', '🔵', '🔶', '🔷', '🔸', '🔹', '🔺', '🔻', '🔼', '🔽', '🕉', '🕊', '🕋', '🕌', '🕍', '🕎', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛', '🕜', '🕝', '🕞', '🕟', '🕠', '🕡', '🕢', '🕣', '🕤', '🕥', '🕦', '🕧', '🕯', '🕰', '🕳', '🕴', '🕵', '🕶', '🕷', '🕸', '🕹', '🕺', '🖇', '🖊', '🖋', '🖌', '🖍', '🖐', '🖕', '🖖', '🖤', '🖥', '🖨', '🖱', '🖲', '🖼', '🗂', '🗃', '🗄', '🗑', '🗒', '🗓', '🗜', '🗝', '🗞', '🗡', '🗣', '🗨', '🗯', '🗳', '🗺', '🗻', '🗼', '🗽', '🗾', '🗿', '😀', '😁', '😂', '😃', '😄', '😅', '😆', '😇', '😈', '😉', '😊', '😋', '😌', '😍', '😎', '😏', '😐', '😑', '😒', '😓', '😔', '😕', '😖', '😗', '😘', '😙', '😚', '😛', '😜', '😝', '😞', '😟', '😠', '😡', '😢', '😣', '😤', '😥', '😦', '😧', '😨', '😩', '😪', '😫', '😬', '😭', '😮', '😯', '😰', '😱', '😲', '😳', '😴', '😵', '😶', '😷', '😸', '😹', '😺', '😻', '😼', '😽', '😾', '😿', '🙀', '🙁', '🙂', '🙃', '🙄', '🙅', '🙆', '🙇', '🙈', '🙉', '🙊', '🙋', '🙌', '🙍', '🙎', '🙏', '🚀', '🚁', '🚂', '🚃', '🚄', '🚅', '🚆', '🚇', '🚈', '🚉', '🚊', '🚋', '🚌', '🚍', '🚎', '🚏', '🚐', '🚑', '🚒', '🚓', '🚔', '🚕', '🚖', '🚗', '🚘', '🚙', '🚚', '🚛', '🚜', '🚝', '🚞', '🚟', '🚠', '🚡', '🚢', '🚣', '🚤', '🚥', '🚦', '🚧', '🚨', '🚩', '🚪', '🚫', '🚬', '🚭', '🚮', '🚯', '🚰', '🚱', '🚲', '🚳', '🚴', '🚵', '🚶', '🚷', '🚸', '🚹', '🚺', '🚻', '🚼', '🚽', '🚾', '🚿', '🛀', '🛁', '🛂', '🛃', '🛄', '🛅', '🛋', '🛌', '🛍', '🛎', '🛏', '🛐', '🛑', '🛒', '🛕', '🛖', '🛗', '🛠', '🛡', '🛢', '🛣', '🛤', '🛥', '🛩', '🛫', '🛬', '🛰', '🛳', '🛴', '🛵', '🛶', '🛷', '🛸', '🛹', '🛺', '🛻', '🛼', '🟠', '🟡', '🟢', '🟣', '🟤', '🟥', '🟦', '🟧', '🟨', '🟩', '🟪', '🟫', '🤌', '🤍', '🤎', '🤏', '🤐', '🤑', '🤒', '🤓', '🤔', '🤕', '🤖', '🤗', '🤘', '🤙', '🤚', '🤛', '🤜', '🤝', '🤞', '🤟', '🤠', '🤡', '🤢', '🤣', '🤤', '🤥', '🤦', '🤧', '🤨', '🤩', '🤪', '🤫', '🤬', '🤭', '🤮', '🤯', '🤰', '🤱', '🤲', '🤳', '🤴', '🤵', '🤶', '🤷', '🤸', '🤹', '🤺', '🤼', '🤽', '🤾', '🤿', '🥀', '🥁', '🥂', '🥃', '🥄', '🥅', '🥇', '🥈', '🥉', '🥊', '🥋', '🥌', '🥍', '🥎', '🥏', '🥐', '🥑', '🥒', '🥓', '🥔', '🥕', '🥖', '🥗', '🥘', '🥙', '🥚', '🥛', '🥜', '🥝', '🥞', '🥟', '🥠', '🥡', '🥢', '🥣', '🥤', '🥥', '🥦', '🥧', '🥨', '🥩', '🥪', '🥫', '🥬', '🥭', '🥮', '🥯', '🥰', '🥱', '🥲', '🥳', '🥴', '🥵', '🥶', '🥷', '🥸', '🥺', '🥻', '🥼', '🥽', '🥾', '🥿', '🦀', '🦁', '🦂', '🦃', '🦄', '🦅', '🦆', '🦇', '🦈', '🦉', '🦊', '🦋', '🦌', '🦍', '🦎', '🦏', '🦐', '🦑', '🦒', '🦓', '🦔', '🦕', '🦖', '🦗', '🦘', '🦙', '🦚', '🦛', '🦜', '🦝', '🦞', '🦟', '🦠', '🦡', '🦢', '🦣', '🦤', '🦥', '🦦', '🦧', '🦨', '🦩', '🦪', '🦫', '🦬', '🦭', '🦮', '🦯', '🦰', '🦱', '🦲', '🦳', '🦴', '🦵', '🦶', '🦷', '🦸', '🦹', '🦺', '🦻', '🦼', '🦽', '🦾', '🦿', '🧀', '🧁', '🧂', '🧃', '🧄', '🧅', '🧆', '🧇', '🧈', '🧉', '🧊', '🧋', '🧍', '🧎', '🧏', '🧐', '🧑', '🧒', '🧓', '🧔', '🧕', '🧖', '🧗', '🧘', '🧙', '🧚', '🧛', '🧜', '🧝', '🧞', '🧟', '🧠', '🧡', '🧢', '🧣', '🧤', '🧥', '🧦', '🧧', '🧨', '🧩', '🧪', '🧫', '🧬', '🧭', '🧮', '🧯', '🧰', '🧱', '🧲', '🧳', '🧴', '🧵', '🧶', '🧷', '🧸', '🧹', '🧺', '🧻', '🧼', '🧽', '🧾', '🧿', '🩰', '🩱', '🩲', '🩳', '🩴', '🩸', '🩹', '🩺', '🪀', '🪁', '🪂', '🪃', '🪄', '🪅', '🪆', '🪐', '🪑', '🪒', '🪓', '🪔', '🪕', '🪖', '🪗', '🪘', '🪙', '🪚', '🪛', '🪜', '🪝', '🪞', '🪟', '🪠', '🪡', '🪢', '🪣', '🪤', '🪥', '🪦', '🪧', '🪨', '🪰', '🪱', '🪲', '🪳', '🪴', '🪵', '🪶', '🫀', '🫁', '🫂', '🫐', '🫑', '🫒', '🫓', '🫔', '🫕', '🫖', '‼', '⁉', '™', 'ℹ', '↔', '↕', '↖', '↗', '↘', '↙', '↩', '↪', '⌚', '⌛', '⌨', '⏏', '⏩', '⏪', '⏫', '⏬', '⏭', '⏮', '⏯', '⏰', '⏱', '⏲', '⏳', '⏸', '⏹', '⏺', 'Ⓜ', '▪', '▫', '▶', '◀', '◻', '◼', '◽', '◾', '☀', '☁', '☂', '☃', '☄', '☎', '☑', '☔', '☕', '☘', '☝', '☠', '☢', '☣', '☦', '☪', '☮', '☯', '☸', '☹', '☺', '♀', '♂', '♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '♟', '♠', '♣', '♥', '♦', '♨', '♻', '♾', '♿', '⚒', '⚓', '⚔', '⚕', '⚖', '⚗', '⚙', '⚛', '⚜', '⚠', '⚡', '⚧', '⚪', '⚫', '⚰', '⚱', '⚽', '⚾', '⛄', '⛅', '⛈', '⛎', '⛏', '⛑', '⛓', '⛔', '⛩', '⛪', '⛰', '⛱', '⛲', '⛳', '⛴', '⛵', '⛷', '⛸', '⛹', '⛺', '⛽', '✂', '✅', '✈', '✉', '✊', '✋', '✌', '✍', '✏', '✒', '✔', '✖', '✝', '✡', '✨', '✳', '✴', '❄', '❇', '❌', '❎', '❓', '❔', '❕', '❗', '❣', '❤', '➕', '➖', '➗', '➡', '➰', '➿', '⤴', '⤵', '⬅', '⬆', '⬇', '⬛', '⬜', '⭐', '⭕', '〰', '〽', '㊗', '㊙', '' );
+ $partials = array( '🀄', '🃏', '🅰', '🅱', '🅾', '🅿', '🆎', '🆑', '🆒', '🆓', '🆔', '🆕', '🆖', '🆗', '🆘', '🆙', '🆚', '🇦', '🇨', '🇩', '🇪', '🇫', '🇬', '🇮', '🇱', '🇲', '🇴', '🇶', '🇷', '🇸', '🇹', '🇺', '🇼', '🇽', '🇿', '🇧', '🇭', '🇯', '🇳', '🇻', '🇾', '🇰', '🇵', '🈁', '🈂', '🈚', '🈯', '🈲', '🈳', '🈴', '🈵', '🈶', '🈷', '🈸', '🈹', '🈺', '🉐', '🉑', '🌀', '🌁', '🌂', '🌃', '🌄', '🌅', '🌆', '🌇', '🌈', '🌉', '🌊', '🌋', '🌌', '🌍', '🌎', '🌏', '🌐', '🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘', '🌙', '🌚', '🌛', '🌜', '🌝', '🌞', '🌟', '🌠', '🌡', '🌤', '🌥', '🌦', '🌧', '🌨', '🌩', '🌪', '🌫', '🌬', '🌭', '🌮', '🌯', '🌰', '🌱', '🌲', '🌳', '🌴', '🌵', '🌶', '🌷', '🌸', '🌹', '🌺', '🌻', '🌼', '🌽', '🌾', '🌿', '🍀', '🍁', '🍂', '🍃', '🍄', '🍅', '🍆', '🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🍎', '🍏', '🍐', '🍑', '🍒', '🍓', '🍔', '🍕', '🍖', '🍗', '🍘', '🍙', '🍚', '🍛', '🍜', '🍝', '🍞', '🍟', '🍠', '🍡', '🍢', '🍣', '🍤', '🍥', '🍦', '🍧', '🍨', '🍩', '🍪', '🍫', '🍬', '🍭', '🍮', '🍯', '🍰', '🍱', '🍲', '🍳', '🍴', '🍵', '🍶', '🍷', '🍸', '🍹', '🍺', '🍻', '🍼', '🍽', '🍾', '🍿', '🎀', '🎁', '🎂', '🎃', '🎄', '🎅', '🏻', '🏼', '🏽', '🏾', '🏿', '🎆', '🎇', '🎈', '🎉', '🎊', '🎋', '🎌', '🎍', '🎎', '🎏', '🎐', '🎑', '🎒', '🎓', '🎖', '🎗', '🎙', '🎚', '🎛', '🎞', '🎟', '🎠', '🎡', '🎢', '🎣', '🎤', '🎥', '🎦', '🎧', '🎨', '🎩', '🎪', '🎫', '🎬', '🎭', '🎮', '🎯', '🎰', '🎱', '🎲', '🎳', '🎴', '🎵', '🎶', '🎷', '🎸', '🎹', '🎺', '🎻', '🎼', '🎽', '🎾', '🎿', '🏀', '🏁', '🏂', '🏃', '‍', '♀', '️', '♂', '🏄', '🏅', '🏆', '🏇', '🏈', '🏉', '🏊', '🏋', '🏌', '🏍', '🏎', '🏏', '🏐', '🏑', '🏒', '🏓', '🏔', '🏕', '🏖', '🏗', '🏘', '🏙', '🏚', '🏛', '🏜', '🏝', '🏞', '🏟', '🏠', '🏡', '🏢', '🏣', '🏤', '🏥', '🏦', '🏧', '🏨', '🏩', '🏪', '🏫', '🏬', '🏭', '🏮', '🏯', '🏰', '🏳', '⚧', '🏴', '☠', '󠁧', '󠁢', '󠁥', '󠁮', '󠁿', '󠁳', '󠁣', '󠁴', '󠁷', '󠁬', '🏵', '🏷', '🏸', '🏹', '🏺', '🐀', '🐁', '🐂', '🐃', '🐄', '🐅', '🐆', '🐇', '🐈', '⬛', '🐉', '🐊', '🐋', '🐌', '🐍', '🐎', '🐏', '🐐', '🐑', '🐒', '🐓', '🐔', '🐕', '🦺', '🐖', '🐗', '🐘', '🐙', '🐚', '🐛', '🐜', '🐝', '🐞', '🐟', '🐠', '🐡', '🐢', '🐣', '🐤', '🐥', '🐦', '🐧', '🐨', '🐩', '🐪', '🐫', '🐬', '🐭', '🐮', '🐯', '🐰', '🐱', '🐲', '🐳', '🐴', '🐵', '🐶', '🐷', '🐸', '🐹', '🐺', '🐻', '❄', '🐼', '🐽', '🐾', '🐿', '👀', '👁', '🗨', '👂', '👃', '👄', '👅', '👆', '👇', '👈', '👉', '👊', '👋', '👌', '👍', '👎', '👏', '👐', '👑', '👒', '👓', '👔', '👕', '👖', '👗', '👘', '👙', '👚', '👛', '👜', '👝', '👞', '👟', '👠', '👡', '👢', '👣', '👤', '👥', '👦', '👧', '👨', '💻', '💼', '🔧', '🔬', '🚀', '🚒', '🤝', '🦯', '🦰', '🦱', '🦲', '🦳', '🦼', '🦽', '⚕', '⚖', '✈', '👩', '❤', '💋', '👪', '👫', '👬', '👭', '👮', '👯', '👰', '👱', '👲', '👳', '👴', '👵', '👶', '👷', '👸', '👹', '👺', '👻', '👼', '👽', '👾', '👿', '💀', '💁', '💂', '💃', '💄', '💅', '💆', '💇', '💈', '💉', '💊', '💌', '💍', '💎', '💏', '💐', '💑', '💒', '💓', '💔', '💕', '💖', '💗', '💘', '💙', '💚', '💛', '💜', '💝', '💞', '💟', '💠', '💡', '💢', '💣', '💤', '💥', '💦', '💧', '💨', '💩', '💪', '💫', '💬', '💭', '💮', '💯', '💰', '💱', '💲', '💳', '💴', '💵', '💶', '💷', '💸', '💹', '💺', '💽', '💾', '💿', '📀', '📁', '📂', '📃', '📄', '📅', '📆', '📇', '📈', '📉', '📊', '📋', '📌', '📍', '📎', '📏', '📐', '📑', '📒', '📓', '📔', '📕', '📖', '📗', '📘', '📙', '📚', '📛', '📜', '📝', '📞', '📟', '📠', '📡', '📢', '📣', '📤', '📥', '📦', '📧', '📨', '📩', '📪', '📫', '📬', '📭', '📮', '📯', '📰', '📱', '📲', '📳', '📴', '📵', '📶', '📷', '📸', '📹', '📺', '📻', '📼', '📽', '📿', '🔀', '🔁', '🔂', '🔃', '🔄', '🔅', '🔆', '🔇', '🔈', '🔉', '🔊', '🔋', '🔌', '🔍', '🔎', '🔏', '🔐', '🔑', '🔒', '🔓', '🔔', '🔕', '🔖', '🔗', '🔘', '🔙', '🔚', '🔛', '🔜', '🔝', '🔞', '🔟', '🔠', '🔡', '🔢', '🔣', '🔤', '🔥', '🔦', '🔨', '🔩', '🔪', '🔫', '🔭', '🔮', '🔯', '🔰', '🔱', '🔲', '🔳', '🔴', '🔵', '🔶', '🔷', '🔸', '🔹', '🔺', '🔻', '🔼', '🔽', '🕉', '🕊', '🕋', '🕌', '🕍', '🕎', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛', '🕜', '🕝', '🕞', '🕟', '🕠', '🕡', '🕢', '🕣', '🕤', '🕥', '🕦', '🕧', '🕯', '🕰', '🕳', '🕴', '🕵', '🕶', '🕷', '🕸', '🕹', '🕺', '🖇', '🖊', '🖋', '🖌', '🖍', '🖐', '🖕', '🖖', '🖤', '🖥', '🖨', '🖱', '🖲', '🖼', '🗂', '🗃', '🗄', '🗑', '🗒', '🗓', '🗜', '🗝', '🗞', '🗡', '🗣', '🗯', '🗳', '🗺', '🗻', '🗼', '🗽', '🗾', '🗿', '😀', '😁', '😂', '😃', '😄', '😅', '😆', '😇', '😈', '😉', '😊', '😋', '😌', '😍', '😎', '😏', '😐', '😑', '😒', '😓', '😔', '😕', '😖', '😗', '😘', '😙', '😚', '😛', '😜', '😝', '😞', '😟', '😠', '😡', '😢', '😣', '😤', '😥', '😦', '😧', '😨', '😩', '😪', '😫', '😬', '😭', '😮', '😯', '😰', '😱', '😲', '😳', '😴', '😵', '😶', '😷', '😸', '😹', '😺', '😻', '😼', '😽', '😾', '😿', '🙀', '🙁', '🙂', '🙃', '🙄', '🙅', '🙆', '🙇', '🙈', '🙉', '🙊', '🙋', '🙌', '🙍', '🙎', '🙏', '🚁', '🚂', '🚃', '🚄', '🚅', '🚆', '🚇', '🚈', '🚉', '🚊', '🚋', '🚌', '🚍', '🚎', '🚏', '🚐', '🚑', '🚓', '🚔', '🚕', '🚖', '🚗', '🚘', '🚙', '🚚', '🚛', '🚜', '🚝', '🚞', '🚟', '🚠', '🚡', '🚢', '🚣', '🚤', '🚥', '🚦', '🚧', '🚨', '🚩', '🚪', '🚫', '🚬', '🚭', '🚮', '🚯', '🚰', '🚱', '🚲', '🚳', '🚴', '🚵', '🚶', '🚷', '🚸', '🚹', '🚺', '🚻', '🚼', '🚽', '🚾', '🚿', '🛀', '🛁', '🛂', '🛃', '🛄', '🛅', '🛋', '🛌', '🛍', '🛎', '🛏', '🛐', '🛑', '🛒', '🛕', '🛖', '🛗', '🛠', '🛡', '🛢', '🛣', '🛤', '🛥', '🛩', '🛫', '🛬', '🛰', '🛳', '🛴', '🛵', '🛶', '🛷', '🛸', '🛹', '🛺', '🛻', '🛼', '🟠', '🟡', '🟢', '🟣', '🟤', '🟥', '🟦', '🟧', '🟨', '🟩', '🟪', '🟫', '🤌', '🤍', '🤎', '🤏', '🤐', '🤑', '🤒', '🤓', '🤔', '🤕', '🤖', '🤗', '🤘', '🤙', '🤚', '🤛', '🤜', '🤞', '🤟', '🤠', '🤡', '🤢', '🤣', '🤤', '🤥', '🤦', '🤧', '🤨', '🤩', '🤪', '🤫', '🤬', '🤭', '🤮', '🤯', '🤰', '🤱', '🤲', '🤳', '🤴', '🤵', '🤶', '🤷', '🤸', '🤹', '🤺', '🤼', '🤽', '🤾', '🤿', '🥀', '🥁', '🥂', '🥃', '🥄', '🥅', '🥇', '🥈', '🥉', '🥊', '🥋', '🥌', '🥍', '🥎', '🥏', '🥐', '🥑', '🥒', '🥓', '🥔', '🥕', '🥖', '🥗', '🥘', '🥙', '🥚', '🥛', '🥜', '🥝', '🥞', '🥟', '🥠', '🥡', '🥢', '🥣', '🥤', '🥥', '🥦', '🥧', '🥨', '🥩', '🥪', '🥫', '🥬', '🥭', '🥮', '🥯', '🥰', '🥱', '🥲', '🥳', '🥴', '🥵', '🥶', '🥷', '🥸', '🥺', '🥻', '🥼', '🥽', '🥾', '🥿', '🦀', '🦁', '🦂', '🦃', '🦄', '🦅', '🦆', '🦇', '🦈', '🦉', '🦊', '🦋', '🦌', '🦍', '🦎', '🦏', '🦐', '🦑', '🦒', '🦓', '🦔', '🦕', '🦖', '🦗', '🦘', '🦙', '🦚', '🦛', '🦜', '🦝', '🦞', '🦟', '🦠', '🦡', '🦢', '🦣', '🦤', '🦥', '🦦', '🦧', '🦨', '🦩', '🦪', '🦫', '🦬', '🦭', '🦮', '🦴', '🦵', '🦶', '🦷', '🦸', '🦹', '🦻', '🦾', '🦿', '🧀', '🧁', '🧂', '🧃', '🧄', '🧅', '🧆', '🧇', '🧈', '🧉', '🧊', '🧋', '🧍', '🧎', '🧏', '🧐', '🧑', '🧒', '🧓', '🧔', '🧕', '🧖', '🧗', '🧘', '🧙', '🧚', '🧛', '🧜', '🧝', '🧞', '🧟', '🧠', '🧡', '🧢', '🧣', '🧤', '🧥', '🧦', '🧧', '🧨', '🧩', '🧪', '🧫', '🧬', '🧭', '🧮', '🧯', '🧰', '🧱', '🧲', '🧳', '🧴', '🧵', '🧶', '🧷', '🧸', '🧹', '🧺', '🧻', '🧼', '🧽', '🧾', '🧿', '🩰', '🩱', '🩲', '🩳', '🩴', '🩸', '🩹', '🩺', '🪀', '🪁', '🪂', '🪃', '🪄', '🪅', '🪆', '🪐', '🪑', '🪒', '🪓', '🪔', '🪕', '🪖', '🪗', '🪘', '🪙', '🪚', '🪛', '🪜', '🪝', '🪞', '🪟', '🪠', '🪡', '🪢', '🪣', '🪤', '🪥', '🪦', '🪧', '🪨', '🪰', '🪱', '🪲', '🪳', '🪴', '🪵', '🪶', '🫀', '🫁', '🫂', '🫐', '🫑', '🫒', '🫓', '🫔', '🫕', '🫖', '‼', '⁉', '™', 'ℹ', '↔', '↕', '↖', '↗', '↘', '↙', '↩', '↪', '⃣', '⌚', '⌛', '⌨', '⏏', '⏩', '⏪', '⏫', '⏬', '⏭', '⏮', '⏯', '⏰', '⏱', '⏲', '⏳', '⏸', '⏹', '⏺', 'Ⓜ', '▪', '▫', '▶', '◀', '◻', '◼', '◽', '◾', '☀', '☁', '☂', '☃', '☄', '☎', '☑', '☔', '☕', '☘', '☝', '☢', '☣', '☦', '☪', '☮', '☯', '☸', '☹', '☺', '♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '♟', '♠', '♣', '♥', '♦', '♨', '♻', '♾', '♿', '⚒', '⚓', '⚔', '⚗', '⚙', '⚛', '⚜', '⚠', '⚡', '⚪', '⚫', '⚰', '⚱', '⚽', '⚾', '⛄', '⛅', '⛈', '⛎', '⛏', '⛑', '⛓', '⛔', '⛩', '⛪', '⛰', '⛱', '⛲', '⛳', '⛴', '⛵', '⛷', '⛸', '⛹', '⛺', '⛽', '✂', '✅', '✉', '✊', '✋', '✌', '✍', '✏', '✒', '✔', '✖', '✝', '✡', '✨', '✳', '✴', '❇', '❌', '❎', '❓', '❔', '❕', '❗', '❣', '➕', '➖', '➗', '➡', '➰', '➿', '⤴', '⤵', '⬅', '⬆', '⬇', '⬜', '⭐', '⭕', '〰', '〽', '㊗', '㊙', '' );
// END: emoji arrays
if ( 'entities' === $type ) {
@@ -5808,7 +6022,7 @@
*
* 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.
+ * rgba, hsl, rgb, and HTML color names.
*
* Returns either '', a 3 or 6 digit hex color (without a #), or null.
*
@@ -5839,7 +6053,8 @@
* @return string
*/
function maybe_hash_hex_color( $color ) {
- if ( $unhashed = sanitize_hex_color_no_hash( $color ) ) {
+ $unhashed = sanitize_hex_color_no_hash( $color );
+ if ( $unhashed ) {
return '#' . $unhashed;
}