home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / formatting.php < prev    next >
Encoding:
PHP Script  |  2018-01-24  |  260.2 KB  |  5,411 lines

  1. <?php
  2. /**
  3.  * Main WordPress Formatting API.
  4.  *
  5.  * Handles many functions for formatting output.
  6.  *
  7.  * @package WordPress
  8.  */
  9.  
  10. /**
  11.  * Replaces common plain text characters into formatted entities
  12.  *
  13.  * As an example,
  14.  *
  15.  *     'cause today's effort makes it worth tomorrow's "holiday" ...
  16.  *
  17.  * Becomes:
  18.  *
  19.  *     ’cause today’s effort makes it worth tomorrow’s “holiday” …
  20.  *
  21.  * Code within certain html blocks are skipped.
  22.  *
  23.  * Do not use this function before the {@see 'init'} action hook; everything will break.
  24.  *
  25.  * @since 0.71
  26.  *
  27.  * @global array $wp_cockneyreplace Array of formatted entities for certain common phrases
  28.  * @global array $shortcode_tags
  29.  * @staticvar array  $static_characters
  30.  * @staticvar array  $static_replacements
  31.  * @staticvar array  $dynamic_characters
  32.  * @staticvar array  $dynamic_replacements
  33.  * @staticvar array  $default_no_texturize_tags
  34.  * @staticvar array  $default_no_texturize_shortcodes
  35.  * @staticvar bool   $run_texturize
  36.  * @staticvar string $apos
  37.  * @staticvar string $prime
  38.  * @staticvar string $double_prime
  39.  * @staticvar string $opening_quote
  40.  * @staticvar string $closing_quote
  41.  * @staticvar string $opening_single_quote
  42.  * @staticvar string $closing_single_quote
  43.  * @staticvar string $open_q_flag
  44.  * @staticvar string $open_sq_flag
  45.  * @staticvar string $apos_flag
  46.  *
  47.  * @param string $text The text to be formatted
  48.  * @param bool   $reset Set to true for unit testing. Translated patterns will reset.
  49.  * @return string The string replaced with html entities
  50.  */
  51. function wptexturize( $text, $reset = false ) {
  52.     global $wp_cockneyreplace, $shortcode_tags;
  53.     static $static_characters = null,
  54.         $static_replacements = null,
  55.         $dynamic_characters = null,
  56.         $dynamic_replacements = null,
  57.         $default_no_texturize_tags = null,
  58.         $default_no_texturize_shortcodes = null,
  59.         $run_texturize = true,
  60.         $apos = null,
  61.         $prime = null,
  62.         $double_prime = null,
  63.         $opening_quote = null,
  64.         $closing_quote = null,
  65.         $opening_single_quote = null,
  66.         $closing_single_quote = null,
  67.         $open_q_flag = '<!--oq-->',
  68.         $open_sq_flag = '<!--osq-->',
  69.         $apos_flag = '<!--apos-->';
  70.  
  71.     // If there's nothing to do, just stop.
  72.     if ( empty( $text ) || false === $run_texturize ) {
  73.         return $text;
  74.     }
  75.  
  76.     // Set up static variables. Run once only.
  77.     if ( $reset || ! isset( $static_characters ) ) {
  78.         /**
  79.          * Filters whether to skip running wptexturize().
  80.          *
  81.          * Passing false to the filter will effectively short-circuit wptexturize().
  82.          * returning the original text passed to the function instead.
  83.          *
  84.          * The filter runs only once, the first time wptexturize() is called.
  85.          *
  86.          * @since 4.0.0
  87.          *
  88.          * @see wptexturize()
  89.          *
  90.          * @param bool $run_texturize Whether to short-circuit wptexturize().
  91.          */
  92.         $run_texturize = apply_filters( 'run_wptexturize', $run_texturize );
  93.         if ( false === $run_texturize ) {
  94.             return $text;
  95.         }
  96.  
  97.         /* translators: opening curly double quote */
  98.         $opening_quote = _x( '“', 'opening curly double quote' );
  99.         /* translators: closing curly double quote */
  100.         $closing_quote = _x( '”', 'closing curly double quote' );
  101.  
  102.         /* translators: apostrophe, for example in 'cause or can't */
  103.         $apos = _x( '’', 'apostrophe' );
  104.  
  105.         /* translators: prime, for example in 9' (nine feet) */
  106.         $prime = _x( '′', 'prime' );
  107.         /* translators: double prime, for example in 9" (nine inches) */
  108.         $double_prime = _x( '″', 'double prime' );
  109.  
  110.         /* translators: opening curly single quote */
  111.         $opening_single_quote = _x( '‘', 'opening curly single quote' );
  112.         /* translators: closing curly single quote */
  113.         $closing_single_quote = _x( '’', 'closing curly single quote' );
  114.  
  115.         /* translators: en dash */
  116.         $en_dash = _x( '–', 'en dash' );
  117.         /* translators: em dash */
  118.         $em_dash = _x( '—', 'em dash' );
  119.  
  120.         $default_no_texturize_tags = array('pre', 'code', 'kbd', 'style', 'script', 'tt');
  121.         $default_no_texturize_shortcodes = array('code');
  122.  
  123.         // if a plugin has provided an autocorrect array, use it
  124.         if ( isset($wp_cockneyreplace) ) {
  125.             $cockney = array_keys( $wp_cockneyreplace );
  126.             $cockneyreplace = array_values( $wp_cockneyreplace );
  127.         } else {
  128.             /* translators: This is a comma-separated list of words that defy the syntax of quotations in normal use,
  129.              * for example...  'We do not have enough words yet' ... is a typical quoted phrase.  But when we write
  130.              * lines of code 'til we have enough of 'em, then we need to insert apostrophes instead of quotes.
  131.              */
  132.             $cockney = explode( ',', _x( "'tain't,'twere,'twas,'tis,'twill,'til,'bout,'nuff,'round,'cause,'em",
  133.                 'Comma-separated list of words to texturize in your language' ) );
  134.  
  135.             $cockneyreplace = explode( ',', _x( '’tain’t,’twere,’twas,’tis,’twill,’til,’bout,’nuff,’round,’cause,’em',
  136.                 'Comma-separated list of replacement words in your language' ) );
  137.         }
  138.  
  139.         $static_characters = array_merge( array( '...', '``', '\'\'', ' (tm)' ), $cockney );
  140.         $static_replacements = array_merge( array( '…', $opening_quote, $closing_quote, ' ™' ), $cockneyreplace );
  141.  
  142.  
  143.         // Pattern-based replacements of characters.
  144.         // Sort the remaining patterns into several arrays for performance tuning.
  145.         $dynamic_characters = array( 'apos' => array(), 'quote' => array(), 'dash' => array() );
  146.         $dynamic_replacements = array( 'apos' => array(), 'quote' => array(), 'dash' => array() );
  147.         $dynamic = array();
  148.         $spaces = wp_spaces_regexp();
  149.  
  150.         // '99' and '99" are ambiguous among other patterns; assume it's an abbreviated year at the end of a quotation.
  151.         if ( "'" !== $apos || "'" !== $closing_single_quote ) {
  152.             $dynamic[ '/\'(\d\d)\'(?=\Z|[.,:;!?)}\-\]]|>|' . $spaces . ')/' ] = $apos_flag . '$1' . $closing_single_quote;
  153.         }
  154.         if ( "'" !== $apos || '"' !== $closing_quote ) {
  155.             $dynamic[ '/\'(\d\d)"(?=\Z|[.,:;!?)}\-\]]|>|' . $spaces . ')/' ] = $apos_flag . '$1' . $closing_quote;
  156.         }
  157.  
  158.         // '99 '99s '99's (apostrophe)  But never '9 or '99% or '999 or '99.0.
  159.         if ( "'" !== $apos ) {
  160.             $dynamic[ '/\'(?=\d\d(?:\Z|(?![%\d]|[.,]\d)))/' ] = $apos_flag;
  161.         }
  162.  
  163.         // Quoted Numbers like '0.42'
  164.         if ( "'" !== $opening_single_quote && "'" !== $closing_single_quote ) {
  165.             $dynamic[ '/(?<=\A|' . $spaces . ')\'(\d[.,\d]*)\'/' ] = $open_sq_flag . '$1' . $closing_single_quote;
  166.         }
  167.  
  168.         // Single quote at start, or preceded by (, {, <, [, ", -, or spaces.
  169.         if ( "'" !== $opening_single_quote ) {
  170.             $dynamic[ '/(?<=\A|[([{"\-]|<|' . $spaces . ')\'/' ] = $open_sq_flag;
  171.         }
  172.  
  173.         // Apostrophe in a word.  No spaces, double apostrophes, or other punctuation.
  174.         if ( "'" !== $apos ) {
  175.             $dynamic[ '/(?<!' . $spaces . ')\'(?!\Z|[.,:;!?"\'(){}[\]\-]|&[lg]t;|' . $spaces . ')/' ] = $apos_flag;
  176.         }
  177.  
  178.         $dynamic_characters['apos'] = array_keys( $dynamic );
  179.         $dynamic_replacements['apos'] = array_values( $dynamic );
  180.         $dynamic = array();
  181.  
  182.         // Quoted Numbers like "42"
  183.         if ( '"' !== $opening_quote && '"' !== $closing_quote ) {
  184.             $dynamic[ '/(?<=\A|' . $spaces . ')"(\d[.,\d]*)"/' ] = $open_q_flag . '$1' . $closing_quote;
  185.         }
  186.  
  187.         // Double quote at start, or preceded by (, {, <, [, -, or spaces, and not followed by spaces.
  188.         if ( '"' !== $opening_quote ) {
  189.             $dynamic[ '/(?<=\A|[([{\-]|<|' . $spaces . ')"(?!' . $spaces . ')/' ] = $open_q_flag;
  190.         }
  191.  
  192.         $dynamic_characters['quote'] = array_keys( $dynamic );
  193.         $dynamic_replacements['quote'] = array_values( $dynamic );
  194.         $dynamic = array();
  195.  
  196.         // Dashes and spaces
  197.         $dynamic[ '/---/' ] = $em_dash;
  198.         $dynamic[ '/(?<=^|' . $spaces . ')--(?=$|' . $spaces . ')/' ] = $em_dash;
  199.         $dynamic[ '/(?<!xn)--/' ] = $en_dash;
  200.         $dynamic[ '/(?<=^|' . $spaces . ')-(?=$|' . $spaces . ')/' ] = $en_dash;
  201.  
  202.         $dynamic_characters['dash'] = array_keys( $dynamic );
  203.         $dynamic_replacements['dash'] = array_values( $dynamic );
  204.     }
  205.  
  206.     // Must do this every time in case plugins use these filters in a context sensitive manner
  207.     /**
  208.      * Filters the list of HTML elements not to texturize.
  209.      *
  210.      * @since 2.8.0
  211.      *
  212.      * @param array $default_no_texturize_tags An array of HTML element names.
  213.      */
  214.     $no_texturize_tags = apply_filters( 'no_texturize_tags', $default_no_texturize_tags );
  215.     /**
  216.      * Filters the list of shortcodes not to texturize.
  217.      *
  218.      * @since 2.8.0
  219.      *
  220.      * @param array $default_no_texturize_shortcodes An array of shortcode names.
  221.      */
  222.     $no_texturize_shortcodes = apply_filters( 'no_texturize_shortcodes', $default_no_texturize_shortcodes );
  223.  
  224.     $no_texturize_tags_stack = array();
  225.     $no_texturize_shortcodes_stack = array();
  226.  
  227.     // Look for shortcodes and HTML elements.
  228.  
  229.     preg_match_all( '@\[/?([^<>&/\[\]\x00-\x20=]++)@', $text, $matches );
  230.     $tagnames = array_intersect( array_keys( $shortcode_tags ), $matches[1] );
  231.     $found_shortcodes = ! empty( $tagnames );
  232.     $shortcode_regex = $found_shortcodes ? _get_wptexturize_shortcode_regex( $tagnames ) : '';
  233.     $regex = _get_wptexturize_split_regex( $shortcode_regex );
  234.  
  235.     $textarr = preg_split( $regex, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
  236.  
  237.     foreach ( $textarr as &$curl ) {
  238.         // Only call _wptexturize_pushpop_element if $curl is a delimiter.
  239.         $first = $curl[0];
  240.         if ( '<' === $first ) {
  241.             if ( '<!--' === substr( $curl, 0, 4 ) ) {
  242.                 // This is an HTML comment delimiter.
  243.                 continue;
  244.             } else {
  245.                 // This is an HTML element delimiter.
  246.  
  247.                 // Replace each & with & unless it already looks like an entity.
  248.                 $curl = preg_replace( '/&(?!#(?:\d+|x[a-f0-9]+);|[a-z1-4]{1,8};)/i', '&', $curl );
  249.  
  250.                 _wptexturize_pushpop_element( $curl, $no_texturize_tags_stack, $no_texturize_tags );
  251.             }
  252.  
  253.         } elseif ( '' === trim( $curl ) ) {
  254.             // This is a newline between delimiters.  Performance improves when we check this.
  255.             continue;
  256.  
  257.         } elseif ( '[' === $first && $found_shortcodes && 1 === preg_match( '/^' . $shortcode_regex . '$/', $curl ) ) {
  258.             // This is a shortcode delimiter.
  259.  
  260.             if ( '[[' !== substr( $curl, 0, 2 ) && ']]' !== substr( $curl, -2 ) ) {
  261.                 // Looks like a normal shortcode.
  262.                 _wptexturize_pushpop_element( $curl, $no_texturize_shortcodes_stack, $no_texturize_shortcodes );
  263.             } else {
  264.                 // Looks like an escaped shortcode.
  265.                 continue;
  266.             }
  267.  
  268.         } elseif ( empty( $no_texturize_shortcodes_stack ) && empty( $no_texturize_tags_stack ) ) {
  269.             // This is neither a delimiter, nor is this content inside of no_texturize pairs.  Do texturize.
  270.  
  271.             $curl = str_replace( $static_characters, $static_replacements, $curl );
  272.  
  273.             if ( false !== strpos( $curl, "'" ) ) {
  274.                 $curl = preg_replace( $dynamic_characters['apos'], $dynamic_replacements['apos'], $curl );
  275.                 $curl = wptexturize_primes( $curl, "'", $prime, $open_sq_flag, $closing_single_quote );
  276.                 $curl = str_replace( $apos_flag, $apos, $curl );
  277.                 $curl = str_replace( $open_sq_flag, $opening_single_quote, $curl );
  278.             }
  279.             if ( false !== strpos( $curl, '"' ) ) {
  280.                 $curl = preg_replace( $dynamic_characters['quote'], $dynamic_replacements['quote'], $curl );
  281.                 $curl = wptexturize_primes( $curl, '"', $double_prime, $open_q_flag, $closing_quote );
  282.                 $curl = str_replace( $open_q_flag, $opening_quote, $curl );
  283.             }
  284.             if ( false !== strpos( $curl, '-' ) ) {
  285.                 $curl = preg_replace( $dynamic_characters['dash'], $dynamic_replacements['dash'], $curl );
  286.             }
  287.  
  288.             // 9x9 (times), but never 0x9999
  289.             if ( 1 === preg_match( '/(?<=\d)x\d/', $curl ) ) {
  290.                 // Searching for a digit is 10 times more expensive than for the x, so we avoid doing this one!
  291.                 $curl = preg_replace( '/\b(\d(?(?<=0)[\d\.,]+|[\d\.,]*))x(\d[\d\.,]*)\b/', '$1×$2', $curl );
  292.             }
  293.  
  294.             // Replace each & with & unless it already looks like an entity.
  295.             $curl = preg_replace( '/&(?!#(?:\d+|x[a-f0-9]+);|[a-z1-4]{1,8};)/i', '&', $curl );
  296.         }
  297.     }
  298.  
  299.     return implode( '', $textarr );
  300. }
  301.  
  302. /**
  303.  * Implements a logic tree to determine whether or not "7'." represents seven feet,
  304.  * then converts the special char into either a prime char or a closing quote char.
  305.  *
  306.  * @since 4.3.0
  307.  *
  308.  * @param string $haystack    The plain text to be searched.
  309.  * @param string $needle      The character to search for such as ' or ".
  310.  * @param string $prime       The prime char to use for replacement.
  311.  * @param string $open_quote  The opening quote char. Opening quote replacement must be
  312.  *                            accomplished already.
  313.  * @param string $close_quote The closing quote char to use for replacement.
  314.  * @return string The $haystack value after primes and quotes replacements.
  315.  */
  316. function wptexturize_primes( $haystack, $needle, $prime, $open_quote, $close_quote ) {
  317.     $spaces = wp_spaces_regexp();
  318.     $flag = '<!--wp-prime-or-quote-->';
  319.     $quote_pattern = "/$needle(?=\\Z|[.,:;!?)}\\-\\]]|>|" . $spaces . ")/";
  320.     $prime_pattern    = "/(?<=\\d)$needle/";
  321.     $flag_after_digit = "/(?<=\\d)$flag/";
  322.     $flag_no_digit    = "/(?<!\\d)$flag/";
  323.  
  324.     $sentences = explode( $open_quote, $haystack );
  325.  
  326.     foreach ( $sentences as $key => &$sentence ) {
  327.         if ( false === strpos( $sentence, $needle ) ) {
  328.             continue;
  329.         } elseif ( 0 !== $key && 0 === substr_count( $sentence, $close_quote ) ) {
  330.             $sentence = preg_replace( $quote_pattern, $flag, $sentence, -1, $count );
  331.             if ( $count > 1 ) {
  332.                 // This sentence appears to have multiple closing quotes.  Attempt Vulcan logic.
  333.                 $sentence = preg_replace( $flag_no_digit, $close_quote, $sentence, -1, $count2 );
  334.                 if ( 0 === $count2 ) {
  335.                     // Try looking for a quote followed by a period.
  336.                     $count2 = substr_count( $sentence, "$flag." );
  337.                     if ( $count2 > 0 ) {
  338.                         // Assume the rightmost quote-period match is the end of quotation.
  339.                         $pos = strrpos( $sentence, "$flag." );
  340.                     } else {
  341.                         // When all else fails, make the rightmost candidate a closing quote.
  342.                         // This is most likely to be problematic in the context of bug #18549.
  343.                         $pos = strrpos( $sentence, $flag );
  344.                     }
  345.                     $sentence = substr_replace( $sentence, $close_quote, $pos, strlen( $flag ) );
  346.                 }
  347.                 // Use conventional replacement on any remaining primes and quotes.
  348.                 $sentence = preg_replace( $prime_pattern, $prime, $sentence );
  349.                 $sentence = preg_replace( $flag_after_digit, $prime, $sentence );
  350.                 $sentence = str_replace( $flag, $close_quote, $sentence );
  351.             } elseif ( 1 == $count ) {
  352.                 // Found only one closing quote candidate, so give it priority over primes.
  353.                 $sentence = str_replace( $flag, $close_quote, $sentence );
  354.                 $sentence = preg_replace( $prime_pattern, $prime, $sentence );
  355.             } else {
  356.                 // No closing quotes found.  Just run primes pattern.
  357.                 $sentence = preg_replace( $prime_pattern, $prime, $sentence );
  358.             }
  359.         } else {
  360.             $sentence = preg_replace( $prime_pattern, $prime, $sentence );
  361.             $sentence = preg_replace( $quote_pattern, $close_quote, $sentence );
  362.         }
  363.         if ( '"' == $needle && false !== strpos( $sentence, '"' ) ) {
  364.             $sentence = str_replace( '"', $close_quote, $sentence );
  365.         }
  366.     }
  367.  
  368.     return implode( $open_quote, $sentences );
  369. }
  370.  
  371. /**
  372.  * Search for disabled element tags. Push element to stack on tag open and pop
  373.  * on tag close.
  374.  *
  375.  * Assumes first char of $text is tag opening and last char is tag closing.
  376.  * Assumes second char of $text is optionally '/' to indicate closing as in </html>.
  377.  *
  378.  * @since 2.9.0
  379.  * @access private
  380.  *
  381.  * @param string $text Text to check. Must be a tag like `<html>` or `[shortcode]`.
  382.  * @param array  $stack List of open tag elements.
  383.  * @param array  $disabled_elements The tag names to match against. Spaces are not allowed in tag names.
  384.  */
  385. function _wptexturize_pushpop_element( $text, &$stack, $disabled_elements ) {
  386.     // Is it an opening tag or closing tag?
  387.     if ( isset( $text[1] ) && '/' !== $text[1] ) {
  388.         $opening_tag = true;
  389.         $name_offset = 1;
  390.     } elseif ( 0 == count( $stack ) ) {
  391.         // Stack is empty. Just stop.
  392.         return;
  393.     } else {
  394.         $opening_tag = false;
  395.         $name_offset = 2;
  396.     }
  397.  
  398.     // Parse out the tag name.
  399.     $space = strpos( $text, ' ' );
  400.     if ( false === $space ) {
  401.         $space = -1;
  402.     } else {
  403.         $space -= $name_offset;
  404.     }
  405.     $tag = substr( $text, $name_offset, $space );
  406.  
  407.     // Handle disabled tags.
  408.     if ( in_array( $tag, $disabled_elements ) ) {
  409.         if ( $opening_tag ) {
  410.             /*
  411.              * This disables texturize until we find a closing tag of our type
  412.              * (e.g. <pre>) even if there was invalid nesting before that
  413.              *
  414.              * Example: in the case <pre>sadsadasd</code>"baba"</pre>
  415.              *          "baba" won't be texturize
  416.              */
  417.  
  418.             array_push( $stack, $tag );
  419.         } elseif ( end( $stack ) == $tag ) {
  420.             array_pop( $stack );
  421.         }
  422.     }
  423. }
  424.  
  425. /**
  426.  * Replaces double line-breaks with paragraph elements.
  427.  *
  428.  * A group of regex replaces used to identify text formatted with newlines and
  429.  * replace double line-breaks with HTML paragraph tags. The remaining line-breaks
  430.  * after conversion become <<br />> tags, unless $br is set to '0' or 'false'.
  431.  *
  432.  * @since 0.71
  433.  *
  434.  * @param string $pee The text which has to be formatted.
  435.  * @param bool   $br  Optional. If set, this will convert all remaining line-breaks
  436.  *                    after paragraphing. Default true.
  437.  * @return string Text which has been converted into correct paragraph tags.
  438.  */
  439. function wpautop( $pee, $br = true ) {
  440.     $pre_tags = array();
  441.  
  442.     if ( trim($pee) === '' )
  443.         return '';
  444.  
  445.     // Just to make things a little easier, pad the end.
  446.     $pee = $pee . "\n";
  447.  
  448.     /*
  449.      * Pre tags shouldn't be touched by autop.
  450.      * Replace pre tags with placeholders and bring them back after autop.
  451.      */
  452.     if ( strpos($pee, '<pre') !== false ) {
  453.         $pee_parts = explode( '</pre>', $pee );
  454.         $last_pee = array_pop($pee_parts);
  455.         $pee = '';
  456.         $i = 0;
  457.  
  458.         foreach ( $pee_parts as $pee_part ) {
  459.             $start = strpos($pee_part, '<pre');
  460.  
  461.             // Malformed html?
  462.             if ( $start === false ) {
  463.                 $pee .= $pee_part;
  464.                 continue;
  465.             }
  466.  
  467.             $name = "<pre wp-pre-tag-$i></pre>";
  468.             $pre_tags[$name] = substr( $pee_part, $start ) . '</pre>';
  469.  
  470.             $pee .= substr( $pee_part, 0, $start ) . $name;
  471.             $i++;
  472.         }
  473.  
  474.         $pee .= $last_pee;
  475.     }
  476.     // Change multiple <br>s into two line breaks, which will turn into paragraphs.
  477.     $pee = preg_replace('|<br\s*/?>\s*<br\s*/?>|', "\n\n", $pee);
  478.  
  479.     $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)';
  480.  
  481.     // Add a double line break above block-level opening tags.
  482.     $pee = preg_replace('!(<' . $allblocks . '[\s/>])!', "\n\n$1", $pee);
  483.  
  484.     // Add a double line break below block-level closing tags.
  485.     $pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
  486.  
  487.     // Standardize newline characters to "\n".
  488.     $pee = str_replace(array("\r\n", "\r"), "\n", $pee);
  489.  
  490.     // Find newlines in all elements and add placeholders.
  491.     $pee = wp_replace_in_html_tags( $pee, array( "\n" => " <!-- wpnl --> " ) );
  492.  
  493.     // Collapse line breaks before and after <option> elements so they don't get autop'd.
  494.     if ( strpos( $pee, '<option' ) !== false ) {
  495.         $pee = preg_replace( '|\s*<option|', '<option', $pee );
  496.         $pee = preg_replace( '|</option>\s*|', '</option>', $pee );
  497.     }
  498.  
  499.     /*
  500.      * Collapse line breaks inside <object> elements, before <param> and <embed> elements
  501.      * so they don't get autop'd.
  502.      */
  503.     if ( strpos( $pee, '</object>' ) !== false ) {
  504.         $pee = preg_replace( '|(<object[^>]*>)\s*|', '$1', $pee );
  505.         $pee = preg_replace( '|\s*</object>|', '</object>', $pee );
  506.         $pee = preg_replace( '%\s*(</?(?:param|embed)[^>]*>)\s*%', '$1', $pee );
  507.     }
  508.  
  509.     /*
  510.      * Collapse line breaks inside <audio> and <video> elements,
  511.      * before and after <source> and <track> elements.
  512.      */
  513.     if ( strpos( $pee, '<source' ) !== false || strpos( $pee, '<track' ) !== false ) {
  514.         $pee = preg_replace( '%([<\[](?:audio|video)[^>\]]*[>\]])\s*%', '$1', $pee );
  515.         $pee = preg_replace( '%\s*([<\[]/(?:audio|video)[>\]])%', '$1', $pee );
  516.         $pee = preg_replace( '%\s*(<(?:source|track)[^>]*>)\s*%', '$1', $pee );
  517.     }
  518.  
  519.     // Collapse line breaks before and after <figcaption> elements.
  520.     if ( strpos( $pee, '<figcaption' ) !== false ) {
  521.         $pee = preg_replace( '|\s*(<figcaption[^>]*>)|', '$1', $pee );
  522.         $pee = preg_replace( '|</figcaption>\s*|', '</figcaption>', $pee );
  523.     }
  524.  
  525.     // Remove more than two contiguous line breaks.
  526.     $pee = preg_replace("/\n\n+/", "\n\n", $pee);
  527.  
  528.     // Split up the contents into an array of strings, separated by double line breaks.
  529.     $pees = preg_split('/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY);
  530.  
  531.     // Reset $pee prior to rebuilding.
  532.     $pee = '';
  533.  
  534.     // Rebuild the content as a string, wrapping every bit with a <p>.
  535.     foreach ( $pees as $tinkle ) {
  536.         $pee .= '<p>' . trim($tinkle, "\n") . "</p>\n";
  537.     }
  538.  
  539.     // Under certain strange conditions it could create a P of entirely whitespace.
  540.     $pee = preg_replace('|<p>\s*</p>|', '', $pee);
  541.  
  542.     // Add a closing <p> inside <div>, <address>, or <form> tag if missing.
  543.     $pee = preg_replace('!<p>([^<]+)</(div|address|form)>!', "<p>$1</p></$2>", $pee);
  544.  
  545.     // If an opening or closing block element tag is wrapped in a <p>, unwrap it.
  546.     $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
  547.  
  548.     // In some cases <li> may get wrapped in <p>, fix them.
  549.     $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee);
  550.  
  551.     // If a <blockquote> is wrapped with a <p>, move it inside the <blockquote>.
  552.     $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
  553.     $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
  554.  
  555.     // If an opening or closing block element tag is preceded by an opening <p> tag, remove it.
  556.     $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
  557.  
  558.     // If an opening or closing block element tag is followed by a closing <p> tag, remove it.
  559.     $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
  560.  
  561.     // Optionally insert line breaks.
  562.     if ( $br ) {
  563.         // Replace newlines that shouldn't be touched with a placeholder.
  564.         $pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', '_autop_newline_preservation_helper', $pee);
  565.  
  566.         // Normalize <br>
  567.         $pee = str_replace( array( '<br>', '<br/>' ), '<br />', $pee );
  568.  
  569.         // Replace any new line characters that aren't preceded by a <br /> with a <br />.
  570.         $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee);
  571.  
  572.         // Replace newline placeholders with newlines.
  573.         $pee = str_replace('<WPPreserveNewline />', "\n", $pee);
  574.     }
  575.  
  576.     // If a <br /> tag is after an opening or closing block tag, remove it.
  577.     $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
  578.  
  579.     // If a <br /> tag is before a subset of opening or closing block tags, remove it.
  580.     $pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
  581.     $pee = preg_replace( "|\n</p>$|", '</p>', $pee );
  582.  
  583.     // Replace placeholder <pre> tags with their original content.
  584.     if ( !empty($pre_tags) )
  585.         $pee = str_replace(array_keys($pre_tags), array_values($pre_tags), $pee);
  586.  
  587.     // Restore newlines in all elements.
  588.     if ( false !== strpos( $pee, '<!-- wpnl -->' ) ) {
  589.         $pee = str_replace( array( ' <!-- wpnl --> ', '<!-- wpnl -->' ), "\n", $pee );
  590.     }
  591.  
  592.     return $pee;
  593. }
  594.  
  595. /**
  596.  * Separate HTML elements and comments from the text.
  597.  *
  598.  * @since 4.2.4
  599.  *
  600.  * @param string $input The text which has to be formatted.
  601.  * @return array The formatted text.
  602.  */
  603. function wp_html_split( $input ) {
  604.     return preg_split( get_html_split_regex(), $input, -1, PREG_SPLIT_DELIM_CAPTURE );
  605. }
  606.  
  607. /**
  608.  * Retrieve the regular expression for an HTML element.
  609.  *
  610.  * @since 4.4.0
  611.  *
  612.  * @staticvar string $regex
  613.  *
  614.  * @return string The regular expression
  615.  */
  616. function get_html_split_regex() {
  617.     static $regex;
  618.  
  619.     if ( ! isset( $regex ) ) {
  620.         $comments =
  621.               '!'           // Start of comment, after the <.
  622.             . '(?:'         // Unroll the loop: Consume everything until --> is found.
  623.             .     '-(?!->)' // Dash not followed by end of comment.
  624.             .     '[^\-]*+' // Consume non-dashes.
  625.             . ')*+'         // Loop possessively.
  626.             . '(?:-->)?';   // End of comment. If not found, match all input.
  627.  
  628.         $cdata =
  629.               '!\[CDATA\['  // Start of comment, after the <.
  630.             . '[^\]]*+'     // Consume non-].
  631.             . '(?:'         // Unroll the loop: Consume everything until ]]> is found.
  632.             .     '](?!]>)' // One ] not followed by end of comment.
  633.             .     '[^\]]*+' // Consume non-].
  634.             . ')*+'         // Loop possessively.
  635.             . '(?:]]>)?';   // End of comment. If not found, match all input.
  636.  
  637.         $escaped =
  638.               '(?='           // Is the element escaped?
  639.             .    '!--'
  640.             . '|'
  641.             .    '!\[CDATA\['
  642.             . ')'
  643.             . '(?(?=!-)'      // If yes, which type?
  644.             .     $comments
  645.             . '|'
  646.             .     $cdata
  647.             . ')';
  648.  
  649.         $regex =
  650.               '/('              // Capture the entire match.
  651.             .     '<'           // Find start of element.
  652.             .     '(?'          // Conditional expression follows.
  653.             .         $escaped  // Find end of escaped element.
  654.             .     '|'           // ... else ...
  655.             .         '[^>]*>?' // Find end of normal element.
  656.             .     ')'
  657.             . ')/';
  658.     }
  659.  
  660.     return $regex;
  661. }
  662.  
  663. /**
  664.  * Retrieve the combined regular expression for HTML and shortcodes.
  665.  *
  666.  * @access private
  667.  * @ignore
  668.  * @internal This function will be removed in 4.5.0 per Shortcode API Roadmap.
  669.  * @since 4.4.0
  670.  *
  671.  * @staticvar string $html_regex
  672.  *
  673.  * @param string $shortcode_regex The result from _get_wptexturize_shortcode_regex().  Optional.
  674.  * @return string The regular expression
  675.  */
  676. function _get_wptexturize_split_regex( $shortcode_regex = '' ) {
  677.     static $html_regex;
  678.  
  679.     if ( ! isset( $html_regex ) ) {
  680.         $comment_regex =
  681.               '!'           // Start of comment, after the <.
  682.             . '(?:'         // Unroll the loop: Consume everything until --> is found.
  683.             .     '-(?!->)' // Dash not followed by end of comment.
  684.             .     '[^\-]*+' // Consume non-dashes.
  685.             . ')*+'         // Loop possessively.
  686.             . '(?:-->)?';   // End of comment. If not found, match all input.
  687.  
  688.         $html_regex =             // Needs replaced with wp_html_split() per Shortcode API Roadmap.
  689.               '<'                // Find start of element.
  690.             . '(?(?=!--)'        // Is this a comment?
  691.             .     $comment_regex // Find end of comment.
  692.             . '|'
  693.             .     '[^>]*>?'      // Find end of element. If not found, match all input.
  694.             . ')';
  695.     }
  696.  
  697.     if ( empty( $shortcode_regex ) ) {
  698.         $regex = '/(' . $html_regex . ')/';
  699.     } else {
  700.         $regex = '/(' . $html_regex . '|' . $shortcode_regex . ')/';
  701.     }
  702.  
  703.     return $regex;
  704. }
  705.  
  706. /**
  707.  * Retrieve the regular expression for shortcodes.
  708.  *
  709.  * @access private
  710.  * @ignore
  711.  * @internal This function will be removed in 4.5.0 per Shortcode API Roadmap.
  712.  * @since 4.4.0
  713.  *
  714.  * @param array $tagnames List of shortcodes to find.
  715.  * @return string The regular expression
  716.  */
  717. function _get_wptexturize_shortcode_regex( $tagnames ) {
  718.     $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) );
  719.     $tagregexp = "(?:$tagregexp)(?=[\\s\\]\\/])"; // Excerpt of get_shortcode_regex().
  720.     $regex =
  721.           '\['              // Find start of shortcode.
  722.         . '[\/\[]?'         // Shortcodes may begin with [/ or [[
  723.         . $tagregexp        // Only match registered shortcodes, because performance.
  724.         . '(?:'
  725.         .     '[^\[\]<>]+'  // Shortcodes do not contain other shortcodes. Quantifier critical.
  726.         . '|'
  727.         .     '<[^\[\]>]*>' // HTML elements permitted. Prevents matching ] before >.
  728.         . ')*+'             // Possessive critical.
  729.         . '\]'              // Find end of shortcode.
  730.         . '\]?';            // Shortcodes may end with ]]
  731.  
  732.     return $regex;
  733. }
  734.  
  735. /**
  736.  * Replace characters or phrases within HTML elements only.
  737.  *
  738.  * @since 4.2.3
  739.  *
  740.  * @param string $haystack The text which has to be formatted.
  741.  * @param array $replace_pairs In the form array('from' => 'to', ...).
  742.  * @return string The formatted text.
  743.  */
  744. function wp_replace_in_html_tags( $haystack, $replace_pairs ) {
  745.     // Find all elements.
  746.     $textarr = wp_html_split( $haystack );
  747.     $changed = false;
  748.  
  749.     // Optimize when searching for one item.
  750.     if ( 1 === count( $replace_pairs ) ) {
  751.         // Extract $needle and $replace.
  752.         foreach ( $replace_pairs as $needle => $replace );
  753.  
  754.         // Loop through delimiters (elements) only.
  755.         for ( $i = 1, $c = count( $textarr ); $i < $c; $i += 2 ) {
  756.             if ( false !== strpos( $textarr[$i], $needle ) ) {
  757.                 $textarr[$i] = str_replace( $needle, $replace, $textarr[$i] );
  758.                 $changed = true;
  759.             }
  760.         }
  761.     } else {
  762.         // Extract all $needles.
  763.         $needles = array_keys( $replace_pairs );
  764.  
  765.         // Loop through delimiters (elements) only.
  766.         for ( $i = 1, $c = count( $textarr ); $i < $c; $i += 2 ) {
  767.             foreach ( $needles as $needle ) {
  768.                 if ( false !== strpos( $textarr[$i], $needle ) ) {
  769.                     $textarr[$i] = strtr( $textarr[$i], $replace_pairs );
  770.                     $changed = true;
  771.                     // After one strtr() break out of the foreach loop and look at next element.
  772.                     break;
  773.                 }
  774.             }
  775.         }
  776.     }
  777.  
  778.     if ( $changed ) {
  779.         $haystack = implode( $textarr );
  780.     }
  781.  
  782.     return $haystack;
  783. }
  784.  
  785. /**
  786.  * Newline preservation help function for wpautop
  787.  *
  788.  * @since 3.1.0
  789.  * @access private
  790.  *
  791.  * @param array $matches preg_replace_callback matches array
  792.  * @return string
  793.  */
  794. function _autop_newline_preservation_helper( $matches ) {
  795.     return str_replace( "\n", "<WPPreserveNewline />", $matches[0] );
  796. }
  797.  
  798. /**
  799.  * Don't auto-p wrap shortcodes that stand alone
  800.  *
  801.  * Ensures that shortcodes are not wrapped in `<p>...</p>`.
  802.  *
  803.  * @since 2.9.0
  804.  *
  805.  * @global array $shortcode_tags
  806.  *
  807.  * @param string $pee The content.
  808.  * @return string The filtered content.
  809.  */
  810. function shortcode_unautop( $pee ) {
  811.     global $shortcode_tags;
  812.  
  813.     if ( empty( $shortcode_tags ) || !is_array( $shortcode_tags ) ) {
  814.         return $pee;
  815.     }
  816.  
  817.     $tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags ) ) );
  818.     $spaces = wp_spaces_regexp();
  819.  
  820.     $pattern =
  821.           '/'
  822.         . '<p>'                              // Opening paragraph
  823.         . '(?:' . $spaces . ')*+'            // Optional leading whitespace
  824.         . '('                                // 1: The shortcode
  825.         .     '\\['                          // Opening bracket
  826.         .     "($tagregexp)"                 // 2: Shortcode name
  827.         .     '(?![\\w-])'                   // Not followed by word character or hyphen
  828.                                              // Unroll the loop: Inside the opening shortcode tag
  829.         .     '[^\\]\\/]*'                   // Not a closing bracket or forward slash
  830.         .     '(?:'
  831.         .         '\\/(?!\\])'               // A forward slash not followed by a closing bracket
  832.         .         '[^\\]\\/]*'               // Not a closing bracket or forward slash
  833.         .     ')*?'
  834.         .     '(?:'
  835.         .         '\\/\\]'                   // Self closing tag and closing bracket
  836.         .     '|'
  837.         .         '\\]'                      // Closing bracket
  838.         .         '(?:'                      // Unroll the loop: Optionally, anything between the opening and closing shortcode tags
  839.         .             '[^\\[]*+'             // Not an opening bracket
  840.         .             '(?:'
  841.         .                 '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag
  842.         .                 '[^\\[]*+'         // Not an opening bracket
  843.         .             ')*+'
  844.         .             '\\[\\/\\2\\]'         // Closing shortcode tag
  845.         .         ')?'
  846.         .     ')'
  847.         . ')'
  848.         . '(?:' . $spaces . ')*+'            // optional trailing whitespace
  849.         . '<\\/p>'                           // closing paragraph
  850.         . '/';
  851.  
  852.     return preg_replace( $pattern, '$1', $pee );
  853. }
  854.  
  855. /**
  856.  * Checks to see if a string is utf8 encoded.
  857.  *
  858.  * NOTE: This function checks for 5-Byte sequences, UTF8
  859.  *       has Bytes Sequences with a maximum length of 4.
  860.  *
  861.  * @author bmorel at ssi dot fr (modified)
  862.  * @since 1.2.1
  863.  *
  864.  * @param string $str The string to be checked
  865.  * @return bool True if $str fits a UTF-8 model, false otherwise.
  866.  */
  867. function seems_utf8( $str ) {
  868.     mbstring_binary_safe_encoding();
  869.     $length = strlen($str);
  870.     reset_mbstring_encoding();
  871.     for ($i=0; $i < $length; $i++) {
  872.         $c = ord($str[$i]);
  873.         if ($c < 0x80) $n = 0; // 0bbbbbbb
  874.         elseif (($c & 0xE0) == 0xC0) $n=1; // 110bbbbb
  875.         elseif (($c & 0xF0) == 0xE0) $n=2; // 1110bbbb
  876.         elseif (($c & 0xF8) == 0xF0) $n=3; // 11110bbb
  877.         elseif (($c & 0xFC) == 0xF8) $n=4; // 111110bb
  878.         elseif (($c & 0xFE) == 0xFC) $n=5; // 1111110b
  879.         else return false; // Does not match any model
  880.         for ($j=0; $j<$n; $j++) { // n bytes matching 10bbbbbb follow ?
  881.             if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
  882.                 return false;
  883.         }
  884.     }
  885.     return true;
  886. }
  887.  
  888. /**
  889.  * Converts a number of special characters into their HTML entities.
  890.  *
  891.  * Specifically deals with: &, <, >, ", and '.
  892.  *
  893.  * $quote_style can be set to ENT_COMPAT to encode " to
  894.  * ", or ENT_QUOTES to do both. Default is ENT_NOQUOTES where no quotes are encoded.
  895.  *
  896.  * @since 1.2.2
  897.  * @access private
  898.  *
  899.  * @staticvar string $_charset
  900.  *
  901.  * @param string     $string         The text which is to be encoded.
  902.  * @param int|string $quote_style    Optional. Converts double quotes if set to ENT_COMPAT,
  903.  *                                   both single and double if set to ENT_QUOTES or none if set to ENT_NOQUOTES.
  904.  *                                   Also compatible with old values; converting single quotes if set to 'single',
  905.  *                                   double if set to 'double' or both if otherwise set.
  906.  *                                   Default is ENT_NOQUOTES.
  907.  * @param string     $charset        Optional. The character encoding of the string. Default is false.
  908.  * @param bool       $double_encode  Optional. Whether to encode existing html entities. Default is false.
  909.  * @return string The encoded text with HTML entities.
  910.  */
  911. function _wp_specialchars( $string, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false ) {
  912.     $string = (string) $string;
  913.  
  914.     if ( 0 === strlen( $string ) )
  915.         return '';
  916.  
  917.     // Don't bother if there are no specialchars - saves some processing
  918.     if ( ! preg_match( '/[&<>"\']/', $string ) )
  919.         return $string;
  920.  
  921.     // Account for the previous behaviour of the function when the $quote_style is not an accepted value
  922.     if ( empty( $quote_style ) )
  923.         $quote_style = ENT_NOQUOTES;
  924.     elseif ( ! in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) )
  925.         $quote_style = ENT_QUOTES;
  926.  
  927.     // Store the site charset as a static to avoid multiple calls to wp_load_alloptions()
  928.     if ( ! $charset ) {
  929.         static $_charset = null;
  930.         if ( ! isset( $_charset ) ) {
  931.             $alloptions = wp_load_alloptions();
  932.             $_charset = isset( $alloptions['blog_charset'] ) ? $alloptions['blog_charset'] : '';
  933.         }
  934.         $charset = $_charset;
  935.     }
  936.  
  937.     if ( in_array( $charset, array( 'utf8', 'utf-8', 'UTF8' ) ) )
  938.         $charset = 'UTF-8';
  939.  
  940.     $_quote_style = $quote_style;
  941.  
  942.     if ( $quote_style === 'double' ) {
  943.         $quote_style = ENT_COMPAT;
  944.         $_quote_style = ENT_COMPAT;
  945.     } elseif ( $quote_style === 'single' ) {
  946.         $quote_style = ENT_NOQUOTES;
  947.     }
  948.  
  949.     if ( ! $double_encode ) {
  950.         // Guarantee every &entity; is valid, convert &garbage; into &garbage;
  951.         // This is required for PHP < 5.4.0 because ENT_HTML401 flag is unavailable.
  952.         $string = wp_kses_normalize_entities( $string );
  953.     }
  954.  
  955.     $string = @htmlspecialchars( $string, $quote_style, $charset, $double_encode );
  956.  
  957.     // Back-compat.
  958.     if ( 'single' === $_quote_style )
  959.         $string = str_replace( "'", ''', $string );
  960.  
  961.     return $string;
  962. }
  963.  
  964. /**
  965.  * Converts a number of HTML entities into their special characters.
  966.  *
  967.  * Specifically deals with: &, <, >, ", and '.
  968.  *
  969.  * $quote_style can be set to ENT_COMPAT to decode " entities,
  970.  * or ENT_QUOTES to do both " and '. Default is ENT_NOQUOTES where no quotes are decoded.
  971.  *
  972.  * @since 2.8.0
  973.  *
  974.  * @param string     $string The text which is to be decoded.
  975.  * @param string|int $quote_style Optional. Converts double quotes if set to ENT_COMPAT,
  976.  *                                both single and double if set to ENT_QUOTES or
  977.  *                                none if set to ENT_NOQUOTES.
  978.  *                                Also compatible with old _wp_specialchars() values;
  979.  *                                converting single quotes if set to 'single',
  980.  *                                double if set to 'double' or both if otherwise set.
  981.  *                                Default is ENT_NOQUOTES.
  982.  * @return string The decoded text without HTML entities.
  983.  */
  984. function wp_specialchars_decode( $string, $quote_style = ENT_NOQUOTES ) {
  985.     $string = (string) $string;
  986.  
  987.     if ( 0 === strlen( $string ) ) {
  988.         return '';
  989.     }
  990.  
  991.     // Don't bother if there are no entities - saves a lot of processing
  992.     if ( strpos( $string, '&' ) === false ) {
  993.         return $string;
  994.     }
  995.  
  996.     // Match the previous behaviour of _wp_specialchars() when the $quote_style is not an accepted value
  997.     if ( empty( $quote_style ) ) {
  998.         $quote_style = ENT_NOQUOTES;
  999.     } elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) {
  1000.         $quote_style = ENT_QUOTES;
  1001.     }
  1002.  
  1003.     // More complete than get_html_translation_table( HTML_SPECIALCHARS )
  1004.     $single = array( '''  => '\'', ''' => '\'' );
  1005.     $single_preg = array( '/�*39;/'  => ''', '/�*27;/i' => ''' );
  1006.     $double = array( '"' => '"', '"'  => '"', '"' => '"' );
  1007.     $double_preg = array( '/�*34;/'  => '"', '/�*22;/i' => '"' );
  1008.     $others = array( '<'   => '<', '<'  => '<', '>'   => '>', '>'  => '>', '&'  => '&', '&'  => '&', '&' => '&' );
  1009.     $others_preg = array( '/�*60;/'  => '<', '/�*62;/'  => '>', '/�*38;/'  => '&', '/�*26;/i' => '&' );
  1010.  
  1011.     if ( $quote_style === ENT_QUOTES ) {
  1012.         $translation = array_merge( $single, $double, $others );
  1013.         $translation_preg = array_merge( $single_preg, $double_preg, $others_preg );
  1014.     } elseif ( $quote_style === ENT_COMPAT || $quote_style === 'double' ) {
  1015.         $translation = array_merge( $double, $others );
  1016.         $translation_preg = array_merge( $double_preg, $others_preg );
  1017.     } elseif ( $quote_style === 'single' ) {
  1018.         $translation = array_merge( $single, $others );
  1019.         $translation_preg = array_merge( $single_preg, $others_preg );
  1020.     } elseif ( $quote_style === ENT_NOQUOTES ) {
  1021.         $translation = $others;
  1022.         $translation_preg = $others_preg;
  1023.     }
  1024.  
  1025.     // Remove zero padding on numeric entities
  1026.     $string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string );
  1027.  
  1028.     // Replace characters according to translation table
  1029.     return strtr( $string, $translation );
  1030. }
  1031.  
  1032. /**
  1033.  * Checks for invalid UTF8 in a string.
  1034.  *
  1035.  * @since 2.8.0
  1036.  *
  1037.  * @staticvar bool $is_utf8
  1038.  * @staticvar bool $utf8_pcre
  1039.  *
  1040.  * @param string  $string The text which is to be checked.
  1041.  * @param bool    $strip Optional. Whether to attempt to strip out invalid UTF8. Default is false.
  1042.  * @return string The checked text.
  1043.  */
  1044. function wp_check_invalid_utf8( $string, $strip = false ) {
  1045.     $string = (string) $string;
  1046.  
  1047.     if ( 0 === strlen( $string ) ) {
  1048.         return '';
  1049.     }
  1050.  
  1051.     // Store the site charset as a static to avoid multiple calls to get_option()
  1052.     static $is_utf8 = null;
  1053.     if ( ! isset( $is_utf8 ) ) {
  1054.         $is_utf8 = in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) );
  1055.     }
  1056.     if ( ! $is_utf8 ) {
  1057.         return $string;
  1058.     }
  1059.  
  1060.     // Check for support for utf8 in the installed PCRE library once and store the result in a static
  1061.     static $utf8_pcre = null;
  1062.     if ( ! isset( $utf8_pcre ) ) {
  1063.         $utf8_pcre = @preg_match( '/^./u', 'a' );
  1064.     }
  1065.     // We can't demand utf8 in the PCRE installation, so just return the string in those cases
  1066.     if ( !$utf8_pcre ) {
  1067.         return $string;
  1068.     }
  1069.  
  1070.     // preg_match fails when it encounters invalid UTF8 in $string
  1071.     if ( 1 === @preg_match( '/^./us', $string ) ) {
  1072.         return $string;
  1073.     }
  1074.  
  1075.     // Attempt to strip the bad chars if requested (not recommended)
  1076.     if ( $strip && function_exists( 'iconv' ) ) {
  1077.         return iconv( 'utf-8', 'utf-8', $string );
  1078.     }
  1079.  
  1080.     return '';
  1081. }
  1082.  
  1083. /**
  1084.  * Encode the Unicode values to be used in the URI.
  1085.  *
  1086.  * @since 1.5.0
  1087.  *
  1088.  * @param string $utf8_string
  1089.  * @param int    $length Max  length of the string
  1090.  * @return string String with Unicode encoded for URI.
  1091.  */
  1092. function utf8_uri_encode( $utf8_string, $length = 0 ) {
  1093.     $unicode = '';
  1094.     $values = array();
  1095.     $num_octets = 1;
  1096.     $unicode_length = 0;
  1097.  
  1098.     mbstring_binary_safe_encoding();
  1099.     $string_length = strlen( $utf8_string );
  1100.     reset_mbstring_encoding();
  1101.  
  1102.     for ($i = 0; $i < $string_length; $i++ ) {
  1103.  
  1104.         $value = ord( $utf8_string[ $i ] );
  1105.  
  1106.         if ( $value < 128 ) {
  1107.             if ( $length && ( $unicode_length >= $length ) )
  1108.                 break;
  1109.             $unicode .= chr($value);
  1110.             $unicode_length++;
  1111.         } else {
  1112.             if ( count( $values ) == 0 ) {
  1113.                 if ( $value < 224 ) {
  1114.                     $num_octets = 2;
  1115.                 } elseif ( $value < 240 ) {
  1116.                     $num_octets = 3;
  1117.                 } else {
  1118.                     $num_octets = 4;
  1119.                 }
  1120.             }
  1121.  
  1122.             $values[] = $value;
  1123.  
  1124.             if ( $length && ( $unicode_length + ($num_octets * 3) ) > $length )
  1125.                 break;
  1126.             if ( count( $values ) == $num_octets ) {
  1127.                 for ( $j = 0; $j < $num_octets; $j++ ) {
  1128.                     $unicode .= '%' . dechex( $values[ $j ] );
  1129.                 }
  1130.  
  1131.                 $unicode_length += $num_octets * 3;
  1132.  
  1133.                 $values = array();
  1134.                 $num_octets = 1;
  1135.             }
  1136.         }
  1137.     }
  1138.  
  1139.     return $unicode;
  1140. }
  1141.  
  1142. /**
  1143.  * Converts all accent characters to ASCII characters.
  1144.  *
  1145.  * If there are no accent characters, then the string given is just returned.
  1146.  *
  1147.  * **Accent characters converted:**
  1148.  *
  1149.  * Currency signs:
  1150.  *
  1151.  * |   Code   | Glyph | Replacement |     Description     |
  1152.  * | -------- | ----- | ----------- | ------------------- |
  1153.  * | U+00A3   | ┬ú     | (empty)     | British Pound sign  |
  1154.  * | U+20AC   | Γé¼     | E           | Euro sign           |
  1155.  *
  1156.  * Decompositions for Latin-1 Supplement:
  1157.  *
  1158.  * |  Code   | Glyph | Replacement |               Description              |
  1159.  * | ------- | ----- | ----------- | -------------------------------------- |
  1160.  * | U+00AA  | ┬¬     | a           | Feminine ordinal indicator             |
  1161.  * | U+00BA  | ┬║     | o           | Masculine ordinal indicator            |
  1162.  * | U+00C0  | ├Ç     | A           | Latin capital letter A with grave      |
  1163.  * | U+00C1  | ├ü     | A           | Latin capital letter A with acute      |
  1164.  * | U+00C2  | ├é     | A           | Latin capital letter A with circumflex |
  1165.  * | U+00C3  | ├â     | A           | Latin capital letter A with tilde      |
  1166.  * | U+00C4  | ├ä     | A           | Latin capital letter A with diaeresis  |
  1167.  * | U+00C5  | ├à     | A           | Latin capital letter A with ring above |
  1168.  * | U+00C6  | ├å     | AE          | Latin capital letter AE                |
  1169.  * | U+00C7  | ├ç     | C           | Latin capital letter C with cedilla    |
  1170.  * | U+00C8  | ├ê     | E           | Latin capital letter E with grave      |
  1171.  * | U+00C9  | ├ë     | E           | Latin capital letter E with acute      |
  1172.  * | U+00CA  | ├è     | E           | Latin capital letter E with circumflex |
  1173.  * | U+00CB  | ├ï     | E           | Latin capital letter E with diaeresis  |
  1174.  * | U+00CC  | ├î     | I           | Latin capital letter I with grave      |
  1175.  * | U+00CD  | ├ì     | I           | Latin capital letter I with acute      |
  1176.  * | U+00CE  | ├Ä     | I           | Latin capital letter I with circumflex |
  1177.  * | U+00CF  | ├Å     | I           | Latin capital letter I with diaeresis  |
  1178.  * | U+00D0  | ├É     | D           | Latin capital letter Eth               |
  1179.  * | U+00D1  | ├æ     | N           | Latin capital letter N with tilde      |
  1180.  * | U+00D2  | ├Æ     | O           | Latin capital letter O with grave      |
  1181.  * | U+00D3  | ├ô     | O           | Latin capital letter O with acute      |
  1182.  * | U+00D4  | ├ö     | O           | Latin capital letter O with circumflex |
  1183.  * | U+00D5  | ├ò     | O           | Latin capital letter O with tilde      |
  1184.  * | U+00D6  | ├û     | O           | Latin capital letter O with diaeresis  |
  1185.  * | U+00D8  | ├ÿ     | O           | Latin capital letter O with stroke     |
  1186.  * | U+00D9  | ├Ö     | U           | Latin capital letter U with grave      |
  1187.  * | U+00DA  | ├Ü     | U           | Latin capital letter U with acute      |
  1188.  * | U+00DB  | ├¢     | U           | Latin capital letter U with circumflex |
  1189.  * | U+00DC  | ├£     | U           | Latin capital letter U with diaeresis  |
  1190.  * | U+00DD  | ├¥     | Y           | Latin capital letter Y with acute      |
  1191.  * | U+00DE  | ├₧     | TH          | Latin capital letter Thorn             |
  1192.  * | U+00DF  | ├ƒ     | s           | Latin small letter sharp s             |
  1193.  * | U+00E0  | ├á     | a           | Latin small letter a with grave        |
  1194.  * | U+00E1  | ├í     | a           | Latin small letter a with acute        |
  1195.  * | U+00E2  | ├ó     | a           | Latin small letter a with circumflex   |
  1196.  * | U+00E3  | ├ú     | a           | Latin small letter a with tilde        |
  1197.  * | U+00E4  | ├ñ     | a           | Latin small letter a with diaeresis    |
  1198.  * | U+00E5  | ├Ñ     | a           | Latin small letter a with ring above   |
  1199.  * | U+00E6  | ├ª     | ae          | Latin small letter ae                  |
  1200.  * | U+00E7  | ├º     | c           | Latin small letter c with cedilla      |
  1201.  * | U+00E8  | ├¿     | e           | Latin small letter e with grave        |
  1202.  * | U+00E9  | ├⌐     | e           | Latin small letter e with acute        |
  1203.  * | U+00EA  | ├¬     | e           | Latin small letter e with circumflex   |
  1204.  * | U+00EB  | ├½     | e           | Latin small letter e with diaeresis    |
  1205.  * | U+00EC  | ├¼     | i           | Latin small letter i with grave        |
  1206.  * | U+00ED  | ├¡     | i           | Latin small letter i with acute        |
  1207.  * | U+00EE  | ├«     | i           | Latin small letter i with circumflex   |
  1208.  * | U+00EF  | ├»     | i           | Latin small letter i with diaeresis    |
  1209.  * | U+00F0  | ├░     | d           | Latin small letter Eth                 |
  1210.  * | U+00F1  | ├▒     | n           | Latin small letter n with tilde        |
  1211.  * | U+00F2  | ├▓     | o           | Latin small letter o with grave        |
  1212.  * | U+00F3  | ├│     | o           | Latin small letter o with acute        |
  1213.  * | U+00F4  | ├┤     | o           | Latin small letter o with circumflex   |
  1214.  * | U+00F5  | ├╡     | o           | Latin small letter o with tilde        |
  1215.  * | U+00F6  | ├╢     | o           | Latin small letter o with diaeresis    |
  1216.  * | U+00F8  | ├╕     | o           | Latin small letter o with stroke       |
  1217.  * | U+00F9  | ├╣     | u           | Latin small letter u with grave        |
  1218.  * | U+00FA  | ├║     | u           | Latin small letter u with acute        |
  1219.  * | U+00FB  | ├╗     | u           | Latin small letter u with circumflex   |
  1220.  * | U+00FC  | ├╝     | u           | Latin small letter u with diaeresis    |
  1221.  * | U+00FD  | ├╜     | y           | Latin small letter y with acute        |
  1222.  * | U+00FE  | ├╛     | th          | Latin small letter Thorn               |
  1223.  * | U+00FF  | ├┐     | y           | Latin small letter y with diaeresis    |
  1224.  *
  1225.  * Decompositions for Latin Extended-A:
  1226.  *
  1227.  * |  Code   | Glyph | Replacement |                    Description                    |
  1228.  * | ------- | ----- | ----------- | ------------------------------------------------- |
  1229.  * | U+0100  | ─Ç     | A           | Latin capital letter A with macron                |
  1230.  * | U+0101  | ─ü     | a           | Latin small letter a with macron                  |
  1231.  * | U+0102  | ─é     | A           | Latin capital letter A with breve                 |
  1232.  * | U+0103  | ─â     | a           | Latin small letter a with breve                   |
  1233.  * | U+0104  | ─ä     | A           | Latin capital letter A with ogonek                |
  1234.  * | U+0105  | ─à     | a           | Latin small letter a with ogonek                  |
  1235.  * | U+01006 | ─å     | C           | Latin capital letter C with acute                 |
  1236.  * | U+0107  | ─ç     | c           | Latin small letter c with acute                   |
  1237.  * | U+0108  | ─ê     | C           | Latin capital letter C with circumflex            |
  1238.  * | U+0109  | ─ë     | c           | Latin small letter c with circumflex              |
  1239.  * | U+010A  | ─è     | C           | Latin capital letter C with dot above             |
  1240.  * | U+010B  | ─ï     | c           | Latin small letter c with dot above               |
  1241.  * | U+010C  | ─î     | C           | Latin capital letter C with caron                 |
  1242.  * | U+010D  | ─ì     | c           | Latin small letter c with caron                   |
  1243.  * | U+010E  | ─Ä     | D           | Latin capital letter D with caron                 |
  1244.  * | U+010F  | ─Å     | d           | Latin small letter d with caron                   |
  1245.  * | U+0110  | ─É     | D           | Latin capital letter D with stroke                |
  1246.  * | U+0111  | ─æ     | d           | Latin small letter d with stroke                  |
  1247.  * | U+0112  | ─Æ     | E           | Latin capital letter E with macron                |
  1248.  * | U+0113  | ─ô     | e           | Latin small letter e with macron                  |
  1249.  * | U+0114  | ─ö     | E           | Latin capital letter E with breve                 |
  1250.  * | U+0115  | ─ò     | e           | Latin small letter e with breve                   |
  1251.  * | U+0116  | ─û     | E           | Latin capital letter E with dot above             |
  1252.  * | U+0117  | ─ù     | e           | Latin small letter e with dot above               |
  1253.  * | U+0118  | ─ÿ     | E           | Latin capital letter E with ogonek                |
  1254.  * | U+0119  | ─Ö     | e           | Latin small letter e with ogonek                  |
  1255.  * | U+011A  | ─Ü     | E           | Latin capital letter E with caron                 |
  1256.  * | U+011B  | ─¢     | e           | Latin small letter e with caron                   |
  1257.  * | U+011C  | ─£     | G           | Latin capital letter G with circumflex            |
  1258.  * | U+011D  | ─¥     | g           | Latin small letter g with circumflex              |
  1259.  * | U+011E  | ─₧     | G           | Latin capital letter G with breve                 |
  1260.  * | U+011F  | ─ƒ     | g           | Latin small letter g with breve                   |
  1261.  * | U+0120  | ─á     | G           | Latin capital letter G with dot above             |
  1262.  * | U+0121  | ─í     | g           | Latin small letter g with dot above               |
  1263.  * | U+0122  | ─ó     | G           | Latin capital letter G with cedilla               |
  1264.  * | U+0123  | ─ú     | g           | Latin small letter g with cedilla                 |
  1265.  * | U+0124  | ─ñ     | H           | Latin capital letter H with circumflex            |
  1266.  * | U+0125  | ─Ñ     | h           | Latin small letter h with circumflex              |
  1267.  * | U+0126  | ─ª     | H           | Latin capital letter H with stroke                |
  1268.  * | U+0127  | ─º     | h           | Latin small letter h with stroke                  |
  1269.  * | U+0128  | ─¿     | I           | Latin capital letter I with tilde                 |
  1270.  * | U+0129  | ─⌐     | i           | Latin small letter i with tilde                   |
  1271.  * | U+012A  | ─¬     | I           | Latin capital letter I with macron                |
  1272.  * | U+012B  | ─½     | i           | Latin small letter i with macron                  |
  1273.  * | U+012C  | ─¼     | I           | Latin capital letter I with breve                 |
  1274.  * | U+012D  | ─¡     | i           | Latin small letter i with breve                   |
  1275.  * | U+012E  | ─«     | I           | Latin capital letter I with ogonek                |
  1276.  * | U+012F  | ─»     | i           | Latin small letter i with ogonek                  |
  1277.  * | U+0130  | ─░     | I           | Latin capital letter I with dot above             |
  1278.  * | U+0131  | ─▒     | i           | Latin small letter dotless i                      |
  1279.  * | U+0132  | ─▓     | IJ          | Latin capital ligature IJ                         |
  1280.  * | U+0133  | ─│     | ij          | Latin small ligature ij                           |
  1281.  * | U+0134  | ─┤     | J           | Latin capital letter J with circumflex            |
  1282.  * | U+0135  | ─╡     | j           | Latin small letter j with circumflex              |
  1283.  * | U+0136  | ─╢     | K           | Latin capital letter K with cedilla               |
  1284.  * | U+0137  | ─╖     | k           | Latin small letter k with cedilla                 |
  1285.  * | U+0138  | ─╕     | k           | Latin small letter Kra                            |
  1286.  * | U+0139  | ─╣     | L           | Latin capital letter L with acute                 |
  1287.  * | U+013A  | ─║     | l           | Latin small letter l with acute                   |
  1288.  * | U+013B  | ─╗     | L           | Latin capital letter L with cedilla               |
  1289.  * | U+013C  | ─╝     | l           | Latin small letter l with cedilla                 |
  1290.  * | U+013D  | ─╜     | L           | Latin capital letter L with caron                 |
  1291.  * | U+013E  | ─╛     | l           | Latin small letter l with caron                   |
  1292.  * | U+013F  | ─┐     | L           | Latin capital letter L with middle dot            |
  1293.  * | U+0140  | ┼Ç     | l           | Latin small letter l with middle dot              |
  1294.  * | U+0141  | ┼ü     | L           | Latin capital letter L with stroke                |
  1295.  * | U+0142  | ┼é     | l           | Latin small letter l with stroke                  |
  1296.  * | U+0143  | ┼â     | N           | Latin capital letter N with acute                 |
  1297.  * | U+0144  | ┼ä     | n           | Latin small letter N with acute                   |
  1298.  * | U+0145  | ┼à     | N           | Latin capital letter N with cedilla               |
  1299.  * | U+0146  | ┼å     | n           | Latin small letter n with cedilla                 |
  1300.  * | U+0147  | ┼ç     | N           | Latin capital letter N with caron                 |
  1301.  * | U+0148  | ┼ê     | n           | Latin small letter n with caron                   |
  1302.  * | U+0149  | ┼ë     | n           | Latin small letter n preceded by apostrophe       |
  1303.  * | U+014A  | ┼è     | N           | Latin capital letter Eng                          |
  1304.  * | U+014B  | ┼ï     | n           | Latin small letter Eng                            |
  1305.  * | U+014C  | ┼î     | O           | Latin capital letter O with macron                |
  1306.  * | U+014D  | ┼ì     | o           | Latin small letter o with macron                  |
  1307.  * | U+014E  | ┼Ä     | O           | Latin capital letter O with breve                 |
  1308.  * | U+014F  | ┼Å     | o           | Latin small letter o with breve                   |
  1309.  * | U+0150  | ┼É     | O           | Latin capital letter O with double acute          |
  1310.  * | U+0151  | ┼æ     | o           | Latin small letter o with double acute            |
  1311.  * | U+0152  | ┼Æ     | OE          | Latin capital ligature OE                         |
  1312.  * | U+0153  | ┼ô     | oe          | Latin small ligature oe                           |
  1313.  * | U+0154  | ┼ö     | R           | Latin capital letter R with acute                 |
  1314.  * | U+0155  | ┼ò     | r           | Latin small letter r with acute                   |
  1315.  * | U+0156  | ┼û     | R           | Latin capital letter R with cedilla               |
  1316.  * | U+0157  | ┼ù     | r           | Latin small letter r with cedilla                 |
  1317.  * | U+0158  | ┼ÿ     | R           | Latin capital letter R with caron                 |
  1318.  * | U+0159  | ┼Ö     | r           | Latin small letter r with caron                   |
  1319.  * | U+015A  | ┼Ü     | S           | Latin capital letter S with acute                 |
  1320.  * | U+015B  | ┼¢     | s           | Latin small letter s with acute                   |
  1321.  * | U+015C  | ┼£     | S           | Latin capital letter S with circumflex            |
  1322.  * | U+015D  | ┼¥     | s           | Latin small letter s with circumflex              |
  1323.  * | U+015E  | ┼₧     | S           | Latin capital letter S with cedilla               |
  1324.  * | U+015F  | ┼ƒ     | s           | Latin small letter s with cedilla                 |
  1325.  * | U+0160  | ┼á     | S           | Latin capital letter S with caron                 |
  1326.  * | U+0161  | ┼í     | s           | Latin small letter s with caron                   |
  1327.  * | U+0162  | ┼ó     | T           | Latin capital letter T with cedilla               |
  1328.  * | U+0163  | ┼ú     | t           | Latin small letter t with cedilla                 |
  1329.  * | U+0164  | ┼ñ     | T           | Latin capital letter T with caron                 |
  1330.  * | U+0165  | ┼Ñ     | t           | Latin small letter t with caron                   |
  1331.  * | U+0166  | ┼ª     | T           | Latin capital letter T with stroke                |
  1332.  * | U+0167  | ┼º     | t           | Latin small letter t with stroke                  |
  1333.  * | U+0168  | ┼¿     | U           | Latin capital letter U with tilde                 |
  1334.  * | U+0169  | ┼⌐     | u           | Latin small letter u with tilde                   |
  1335.  * | U+016A  | ┼¬     | U           | Latin capital letter U with macron                |
  1336.  * | U+016B  | ┼½     | u           | Latin small letter u with macron                  |
  1337.  * | U+016C  | ┼¼     | U           | Latin capital letter U with breve                 |
  1338.  * | U+016D  | ┼¡     | u           | Latin small letter u with breve                   |
  1339.  * | U+016E  | ┼«     | U           | Latin capital letter U with ring above            |
  1340.  * | U+016F  | ┼»     | u           | Latin small letter u with ring above              |
  1341.  * | U+0170  | ┼░     | U           | Latin capital letter U with double acute          |
  1342.  * | U+0171  | ┼▒     | u           | Latin small letter u with double acute            |
  1343.  * | U+0172  | ┼▓     | U           | Latin capital letter U with ogonek                |
  1344.  * | U+0173  | ┼│     | u           | Latin small letter u with ogonek                  |
  1345.  * | U+0174  | ┼┤     | W           | Latin capital letter W with circumflex            |
  1346.  * | U+0175  | ┼╡     | w           | Latin small letter w with circumflex              |
  1347.  * | U+0176  | ┼╢     | Y           | Latin capital letter Y with circumflex            |
  1348.  * | U+0177  | ┼╖     | y           | Latin small letter y with circumflex              |
  1349.  * | U+0178  | ┼╕     | Y           | Latin capital letter Y with diaeresis             |
  1350.  * | U+0179  | ┼╣     | Z           | Latin capital letter Z with acute                 |
  1351.  * | U+017A  | ┼║     | z           | Latin small letter z with acute                   |
  1352.  * | U+017B  | ┼╗     | Z           | Latin capital letter Z with dot above             |
  1353.  * | U+017C  | ┼╝     | z           | Latin small letter z with dot above               |
  1354.  * | U+017D  | ┼╜     | Z           | Latin capital letter Z with caron                 |
  1355.  * | U+017E  | ┼╛     | z           | Latin small letter z with caron                   |
  1356.  * | U+017F  | ┼┐     | s           | Latin small letter long s                         |
  1357.  * | U+01A0  | ╞á     | O           | Latin capital letter O with horn                  |
  1358.  * | U+01A1  | ╞í     | o           | Latin small letter o with horn                    |
  1359.  * | U+01AF  | ╞»     | U           | Latin capital letter U with horn                  |
  1360.  * | U+01B0  | ╞░     | u           | Latin small letter u with horn                    |
  1361.  * | U+01CD  | ╟ì     | A           | Latin capital letter A with caron                 |
  1362.  * | U+01CE  | ╟Ä     | a           | Latin small letter a with caron                   |
  1363.  * | U+01CF  | ╟Å     | I           | Latin capital letter I with caron                 |
  1364.  * | U+01D0  | ╟É     | i           | Latin small letter i with caron                   |
  1365.  * | U+01D1  | ╟æ     | O           | Latin capital letter O with caron                 |
  1366.  * | U+01D2  | ╟Æ     | o           | Latin small letter o with caron                   |
  1367.  * | U+01D3  | ╟ô     | U           | Latin capital letter U with caron                 |
  1368.  * | U+01D4  | ╟ö     | u           | Latin small letter u with caron                   |
  1369.  * | U+01D5  | ╟ò     | U           | Latin capital letter U with diaeresis and macron  |
  1370.  * | U+01D6  | ╟û     | u           | Latin small letter u with diaeresis and macron    |
  1371.  * | U+01D7  | ╟ù     | U           | Latin capital letter U with diaeresis and acute   |
  1372.  * | U+01D8  | ╟ÿ     | u           | Latin small letter u with diaeresis and acute     |
  1373.  * | U+01D9  | ╟Ö     | U           | Latin capital letter U with diaeresis and caron   |
  1374.  * | U+01DA  | ╟Ü     | u           | Latin small letter u with diaeresis and caron     |
  1375.  * | U+01DB  | ╟¢     | U           | Latin capital letter U with diaeresis and grave   |
  1376.  * | U+01DC  | ╟£     | u           | Latin small letter u with diaeresis and grave     |
  1377.  *
  1378.  * Decompositions for Latin Extended-B:
  1379.  *
  1380.  * |   Code   | Glyph | Replacement |                Description                |
  1381.  * | -------- | ----- | ----------- | ----------------------------------------- |
  1382.  * | U+0218   | ╚ÿ     | S           | Latin capital letter S with comma below   |
  1383.  * | U+0219   | ╚Ö     | s           | Latin small letter s with comma below     |
  1384.  * | U+021A   | ╚Ü     | T           | Latin capital letter T with comma below   |
  1385.  * | U+021B   | ╚¢     | t           | Latin small letter t with comma below     |
  1386.  *
  1387.  * Vowels with diacritic (Chinese, Hanyu Pinyin):
  1388.  *
  1389.  * |   Code   | Glyph | Replacement |                      Description                      |
  1390.  * | -------- | ----- | ----------- | ----------------------------------------------------- |
  1391.  * | U+0251   | ╔æ     | a           | Latin small letter alpha                              |
  1392.  * | U+1EA0   | ß║á     | A           | Latin capital letter A with dot below                 |
  1393.  * | U+1EA1   | ß║í     | a           | Latin small letter a with dot below                   |
  1394.  * | U+1EA2   | ß║ó     | A           | Latin capital letter A with hook above                |
  1395.  * | U+1EA3   | ß║ú     | a           | Latin small letter a with hook above                  |
  1396.  * | U+1EA4   | ß║ñ     | A           | Latin capital letter A with circumflex and acute      |
  1397.  * | U+1EA5   | ß║Ñ     | a           | Latin small letter a with circumflex and acute        |
  1398.  * | U+1EA6   | ß║ª     | A           | Latin capital letter A with circumflex and grave      |
  1399.  * | U+1EA7   | ß║º     | a           | Latin small letter a with circumflex and grave        |
  1400.  * | U+1EA8   | ß║¿     | A           | Latin capital letter A with circumflex and hook above |
  1401.  * | U+1EA9   | ß║⌐     | a           | Latin small letter a with circumflex and hook above   |
  1402.  * | U+1EAA   | ß║¬     | A           | Latin capital letter A with circumflex and tilde      |
  1403.  * | U+1EAB   | ß║½     | a           | Latin small letter a with circumflex and tilde        |
  1404.  * | U+1EA6   | ß║¼     | A           | Latin capital letter A with circumflex and dot below  |
  1405.  * | U+1EAD   | ß║¡     | a           | Latin small letter a with circumflex and dot below    |
  1406.  * | U+1EAE   | ß║«     | A           | Latin capital letter A with breve and acute           |
  1407.  * | U+1EAF   | ß║»     | a           | Latin small letter a with breve and acute             |
  1408.  * | U+1EB0   | ß║░     | A           | Latin capital letter A with breve and grave           |
  1409.  * | U+1EB1   | ß║▒     | a           | Latin small letter a with breve and grave             |
  1410.  * | U+1EB2   | ß║▓     | A           | Latin capital letter A with breve and hook above      |
  1411.  * | U+1EB3   | ß║│     | a           | Latin small letter a with breve and hook above        |
  1412.  * | U+1EB4   | ß║┤     | A           | Latin capital letter A with breve and tilde           |
  1413.  * | U+1EB5   | ß║╡     | a           | Latin small letter a with breve and tilde             |
  1414.  * | U+1EB6   | ß║╢     | A           | Latin capital letter A with breve and dot below       |
  1415.  * | U+1EB7   | ß║╖     | a           | Latin small letter a with breve and dot below         |
  1416.  * | U+1EB8   | ß║╕     | E           | Latin capital letter E with dot below                 |
  1417.  * | U+1EB9   | ß║╣     | e           | Latin small letter e with dot below                   |
  1418.  * | U+1EBA   | ß║║     | E           | Latin capital letter E with hook above                |
  1419.  * | U+1EBB   | ß║╗     | e           | Latin small letter e with hook above                  |
  1420.  * | U+1EBC   | ß║╝     | E           | Latin capital letter E with tilde                     |
  1421.  * | U+1EBD   | ß║╜     | e           | Latin small letter e with tilde                       |
  1422.  * | U+1EBE   | ß║╛     | E           | Latin capital letter E with circumflex and acute      |
  1423.  * | U+1EBF   | ß║┐     | e           | Latin small letter e with circumflex and acute        |
  1424.  * | U+1EC0   | ß╗Ç     | E           | Latin capital letter E with circumflex and grave      |
  1425.  * | U+1EC1   | ß╗ü     | e           | Latin small letter e with circumflex and grave        |
  1426.  * | U+1EC2   | ß╗é     | E           | Latin capital letter E with circumflex and hook above |
  1427.  * | U+1EC3   | ß╗â     | e           | Latin small letter e with circumflex and hook above   |
  1428.  * | U+1EC4   | ß╗ä     | E           | Latin capital letter E with circumflex and tilde      |
  1429.  * | U+1EC5   | ß╗à     | e           | Latin small letter e with circumflex and tilde        |
  1430.  * | U+1EC6   | ß╗å     | E           | Latin capital letter E with circumflex and dot below  |
  1431.  * | U+1EC7   | ß╗ç     | e           | Latin small letter e with circumflex and dot below    |
  1432.  * | U+1EC8   | ß╗ê     | I           | Latin capital letter I with hook above                |
  1433.  * | U+1EC9   | ß╗ë     | i           | Latin small letter i with hook above                  |
  1434.  * | U+1ECA   | ß╗è     | I           | Latin capital letter I with dot below                 |
  1435.  * | U+1ECB   | ß╗ï     | i           | Latin small letter i with dot below                   |
  1436.  * | U+1ECC   | ß╗î     | O           | Latin capital letter O with dot below                 |
  1437.  * | U+1ECD   | ß╗ì     | o           | Latin small letter o with dot below                   |
  1438.  * | U+1ECE   | ß╗Ä     | O           | Latin capital letter O with hook above                |
  1439.  * | U+1ECF   | ß╗Å     | o           | Latin small letter o with hook above                  |
  1440.  * | U+1ED0   | ß╗É     | O           | Latin capital letter O with circumflex and acute      |
  1441.  * | U+1ED1   | ß╗æ     | o           | Latin small letter o with circumflex and acute        |
  1442.  * | U+1ED2   | ß╗Æ     | O           | Latin capital letter O with circumflex and grave      |
  1443.  * | U+1ED3   | ß╗ô     | o           | Latin small letter o with circumflex and grave        |
  1444.  * | U+1ED4   | ß╗ö     | O           | Latin capital letter O with circumflex and hook above |
  1445.  * | U+1ED5   | ß╗ò     | o           | Latin small letter o with circumflex and hook above   |
  1446.  * | U+1ED6   | ß╗û     | O           | Latin capital letter O with circumflex and tilde      |
  1447.  * | U+1ED7   | ß╗ù     | o           | Latin small letter o with circumflex and tilde        |
  1448.  * | U+1ED8   | ß╗ÿ     | O           | Latin capital letter O with circumflex and dot below  |
  1449.  * | U+1ED9   | ß╗Ö     | o           | Latin small letter o with circumflex and dot below    |
  1450.  * | U+1EDA   | ß╗Ü     | O           | Latin capital letter O with horn and acute            |
  1451.  * | U+1EDB   | ß╗¢     | o           | Latin small letter o with horn and acute              |
  1452.  * | U+1EDC   | ß╗£     | O           | Latin capital letter O with horn and grave            |
  1453.  * | U+1EDD   | ß╗¥     | o           | Latin small letter o with horn and grave              |
  1454.  * | U+1EDE   | ß╗₧     | O           | Latin capital letter O with horn and hook above       |
  1455.  * | U+1EDF   | ß╗ƒ     | o           | Latin small letter o with horn and hook above         |
  1456.  * | U+1EE0   | ß╗á     | O           | Latin capital letter O with horn and tilde            |
  1457.  * | U+1EE1   | ß╗í     | o           | Latin small letter o with horn and tilde              |
  1458.  * | U+1EE2   | ß╗ó     | O           | Latin capital letter O with horn and dot below        |
  1459.  * | U+1EE3   | ß╗ú     | o           | Latin small letter o with horn and dot below          |
  1460.  * | U+1EE4   | ß╗ñ     | U           | Latin capital letter U with dot below                 |
  1461.  * | U+1EE5   | ß╗Ñ     | u           | Latin small letter u with dot below                   |
  1462.  * | U+1EE6   | ß╗ª     | U           | Latin capital letter U with hook above                |
  1463.  * | U+1EE7   | ß╗º     | u           | Latin small letter u with hook above                  |
  1464.  * | U+1EE8   | ß╗¿     | U           | Latin capital letter U with horn and acute            |
  1465.  * | U+1EE9   | ß╗⌐     | u           | Latin small letter u with horn and acute              |
  1466.  * | U+1EEA   | ß╗¬     | U           | Latin capital letter U with horn and grave            |
  1467.  * | U+1EEB   | ß╗½     | u           | Latin small letter u with horn and grave              |
  1468.  * | U+1EEC   | ß╗¼     | U           | Latin capital letter U with horn and hook above       |
  1469.  * | U+1EED   | ß╗¡     | u           | Latin small letter u with horn and hook above         |
  1470.  * | U+1EEE   | ß╗«     | U           | Latin capital letter U with horn and tilde            |
  1471.  * | U+1EEF   | ß╗»     | u           | Latin small letter u with horn and tilde              |
  1472.  * | U+1EF0   | ß╗░     | U           | Latin capital letter U with horn and dot below        |
  1473.  * | U+1EF1   | ß╗▒     | u           | Latin small letter u with horn and dot below          |
  1474.  * | U+1EF2   | ß╗▓     | Y           | Latin capital letter Y with grave                     |
  1475.  * | U+1EF3   | ß╗│     | y           | Latin small letter y with grave                       |
  1476.  * | U+1EF4   | ß╗┤     | Y           | Latin capital letter Y with dot below                 |
  1477.  * | U+1EF5   | ß╗╡     | y           | Latin small letter y with dot below                   |
  1478.  * | U+1EF6   | ß╗╢     | Y           | Latin capital letter Y with hook above                |
  1479.  * | U+1EF7   | ß╗╖     | y           | Latin small letter y with hook above                  |
  1480.  * | U+1EF8   | ß╗╕     | Y           | Latin capital letter Y with tilde                     |
  1481.  * | U+1EF9   | ß╗╣     | y           | Latin small letter y with tilde                       |
  1482.  *
  1483.  * German (`de_DE`), German formal (`de_DE_formal`), German (Switzerland) formal (`de_CH`),
  1484.  * and German (Switzerland) informal (`de_CH_informal`) locales:
  1485.  *
  1486.  * |   Code   | Glyph | Replacement |               Description               |
  1487.  * | -------- | ----- | ----------- | --------------------------------------- |
  1488.  * | U+00C4   | ├ä     | Ae          | Latin capital letter A with diaeresis   |
  1489.  * | U+00E4   | ├ñ     | ae          | Latin small letter a with diaeresis     |
  1490.  * | U+00D6   | ├û     | Oe          | Latin capital letter O with diaeresis   |
  1491.  * | U+00F6   | ├╢     | oe          | Latin small letter o with diaeresis     |
  1492.  * | U+00DC   | ├£     | Ue          | Latin capital letter U with diaeresis   |
  1493.  * | U+00FC   | ├╝     | ue          | Latin small letter u with diaeresis     |
  1494.  * | U+00DF   | ├ƒ     | ss          | Latin small letter sharp s              |
  1495.  *
  1496.  * Danish (`da_DK`) locale:
  1497.  *
  1498.  * |   Code   | Glyph | Replacement |               Description               |
  1499.  * | -------- | ----- | ----------- | --------------------------------------- |
  1500.  * | U+00C6   | ├å     | Ae          | Latin capital letter AE                 |
  1501.  * | U+00E6   | ├ª     | ae          | Latin small letter ae                   |
  1502.  * | U+00D8   | ├ÿ     | Oe          | Latin capital letter O with stroke      |
  1503.  * | U+00F8   | ├╕     | oe          | Latin small letter o with stroke        |
  1504.  * | U+00C5   | ├à     | Aa          | Latin capital letter A with ring above  |
  1505.  * | U+00E5   | ├Ñ     | aa          | Latin small letter a with ring above    |
  1506.  *
  1507.  * Catalan (`ca`) locale:
  1508.  *
  1509.  * |   Code   | Glyph | Replacement |               Description               |
  1510.  * | -------- | ----- | ----------- | --------------------------------------- |
  1511.  * | U+00B7   | l┬╖l   | ll          | Flown dot (between two Ls)              |
  1512.  *
  1513.  * Serbian (`sr_RS`) and Bosnian (`bs_BA`) locales:
  1514.  *
  1515.  * |   Code   | Glyph | Replacement |               Description               |
  1516.  * | -------- | ----- | ----------- | --------------------------------------- |
  1517.  * | U+0110   | ─É     | DJ          | Latin capital letter D with stroke      |
  1518.  * | U+0111   | ─æ     | dj          | Latin small letter d with stroke        |
  1519.  *
  1520.  * @since 1.2.1
  1521.  * @since 4.6.0 Added locale support for `de_CH`, `de_CH_informal`, and `ca`.
  1522.  * @since 4.7.0 Added locale support for `sr_RS`.
  1523.  * @since 4.8.0 Added locale support for `bs_BA`.
  1524.  *
  1525.  * @param string $string Text that might have accent characters
  1526.  * @return string Filtered string with replaced "nice" characters.
  1527.  */
  1528. function remove_accents( $string ) {
  1529.     if ( !preg_match('/[\x80-\xff]/', $string) )
  1530.         return $string;
  1531.  
  1532.     if (seems_utf8($string)) {
  1533.         $chars = array(
  1534.         // Decompositions for Latin-1 Supplement
  1535.         '┬¬' => 'a', '┬║' => 'o',
  1536.         '├Ç' => 'A', '├ü' => 'A',
  1537.         '├é' => 'A', '├â' => 'A',
  1538.         '├ä' => 'A', '├à' => 'A',
  1539.         '├å' => 'AE','├ç' => 'C',
  1540.         '├ê' => 'E', '├ë' => 'E',
  1541.         '├è' => 'E', '├ï' => 'E',
  1542.         '├î' => 'I', '├ì' => 'I',
  1543.         '├Ä' => 'I', '├Å' => 'I',
  1544.         '├É' => 'D', '├æ' => 'N',
  1545.         '├Æ' => 'O', '├ô' => 'O',
  1546.         '├ö' => 'O', '├ò' => 'O',
  1547.         '├û' => 'O', '├Ö' => 'U',
  1548.         '├Ü' => 'U', '├¢' => 'U',
  1549.         '├£' => 'U', '├¥' => 'Y',
  1550.         '├₧' => 'TH','├ƒ' => 's',
  1551.         '├á' => 'a', '├í' => 'a',
  1552.         '├ó' => 'a', '├ú' => 'a',
  1553.         '├ñ' => 'a', '├Ñ' => 'a',
  1554.         '├ª' => 'ae','├º' => 'c',
  1555.         '├¿' => 'e', '├⌐' => 'e',
  1556.         '├¬' => 'e', '├½' => 'e',
  1557.         '├¼' => 'i', '├¡' => 'i',
  1558.         '├«' => 'i', '├»' => 'i',
  1559.         '├░' => 'd', '├▒' => 'n',
  1560.         '├▓' => 'o', '├│' => 'o',
  1561.         '├┤' => 'o', '├╡' => 'o',
  1562.         '├╢' => 'o', '├╕' => 'o',
  1563.         '├╣' => 'u', '├║' => 'u',
  1564.         '├╗' => 'u', '├╝' => 'u',
  1565.         '├╜' => 'y', '├╛' => 'th',
  1566.         '├┐' => 'y', '├ÿ' => 'O',
  1567.         // Decompositions for Latin Extended-A
  1568.         '─Ç' => 'A', '─ü' => 'a',
  1569.         '─é' => 'A', '─â' => 'a',
  1570.         '─ä' => 'A', '─à' => 'a',
  1571.         '─å' => 'C', '─ç' => 'c',
  1572.         '─ê' => 'C', '─ë' => 'c',
  1573.         '─è' => 'C', '─ï' => 'c',
  1574.         '─î' => 'C', '─ì' => 'c',
  1575.         '─Ä' => 'D', '─Å' => 'd',
  1576.         '─É' => 'D', '─æ' => 'd',
  1577.         '─Æ' => 'E', '─ô' => 'e',
  1578.         '─ö' => 'E', '─ò' => 'e',
  1579.         '─û' => 'E', '─ù' => 'e',
  1580.         '─ÿ' => 'E', '─Ö' => 'e',
  1581.         '─Ü' => 'E', '─¢' => 'e',
  1582.         '─£' => 'G', '─¥' => 'g',
  1583.         '─₧' => 'G', '─ƒ' => 'g',
  1584.         '─á' => 'G', '─í' => 'g',
  1585.         '─ó' => 'G', '─ú' => 'g',
  1586.         '─ñ' => 'H', '─Ñ' => 'h',
  1587.         '─ª' => 'H', '─º' => 'h',
  1588.         '─¿' => 'I', '─⌐' => 'i',
  1589.         '─¬' => 'I', '─½' => 'i',
  1590.         '─¼' => 'I', '─¡' => 'i',
  1591.         '─«' => 'I', '─»' => 'i',
  1592.         '─░' => 'I', '─▒' => 'i',
  1593.         '─▓' => 'IJ','─│' => 'ij',
  1594.         '─┤' => 'J', '─╡' => 'j',
  1595.         '─╢' => 'K', '─╖' => 'k',
  1596.         '─╕' => 'k', '─╣' => 'L',
  1597.         '─║' => 'l', '─╗' => 'L',
  1598.         '─╝' => 'l', '─╜' => 'L',
  1599.         '─╛' => 'l', '─┐' => 'L',
  1600.         '┼Ç' => 'l', '┼ü' => 'L',
  1601.         '┼é' => 'l', '┼â' => 'N',
  1602.         '┼ä' => 'n', '┼à' => 'N',
  1603.         '┼å' => 'n', '┼ç' => 'N',
  1604.         '┼ê' => 'n', '┼ë' => 'n',
  1605.         '┼è' => 'N', '┼ï' => 'n',
  1606.         '┼î' => 'O', '┼ì' => 'o',
  1607.         '┼Ä' => 'O', '┼Å' => 'o',
  1608.         '┼É' => 'O', '┼æ' => 'o',
  1609.         '┼Æ' => 'OE','┼ô' => 'oe',
  1610.         '┼ö' => 'R','┼ò' => 'r',
  1611.         '┼û' => 'R','┼ù' => 'r',
  1612.         '┼ÿ' => 'R','┼Ö' => 'r',
  1613.         '┼Ü' => 'S','┼¢' => 's',
  1614.         '┼£' => 'S','┼¥' => 's',
  1615.         '┼₧' => 'S','┼ƒ' => 's',
  1616.         '┼á' => 'S', '┼í' => 's',
  1617.         '┼ó' => 'T', '┼ú' => 't',
  1618.         '┼ñ' => 'T', '┼Ñ' => 't',
  1619.         '┼ª' => 'T', '┼º' => 't',
  1620.         '┼¿' => 'U', '┼⌐' => 'u',
  1621.         '┼¬' => 'U', '┼½' => 'u',
  1622.         '┼¼' => 'U', '┼¡' => 'u',
  1623.         '┼«' => 'U', '┼»' => 'u',
  1624.         '┼░' => 'U', '┼▒' => 'u',
  1625.         '┼▓' => 'U', '┼│' => 'u',
  1626.         '┼┤' => 'W', '┼╡' => 'w',
  1627.         '┼╢' => 'Y', '┼╖' => 'y',
  1628.         '┼╕' => 'Y', '┼╣' => 'Z',
  1629.         '┼║' => 'z', '┼╗' => 'Z',
  1630.         '┼╝' => 'z', '┼╜' => 'Z',
  1631.         '┼╛' => 'z', '┼┐' => 's',
  1632.         // Decompositions for Latin Extended-B
  1633.         '╚ÿ' => 'S', '╚Ö' => 's',
  1634.         '╚Ü' => 'T', '╚¢' => 't',
  1635.         // Euro Sign
  1636.         'Γé¼' => 'E',
  1637.         // GBP (Pound) Sign
  1638.         '┬ú' => '',
  1639.         // Vowels with diacritic (Vietnamese)
  1640.         // unmarked
  1641.         '╞á' => 'O', '╞í' => 'o',
  1642.         '╞»' => 'U', '╞░' => 'u',
  1643.         // grave accent
  1644.         'ß║ª' => 'A', 'ß║º' => 'a',
  1645.         'ß║░' => 'A', 'ß║▒' => 'a',
  1646.         'ß╗Ç' => 'E', 'ß╗ü' => 'e',
  1647.         'ß╗Æ' => 'O', 'ß╗ô' => 'o',
  1648.         'ß╗£' => 'O', 'ß╗¥' => 'o',
  1649.         'ß╗¬' => 'U', 'ß╗½' => 'u',
  1650.         'ß╗▓' => 'Y', 'ß╗│' => 'y',
  1651.         // hook
  1652.         'ß║ó' => 'A', 'ß║ú' => 'a',
  1653.         'ß║¿' => 'A', 'ß║⌐' => 'a',
  1654.         'ß║▓' => 'A', 'ß║│' => 'a',
  1655.         'ß║║' => 'E', 'ß║╗' => 'e',
  1656.         'ß╗é' => 'E', 'ß╗â' => 'e',
  1657.         'ß╗ê' => 'I', 'ß╗ë' => 'i',
  1658.         'ß╗Ä' => 'O', 'ß╗Å' => 'o',
  1659.         'ß╗ö' => 'O', 'ß╗ò' => 'o',
  1660.         'ß╗₧' => 'O', 'ß╗ƒ' => 'o',
  1661.         'ß╗ª' => 'U', 'ß╗º' => 'u',
  1662.         'ß╗¼' => 'U', 'ß╗¡' => 'u',
  1663.         'ß╗╢' => 'Y', 'ß╗╖' => 'y',
  1664.         // tilde
  1665.         'ß║¬' => 'A', 'ß║½' => 'a',
  1666.         'ß║┤' => 'A', 'ß║╡' => 'a',
  1667.         'ß║╝' => 'E', 'ß║╜' => 'e',
  1668.         'ß╗ä' => 'E', 'ß╗à' => 'e',
  1669.         'ß╗û' => 'O', 'ß╗ù' => 'o',
  1670.         'ß╗á' => 'O', 'ß╗í' => 'o',
  1671.         'ß╗«' => 'U', 'ß╗»' => 'u',
  1672.         'ß╗╕' => 'Y', 'ß╗╣' => 'y',
  1673.         // acute accent
  1674.         'ß║ñ' => 'A', 'ß║Ñ' => 'a',
  1675.         'ß║«' => 'A', 'ß║»' => 'a',
  1676.         'ß║╛' => 'E', 'ß║┐' => 'e',
  1677.         'ß╗É' => 'O', 'ß╗æ' => 'o',
  1678.         'ß╗Ü' => 'O', 'ß╗¢' => 'o',
  1679.         'ß╗¿' => 'U', 'ß╗⌐' => 'u',
  1680.         // dot below
  1681.         'ß║á' => 'A', 'ß║í' => 'a',
  1682.         'ß║¼' => 'A', 'ß║¡' => 'a',
  1683.         'ß║╢' => 'A', 'ß║╖' => 'a',
  1684.         'ß║╕' => 'E', 'ß║╣' => 'e',
  1685.         'ß╗å' => 'E', 'ß╗ç' => 'e',
  1686.         'ß╗è' => 'I', 'ß╗ï' => 'i',
  1687.         'ß╗î' => 'O', 'ß╗ì' => 'o',
  1688.         'ß╗ÿ' => 'O', 'ß╗Ö' => 'o',
  1689.         'ß╗ó' => 'O', 'ß╗ú' => 'o',
  1690.         'ß╗ñ' => 'U', 'ß╗Ñ' => 'u',
  1691.         'ß╗░' => 'U', 'ß╗▒' => 'u',
  1692.         'ß╗┤' => 'Y', 'ß╗╡' => 'y',
  1693.         // Vowels with diacritic (Chinese, Hanyu Pinyin)
  1694.         '╔æ' => 'a',
  1695.         // macron
  1696.         '╟ò' => 'U', '╟û' => 'u',
  1697.         // acute accent
  1698.         '╟ù' => 'U', '╟ÿ' => 'u',
  1699.         // caron
  1700.         '╟ì' => 'A', '╟Ä' => 'a',
  1701.         '╟Å' => 'I', '╟É' => 'i',
  1702.         '╟æ' => 'O', '╟Æ' => 'o',
  1703.         '╟ô' => 'U', '╟ö' => 'u',
  1704.         '╟Ö' => 'U', '╟Ü' => 'u',
  1705.         // grave accent
  1706.         '╟¢' => 'U', '╟£' => 'u',
  1707.         );
  1708.  
  1709.         // Used for locale-specific rules
  1710.         $locale = get_locale();
  1711.  
  1712.         if ( 'de_DE' == $locale || 'de_DE_formal' == $locale || 'de_CH' == $locale || 'de_CH_informal' == $locale ) {
  1713.             $chars[ '├ä' ] = 'Ae';
  1714.             $chars[ '├ñ' ] = 'ae';
  1715.             $chars[ '├û' ] = 'Oe';
  1716.             $chars[ '├╢' ] = 'oe';
  1717.             $chars[ '├£' ] = 'Ue';
  1718.             $chars[ '├╝' ] = 'ue';
  1719.             $chars[ '├ƒ' ] = 'ss';
  1720.         } elseif ( 'da_DK' === $locale ) {
  1721.             $chars[ '├å' ] = 'Ae';
  1722.              $chars[ '├ª' ] = 'ae';
  1723.             $chars[ '├ÿ' ] = 'Oe';
  1724.             $chars[ '├╕' ] = 'oe';
  1725.             $chars[ '├à' ] = 'Aa';
  1726.             $chars[ '├Ñ' ] = 'aa';
  1727.         } elseif ( 'ca' === $locale ) {
  1728.             $chars[ 'l┬╖l' ] = 'll';
  1729.         } elseif ( 'sr_RS' === $locale || 'bs_BA' === $locale ) {
  1730.             $chars[ '─É' ] = 'DJ';
  1731.             $chars[ '─æ' ] = 'dj';
  1732.         }
  1733.  
  1734.         $string = strtr($string, $chars);
  1735.     } else {
  1736.         $chars = array();
  1737.         // Assume ISO-8859-1 if not UTF-8
  1738.         $chars['in'] = "\x80\x83\x8a\x8e\x9a\x9e"
  1739.             ."\x9f\xa2\xa5\xb5\xc0\xc1\xc2"
  1740.             ."\xc3\xc4\xc5\xc7\xc8\xc9\xca"
  1741.             ."\xcb\xcc\xcd\xce\xcf\xd1\xd2"
  1742.             ."\xd3\xd4\xd5\xd6\xd8\xd9\xda"
  1743.             ."\xdb\xdc\xdd\xe0\xe1\xe2\xe3"
  1744.             ."\xe4\xe5\xe7\xe8\xe9\xea\xeb"
  1745.             ."\xec\xed\xee\xef\xf1\xf2\xf3"
  1746.             ."\xf4\xf5\xf6\xf8\xf9\xfa\xfb"
  1747.             ."\xfc\xfd\xff";
  1748.  
  1749.         $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
  1750.  
  1751.         $string = strtr($string, $chars['in'], $chars['out']);
  1752.         $double_chars = array();
  1753.         $double_chars['in'] = array("\x8c", "\x9c", "\xc6", "\xd0", "\xde", "\xdf", "\xe6", "\xf0", "\xfe");
  1754.         $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
  1755.         $string = str_replace($double_chars['in'], $double_chars['out'], $string);
  1756.     }
  1757.  
  1758.     return $string;
  1759. }
  1760.  
  1761. /**
  1762.  * Sanitizes a filename, replacing whitespace with dashes.
  1763.  *
  1764.  * Removes special characters that are illegal in filenames on certain
  1765.  * operating systems and special characters requiring special escaping
  1766.  * to manipulate at the command line. Replaces spaces and consecutive
  1767.  * dashes with a single dash. Trims period, dash and underscore from beginning
  1768.  * and end of filename. It is not guaranteed that this function will return a
  1769.  * filename that is allowed to be uploaded.
  1770.  *
  1771.  * @since 2.1.0
  1772.  *
  1773.  * @param string $filename The filename to be sanitized
  1774.  * @return string The sanitized filename
  1775.  */
  1776. function sanitize_file_name( $filename ) {
  1777.     $filename_raw = $filename;
  1778.     $special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", "%", "+", chr(0));
  1779.     /**
  1780.      * Filters the list of characters to remove from a filename.
  1781.      *
  1782.      * @since 2.8.0
  1783.      *
  1784.      * @param array  $special_chars Characters to remove.
  1785.      * @param string $filename_raw  Filename as it was passed into sanitize_file_name().
  1786.      */
  1787.     $special_chars = apply_filters( 'sanitize_file_name_chars', $special_chars, $filename_raw );
  1788.     $filename = preg_replace( "#\x{00a0}#siu", ' ', $filename );
  1789.     $filename = str_replace( $special_chars, '', $filename );
  1790.     $filename = str_replace( array( '%20', '+' ), '-', $filename );
  1791.     $filename = preg_replace( '/[\r\n\t -]+/', '-', $filename );
  1792.     $filename = trim( $filename, '.-_' );
  1793.  
  1794.     if ( false === strpos( $filename, '.' ) ) {
  1795.         $mime_types = wp_get_mime_types();
  1796.         $filetype = wp_check_filetype( 'test.' . $filename, $mime_types );
  1797.         if ( $filetype['ext'] === $filename ) {
  1798.             $filename = 'unnamed-file.' . $filetype['ext'];
  1799.         }
  1800.     }
  1801.  
  1802.     // Split the filename into a base and extension[s]
  1803.     $parts = explode('.', $filename);
  1804.  
  1805.     // Return if only one extension
  1806.     if ( count( $parts ) <= 2 ) {
  1807.         /**
  1808.          * Filters a sanitized filename string.
  1809.          *
  1810.          * @since 2.8.0
  1811.          *
  1812.          * @param string $filename     Sanitized filename.
  1813.          * @param string $filename_raw The filename prior to sanitization.
  1814.          */
  1815.         return apply_filters( 'sanitize_file_name', $filename, $filename_raw );
  1816.     }
  1817.  
  1818.     // Process multiple extensions
  1819.     $filename = array_shift($parts);
  1820.     $extension = array_pop($parts);
  1821.     $mimes = get_allowed_mime_types();
  1822.  
  1823.     /*
  1824.      * Loop over any intermediate extensions. Postfix them with a trailing underscore
  1825.      * if they are a 2 - 5 character long alpha string not in the extension whitelist.
  1826.      */
  1827.     foreach ( (array) $parts as $part) {
  1828.         $filename .= '.' . $part;
  1829.  
  1830.         if ( preg_match("/^[a-zA-Z]{2,5}\d?$/", $part) ) {
  1831.             $allowed = false;
  1832.             foreach ( $mimes as $ext_preg => $mime_match ) {
  1833.                 $ext_preg = '!^(' . $ext_preg . ')$!i';
  1834.                 if ( preg_match( $ext_preg, $part ) ) {
  1835.                     $allowed = true;
  1836.                     break;
  1837.                 }
  1838.             }
  1839.             if ( !$allowed )
  1840.                 $filename .= '_';
  1841.         }
  1842.     }
  1843.     $filename .= '.' . $extension;
  1844.     /** This filter is documented in wp-includes/formatting.php */
  1845.     return apply_filters('sanitize_file_name', $filename, $filename_raw);
  1846. }
  1847.  
  1848. /**
  1849.  * Sanitizes a username, stripping out unsafe characters.
  1850.  *
  1851.  * Removes tags, octets, entities, and if strict is enabled, will only keep
  1852.  * alphanumeric, _, space, ., -, @. After sanitizing, it passes the username,
  1853.  * raw username (the username in the parameter), and the value of $strict as
  1854.  * parameters for the {@see 'sanitize_user'} filter.
  1855.  *
  1856.  * @since 2.0.0
  1857.  *
  1858.  * @param string $username The username to be sanitized.
  1859.  * @param bool   $strict   If set limits $username to specific characters. Default false.
  1860.  * @return string The sanitized username, after passing through filters.
  1861.  */
  1862. function sanitize_user( $username, $strict = false ) {
  1863.     $raw_username = $username;
  1864.     $username = wp_strip_all_tags( $username );
  1865.     $username = remove_accents( $username );
  1866.     // Kill octets
  1867.     $username = preg_replace( '|%([a-fA-F0-9][a-fA-F0-9])|', '', $username );
  1868.     $username = preg_replace( '/&.+?;/', '', $username ); // Kill entities
  1869.  
  1870.     // If strict, reduce to ASCII for max portability.
  1871.     if ( $strict )
  1872.         $username = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $username );
  1873.  
  1874.     $username = trim( $username );
  1875.     // Consolidate contiguous whitespace
  1876.     $username = preg_replace( '|\s+|', ' ', $username );
  1877.  
  1878.     /**
  1879.      * Filters a sanitized username string.
  1880.      *
  1881.      * @since 2.0.1
  1882.      *
  1883.      * @param string $username     Sanitized username.
  1884.      * @param string $raw_username The username prior to sanitization.
  1885.      * @param bool   $strict       Whether to limit the sanitization to specific characters. Default false.
  1886.      */
  1887.     return apply_filters( 'sanitize_user', $username, $raw_username, $strict );
  1888. }
  1889.  
  1890. /**
  1891.  * Sanitizes a string key.
  1892.  *
  1893.  * Keys are used as internal identifiers. Lowercase alphanumeric characters, dashes and underscores are allowed.
  1894.  *
  1895.  * @since 3.0.0
  1896.  *
  1897.  * @param string $key String key
  1898.  * @return string Sanitized key
  1899.  */
  1900. function sanitize_key( $key ) {
  1901.     $raw_key = $key;
  1902.     $key = strtolower( $key );
  1903.     $key = preg_replace( '/[^a-z0-9_\-]/', '', $key );
  1904.  
  1905.     /**
  1906.      * Filters a sanitized key string.
  1907.      *
  1908.      * @since 3.0.0
  1909.      *
  1910.      * @param string $key     Sanitized key.
  1911.      * @param string $raw_key The key prior to sanitization.
  1912.      */
  1913.     return apply_filters( 'sanitize_key', $key, $raw_key );
  1914. }
  1915.  
  1916. /**
  1917.  * Sanitizes a title, or returns a fallback title.
  1918.  *
  1919.  * Specifically, HTML and PHP tags are stripped. Further actions can be added
  1920.  * via the plugin API. If $title is empty and $fallback_title is set, the latter
  1921.  * will be used.
  1922.  *
  1923.  * @since 1.0.0
  1924.  *
  1925.  * @param string $title          The string to be sanitized.
  1926.  * @param string $fallback_title Optional. A title to use if $title is empty.
  1927.  * @param string $context        Optional. The operation for which the string is sanitized
  1928.  * @return string The sanitized string.
  1929.  */
  1930. function sanitize_title( $title, $fallback_title = '', $context = 'save' ) {
  1931.     $raw_title = $title;
  1932.  
  1933.     if ( 'save' == $context )
  1934.         $title = remove_accents($title);
  1935.  
  1936.     /**
  1937.      * Filters a sanitized title string.
  1938.      *
  1939.      * @since 1.2.0
  1940.      *
  1941.      * @param string $title     Sanitized title.
  1942.      * @param string $raw_title The title prior to sanitization.
  1943.      * @param string $context   The context for which the title is being sanitized.
  1944.      */
  1945.     $title = apply_filters( 'sanitize_title', $title, $raw_title, $context );
  1946.  
  1947.     if ( '' === $title || false === $title )
  1948.         $title = $fallback_title;
  1949.  
  1950.     return $title;
  1951. }
  1952.  
  1953. /**
  1954.  * Sanitizes a title with the 'query' context.
  1955.  *
  1956.  * Used for querying the database for a value from URL.
  1957.  *
  1958.  * @since 3.1.0
  1959.  *
  1960.  * @param string $title The string to be sanitized.
  1961.  * @return string The sanitized string.
  1962.  */
  1963. function sanitize_title_for_query( $title ) {
  1964.     return sanitize_title( $title, '', 'query' );
  1965. }
  1966.  
  1967. /**
  1968.  * Sanitizes a title, replacing whitespace and a few other characters with dashes.
  1969.  *
  1970.  * Limits the output to alphanumeric characters, underscore (_) and dash (-).
  1971.  * Whitespace becomes a dash.
  1972.  *
  1973.  * @since 1.2.0
  1974.  *
  1975.  * @param string $title     The title to be sanitized.
  1976.  * @param string $raw_title Optional. Not used.
  1977.  * @param string $context   Optional. The operation for which the string is sanitized.
  1978.  * @return string The sanitized title.
  1979.  */
  1980. function sanitize_title_with_dashes( $title, $raw_title = '', $context = 'display' ) {
  1981.     $title = strip_tags($title);
  1982.     // Preserve escaped octets.
  1983.     $title = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $title);
  1984.     // Remove percent signs that are not part of an octet.
  1985.     $title = str_replace('%', '', $title);
  1986.     // Restore octets.
  1987.     $title = preg_replace('|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $title);
  1988.  
  1989.     if (seems_utf8($title)) {
  1990.         if (function_exists('mb_strtolower')) {
  1991.             $title = mb_strtolower($title, 'UTF-8');
  1992.         }
  1993.         $title = utf8_uri_encode($title, 200);
  1994.     }
  1995.  
  1996.     $title = strtolower($title);
  1997.  
  1998.     if ( 'save' == $context ) {
  1999.         // Convert nbsp, ndash and mdash to hyphens
  2000.         $title = str_replace( array( '%c2%a0', '%e2%80%93', '%e2%80%94' ), '-', $title );
  2001.         // Convert nbsp, ndash and mdash HTML entities to hyphens
  2002.         $title = str_replace( array( ' ', ' ', '–', '–', '—', '—' ), '-', $title );
  2003.         // Convert forward slash to hyphen
  2004.         $title = str_replace( '/', '-', $title );
  2005.  
  2006.         // Strip these characters entirely
  2007.         $title = str_replace( array(
  2008.             // iexcl and iquest
  2009.             '%c2%a1', '%c2%bf',
  2010.             // angle quotes
  2011.             '%c2%ab', '%c2%bb', '%e2%80%b9', '%e2%80%ba',
  2012.             // curly quotes
  2013.             '%e2%80%98', '%e2%80%99', '%e2%80%9c', '%e2%80%9d',
  2014.             '%e2%80%9a', '%e2%80%9b', '%e2%80%9e', '%e2%80%9f',
  2015.             // copy, reg, deg, hellip and trade
  2016.             '%c2%a9', '%c2%ae', '%c2%b0', '%e2%80%a6', '%e2%84%a2',
  2017.             // acute accents
  2018.             '%c2%b4', '%cb%8a', '%cc%81', '%cd%81',
  2019.             // grave accent, macron, caron
  2020.             '%cc%80', '%cc%84', '%cc%8c',
  2021.         ), '', $title );
  2022.  
  2023.         // Convert times to x
  2024.         $title = str_replace( '%c3%97', 'x', $title );
  2025.     }
  2026.  
  2027.     $title = preg_replace('/&.+?;/', '', $title); // kill entities
  2028.     $title = str_replace('.', '-', $title);
  2029.  
  2030.     $title = preg_replace('/[^%a-z0-9 _-]/', '', $title);
  2031.     $title = preg_replace('/\s+/', '-', $title);
  2032.     $title = preg_replace('|-+|', '-', $title);
  2033.     $title = trim($title, '-');
  2034.  
  2035.     return $title;
  2036. }
  2037.  
  2038. /**
  2039.  * Ensures a string is a valid SQL 'order by' clause.
  2040.  *
  2041.  * Accepts one or more columns, with or without a sort order (ASC / DESC).
  2042.  * e.g. 'column_1', 'column_1, column_2', 'column_1 ASC, column_2 DESC' etc.
  2043.  *
  2044.  * Also accepts 'RAND()'.
  2045.  *
  2046.  * @since 2.5.1
  2047.  *
  2048.  * @param string $orderby Order by clause to be validated.
  2049.  * @return string|false Returns $orderby if valid, false otherwise.
  2050.  */
  2051. function sanitize_sql_orderby( $orderby ) {
  2052.     if ( preg_match( '/^\s*(([a-z0-9_]+|`[a-z0-9_]+`)(\s+(ASC|DESC))?\s*(,\s*(?=[a-z0-9_`])|$))+$/i', $orderby ) || preg_match( '/^\s*RAND\(\s*\)\s*$/i', $orderby ) ) {
  2053.         return $orderby;
  2054.     }
  2055.     return false;
  2056. }
  2057.  
  2058. /**
  2059.  * Sanitizes an HTML classname to ensure it only contains valid characters.
  2060.  *
  2061.  * Strips the string down to A-Z,a-z,0-9,_,-. If this results in an empty
  2062.  * string then it will return the alternative value supplied.
  2063.  *
  2064.  * @todo Expand to support the full range of CDATA that a class attribute can contain.
  2065.  *
  2066.  * @since 2.8.0
  2067.  *
  2068.  * @param string $class    The classname to be sanitized
  2069.  * @param string $fallback Optional. The value to return if the sanitization ends up as an empty string.
  2070.  *     Defaults to an empty string.
  2071.  * @return string The sanitized value
  2072.  */
  2073. function sanitize_html_class( $class, $fallback = '' ) {
  2074.     //Strip out any % encoded octets
  2075.     $sanitized = preg_replace( '|%[a-fA-F0-9][a-fA-F0-9]|', '', $class );
  2076.  
  2077.     //Limit to A-Z,a-z,0-9,_,-
  2078.     $sanitized = preg_replace( '/[^A-Za-z0-9_-]/', '', $sanitized );
  2079.  
  2080.     if ( '' == $sanitized && $fallback ) {
  2081.         return sanitize_html_class( $fallback );
  2082.     }
  2083.     /**
  2084.      * Filters a sanitized HTML class string.
  2085.      *
  2086.      * @since 2.8.0
  2087.      *
  2088.      * @param string $sanitized The sanitized HTML class.
  2089.      * @param string $class     HTML class before sanitization.
  2090.      * @param string $fallback  The fallback string.
  2091.      */
  2092.     return apply_filters( 'sanitize_html_class', $sanitized, $class, $fallback );
  2093. }
  2094.  
  2095. /**
  2096.  * Converts lone & characters into `&` (a.k.a. `&`)
  2097.  *
  2098.  * @since 0.71
  2099.  *
  2100.  * @param string $content    String of characters to be converted.
  2101.  * @param string $deprecated Not used.
  2102.  * @return string Converted string.
  2103.  */
  2104. function convert_chars( $content, $deprecated = '' ) {
  2105.     if ( ! empty( $deprecated ) ) {
  2106.         _deprecated_argument( __FUNCTION__, '0.71' );
  2107.     }
  2108.  
  2109.     if ( strpos( $content, '&' ) !== false ) {
  2110.         $content = preg_replace( '/&([^#])(?![a-z1-4]{1,8};)/i', '&$1', $content );
  2111.     }
  2112.  
  2113.     return $content;
  2114. }
  2115.  
  2116. /**
  2117.  * Converts invalid Unicode references range to valid range.
  2118.  *
  2119.  * @since 4.3.0
  2120.  *
  2121.  * @param string $content String with entities that need converting.
  2122.  * @return string Converted string.
  2123.  */
  2124. function convert_invalid_entities( $content ) {
  2125.     $wp_htmltranswinuni = array(
  2126.         '€' => '€', // the Euro sign
  2127.         '' => '',
  2128.         '‚' => '‚', // these are Windows CP1252 specific characters
  2129.         'ƒ' => 'ƒ',  // they would look weird on non-Windows browsers
  2130.         '„' => '„',
  2131.         '…' => '…',
  2132.         '†' => '†',
  2133.         '‡' => '‡',
  2134.         'ˆ' => 'ˆ',
  2135.         '‰' => '‰',
  2136.         'Š' => 'Š',
  2137.         '‹' => '‹',
  2138.         'Œ' => 'Œ',
  2139.         '' => '',
  2140.         'Ž' => 'Ž',
  2141.         '' => '',
  2142.         '' => '',
  2143.         '‘' => '‘',
  2144.         '’' => '’',
  2145.         '“' => '“',
  2146.         '”' => '”',
  2147.         '•' => '•',
  2148.         '–' => '–',
  2149.         '—' => '—',
  2150.         '˜' => '˜',
  2151.         '™' => '™',
  2152.         'š' => 'š',
  2153.         '›' => '›',
  2154.         'œ' => 'œ',
  2155.         '' => '',
  2156.         'ž' => 'ž',
  2157.         'Ÿ' => 'Ÿ'
  2158.     );
  2159.  
  2160.     if ( strpos( $content, '' ) !== false ) {
  2161.         $content = strtr( $content, $wp_htmltranswinuni );
  2162.     }
  2163.  
  2164.     return $content;
  2165. }
  2166.  
  2167. /**
  2168.  * Balances tags if forced to, or if the 'use_balanceTags' option is set to true.
  2169.  *
  2170.  * @since 0.71
  2171.  *
  2172.  * @param string $text  Text to be balanced
  2173.  * @param bool   $force If true, forces balancing, ignoring the value of the option. Default false.
  2174.  * @return string Balanced text
  2175.  */
  2176. function balanceTags( $text, $force = false ) {
  2177.     if ( $force || get_option('use_balanceTags') == 1 ) {
  2178.         return force_balance_tags( $text );
  2179.     } else {
  2180.         return $text;
  2181.     }
  2182. }
  2183.  
  2184. /**
  2185.  * Balances tags of string using a modified stack.
  2186.  *
  2187.  * @since 2.0.4
  2188.  *
  2189.  * @author Leonard Lin <leonard@acm.org>
  2190.  * @license GPL
  2191.  * @copyright November 4, 2001
  2192.  * @version 1.1
  2193.  * @todo Make better - change loop condition to $text in 1.2
  2194.  * @internal Modified by Scott Reilly (coffee2code) 02 Aug 2004
  2195.  *        1.1  Fixed handling of append/stack pop order of end text
  2196.  *             Added Cleaning Hooks
  2197.  *        1.0  First Version
  2198.  *
  2199.  * @param string $text Text to be balanced.
  2200.  * @return string Balanced text.
  2201.  */
  2202. function force_balance_tags( $text ) {
  2203.     $tagstack = array();
  2204.     $stacksize = 0;
  2205.     $tagqueue = '';
  2206.     $newtext = '';
  2207.     // Known single-entity/self-closing tags
  2208.     $single_tags = array( 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'source' );
  2209.     // Tags that can be immediately nested within themselves
  2210.     $nestable_tags = array( 'blockquote', 'div', 'object', 'q', 'span' );
  2211.  
  2212.     // WP bug fix for comments - in case you REALLY meant to type '< !--'
  2213.     $text = str_replace('< !--', '<    !--', $text);
  2214.     // WP bug fix for LOVE <3 (and other situations with '<' before a number)
  2215.     $text = preg_replace('#<([0-9]{1})#', '<$1', $text);
  2216.  
  2217.     while ( preg_match("/<(\/?[\w:]*)\s*([^>]*)>/", $text, $regex) ) {
  2218.         $newtext .= $tagqueue;
  2219.  
  2220.         $i = strpos($text, $regex[0]);
  2221.         $l = strlen($regex[0]);
  2222.  
  2223.         // clear the shifter
  2224.         $tagqueue = '';
  2225.         // Pop or Push
  2226.         if ( isset($regex[1][0]) && '/' == $regex[1][0] ) { // End Tag
  2227.             $tag = strtolower(substr($regex[1],1));
  2228.             // if too many closing tags
  2229.             if ( $stacksize <= 0 ) {
  2230.                 $tag = '';
  2231.                 // or close to be safe $tag = '/' . $tag;
  2232.             }
  2233.             // if stacktop value = tag close value then pop
  2234.             elseif ( $tagstack[$stacksize - 1] == $tag ) { // found closing tag
  2235.                 $tag = '</' . $tag . '>'; // Close Tag
  2236.                 // Pop
  2237.                 array_pop( $tagstack );
  2238.                 $stacksize--;
  2239.             } else { // closing tag not at top, search for it
  2240.                 for ( $j = $stacksize-1; $j >= 0; $j-- ) {
  2241.                     if ( $tagstack[$j] == $tag ) {
  2242.                     // add tag to tagqueue
  2243.                         for ( $k = $stacksize-1; $k >= $j; $k--) {
  2244.                             $tagqueue .= '</' . array_pop( $tagstack ) . '>';
  2245.                             $stacksize--;
  2246.                         }
  2247.                         break;
  2248.                     }
  2249.                 }
  2250.                 $tag = '';
  2251.             }
  2252.         } else { // Begin Tag
  2253.             $tag = strtolower($regex[1]);
  2254.  
  2255.             // Tag Cleaning
  2256.  
  2257.             // If it's an empty tag "< >", do nothing
  2258.             if ( '' == $tag ) {
  2259.                 // do nothing
  2260.             }
  2261.             // ElseIf it presents itself as a self-closing tag...
  2262.             elseif ( substr( $regex[2], -1 ) == '/' ) {
  2263.                 // ...but it isn't a known single-entity self-closing tag, then don't let it be treated as such and
  2264.                 // immediately close it with a closing tag (the tag will encapsulate no text as a result)
  2265.                 if ( ! in_array( $tag, $single_tags ) )
  2266.                     $regex[2] = trim( substr( $regex[2], 0, -1 ) ) . "></$tag";
  2267.             }
  2268.             // ElseIf it's a known single-entity tag but it doesn't close itself, do so
  2269.             elseif ( in_array($tag, $single_tags) ) {
  2270.                 $regex[2] .= '/';
  2271.             }
  2272.             // Else it's not a single-entity tag
  2273.             else {
  2274.                 // If the top of the stack is the same as the tag we want to push, close previous tag
  2275.                 if ( $stacksize > 0 && !in_array($tag, $nestable_tags) && $tagstack[$stacksize - 1] == $tag ) {
  2276.                     $tagqueue = '</' . array_pop( $tagstack ) . '>';
  2277.                     $stacksize--;
  2278.                 }
  2279.                 $stacksize = array_push( $tagstack, $tag );
  2280.             }
  2281.  
  2282.             // Attributes
  2283.             $attributes = $regex[2];
  2284.             if ( ! empty( $attributes ) && $attributes[0] != '>' )
  2285.                 $attributes = ' ' . $attributes;
  2286.  
  2287.             $tag = '<' . $tag . $attributes . '>';
  2288.             //If already queuing a close tag, then put this tag on, too
  2289.             if ( !empty($tagqueue) ) {
  2290.                 $tagqueue .= $tag;
  2291.                 $tag = '';
  2292.             }
  2293.         }
  2294.         $newtext .= substr($text, 0, $i) . $tag;
  2295.         $text = substr($text, $i + $l);
  2296.     }
  2297.  
  2298.     // Clear Tag Queue
  2299.     $newtext .= $tagqueue;
  2300.  
  2301.     // Add Remaining text
  2302.     $newtext .= $text;
  2303.  
  2304.     // Empty Stack
  2305.     while( $x = array_pop($tagstack) )
  2306.         $newtext .= '</' . $x . '>'; // Add remaining tags to close
  2307.  
  2308.     // WP fix for the bug with HTML comments
  2309.     $newtext = str_replace("< !--","<!--",$newtext);
  2310.     $newtext = str_replace("<    !--","< !--",$newtext);
  2311.  
  2312.     return $newtext;
  2313. }
  2314.  
  2315. /**
  2316.  * Acts on text which is about to be edited.
  2317.  *
  2318.  * The $content is run through esc_textarea(), which uses htmlspecialchars()
  2319.  * to convert special characters to HTML entities. If `$richedit` is set to true,
  2320.  * it is simply a holder for the {@see 'format_to_edit'} filter.
  2321.  *
  2322.  * @since 0.71
  2323.  * @since 4.4.0 The `$richedit` parameter was renamed to `$rich_text` for clarity.
  2324.  *
  2325.  * @param string $content   The text about to be edited.
  2326.  * @param bool   $rich_text Optional. Whether `$content` should be considered rich text,
  2327.  *                          in which case it would not be passed through esc_textarea().
  2328.  *                          Default false.
  2329.  * @return string The text after the filter (and possibly htmlspecialchars()) has been run.
  2330.  */
  2331. function format_to_edit( $content, $rich_text = false ) {
  2332.     /**
  2333.      * Filters the text to be formatted for editing.
  2334.      *
  2335.      * @since 1.2.0
  2336.      *
  2337.      * @param string $content The text, prior to formatting for editing.
  2338.      */
  2339.     $content = apply_filters( 'format_to_edit', $content );
  2340.     if ( ! $rich_text )
  2341.         $content = esc_textarea( $content );
  2342.     return $content;
  2343. }
  2344.  
  2345. /**
  2346.  * Add leading zeros when necessary.
  2347.  *
  2348.  * If you set the threshold to '4' and the number is '10', then you will get
  2349.  * back '0010'. If you set the threshold to '4' and the number is '5000', then you
  2350.  * will get back '5000'.
  2351.  *
  2352.  * Uses sprintf to append the amount of zeros based on the $threshold parameter
  2353.  * and the size of the number. If the number is large enough, then no zeros will
  2354.  * be appended.
  2355.  *
  2356.  * @since 0.71
  2357.  *
  2358.  * @param int $number     Number to append zeros to if not greater than threshold.
  2359.  * @param int $threshold  Digit places number needs to be to not have zeros added.
  2360.  * @return string Adds leading zeros to number if needed.
  2361.  */
  2362. function zeroise( $number, $threshold ) {
  2363.     return sprintf( '%0' . $threshold . 's', $number );
  2364. }
  2365.  
  2366. /**
  2367.  * Adds backslashes before letters and before a number at the start of a string.
  2368.  *
  2369.  * @since 0.71
  2370.  *
  2371.  * @param string $string Value to which backslashes will be added.
  2372.  * @return string String with backslashes inserted.
  2373.  */
  2374. function backslashit( $string ) {
  2375.     if ( isset( $string[0] ) && $string[0] >= '0' && $string[0] <= '9' )
  2376.         $string = '\\\\' . $string;
  2377.     return addcslashes( $string, 'A..Za..z' );
  2378. }
  2379.  
  2380. /**
  2381.  * Appends a trailing slash.
  2382.  *
  2383.  * Will remove trailing forward and backslashes if it exists already before adding
  2384.  * a trailing forward slash. This prevents double slashing a string or path.
  2385.  *
  2386.  * The primary use of this is for paths and thus should be used for paths. It is
  2387.  * not restricted to paths and offers no specific path support.
  2388.  *
  2389.  * @since 1.2.0
  2390.  *
  2391.  * @param string $string What to add the trailing slash to.
  2392.  * @return string String with trailing slash added.
  2393.  */
  2394. function trailingslashit( $string ) {
  2395.     return untrailingslashit( $string ) . '/';
  2396. }
  2397.  
  2398. /**
  2399.  * Removes trailing forward slashes and backslashes if they exist.
  2400.  *
  2401.  * The primary use of this is for paths and thus should be used for paths. It is
  2402.  * not restricted to paths and offers no specific path support.
  2403.  *
  2404.  * @since 2.2.0
  2405.  *
  2406.  * @param string $string What to remove the trailing slashes from.
  2407.  * @return string String without the trailing slashes.
  2408.  */
  2409. function untrailingslashit( $string ) {
  2410.     return rtrim( $string, '/\\' );
  2411. }
  2412.  
  2413. /**
  2414.  * Adds slashes to escape strings.
  2415.  *
  2416.  * Slashes will first be removed if magic_quotes_gpc is set, see {@link
  2417.  * https://secure.php.net/magic_quotes} for more details.
  2418.  *
  2419.  * @since 0.71
  2420.  *
  2421.  * @param string $gpc The string returned from HTTP request data.
  2422.  * @return string Returns a string escaped with slashes.
  2423.  */
  2424. function addslashes_gpc($gpc) {
  2425.     if ( get_magic_quotes_gpc() )
  2426.         $gpc = stripslashes($gpc);
  2427.  
  2428.     return wp_slash($gpc);
  2429. }
  2430.  
  2431. /**
  2432.  * Navigates through an array, object, or scalar, and removes slashes from the values.
  2433.  *
  2434.  * @since 2.0.0
  2435.  *
  2436.  * @param mixed $value The value to be stripped.
  2437.  * @return mixed Stripped value.
  2438.  */
  2439. function stripslashes_deep( $value ) {
  2440.     return map_deep( $value, 'stripslashes_from_strings_only' );
  2441. }
  2442.  
  2443. /**
  2444.  * Callback function for `stripslashes_deep()` which strips slashes from strings.
  2445.  *
  2446.  * @since 4.4.0
  2447.  *
  2448.  * @param mixed $value The array or string to be stripped.
  2449.  * @return mixed $value The stripped value.
  2450.  */
  2451. function stripslashes_from_strings_only( $value ) {
  2452.     return is_string( $value ) ? stripslashes( $value ) : $value;
  2453. }
  2454.  
  2455. /**
  2456.  * Navigates through an array, object, or scalar, and encodes the values to be used in a URL.
  2457.  *
  2458.  * @since 2.2.0
  2459.  *
  2460.  * @param mixed $value The array or string to be encoded.
  2461.  * @return mixed $value The encoded value.
  2462.  */
  2463. function urlencode_deep( $value ) {
  2464.     return map_deep( $value, 'urlencode' );
  2465. }
  2466.  
  2467. /**
  2468.  * Navigates through an array, object, or scalar, and raw-encodes the values to be used in a URL.
  2469.  *
  2470.  * @since 3.4.0
  2471.  *
  2472.  * @param mixed $value The array or string to be encoded.
  2473.  * @return mixed $value The encoded value.
  2474.  */
  2475. function rawurlencode_deep( $value ) {
  2476.     return map_deep( $value, 'rawurlencode' );
  2477. }
  2478.  
  2479. /**
  2480.  * Navigates through an array, object, or scalar, and decodes URL-encoded values
  2481.  *
  2482.  * @since 4.4.0
  2483.  *
  2484.  * @param mixed $value The array or string to be decoded.
  2485.  * @return mixed $value The decoded value.
  2486.  */
  2487. function urldecode_deep( $value ) {
  2488.     return map_deep( $value, 'urldecode' );
  2489. }
  2490.  
  2491. /**
  2492.  * Converts email addresses characters to HTML entities to block spam bots.
  2493.  *
  2494.  * @since 0.71
  2495.  *
  2496.  * @param string $email_address Email address.
  2497.  * @param int    $hex_encoding  Optional. Set to 1 to enable hex encoding.
  2498.  * @return string Converted email address.
  2499.  */
  2500. function antispambot( $email_address, $hex_encoding = 0 ) {
  2501.     $email_no_spam_address = '';
  2502.     for ( $i = 0, $len = strlen( $email_address ); $i < $len; $i++ ) {
  2503.         $j = rand( 0, 1 + $hex_encoding );
  2504.         if ( $j == 0 ) {
  2505.             $email_no_spam_address .= '&#' . ord( $email_address[$i] ) . ';';
  2506.         } elseif ( $j == 1 ) {
  2507.             $email_no_spam_address .= $email_address[$i];
  2508.         } elseif ( $j == 2 ) {
  2509.             $email_no_spam_address .= '%' . zeroise( dechex( ord( $email_address[$i] ) ), 2 );
  2510.         }
  2511.     }
  2512.  
  2513.     return str_replace( '@', '@', $email_no_spam_address );
  2514. }
  2515.  
  2516. /**
  2517.  * Callback to convert URI match to HTML A element.
  2518.  *
  2519.  * This function was backported from 2.5.0 to 2.3.2. Regex callback for make_clickable().
  2520.  *
  2521.  * @since 2.3.2
  2522.  * @access private
  2523.  *
  2524.  * @param array $matches Single Regex Match.
  2525.  * @return string HTML A element with URI address.
  2526.  */
  2527. function _make_url_clickable_cb( $matches ) {
  2528.     $url = $matches[2];
  2529.  
  2530.     if ( ')' == $matches[3] && strpos( $url, '(' ) ) {
  2531.         // If the trailing character is a closing parethesis, and the URL has an opening parenthesis in it, add the closing parenthesis to the URL.
  2532.         // Then we can let the parenthesis balancer do its thing below.
  2533.         $url .= $matches[3];
  2534.         $suffix = '';
  2535.     } else {
  2536.         $suffix = $matches[3];
  2537.     }
  2538.  
  2539.     // Include parentheses in the URL only if paired
  2540.     while ( substr_count( $url, '(' ) < substr_count( $url, ')' ) ) {
  2541.         $suffix = strrchr( $url, ')' ) . $suffix;
  2542.         $url = substr( $url, 0, strrpos( $url, ')' ) );
  2543.     }
  2544.  
  2545.     $url = esc_url($url);
  2546.     if ( empty($url) )
  2547.         return $matches[0];
  2548.  
  2549.     return $matches[1] . "<a href=\"$url\" rel=\"nofollow\">$url</a>" . $suffix;
  2550. }
  2551.  
  2552. /**
  2553.  * Callback to convert URL match to HTML A element.
  2554.  *
  2555.  * This function was backported from 2.5.0 to 2.3.2. Regex callback for make_clickable().
  2556.  *
  2557.  * @since 2.3.2
  2558.  * @access private
  2559.  *
  2560.  * @param array $matches Single Regex Match.
  2561.  * @return string HTML A element with URL address.
  2562.  */
  2563. function _make_web_ftp_clickable_cb( $matches ) {
  2564.     $ret = '';
  2565.     $dest = $matches[2];
  2566.     $dest = 'http://' . $dest;
  2567.  
  2568.     // removed trailing [.,;:)] from URL
  2569.     if ( in_array( substr($dest, -1), array('.', ',', ';', ':', ')') ) === true ) {
  2570.         $ret = substr($dest, -1);
  2571.         $dest = substr($dest, 0, strlen($dest)-1);
  2572.     }
  2573.  
  2574.     $dest = esc_url($dest);
  2575.     if ( empty($dest) )
  2576.         return $matches[0];
  2577.  
  2578.     return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>$ret";
  2579. }
  2580.  
  2581. /**
  2582.  * Callback to convert email address match to HTML A element.
  2583.  *
  2584.  * This function was backported from 2.5.0 to 2.3.2. Regex callback for make_clickable().
  2585.  *
  2586.  * @since 2.3.2
  2587.  * @access private
  2588.  *
  2589.  * @param array $matches Single Regex Match.
  2590.  * @return string HTML A element with email address.
  2591.  */
  2592. function _make_email_clickable_cb( $matches ) {
  2593.     $email = $matches[2] . '@' . $matches[3];
  2594.     return $matches[1] . "<a href=\"mailto:$email\">$email</a>";
  2595. }
  2596.  
  2597. /**
  2598.  * Convert plaintext URI to HTML links.
  2599.  *
  2600.  * Converts URI, www and ftp, and email addresses. Finishes by fixing links
  2601.  * within links.
  2602.  *
  2603.  * @since 0.71
  2604.  *
  2605.  * @param string $text Content to convert URIs.
  2606.  * @return string Content with converted URIs.
  2607.  */
  2608. function make_clickable( $text ) {
  2609.     $r = '';
  2610.     $textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
  2611.     $nested_code_pre = 0; // Keep track of how many levels link is nested inside <pre> or <code>
  2612.     foreach ( $textarr as $piece ) {
  2613.  
  2614.         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 ) )
  2615.             $nested_code_pre++;
  2616.         elseif ( $nested_code_pre && ( '</code>' === strtolower( $piece ) || '</pre>' === strtolower( $piece ) || '</script>' === strtolower( $piece ) || '</style>' === strtolower( $piece ) ) )
  2617.             $nested_code_pre--;
  2618.  
  2619.         if ( $nested_code_pre || empty( $piece ) || ( $piece[0] === '<' && ! preg_match( '|^<\s*[\w]{1,20}+://|', $piece ) ) ) {
  2620.             $r .= $piece;
  2621.             continue;
  2622.         }
  2623.  
  2624.         // Long strings might contain expensive edge cases ...
  2625.         if ( 10000 < strlen( $piece ) ) {
  2626.             // ... break it up
  2627.             foreach ( _split_str_by_whitespace( $piece, 2100 ) as $chunk ) { // 2100: Extra room for scheme and leading and trailing paretheses
  2628.                 if ( 2101 < strlen( $chunk ) ) {
  2629.                     $r .= $chunk; // Too big, no whitespace: bail.
  2630.                 } else {
  2631.                     $r .= make_clickable( $chunk );
  2632.                 }
  2633.             }
  2634.         } else {
  2635.             $ret = " $piece "; // Pad with whitespace to simplify the regexes
  2636.  
  2637.             $url_clickable = '~
  2638.                 ([\\s(<.,;:!?])                                        # 1: Leading whitespace, or punctuation
  2639.                 (                                                      # 2: URL
  2640.                     [\\w]{1,20}+://                                # Scheme and hier-part prefix
  2641.                     (?=\S{1,2000}\s)                               # Limit to URLs less than about 2000 characters long
  2642.                     [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+         # Non-punctuation URL character
  2643.                     (?:                                            # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character
  2644.                         [\'.,;:!?)]                            # Punctuation URL character
  2645.                         [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character
  2646.                     )*
  2647.                 )
  2648.                 (\)?)                                                  # 3: Trailing closing parenthesis (for parethesis balancing post processing)
  2649.             ~xS'; // The regex is a non-anchored pattern and does not have a single fixed starting character.
  2650.                   // Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times.
  2651.  
  2652.             $ret = preg_replace_callback( $url_clickable, '_make_url_clickable_cb', $ret );
  2653.  
  2654.             $ret = preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', '_make_web_ftp_clickable_cb', $ret );
  2655.             $ret = preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret );
  2656.  
  2657.             $ret = substr( $ret, 1, -1 ); // Remove our whitespace padding.
  2658.             $r .= $ret;
  2659.         }
  2660.     }
  2661.  
  2662.     // Cleanup of accidental links within links
  2663.     return preg_replace( '#(<a([ \r\n\t]+[^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', "$1$3</a>", $r );
  2664. }
  2665.  
  2666. /**
  2667.  * Breaks a string into chunks by splitting at whitespace characters.
  2668.  * The length of each returned chunk is as close to the specified length goal as possible,
  2669.  * with the caveat that each chunk includes its trailing delimiter.
  2670.  * Chunks longer than the goal are guaranteed to not have any inner whitespace.
  2671.  *
  2672.  * Joining the returned chunks with empty delimiters reconstructs the input string losslessly.
  2673.  *
  2674.  * Input string must have no null characters (or eventual transformations on output chunks must not care about null characters)
  2675.  *
  2676.  *     _split_str_by_whitespace( "1234 67890 1234 67890a cd 1234   890 123456789 1234567890a    45678   1 3 5 7 90 ", 10 ) ==
  2677.  *     array (
  2678.  *         0 => '1234 67890 ',  // 11 characters: Perfect split
  2679.  *         1 => '1234 ',        //  5 characters: '1234 67890a' was too long
  2680.  *         2 => '67890a cd ',   // 10 characters: '67890a cd 1234' was too long
  2681.  *         3 => '1234   890 ',  // 11 characters: Perfect split
  2682.  *         4 => '123456789 ',   // 10 characters: '123456789 1234567890a' was too long
  2683.  *         5 => '1234567890a ', // 12 characters: Too long, but no inner whitespace on which to split
  2684.  *         6 => '   45678   ',  // 11 characters: Perfect split
  2685.  *         7 => '1 3 5 7 90 ',  // 11 characters: End of $string
  2686.  *     );
  2687.  *
  2688.  * @since 3.4.0
  2689.  * @access private
  2690.  *
  2691.  * @param string $string The string to split.
  2692.  * @param int    $goal   The desired chunk length.
  2693.  * @return array Numeric array of chunks.
  2694.  */
  2695. function _split_str_by_whitespace( $string, $goal ) {
  2696.     $chunks = array();
  2697.  
  2698.     $string_nullspace = strtr( $string, "\r\n\t\v\f ", "\000\000\000\000\000\000" );
  2699.  
  2700.     while ( $goal < strlen( $string_nullspace ) ) {
  2701.         $pos = strrpos( substr( $string_nullspace, 0, $goal + 1 ), "\000" );
  2702.  
  2703.         if ( false === $pos ) {
  2704.             $pos = strpos( $string_nullspace, "\000", $goal + 1 );
  2705.             if ( false === $pos ) {
  2706.                 break;
  2707.             }
  2708.         }
  2709.  
  2710.         $chunks[] = substr( $string, 0, $pos + 1 );
  2711.         $string = substr( $string, $pos + 1 );
  2712.         $string_nullspace = substr( $string_nullspace, $pos + 1 );
  2713.     }
  2714.  
  2715.     if ( $string ) {
  2716.         $chunks[] = $string;
  2717.     }
  2718.  
  2719.     return $chunks;
  2720. }
  2721.  
  2722. /**
  2723.  * Adds rel nofollow string to all HTML A elements in content.
  2724.  *
  2725.  * @since 1.5.0
  2726.  *
  2727.  * @param string $text Content that may contain HTML A elements.
  2728.  * @return string Converted content.
  2729.  */
  2730. function wp_rel_nofollow( $text ) {
  2731.     // This is a pre save filter, so text is already escaped.
  2732.     $text = stripslashes($text);
  2733.     $text = preg_replace_callback('|<a (.+?)>|i', 'wp_rel_nofollow_callback', $text);
  2734.     return wp_slash( $text );
  2735. }
  2736.  
  2737. /**
  2738.  * Callback to add rel=nofollow string to HTML A element.
  2739.  *
  2740.  * Will remove already existing rel="nofollow" and rel='nofollow' from the
  2741.  * string to prevent from invalidating (X)HTML.
  2742.  *
  2743.  * @since 2.3.0
  2744.  *
  2745.  * @param array $matches Single Match
  2746.  * @return string HTML A Element with rel nofollow.
  2747.  */
  2748. function wp_rel_nofollow_callback( $matches ) {
  2749.     $text = $matches[1];
  2750.     $atts = shortcode_parse_atts( $matches[1] );
  2751.     $rel  = 'nofollow';
  2752.  
  2753.     if ( preg_match( '%href=["\'](' . preg_quote( set_url_scheme( home_url(), 'http' ) ) . ')%i', $text ) ||
  2754.          preg_match( '%href=["\'](' . preg_quote( set_url_scheme( home_url(), 'https' ) ) . ')%i', $text )
  2755.     ) {
  2756.         return "<a $text>";
  2757.     }
  2758.  
  2759.     if ( ! empty( $atts['rel'] ) ) {
  2760.         $parts = array_map( 'trim', explode( ' ', $atts['rel'] ) );
  2761.         if ( false === array_search( 'nofollow', $parts ) ) {
  2762.             $parts[] = 'nofollow';
  2763.         }
  2764.         $rel = implode( ' ', $parts );
  2765.         unset( $atts['rel'] );
  2766.  
  2767.         $html = '';
  2768.         foreach ( $atts as $name => $value ) {
  2769.             $html .= "{$name}=\"$value\" ";
  2770.         }
  2771.         $text = trim( $html );
  2772.     }
  2773.     return "<a $text rel=\"$rel\">";
  2774. }
  2775.  
  2776. /**
  2777.  * Convert one smiley code to the icon graphic file equivalent.
  2778.  *
  2779.  * Callback handler for convert_smilies().
  2780.  *
  2781.  * Looks up one smiley code in the $wpsmiliestrans global array and returns an
  2782.  * `<img>` string for that smiley.
  2783.  *
  2784.  * @since 2.8.0
  2785.  *
  2786.  * @global array $wpsmiliestrans
  2787.  *
  2788.  * @param array $matches Single match. Smiley code to convert to image.
  2789.  * @return string Image string for smiley.
  2790.  */
  2791. function translate_smiley( $matches ) {
  2792.     global $wpsmiliestrans;
  2793.  
  2794.     if ( count( $matches ) == 0 )
  2795.         return '';
  2796.  
  2797.     $smiley = trim( reset( $matches ) );
  2798.     $img = $wpsmiliestrans[ $smiley ];
  2799.  
  2800.     $matches = array();
  2801.     $ext = preg_match( '/\.([^.]+)$/', $img, $matches ) ? strtolower( $matches[1] ) : false;
  2802.     $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
  2803.  
  2804.     // Don't convert smilies that aren't images - they're probably emoji.
  2805.     if ( ! in_array( $ext, $image_exts ) ) {
  2806.         return $img;
  2807.     }
  2808.  
  2809.     /**
  2810.      * Filters the Smiley image URL before it's used in the image element.
  2811.      *
  2812.      * @since 2.9.0
  2813.      *
  2814.      * @param string $smiley_url URL for the smiley image.
  2815.      * @param string $img        Filename for the smiley image.
  2816.      * @param string $site_url   Site URL, as returned by site_url().
  2817.      */
  2818.     $src_url = apply_filters( 'smilies_src', includes_url( "images/smilies/$img" ), $img, site_url() );
  2819.  
  2820.     return sprintf( '<img src="%s" alt="%s" class="wp-smiley" style="height: 1em; max-height: 1em;" />', esc_url( $src_url ), esc_attr( $smiley ) );
  2821. }
  2822.  
  2823. /**
  2824.  * Convert text equivalent of smilies to images.
  2825.  *
  2826.  * Will only convert smilies if the option 'use_smilies' is true and the global
  2827.  * used in the function isn't empty.
  2828.  *
  2829.  * @since 0.71
  2830.  *
  2831.  * @global string|array $wp_smiliessearch
  2832.  *
  2833.  * @param string $text Content to convert smilies from text.
  2834.  * @return string Converted content with text smilies replaced with images.
  2835.  */
  2836. function convert_smilies( $text ) {
  2837.     global $wp_smiliessearch;
  2838.     $output = '';
  2839.     if ( get_option( 'use_smilies' ) && ! empty( $wp_smiliessearch ) ) {
  2840.         // HTML loop taken from texturize function, could possible be consolidated
  2841.         $textarr = preg_split( '/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // capture the tags as well as in between
  2842.         $stop = count( $textarr );// loop stuff
  2843.  
  2844.         // Ignore proessing of specific tags
  2845.         $tags_to_ignore = 'code|pre|style|script|textarea';
  2846.         $ignore_block_element = '';
  2847.  
  2848.         for ( $i = 0; $i < $stop; $i++ ) {
  2849.             $content = $textarr[$i];
  2850.  
  2851.             // If we're in an ignore block, wait until we find its closing tag
  2852.             if ( '' == $ignore_block_element && preg_match( '/^<(' . $tags_to_ignore . ')>/', $content, $matches ) )  {
  2853.                 $ignore_block_element = $matches[1];
  2854.             }
  2855.  
  2856.             // If it's not a tag and not in ignore block
  2857.             if ( '' ==  $ignore_block_element && strlen( $content ) > 0 && '<' != $content[0] ) {
  2858.                 $content = preg_replace_callback( $wp_smiliessearch, 'translate_smiley', $content );
  2859.             }
  2860.  
  2861.             // did we exit ignore block
  2862.             if ( '' != $ignore_block_element && '</' . $ignore_block_element . '>' == $content )  {
  2863.                 $ignore_block_element = '';
  2864.             }
  2865.  
  2866.             $output .= $content;
  2867.         }
  2868.     } else {
  2869.         // return default text.
  2870.         $output = $text;
  2871.     }
  2872.     return $output;
  2873. }
  2874.  
  2875. /**
  2876.  * Verifies that an email is valid.
  2877.  *
  2878.  * Does not grok i18n domains. Not RFC compliant.
  2879.  *
  2880.  * @since 0.71
  2881.  *
  2882.  * @param string $email      Email address to verify.
  2883.  * @param bool   $deprecated Deprecated.
  2884.  * @return string|bool Either false or the valid email address.
  2885.  */
  2886. function is_email( $email, $deprecated = false ) {
  2887.     if ( ! empty( $deprecated ) )
  2888.         _deprecated_argument( __FUNCTION__, '3.0.0' );
  2889.  
  2890.     // Test for the minimum length the email can be
  2891.     if ( strlen( $email ) < 6 ) {
  2892.         /**
  2893.          * Filters whether an email address is valid.
  2894.          *
  2895.          * This filter is evaluated under several different contexts, such as 'email_too_short',
  2896.          * 'email_no_at', 'local_invalid_chars', 'domain_period_sequence', 'domain_period_limits',
  2897.          * 'domain_no_periods', 'sub_hyphen_limits', 'sub_invalid_chars', or no specific context.
  2898.          *
  2899.          * @since 2.8.0
  2900.          *
  2901.          * @param bool   $is_email Whether the email address has passed the is_email() checks. Default false.
  2902.          * @param string $email    The email address being checked.
  2903.          * @param string $context  Context under which the email was tested.
  2904.          */
  2905.         return apply_filters( 'is_email', false, $email, 'email_too_short' );
  2906.     }
  2907.  
  2908.     // Test for an @ character after the first position
  2909.     if ( strpos( $email, '@', 1 ) === false ) {
  2910.         /** This filter is documented in wp-includes/formatting.php */
  2911.         return apply_filters( 'is_email', false, $email, 'email_no_at' );
  2912.     }
  2913.  
  2914.     // Split out the local and domain parts
  2915.     list( $local, $domain ) = explode( '@', $email, 2 );
  2916.  
  2917.     // LOCAL PART
  2918.     // Test for invalid characters
  2919.     if ( !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) {
  2920.         /** This filter is documented in wp-includes/formatting.php */
  2921.         return apply_filters( 'is_email', false, $email, 'local_invalid_chars' );
  2922.     }
  2923.  
  2924.     // DOMAIN PART
  2925.     // Test for sequences of periods
  2926.     if ( preg_match( '/\.{2,}/', $domain ) ) {
  2927.         /** This filter is documented in wp-includes/formatting.php */
  2928.         return apply_filters( 'is_email', false, $email, 'domain_period_sequence' );
  2929.     }
  2930.  
  2931.     // Test for leading and trailing periods and whitespace
  2932.     if ( trim( $domain, " \t\n\r\0\x0B." ) !== $domain ) {
  2933.         /** This filter is documented in wp-includes/formatting.php */
  2934.         return apply_filters( 'is_email', false, $email, 'domain_period_limits' );
  2935.     }
  2936.  
  2937.     // Split the domain into subs
  2938.     $subs = explode( '.', $domain );
  2939.  
  2940.     // Assume the domain will have at least two subs
  2941.     if ( 2 > count( $subs ) ) {
  2942.         /** This filter is documented in wp-includes/formatting.php */
  2943.         return apply_filters( 'is_email', false, $email, 'domain_no_periods' );
  2944.     }
  2945.  
  2946.     // Loop through each sub
  2947.     foreach ( $subs as $sub ) {
  2948.         // Test for leading and trailing hyphens and whitespace
  2949.         if ( trim( $sub, " \t\n\r\0\x0B-" ) !== $sub ) {
  2950.             /** This filter is documented in wp-includes/formatting.php */
  2951.             return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
  2952.         }
  2953.  
  2954.         // Test for invalid characters
  2955.         if ( !preg_match('/^[a-z0-9-]+$/i', $sub ) ) {
  2956.             /** This filter is documented in wp-includes/formatting.php */
  2957.             return apply_filters( 'is_email', false, $email, 'sub_invalid_chars' );
  2958.         }
  2959.     }
  2960.  
  2961.     // Congratulations your email made it!
  2962.     /** This filter is documented in wp-includes/formatting.php */
  2963.     return apply_filters( 'is_email', $email, $email, null );
  2964. }
  2965.  
  2966. /**
  2967.  * Convert to ASCII from email subjects.
  2968.  *
  2969.  * @since 1.2.0
  2970.  *
  2971.  * @param string $string Subject line
  2972.  * @return string Converted string to ASCII
  2973.  */
  2974. function wp_iso_descrambler( $string ) {
  2975.     /* this may only work with iso-8859-1, I'm afraid */
  2976.     if (!preg_match('#\=\?(.+)\?Q\?(.+)\?\=#i', $string, $matches)) {
  2977.         return $string;
  2978.     } else {
  2979.         $subject = str_replace('_', ' ', $matches[2]);
  2980.         return preg_replace_callback( '#\=([0-9a-f]{2})#i', '_wp_iso_convert', $subject );
  2981.     }
  2982. }
  2983.  
  2984. /**
  2985.  * Helper function to convert hex encoded chars to ASCII
  2986.  *
  2987.  * @since 3.1.0
  2988.  * @access private
  2989.  *
  2990.  * @param array $match The preg_replace_callback matches array
  2991.  * @return string Converted chars
  2992.  */
  2993. function _wp_iso_convert( $match ) {
  2994.     return chr( hexdec( strtolower( $match[1] ) ) );
  2995. }
  2996.  
  2997. /**
  2998.  * Returns a date in the GMT equivalent.
  2999.  *
  3000.  * Requires and returns a date in the Y-m-d H:i:s format. If there is a
  3001.  * timezone_string available, the date is assumed to be in that timezone,
  3002.  * otherwise it simply subtracts the value of the 'gmt_offset' option. Return
  3003.  * format can be overridden using the $format parameter.
  3004.  *
  3005.  * @since 1.2.0
  3006.  *
  3007.  * @param string $string The date to be converted.
  3008.  * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
  3009.  * @return string GMT version of the date provided.
  3010.  */
  3011. function get_gmt_from_date( $string, $format = 'Y-m-d H:i:s' ) {
  3012.     $tz = get_option( 'timezone_string' );
  3013.     if ( $tz ) {
  3014.         $datetime = date_create( $string, new DateTimeZone( $tz ) );
  3015.         if ( ! $datetime ) {
  3016.             return gmdate( $format, 0 );
  3017.         }
  3018.         $datetime->setTimezone( new DateTimeZone( 'UTC' ) );
  3019.         $string_gmt = $datetime->format( $format );
  3020.     } else {
  3021.         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 ) ) {
  3022.             $datetime = strtotime( $string );
  3023.             if ( false === $datetime ) {
  3024.                 return gmdate( $format, 0 );
  3025.             }
  3026.             return gmdate( $format, $datetime );
  3027.         }
  3028.         $string_time = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
  3029.         $string_gmt = gmdate( $format, $string_time - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
  3030.     }
  3031.     return $string_gmt;
  3032. }
  3033.  
  3034. /**
  3035.  * Converts a GMT date into the correct format for the blog.
  3036.  *
  3037.  * Requires and returns a date in the Y-m-d H:i:s format. If there is a
  3038.  * timezone_string available, the returned date is in that timezone, otherwise
  3039.  * it simply adds the value of gmt_offset. Return format can be overridden
  3040.  * using the $format parameter
  3041.  *
  3042.  * @since 1.2.0
  3043.  *
  3044.  * @param string $string The date to be converted.
  3045.  * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
  3046.  * @return string Formatted date relative to the timezone / GMT offset.
  3047.  */
  3048. function get_date_from_gmt( $string, $format = 'Y-m-d H:i:s' ) {
  3049.     $tz = get_option( 'timezone_string' );
  3050.     if ( $tz ) {
  3051.         $datetime = date_create( $string, new DateTimeZone( 'UTC' ) );
  3052.         if ( ! $datetime )
  3053.             return date( $format, 0 );
  3054.         $datetime->setTimezone( new DateTimeZone( $tz ) );
  3055.         $string_localtime = $datetime->format( $format );
  3056.     } else {
  3057.         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) )
  3058.             return date( $format, 0 );
  3059.         $string_time = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
  3060.         $string_localtime = gmdate( $format, $string_time + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
  3061.     }
  3062.     return $string_localtime;
  3063. }
  3064.  
  3065. /**
  3066.  * Computes an offset in seconds from an iso8601 timezone.
  3067.  *
  3068.  * @since 1.5.0
  3069.  *
  3070.  * @param string $timezone Either 'Z' for 0 offset or '┬▒hhmm'.
  3071.  * @return int|float The offset in seconds.
  3072.  */
  3073. function iso8601_timezone_to_offset( $timezone ) {
  3074.     // $timezone is either 'Z' or '[+|-]hhmm'
  3075.     if ($timezone == 'Z') {
  3076.         $offset = 0;
  3077.     } else {
  3078.         $sign    = (substr($timezone, 0, 1) == '+') ? 1 : -1;
  3079.         $hours   = intval(substr($timezone, 1, 2));
  3080.         $minutes = intval(substr($timezone, 3, 4)) / 60;
  3081.         $offset  = $sign * HOUR_IN_SECONDS * ($hours + $minutes);
  3082.     }
  3083.     return $offset;
  3084. }
  3085.  
  3086. /**
  3087.  * Converts an iso8601 date to MySQL DateTime format used by post_date[_gmt].
  3088.  *
  3089.  * @since 1.5.0
  3090.  *
  3091.  * @param string $date_string Date and time in ISO 8601 format {@link https://en.wikipedia.org/wiki/ISO_8601}.
  3092.  * @param string $timezone    Optional. If set to GMT returns the time minus gmt_offset. Default is 'user'.
  3093.  * @return string The date and time in MySQL DateTime format - Y-m-d H:i:s.
  3094.  */
  3095. function iso8601_to_datetime( $date_string, $timezone = 'user' ) {
  3096.     $timezone = strtolower($timezone);
  3097.  
  3098.     if ($timezone == 'gmt') {
  3099.  
  3100.         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);
  3101.  
  3102.         if (!empty($date_bits[7])) { // we have a timezone, so let's compute an offset
  3103.             $offset = iso8601_timezone_to_offset($date_bits[7]);
  3104.         } else { // we don't have a timezone, so we assume user local timezone (not server's!)
  3105.             $offset = HOUR_IN_SECONDS * get_option('gmt_offset');
  3106.         }
  3107.  
  3108.         $timestamp = gmmktime($date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1]);
  3109.         $timestamp -= $offset;
  3110.  
  3111.         return gmdate('Y-m-d H:i:s', $timestamp);
  3112.  
  3113.     } elseif ($timezone == 'user') {
  3114.         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);
  3115.     }
  3116. }
  3117.  
  3118. /**
  3119.  * Strips out all characters that are not allowable in an email.
  3120.  *
  3121.  * @since 1.5.0
  3122.  *
  3123.  * @param string $email Email address to filter.
  3124.  * @return string Filtered email address.
  3125.  */
  3126. function sanitize_email( $email ) {
  3127.     // Test for the minimum length the email can be
  3128.     if ( strlen( $email ) < 6 ) {
  3129.         /**
  3130.          * Filters a sanitized email address.
  3131.          *
  3132.          * This filter is evaluated under several contexts, including 'email_too_short',
  3133.          * 'email_no_at', 'local_invalid_chars', 'domain_period_sequence', 'domain_period_limits',
  3134.          * 'domain_no_periods', 'domain_no_valid_subs', or no context.
  3135.          *
  3136.          * @since 2.8.0
  3137.          *
  3138.          * @param string $email   The sanitized email address.
  3139.          * @param string $email   The email address, as provided to sanitize_email().
  3140.          * @param string $message A message to pass to the user.
  3141.          */
  3142.         return apply_filters( 'sanitize_email', '', $email, 'email_too_short' );
  3143.     }
  3144.  
  3145.     // Test for an @ character after the first position
  3146.     if ( strpos( $email, '@', 1 ) === false ) {
  3147.         /** This filter is documented in wp-includes/formatting.php */
  3148.         return apply_filters( 'sanitize_email', '', $email, 'email_no_at' );
  3149.     }
  3150.  
  3151.     // Split out the local and domain parts
  3152.     list( $local, $domain ) = explode( '@', $email, 2 );
  3153.  
  3154.     // LOCAL PART
  3155.     // Test for invalid characters
  3156.     $local = preg_replace( '/[^a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]/', '', $local );
  3157.     if ( '' === $local ) {
  3158.         /** This filter is documented in wp-includes/formatting.php */
  3159.         return apply_filters( 'sanitize_email', '', $email, 'local_invalid_chars' );
  3160.     }
  3161.  
  3162.     // DOMAIN PART
  3163.     // Test for sequences of periods
  3164.     $domain = preg_replace( '/\.{2,}/', '', $domain );
  3165.     if ( '' === $domain ) {
  3166.         /** This filter is documented in wp-includes/formatting.php */
  3167.         return apply_filters( 'sanitize_email', '', $email, 'domain_period_sequence' );
  3168.     }
  3169.  
  3170.     // Test for leading and trailing periods and whitespace
  3171.     $domain = trim( $domain, " \t\n\r\0\x0B." );
  3172.     if ( '' === $domain ) {
  3173.         /** This filter is documented in wp-includes/formatting.php */
  3174.         return apply_filters( 'sanitize_email', '', $email, 'domain_period_limits' );
  3175.     }
  3176.  
  3177.     // Split the domain into subs
  3178.     $subs = explode( '.', $domain );
  3179.  
  3180.     // Assume the domain will have at least two subs
  3181.     if ( 2 > count( $subs ) ) {
  3182.         /** This filter is documented in wp-includes/formatting.php */
  3183.         return apply_filters( 'sanitize_email', '', $email, 'domain_no_periods' );
  3184.     }
  3185.  
  3186.     // Create an array that will contain valid subs
  3187.     $new_subs = array();
  3188.  
  3189.     // Loop through each sub
  3190.     foreach ( $subs as $sub ) {
  3191.         // Test for leading and trailing hyphens
  3192.         $sub = trim( $sub, " \t\n\r\0\x0B-" );
  3193.  
  3194.         // Test for invalid characters
  3195.         $sub = preg_replace( '/[^a-z0-9-]+/i', '', $sub );
  3196.  
  3197.         // If there's anything left, add it to the valid subs
  3198.         if ( '' !== $sub ) {
  3199.             $new_subs[] = $sub;
  3200.         }
  3201.     }
  3202.  
  3203.     // If there aren't 2 or more valid subs
  3204.     if ( 2 > count( $new_subs ) ) {
  3205.         /** This filter is documented in wp-includes/formatting.php */
  3206.         return apply_filters( 'sanitize_email', '', $email, 'domain_no_valid_subs' );
  3207.     }
  3208.  
  3209.     // Join valid subs into the new domain
  3210.     $domain = join( '.', $new_subs );
  3211.  
  3212.     // Put the email back together
  3213.     $email = $local . '@' . $domain;
  3214.  
  3215.     // Congratulations your email made it!
  3216.     /** This filter is documented in wp-includes/formatting.php */
  3217.     return apply_filters( 'sanitize_email', $email, $email, null );
  3218. }
  3219.  
  3220. /**
  3221.  * Determines the difference between two timestamps.
  3222.  *
  3223.  * The difference is returned in a human readable format such as "1 hour",
  3224.  * "5 mins", "2 days".
  3225.  *
  3226.  * @since 1.5.0
  3227.  *
  3228.  * @param int $from Unix timestamp from which the difference begins.
  3229.  * @param int $to   Optional. Unix timestamp to end the time difference. Default becomes time() if not set.
  3230.  * @return string Human readable time difference.
  3231.  */
  3232. function human_time_diff( $from, $to = '' ) {
  3233.     if ( empty( $to ) ) {
  3234.         $to = time();
  3235.     }
  3236.  
  3237.     $diff = (int) abs( $to - $from );
  3238.  
  3239.     if ( $diff < HOUR_IN_SECONDS ) {
  3240.         $mins = round( $diff / MINUTE_IN_SECONDS );
  3241.         if ( $mins <= 1 )
  3242.             $mins = 1;
  3243.         /* translators: Time difference between two dates, in minutes (min=minute). 1: Number of minutes */
  3244.         $since = sprintf( _n( '%s min', '%s mins', $mins ), $mins );
  3245.     } elseif ( $diff < DAY_IN_SECONDS && $diff >= HOUR_IN_SECONDS ) {
  3246.         $hours = round( $diff / HOUR_IN_SECONDS );
  3247.         if ( $hours <= 1 )
  3248.             $hours = 1;
  3249.         /* translators: Time difference between two dates, in hours. 1: Number of hours */
  3250.         $since = sprintf( _n( '%s hour', '%s hours', $hours ), $hours );
  3251.     } elseif ( $diff < WEEK_IN_SECONDS && $diff >= DAY_IN_SECONDS ) {
  3252.         $days = round( $diff / DAY_IN_SECONDS );
  3253.         if ( $days <= 1 )
  3254.             $days = 1;
  3255.         /* translators: Time difference between two dates, in days. 1: Number of days */
  3256.         $since = sprintf( _n( '%s day', '%s days', $days ), $days );
  3257.     } elseif ( $diff < MONTH_IN_SECONDS && $diff >= WEEK_IN_SECONDS ) {
  3258.         $weeks = round( $diff / WEEK_IN_SECONDS );
  3259.         if ( $weeks <= 1 )
  3260.             $weeks = 1;
  3261.         /* translators: Time difference between two dates, in weeks. 1: Number of weeks */
  3262.         $since = sprintf( _n( '%s week', '%s weeks', $weeks ), $weeks );
  3263.     } elseif ( $diff < YEAR_IN_SECONDS && $diff >= MONTH_IN_SECONDS ) {
  3264.         $months = round( $diff / MONTH_IN_SECONDS );
  3265.         if ( $months <= 1 )
  3266.             $months = 1;
  3267.         /* translators: Time difference between two dates, in months. 1: Number of months */
  3268.         $since = sprintf( _n( '%s month', '%s months', $months ), $months );
  3269.     } elseif ( $diff >= YEAR_IN_SECONDS ) {
  3270.         $years = round( $diff / YEAR_IN_SECONDS );
  3271.         if ( $years <= 1 )
  3272.             $years = 1;
  3273.         /* translators: Time difference between two dates, in years. 1: Number of years */
  3274.         $since = sprintf( _n( '%s year', '%s years', $years ), $years );
  3275.     }
  3276.  
  3277.     /**
  3278.      * Filters the human readable difference between two timestamps.
  3279.      *
  3280.      * @since 4.0.0
  3281.      *
  3282.      * @param string $since The difference in human readable text.
  3283.      * @param int    $diff  The difference in seconds.
  3284.      * @param int    $from  Unix timestamp from which the difference begins.
  3285.      * @param int    $to    Unix timestamp to end the time difference.
  3286.      */
  3287.     return apply_filters( 'human_time_diff', $since, $diff, $from, $to );
  3288. }
  3289.  
  3290. /**
  3291.  * Generates an excerpt from the content, if needed.
  3292.  *
  3293.  * The excerpt word amount will be 55 words and if the amount is greater than
  3294.  * that, then the string ' […]' will be appended to the excerpt. If the string
  3295.  * is less than 55 words, then the content will be returned as is.
  3296.  *
  3297.  * The 55 word limit can be modified by plugins/themes using the {@see 'excerpt_length'} filter
  3298.  * The ' […]' string can be modified by plugins/themes using the {@see 'excerpt_more'} filter
  3299.  *
  3300.  * @since 1.5.0
  3301.  *
  3302.  * @param string $text Optional. The excerpt. If set to empty, an excerpt is generated.
  3303.  * @return string The excerpt.
  3304.  */
  3305. function wp_trim_excerpt( $text = '' ) {
  3306.     $raw_excerpt = $text;
  3307.     if ( '' == $text ) {
  3308.         $text = get_the_content('');
  3309.  
  3310.         $text = strip_shortcodes( $text );
  3311.  
  3312.         /** This filter is documented in wp-includes/post-template.php */
  3313.         $text = apply_filters( 'the_content', $text );
  3314.         $text = str_replace(']]>', ']]>', $text);
  3315.  
  3316.         /**
  3317.          * Filters the number of words in an excerpt.
  3318.          *
  3319.          * @since 2.7.0
  3320.          *
  3321.          * @param int $number The number of words. Default 55.
  3322.          */
  3323.         $excerpt_length = apply_filters( 'excerpt_length', 55 );
  3324.         /**
  3325.          * Filters the string in the "more" link displayed after a trimmed excerpt.
  3326.          *
  3327.          * @since 2.9.0
  3328.          *
  3329.          * @param string $more_string The string shown within the more link.
  3330.          */
  3331.         $excerpt_more = apply_filters( 'excerpt_more', ' ' . '[…]' );
  3332.         $text = wp_trim_words( $text, $excerpt_length, $excerpt_more );
  3333.     }
  3334.     /**
  3335.      * Filters the trimmed excerpt string.
  3336.      *
  3337.      * @since 2.8.0
  3338.      *
  3339.      * @param string $text        The trimmed text.
  3340.      * @param string $raw_excerpt The text prior to trimming.
  3341.      */
  3342.     return apply_filters( 'wp_trim_excerpt', $text, $raw_excerpt );
  3343. }
  3344.  
  3345. /**
  3346.  * Trims text to a certain number of words.
  3347.  *
  3348.  * This function is localized. For languages that count 'words' by the individual
  3349.  * character (such as East Asian languages), the $num_words argument will apply
  3350.  * to the number of individual characters.
  3351.  *
  3352.  * @since 3.3.0
  3353.  *
  3354.  * @param string $text      Text to trim.
  3355.  * @param int    $num_words Number of words. Default 55.
  3356.  * @param string $more      Optional. What to append if $text needs to be trimmed. Default '…'.
  3357.  * @return string Trimmed text.
  3358.  */
  3359. function wp_trim_words( $text, $num_words = 55, $more = null ) {
  3360.     if ( null === $more ) {
  3361.         $more = __( '…' );
  3362.     }
  3363.  
  3364.     $original_text = $text;
  3365.     $text = wp_strip_all_tags( $text );
  3366.  
  3367.     /*
  3368.      * translators: If your word count is based on single characters (e.g. East Asian characters),
  3369.      * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'.
  3370.      * Do not translate into your own language.
  3371.      */
  3372.     if ( strpos( _x( 'words', 'Word count type. Do not translate!' ), 'characters' ) === 0 && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) ) {
  3373.         $text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $text ), ' ' );
  3374.         preg_match_all( '/./u', $text, $words_array );
  3375.         $words_array = array_slice( $words_array[0], 0, $num_words + 1 );
  3376.         $sep = '';
  3377.     } else {
  3378.         $words_array = preg_split( "/[\n\r\t ]+/", $text, $num_words + 1, PREG_SPLIT_NO_EMPTY );
  3379.         $sep = ' ';
  3380.     }
  3381.  
  3382.     if ( count( $words_array ) > $num_words ) {
  3383.         array_pop( $words_array );
  3384.         $text = implode( $sep, $words_array );
  3385.         $text = $text . $more;
  3386.     } else {
  3387.         $text = implode( $sep, $words_array );
  3388.     }
  3389.  
  3390.     /**
  3391.      * Filters the text content after words have been trimmed.
  3392.      *
  3393.      * @since 3.3.0
  3394.      *
  3395.      * @param string $text          The trimmed text.
  3396.      * @param int    $num_words     The number of words to trim the text to. Default 55.
  3397.      * @param string $more          An optional string to append to the end of the trimmed text, e.g. ….
  3398.      * @param string $original_text The text before it was trimmed.
  3399.      */
  3400.     return apply_filters( 'wp_trim_words', $text, $num_words, $more, $original_text );
  3401. }
  3402.  
  3403. /**
  3404.  * Converts named entities into numbered entities.
  3405.  *
  3406.  * @since 1.5.1
  3407.  *
  3408.  * @param string $text The text within which entities will be converted.
  3409.  * @return string Text with converted entities.
  3410.  */
  3411. function ent2ncr( $text ) {
  3412.  
  3413.     /**
  3414.      * Filters text before named entities are converted into numbered entities.
  3415.      *
  3416.      * A non-null string must be returned for the filter to be evaluated.
  3417.      *
  3418.      * @since 3.3.0
  3419.      *
  3420.      * @param null   $converted_text The text to be converted. Default null.
  3421.      * @param string $text           The text prior to entity conversion.
  3422.      */
  3423.     $filtered = apply_filters( 'pre_ent2ncr', null, $text );
  3424.     if ( null !== $filtered )
  3425.         return $filtered;
  3426.  
  3427.     $to_ncr = array(
  3428.         '"' => '"',
  3429.         '&' => '&',
  3430.         '<' => '<',
  3431.         '>' => '>',
  3432.         '|' => '|',
  3433.         ' ' => ' ',
  3434.         '¡' => '¡',
  3435.         '¢' => '¢',
  3436.         '£' => '£',
  3437.         '¤' => '¤',
  3438.         '¥' => '¥',
  3439.         '¦' => '¦',
  3440.         '&brkbar;' => '¦',
  3441.         '§' => '§',
  3442.         '¨' => '¨',
  3443.         '¨' => '¨',
  3444.         '©' => '©',
  3445.         'ª' => 'ª',
  3446.         '«' => '«',
  3447.         '¬' => '¬',
  3448.         '­' => '­',
  3449.         '®' => '®',
  3450.         '¯' => '¯',
  3451.         '&hibar;' => '¯',
  3452.         '°' => '°',
  3453.         '±' => '±',
  3454.         '²' => '²',
  3455.         '³' => '³',
  3456.         '´' => '´',
  3457.         'µ' => 'µ',
  3458.         '¶' => '¶',
  3459.         '·' => '·',
  3460.         '¸' => '¸',
  3461.         '¹' => '¹',
  3462.         'º' => 'º',
  3463.         '»' => '»',
  3464.         '¼' => '¼',
  3465.         '½' => '½',
  3466.         '¾' => '¾',
  3467.         '¿' => '¿',
  3468.         'À' => 'À',
  3469.         'Á' => 'Á',
  3470.         'Â' => 'Â',
  3471.         'Ã' => 'Ã',
  3472.         'Ä' => 'Ä',
  3473.         'Å' => 'Å',
  3474.         'Æ' => 'Æ',
  3475.         'Ç' => 'Ç',
  3476.         'È' => 'È',
  3477.         'É' => 'É',
  3478.         'Ê' => 'Ê',
  3479.         'Ë' => 'Ë',
  3480.         'Ì' => 'Ì',
  3481.         'Í' => 'Í',
  3482.         'Î' => 'Î',
  3483.         'Ï' => 'Ï',
  3484.         'Ð' => 'Ð',
  3485.         'Ñ' => 'Ñ',
  3486.         'Ò' => 'Ò',
  3487.         'Ó' => 'Ó',
  3488.         'Ô' => 'Ô',
  3489.         'Õ' => 'Õ',
  3490.         'Ö' => 'Ö',
  3491.         '×' => '×',
  3492.         'Ø' => 'Ø',
  3493.         'Ù' => 'Ù',
  3494.         'Ú' => 'Ú',
  3495.         'Û' => 'Û',
  3496.         'Ü' => 'Ü',
  3497.         'Ý' => 'Ý',
  3498.         'Þ' => 'Þ',
  3499.         'ß' => 'ß',
  3500.         'à' => 'à',
  3501.         'á' => 'á',
  3502.         'â' => 'â',
  3503.         'ã' => 'ã',
  3504.         'ä' => 'ä',
  3505.         'å' => 'å',
  3506.         'æ' => 'æ',
  3507.         'ç' => 'ç',
  3508.         'è' => 'è',
  3509.         'é' => 'é',
  3510.         'ê' => 'ê',
  3511.         'ë' => 'ë',
  3512.         'ì' => 'ì',
  3513.         'í' => 'í',
  3514.         'î' => 'î',
  3515.         'ï' => 'ï',
  3516.         'ð' => 'ð',
  3517.         'ñ' => 'ñ',
  3518.         'ò' => 'ò',
  3519.         'ó' => 'ó',
  3520.         'ô' => 'ô',
  3521.         'õ' => 'õ',
  3522.         'ö' => 'ö',
  3523.         '÷' => '÷',
  3524.         'ø' => 'ø',
  3525.         'ù' => 'ù',
  3526.         'ú' => 'ú',
  3527.         'û' => 'û',
  3528.         'ü' => 'ü',
  3529.         'ý' => 'ý',
  3530.         'þ' => 'þ',
  3531.         'ÿ' => 'ÿ',
  3532.         'Œ' => 'Œ',
  3533.         'œ' => 'œ',
  3534.         'Š' => 'Š',
  3535.         'š' => 'š',
  3536.         'Ÿ' => 'Ÿ',
  3537.         'ƒ' => 'ƒ',
  3538.         'ˆ' => 'ˆ',
  3539.         '˜' => '˜',
  3540.         'Α' => 'Α',
  3541.         'Β' => 'Β',
  3542.         'Γ' => 'Γ',
  3543.         'Δ' => 'Δ',
  3544.         'Ε' => 'Ε',
  3545.         'Ζ' => 'Ζ',
  3546.         'Η' => 'Η',
  3547.         'Θ' => 'Θ',
  3548.         'Ι' => 'Ι',
  3549.         'Κ' => 'Κ',
  3550.         'Λ' => 'Λ',
  3551.         'Μ' => 'Μ',
  3552.         'Ν' => 'Ν',
  3553.         'Ξ' => 'Ξ',
  3554.         'Ο' => 'Ο',
  3555.         'Π' => 'Π',
  3556.         'Ρ' => 'Ρ',
  3557.         'Σ' => 'Σ',
  3558.         'Τ' => 'Τ',
  3559.         'Υ' => 'Υ',
  3560.         'Φ' => 'Φ',
  3561.         'Χ' => 'Χ',
  3562.         'Ψ' => 'Ψ',
  3563.         'Ω' => 'Ω',
  3564.         'α' => 'α',
  3565.         'β' => 'β',
  3566.         'γ' => 'γ',
  3567.         'δ' => 'δ',
  3568.         'ε' => 'ε',
  3569.         'ζ' => 'ζ',
  3570.         'η' => 'η',
  3571.         'θ' => 'θ',
  3572.         'ι' => 'ι',
  3573.         'κ' => 'κ',
  3574.         'λ' => 'λ',
  3575.         'μ' => 'μ',
  3576.         'ν' => 'ν',
  3577.         'ξ' => 'ξ',
  3578.         'ο' => 'ο',
  3579.         'π' => 'π',
  3580.         'ρ' => 'ρ',
  3581.         'ς' => 'ς',
  3582.         'σ' => 'σ',
  3583.         'τ' => 'τ',
  3584.         'υ' => 'υ',
  3585.         'φ' => 'φ',
  3586.         'χ' => 'χ',
  3587.         'ψ' => 'ψ',
  3588.         'ω' => 'ω',
  3589.         'ϑ' => 'ϑ',
  3590.         'ϒ' => 'ϒ',
  3591.         'ϖ' => 'ϖ',
  3592.         ' ' => ' ',
  3593.         ' ' => ' ',
  3594.         ' ' => ' ',
  3595.         '‌' => '‌',
  3596.         '‍' => '‍',
  3597.         '‎' => '‎',
  3598.         '‏' => '‏',
  3599.         '–' => '–',
  3600.         '—' => '—',
  3601.         '‘' => '‘',
  3602.         '’' => '’',
  3603.         '‚' => '‚',
  3604.         '“' => '“',
  3605.         '”' => '”',
  3606.         '„' => '„',
  3607.         '†' => '†',
  3608.         '‡' => '‡',
  3609.         '•' => '•',
  3610.         '…' => '…',
  3611.         '‰' => '‰',
  3612.         '′' => '′',
  3613.         '″' => '″',
  3614.         '‹' => '‹',
  3615.         '›' => '›',
  3616.         '‾' => '‾',
  3617.         '⁄' => '⁄',
  3618.         '€' => '€',
  3619.         'ℑ' => 'ℑ',
  3620.         '℘' => '℘',
  3621.         'ℜ' => 'ℜ',
  3622.         '™' => '™',
  3623.         'ℵ' => 'ℵ',
  3624.         '↵' => '↵',
  3625.         '⇐' => '⇐',
  3626.         '⇑' => '⇑',
  3627.         '⇒' => '⇒',
  3628.         '⇓' => '⇓',
  3629.         '⇔' => '⇔',
  3630.         '∀' => '∀',
  3631.         '∂' => '∂',
  3632.         '∃' => '∃',
  3633.         '∅' => '∅',
  3634.         '∇' => '∇',
  3635.         '∈' => '∈',
  3636.         '∉' => '∉',
  3637.         '∋' => '∋',
  3638.         '∏' => '∏',
  3639.         '∑' => '∑',
  3640.         '−' => '−',
  3641.         '∗' => '∗',
  3642.         '√' => '√',
  3643.         '∝' => '∝',
  3644.         '∞' => '∞',
  3645.         '∠' => '∠',
  3646.         '∧' => '∧',
  3647.         '∨' => '∨',
  3648.         '∩' => '∩',
  3649.         '∪' => '∪',
  3650.         '∫' => '∫',
  3651.         '∴' => '∴',
  3652.         '∼' => '∼',
  3653.         '≅' => '≅',
  3654.         '≈' => '≈',
  3655.         '≠' => '≠',
  3656.         '≡' => '≡',
  3657.         '≤' => '≤',
  3658.         '≥' => '≥',
  3659.         '⊂' => '⊂',
  3660.         '⊃' => '⊃',
  3661.         '⊄' => '⊄',
  3662.         '⊆' => '⊆',
  3663.         '⊇' => '⊇',
  3664.         '⊕' => '⊕',
  3665.         '⊗' => '⊗',
  3666.         '⊥' => '⊥',
  3667.         '⋅' => '⋅',
  3668.         '⌈' => '⌈',
  3669.         '⌉' => '⌉',
  3670.         '⌊' => '⌊',
  3671.         '⌋' => '⌋',
  3672.         '⟨' => '〈',
  3673.         '⟩' => '〉',
  3674.         '←' => '←',
  3675.         '↑' => '↑',
  3676.         '→' => '→',
  3677.         '↓' => '↓',
  3678.         '↔' => '↔',
  3679.         '◊' => '◊',
  3680.         '♠' => '♠',
  3681.         '♣' => '♣',
  3682.         '♥' => '♥',
  3683.         '♦' => '♦'
  3684.     );
  3685.  
  3686.     return str_replace( array_keys($to_ncr), array_values($to_ncr), $text );
  3687. }
  3688.  
  3689. /**
  3690.  * Formats text for the editor.
  3691.  *
  3692.  * Generally the browsers treat everything inside a textarea as text, but
  3693.  * it is still a good idea to HTML entity encode `<`, `>` and `&` in the content.
  3694.  *
  3695.  * The filter {@see 'format_for_editor'} is applied here. If `$text` is empty the
  3696.  * filter will be applied to an empty string.
  3697.  *
  3698.  * @since 4.3.0
  3699.  *
  3700.  * @see _WP_Editors::editor()
  3701.  *
  3702.  * @param string $text           The text to be formatted.
  3703.  * @param string $default_editor The default editor for the current user.
  3704.  *                               It is usually either 'html' or 'tinymce'.
  3705.  * @return string The formatted text after filter is applied.
  3706.  */
  3707. function format_for_editor( $text, $default_editor = null ) {
  3708.     if ( $text ) {
  3709.         $text = htmlspecialchars( $text, ENT_NOQUOTES, get_option( 'blog_charset' ) );
  3710.     }
  3711.  
  3712.     /**
  3713.      * Filters the text after it is formatted for the editor.
  3714.      *
  3715.      * @since 4.3.0
  3716.      *
  3717.      * @param string $text           The formatted text.
  3718.      * @param string $default_editor The default editor for the current user.
  3719.      *                               It is usually either 'html' or 'tinymce'.
  3720.      */
  3721.     return apply_filters( 'format_for_editor', $text, $default_editor );
  3722. }
  3723.  
  3724. /**
  3725.  * Perform a deep string replace operation to ensure the values in $search are no longer present
  3726.  *
  3727.  * Repeats the replacement operation until it no longer replaces anything so as to remove "nested" values
  3728.  * e.g. $subject = '%0%0%0DDD', $search ='%0D', $result ='' rather than the '%0%0DD' that
  3729.  * str_replace would return
  3730.  *
  3731.  * @since 2.8.1
  3732.  * @access private
  3733.  *
  3734.  * @param string|array $search  The value being searched for, otherwise known as the needle.
  3735.  *                              An array may be used to designate multiple needles.
  3736.  * @param string       $subject The string being searched and replaced on, otherwise known as the haystack.
  3737.  * @return string The string with the replaced svalues.
  3738.  */
  3739. function _deep_replace( $search, $subject ) {
  3740.     $subject = (string) $subject;
  3741.  
  3742.     $count = 1;
  3743.     while ( $count ) {
  3744.         $subject = str_replace( $search, '', $subject, $count );
  3745.     }
  3746.  
  3747.     return $subject;
  3748. }
  3749.  
  3750. /**
  3751.  * Escapes data for use in a MySQL query.
  3752.  *
  3753.  * Usually you should prepare queries using wpdb::prepare().
  3754.  * Sometimes, spot-escaping is required or useful. One example
  3755.  * is preparing an array for use in an IN clause.
  3756.  *
  3757.  * NOTE: Since 4.8.3, '%' characters will be replaced with a placeholder string,
  3758.  * this prevents certain SQLi attacks from taking place. This change in behaviour
  3759.  * may cause issues for code that expects the return value of esc_sql() to be useable
  3760.  * for other purposes.
  3761.  *
  3762.  * @since 2.8.0
  3763.  *
  3764.  * @global wpdb $wpdb WordPress database abstraction object.
  3765.  *
  3766.  * @param string|array $data Unescaped data
  3767.  * @return string|array Escaped data
  3768.  */
  3769. function esc_sql( $data ) {
  3770.     global $wpdb;
  3771.     return $wpdb->_escape( $data );
  3772. }
  3773.  
  3774. /**
  3775.  * Checks and cleans a URL.
  3776.  *
  3777.  * A number of characters are removed from the URL. If the URL is for displaying
  3778.  * (the default behaviour) ampersands are also replaced. The {@see 'clean_url'} filter
  3779.  * is applied to the returned cleaned URL.
  3780.  *
  3781.  * @since 2.8.0
  3782.  *
  3783.  * @param string $url       The URL to be cleaned.
  3784.  * @param array  $protocols Optional. An array of acceptable protocols.
  3785.  *                            Defaults to return value of wp_allowed_protocols()
  3786.  * @param string $_context  Private. Use esc_url_raw() for database usage.
  3787.  * @return string The cleaned $url after the {@see 'clean_url'} filter is applied.
  3788.  */
  3789. function esc_url( $url, $protocols = null, $_context = 'display' ) {
  3790.     $original_url = $url;
  3791.  
  3792.     if ( '' == $url )
  3793.         return $url;
  3794.  
  3795.     $url = str_replace( ' ', '%20', $url );
  3796.     $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url);
  3797.  
  3798.     if ( '' === $url ) {
  3799.         return $url;
  3800.     }
  3801.  
  3802.     if ( 0 !== stripos( $url, 'mailto:' ) ) {
  3803.         $strip = array('%0d', '%0a', '%0D', '%0A');
  3804.         $url = _deep_replace($strip, $url);
  3805.     }
  3806.  
  3807.     $url = str_replace(';//', '://', $url);
  3808.     /* If the URL doesn't appear to contain a scheme, we
  3809.      * presume it needs http:// prepended (unless a relative
  3810.      * link starting with /, # or ? or a php file).
  3811.      */
  3812.     if ( strpos($url, ':') === false && ! in_array( $url[0], array( '/', '#', '?' ) ) &&
  3813.         ! preg_match('/^[a-z0-9-]+?\.php/i', $url) )
  3814.         $url = 'http://' . $url;
  3815.  
  3816.     // Replace ampersands and single quotes only when displaying.
  3817.     if ( 'display' == $_context ) {
  3818.         $url = wp_kses_normalize_entities( $url );
  3819.         $url = str_replace( '&', '&', $url );
  3820.         $url = str_replace( "'", ''', $url );
  3821.     }
  3822.  
  3823.     if ( ( false !== strpos( $url, '[' ) ) || ( false !== strpos( $url, ']' ) ) ) {
  3824.  
  3825.         $parsed = wp_parse_url( $url );
  3826.         $front  = '';
  3827.  
  3828.         if ( isset( $parsed['scheme'] ) ) {
  3829.             $front .= $parsed['scheme'] . '://';
  3830.         } elseif ( '/' === $url[0] ) {
  3831.             $front .= '//';
  3832.         }
  3833.  
  3834.         if ( isset( $parsed['user'] ) ) {
  3835.             $front .= $parsed['user'];
  3836.         }
  3837.  
  3838.         if ( isset( $parsed['pass'] ) ) {
  3839.             $front .= ':' . $parsed['pass'];
  3840.         }
  3841.  
  3842.         if ( isset( $parsed['user'] ) || isset( $parsed['pass'] ) ) {
  3843.             $front .= '@';
  3844.         }
  3845.  
  3846.         if ( isset( $parsed['host'] ) ) {
  3847.             $front .= $parsed['host'];
  3848.         }
  3849.  
  3850.         if ( isset( $parsed['port'] ) ) {
  3851.             $front .= ':' . $parsed['port'];
  3852.         }
  3853.  
  3854.         $end_dirty = str_replace( $front, '', $url );
  3855.         $end_clean = str_replace( array( '[', ']' ), array( '%5B', '%5D' ), $end_dirty );
  3856.         $url       = str_replace( $end_dirty, $end_clean, $url );
  3857.  
  3858.     }
  3859.  
  3860.     if ( '/' === $url[0] ) {
  3861.         $good_protocol_url = $url;
  3862.     } else {
  3863.         if ( ! is_array( $protocols ) )
  3864.             $protocols = wp_allowed_protocols();
  3865.         $good_protocol_url = wp_kses_bad_protocol( $url, $protocols );
  3866.         if ( strtolower( $good_protocol_url ) != strtolower( $url ) )
  3867.             return '';
  3868.     }
  3869.  
  3870.     /**
  3871.      * Filters a string cleaned and escaped for output as a URL.
  3872.      *
  3873.      * @since 2.3.0
  3874.      *
  3875.      * @param string $good_protocol_url The cleaned URL to be returned.
  3876.      * @param string $original_url      The URL prior to cleaning.
  3877.      * @param string $_context          If 'display', replace ampersands and single quotes only.
  3878.      */
  3879.     return apply_filters( 'clean_url', $good_protocol_url, $original_url, $_context );
  3880. }
  3881.  
  3882. /**
  3883.  * Performs esc_url() for database usage.
  3884.  *
  3885.  * @since 2.8.0
  3886.  *
  3887.  * @param string $url       The URL to be cleaned.
  3888.  * @param array  $protocols An array of acceptable protocols.
  3889.  * @return string The cleaned URL.
  3890.  */
  3891. function esc_url_raw( $url, $protocols = null ) {
  3892.     return esc_url( $url, $protocols, 'db' );
  3893. }
  3894.  
  3895. /**
  3896.  * Convert entities, while preserving already-encoded entities.
  3897.  *
  3898.  * @link https://secure.php.net/htmlentities Borrowed from the PHP Manual user notes.
  3899.  *
  3900.  * @since 1.2.2
  3901.  *
  3902.  * @param string $myHTML The text to be converted.
  3903.  * @return string Converted text.
  3904.  */
  3905. function htmlentities2( $myHTML ) {
  3906.     $translation_table = get_html_translation_table( HTML_ENTITIES, ENT_QUOTES );
  3907.     $translation_table[chr(38)] = '&';
  3908.     return preg_replace( "/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/", "&", strtr($myHTML, $translation_table) );
  3909. }
  3910.  
  3911. /**
  3912.  * Escape single quotes, htmlspecialchar " < > &, and fix line endings.
  3913.  *
  3914.  * Escapes text strings for echoing in JS. It is intended to be used for inline JS
  3915.  * (in a tag attribute, for example onclick="..."). Note that the strings have to
  3916.  * be in single quotes. The {@see 'js_escape'} filter is also applied here.
  3917.  *
  3918.  * @since 2.8.0
  3919.  *
  3920.  * @param string $text The text to be escaped.
  3921.  * @return string Escaped text.
  3922.  */
  3923. function esc_js( $text ) {
  3924.     $safe_text = wp_check_invalid_utf8( $text );
  3925.     $safe_text = _wp_specialchars( $safe_text, ENT_COMPAT );
  3926.     $safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) );
  3927.     $safe_text = str_replace( "\r", '', $safe_text );
  3928.     $safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) );
  3929.     /**
  3930.      * Filters a string cleaned and escaped for output in JavaScript.
  3931.      *
  3932.      * Text passed to esc_js() is stripped of invalid or special characters,
  3933.      * and properly slashed for output.
  3934.      *
  3935.      * @since 2.0.6
  3936.      *
  3937.      * @param string $safe_text The text after it has been escaped.
  3938.       * @param string $text      The text prior to being escaped.
  3939.      */
  3940.     return apply_filters( 'js_escape', $safe_text, $text );
  3941. }
  3942.  
  3943. /**
  3944.  * Escaping for HTML blocks.
  3945.  *
  3946.  * @since 2.8.0
  3947.  *
  3948.  * @param string $text
  3949.  * @return string
  3950.  */
  3951. function esc_html( $text ) {
  3952.     $safe_text = wp_check_invalid_utf8( $text );
  3953.     $safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
  3954.     /**
  3955.      * Filters a string cleaned and escaped for output in HTML.
  3956.      *
  3957.      * Text passed to esc_html() is stripped of invalid or special characters
  3958.      * before output.
  3959.      *
  3960.      * @since 2.8.0
  3961.      *
  3962.      * @param string $safe_text The text after it has been escaped.
  3963.       * @param string $text      The text prior to being escaped.
  3964.      */
  3965.     return apply_filters( 'esc_html', $safe_text, $text );
  3966. }
  3967.  
  3968. /**
  3969.  * Escaping for HTML attributes.
  3970.  *
  3971.  * @since 2.8.0
  3972.  *
  3973.  * @param string $text
  3974.  * @return string
  3975.  */
  3976. function esc_attr( $text ) {
  3977.     $safe_text = wp_check_invalid_utf8( $text );
  3978.     $safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
  3979.     /**
  3980.      * Filters a string cleaned and escaped for output in an HTML attribute.
  3981.      *
  3982.      * Text passed to esc_attr() is stripped of invalid or special characters
  3983.      * before output.
  3984.      *
  3985.      * @since 2.0.6
  3986.      *
  3987.      * @param string $safe_text The text after it has been escaped.
  3988.       * @param string $text      The text prior to being escaped.
  3989.      */
  3990.     return apply_filters( 'attribute_escape', $safe_text, $text );
  3991. }
  3992.  
  3993. /**
  3994.  * Escaping for textarea values.
  3995.  *
  3996.  * @since 3.1.0
  3997.  *
  3998.  * @param string $text
  3999.  * @return string
  4000.  */
  4001. function esc_textarea( $text ) {
  4002.     $safe_text = htmlspecialchars( $text, ENT_QUOTES, get_option( 'blog_charset' ) );
  4003.     /**
  4004.      * Filters a string cleaned and escaped for output in a textarea element.
  4005.      *
  4006.      * @since 3.1.0
  4007.      *
  4008.      * @param string $safe_text The text after it has been escaped.
  4009.       * @param string $text      The text prior to being escaped.
  4010.      */
  4011.     return apply_filters( 'esc_textarea', $safe_text, $text );
  4012. }
  4013.  
  4014. /**
  4015.  * Escape an HTML tag name.
  4016.  *
  4017.  * @since 2.5.0
  4018.  *
  4019.  * @param string $tag_name
  4020.  * @return string
  4021.  */
  4022. function tag_escape( $tag_name ) {
  4023.     $safe_tag = strtolower( preg_replace('/[^a-zA-Z0-9_:]/', '', $tag_name) );
  4024.     /**
  4025.      * Filters a string cleaned and escaped for output as an HTML tag.
  4026.      *
  4027.      * @since 2.8.0
  4028.      *
  4029.      * @param string $safe_tag The tag name after it has been escaped.
  4030.       * @param string $tag_name The text before it was escaped.
  4031.      */
  4032.     return apply_filters( 'tag_escape', $safe_tag, $tag_name );
  4033. }
  4034.  
  4035. /**
  4036.  * Convert full URL paths to absolute paths.
  4037.  *
  4038.  * Removes the http or https protocols and the domain. Keeps the path '/' at the
  4039.  * beginning, so it isn't a true relative link, but from the web root base.
  4040.  *
  4041.  * @since 2.1.0
  4042.  * @since 4.1.0 Support was added for relative URLs.
  4043.  *
  4044.  * @param string $link Full URL path.
  4045.  * @return string Absolute path.
  4046.  */
  4047. function wp_make_link_relative( $link ) {
  4048.     return preg_replace( '|^(https?:)?//[^/]+(/?.*)|i', '$2', $link );
  4049. }
  4050.  
  4051. /**
  4052.  * Sanitises various option values based on the nature of the option.
  4053.  *
  4054.  * This is basically a switch statement which will pass $value through a number
  4055.  * of functions depending on the $option.
  4056.  *
  4057.  * @since 2.0.5
  4058.  *
  4059.  * @global wpdb $wpdb WordPress database abstraction object.
  4060.  *
  4061.  * @param string $option The name of the option.
  4062.  * @param string $value  The unsanitised value.
  4063.  * @return string Sanitized value.
  4064.  */
  4065. function sanitize_option( $option, $value ) {
  4066.     global $wpdb;
  4067.  
  4068.     $original_value = $value;
  4069.     $error = '';
  4070.  
  4071.     switch ( $option ) {
  4072.         case 'admin_email' :
  4073.         case 'new_admin_email' :
  4074.             $value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  4075.             if ( is_wp_error( $value ) ) {
  4076.                 $error = $value->get_error_message();
  4077.             } else {
  4078.                 $value = sanitize_email( $value );
  4079.                 if ( ! is_email( $value ) ) {
  4080.                     $error = __( 'The email address entered did not appear to be a valid email address. Please enter a valid email address.' );
  4081.                 }
  4082.             }
  4083.             break;
  4084.  
  4085.         case 'thumbnail_size_w':
  4086.         case 'thumbnail_size_h':
  4087.         case 'medium_size_w':
  4088.         case 'medium_size_h':
  4089.         case 'medium_large_size_w':
  4090.         case 'medium_large_size_h':
  4091.         case 'large_size_w':
  4092.         case 'large_size_h':
  4093.         case 'mailserver_port':
  4094.         case 'comment_max_links':
  4095.         case 'page_on_front':
  4096.         case 'page_for_posts':
  4097.         case 'rss_excerpt_length':
  4098.         case 'default_category':
  4099.         case 'default_email_category':
  4100.         case 'default_link_category':
  4101.         case 'close_comments_days_old':
  4102.         case 'comments_per_page':
  4103.         case 'thread_comments_depth':
  4104.         case 'users_can_register':
  4105.         case 'start_of_week':
  4106.         case 'site_icon':
  4107.             $value = absint( $value );
  4108.             break;
  4109.  
  4110.         case 'posts_per_page':
  4111.         case 'posts_per_rss':
  4112.             $value = (int) $value;
  4113.             if ( empty($value) )
  4114.                 $value = 1;
  4115.             if ( $value < -1 )
  4116.                 $value = abs($value);
  4117.             break;
  4118.  
  4119.         case 'default_ping_status':
  4120.         case 'default_comment_status':
  4121.             // Options that if not there have 0 value but need to be something like "closed"
  4122.             if ( $value == '0' || $value == '')
  4123.                 $value = 'closed';
  4124.             break;
  4125.  
  4126.         case 'blogdescription':
  4127.         case 'blogname':
  4128.             $value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  4129.             if ( $value !== $original_value ) {
  4130.                 $value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', wp_encode_emoji( $original_value ) );
  4131.             }
  4132.  
  4133.             if ( is_wp_error( $value ) ) {
  4134.                 $error = $value->get_error_message();
  4135.             } else {
  4136.                 $value = esc_html( $value );
  4137.             }
  4138.             break;
  4139.  
  4140.         case 'blog_charset':
  4141.             $value = preg_replace('/[^a-zA-Z0-9_-]/', '', $value); // strips slashes
  4142.             break;
  4143.  
  4144.         case 'blog_public':
  4145.             // This is the value if the settings checkbox is not checked on POST. Don't rely on this.
  4146.             if ( null === $value )
  4147.                 $value = 1;
  4148.             else
  4149.                 $value = intval( $value );
  4150.             break;
  4151.  
  4152.         case 'date_format':
  4153.         case 'time_format':
  4154.         case 'mailserver_url':
  4155.         case 'mailserver_login':
  4156.         case 'mailserver_pass':
  4157.         case 'upload_path':
  4158.             $value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  4159.             if ( is_wp_error( $value ) ) {
  4160.                 $error = $value->get_error_message();
  4161.             } else {
  4162.                 $value = strip_tags( $value );
  4163.                 $value = wp_kses_data( $value );
  4164.             }
  4165.             break;
  4166.  
  4167.         case 'ping_sites':
  4168.             $value = explode( "\n", $value );
  4169.             $value = array_filter( array_map( 'trim', $value ) );
  4170.             $value = array_filter( array_map( 'esc_url_raw', $value ) );
  4171.             $value = implode( "\n", $value );
  4172.             break;
  4173.  
  4174.         case 'gmt_offset':
  4175.             $value = preg_replace('/[^0-9:.-]/', '', $value); // strips slashes
  4176.             break;
  4177.  
  4178.         case 'siteurl':
  4179.             $value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  4180.             if ( is_wp_error( $value ) ) {
  4181.                 $error = $value->get_error_message();
  4182.             } else {
  4183.                 if ( preg_match( '#http(s?)://(.+)#i', $value ) ) {
  4184.                     $value = esc_url_raw( $value );
  4185.                 } else {
  4186.                     $error = __( 'The WordPress address you entered did not appear to be a valid URL. Please enter a valid URL.' );
  4187.                 }
  4188.             }
  4189.             break;
  4190.  
  4191.         case 'home':
  4192.             $value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  4193.             if ( is_wp_error( $value ) ) {
  4194.                 $error = $value->get_error_message();
  4195.             } else {
  4196.                 if ( preg_match( '#http(s?)://(.+)#i', $value ) ) {
  4197.                     $value = esc_url_raw( $value );
  4198.                 } else {
  4199.                     $error = __( 'The Site address you entered did not appear to be a valid URL. Please enter a valid URL.' );
  4200.                 }
  4201.             }
  4202.             break;
  4203.  
  4204.         case 'WPLANG':
  4205.             $allowed = get_available_languages();
  4206.             if ( ! is_multisite() && defined( 'WPLANG' ) && '' !== WPLANG && 'en_US' !== WPLANG ) {
  4207.                 $allowed[] = WPLANG;
  4208.             }
  4209.             if ( ! in_array( $value, $allowed ) && ! empty( $value ) ) {
  4210.                 $value = get_option( $option );
  4211.             }
  4212.             break;
  4213.  
  4214.         case 'illegal_names':
  4215.             $value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  4216.             if ( is_wp_error( $value ) ) {
  4217.                 $error = $value->get_error_message();
  4218.             } else {
  4219.                 if ( ! is_array( $value ) )
  4220.                     $value = explode( ' ', $value );
  4221.  
  4222.                 $value = array_values( array_filter( array_map( 'trim', $value ) ) );
  4223.  
  4224.                 if ( ! $value )
  4225.                     $value = '';
  4226.             }
  4227.             break;
  4228.  
  4229.         case 'limited_email_domains':
  4230.         case 'banned_email_domains':
  4231.             $value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  4232.             if ( is_wp_error( $value ) ) {
  4233.                 $error = $value->get_error_message();
  4234.             } else {
  4235.                 if ( ! is_array( $value ) )
  4236.                     $value = explode( "\n", $value );
  4237.  
  4238.                 $domains = array_values( array_filter( array_map( 'trim', $value ) ) );
  4239.                 $value = array();
  4240.  
  4241.                 foreach ( $domains as $domain ) {
  4242.                     if ( ! preg_match( '/(--|\.\.)/', $domain ) && preg_match( '|^([a-zA-Z0-9-\.])+$|', $domain ) ) {
  4243.                         $value[] = $domain;
  4244.                     }
  4245.                 }
  4246.                 if ( ! $value )
  4247.                     $value = '';
  4248.             }
  4249.             break;
  4250.  
  4251.         case 'timezone_string':
  4252.             $allowed_zones = timezone_identifiers_list();
  4253.             if ( ! in_array( $value, $allowed_zones ) && ! empty( $value ) ) {
  4254.                 $error = __( 'The timezone you have entered is not valid. Please select a valid timezone.' );
  4255.             }
  4256.             break;
  4257.  
  4258.         case 'permalink_structure':
  4259.         case 'category_base':
  4260.         case 'tag_base':
  4261.             $value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  4262.             if ( is_wp_error( $value ) ) {
  4263.                 $error = $value->get_error_message();
  4264.             } else {
  4265.                 $value = esc_url_raw( $value );
  4266.                 $value = str_replace( 'http://', '', $value );
  4267.             }
  4268.  
  4269.             if ( 'permalink_structure' === $option && '' !== $value && ! preg_match( '/%[^\/%]+%/', $value ) ) {
  4270.                 $error = sprintf(
  4271.                     /* translators: %s: Codex URL */
  4272.                     __( 'A structure tag is required when using custom permalinks. <a href="%s">Learn more</a>' ),
  4273.                     __( 'https://codex.wordpress.org/Using_Permalinks#Choosing_your_permalink_structure' )
  4274.                 );
  4275.             }
  4276.             break;
  4277.  
  4278.         case 'default_role' :
  4279.             if ( ! get_role( $value ) && get_role( 'subscriber' ) )
  4280.                 $value = 'subscriber';
  4281.             break;
  4282.  
  4283.         case 'moderation_keys':
  4284.         case 'blacklist_keys':
  4285.             $value = $wpdb->strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
  4286.             if ( is_wp_error( $value ) ) {
  4287.                 $error = $value->get_error_message();
  4288.             } else {
  4289.                 $value = explode( "\n", $value );
  4290.                 $value = array_filter( array_map( 'trim', $value ) );
  4291.                 $value = array_unique( $value );
  4292.                 $value = implode( "\n", $value );
  4293.             }
  4294.             break;
  4295.     }
  4296.  
  4297.     if ( ! empty( $error ) ) {
  4298.         $value = get_option( $option );
  4299.         if ( function_exists( 'add_settings_error' ) ) {
  4300.             add_settings_error( $option, "invalid_{$option}", $error );
  4301.         }
  4302.     }
  4303.  
  4304.     /**
  4305.      * Filters an option value following sanitization.
  4306.      *
  4307.      * @since 2.3.0
  4308.      * @since 4.3.0 Added the `$original_value` parameter.
  4309.      *
  4310.      * @param string $value          The sanitized option value.
  4311.      * @param string $option         The option name.
  4312.      * @param string $original_value The original value passed to the function.
  4313.      */
  4314.     return apply_filters( "sanitize_option_{$option}", $value, $option, $original_value );
  4315. }
  4316.  
  4317. /**
  4318.  * Maps a function to all non-iterable elements of an array or an object.
  4319.  *
  4320.  * This is similar to `array_walk_recursive()` but acts upon objects too.
  4321.  *
  4322.  * @since 4.4.0
  4323.  *
  4324.  * @param mixed    $value    The array, object, or scalar.
  4325.  * @param callable $callback The function to map onto $value.
  4326.  * @return mixed The value with the callback applied to all non-arrays and non-objects inside it.
  4327.  */
  4328. function map_deep( $value, $callback ) {
  4329.     if ( is_array( $value ) ) {
  4330.         foreach ( $value as $index => $item ) {
  4331.             $value[ $index ] = map_deep( $item, $callback );
  4332.         }
  4333.     } elseif ( is_object( $value ) ) {
  4334.         $object_vars = get_object_vars( $value );
  4335.         foreach ( $object_vars as $property_name => $property_value ) {
  4336.             $value->$property_name = map_deep( $property_value, $callback );
  4337.         }
  4338.     } else {
  4339.         $value = call_user_func( $callback, $value );
  4340.     }
  4341.  
  4342.     return $value;
  4343. }
  4344.  
  4345. /**
  4346.  * Parses a string into variables to be stored in an array.
  4347.  *
  4348.  * Uses {@link https://secure.php.net/parse_str parse_str()} and stripslashes if
  4349.  * {@link https://secure.php.net/magic_quotes magic_quotes_gpc} is on.
  4350.  *
  4351.  * @since 2.2.1
  4352.  *
  4353.  * @param string $string The string to be parsed.
  4354.  * @param array  $array  Variables will be stored in this array.
  4355.  */
  4356. function wp_parse_str( $string, &$array ) {
  4357.     parse_str( $string, $array );
  4358.     if ( get_magic_quotes_gpc() )
  4359.         $array = stripslashes_deep( $array );
  4360.     /**
  4361.      * Filters the array of variables derived from a parsed string.
  4362.      *
  4363.      * @since 2.3.0
  4364.      *
  4365.      * @param array $array The array populated with variables.
  4366.      */
  4367.     $array = apply_filters( 'wp_parse_str', $array );
  4368. }
  4369.  
  4370. /**
  4371.  * Convert lone less than signs.
  4372.  *
  4373.  * KSES already converts lone greater than signs.
  4374.  *
  4375.  * @since 2.3.0
  4376.  *
  4377.  * @param string $text Text to be converted.
  4378.  * @return string Converted text.
  4379.  */
  4380. function wp_pre_kses_less_than( $text ) {
  4381.     return preg_replace_callback('%<[^>]*?((?=<)|>|$)%', 'wp_pre_kses_less_than_callback', $text);
  4382. }
  4383.  
  4384. /**
  4385.  * Callback function used by preg_replace.
  4386.  *
  4387.  * @since 2.3.0
  4388.  *
  4389.  * @param array $matches Populated by matches to preg_replace.
  4390.  * @return string The text returned after esc_html if needed.
  4391.  */
  4392. function wp_pre_kses_less_than_callback( $matches ) {
  4393.     if ( false === strpos($matches[0], '>') )
  4394.         return esc_html($matches[0]);
  4395.     return $matches[0];
  4396. }
  4397.  
  4398. /**
  4399.  * WordPress implementation of PHP sprintf() with filters.
  4400.  *
  4401.  * @since 2.5.0
  4402.  * @link https://secure.php.net/sprintf
  4403.  *
  4404.  * @param string $pattern   The string which formatted args are inserted.
  4405.  * @param mixed  $args ,... Arguments to be formatted into the $pattern string.
  4406.  * @return string The formatted string.
  4407.  */
  4408. function wp_sprintf( $pattern ) {
  4409.     $args = func_get_args();
  4410.     $len = strlen($pattern);
  4411.     $start = 0;
  4412.     $result = '';
  4413.     $arg_index = 0;
  4414.     while ( $len > $start ) {
  4415.         // Last character: append and break
  4416.         if ( strlen($pattern) - 1 == $start ) {
  4417.             $result .= substr($pattern, -1);
  4418.             break;
  4419.         }
  4420.  
  4421.         // Literal %: append and continue
  4422.         if ( substr($pattern, $start, 2) == '%%' ) {
  4423.             $start += 2;
  4424.             $result .= '%';
  4425.             continue;
  4426.         }
  4427.  
  4428.         // Get fragment before next %
  4429.         $end = strpos($pattern, '%', $start + 1);
  4430.         if ( false === $end )
  4431.             $end = $len;
  4432.         $fragment = substr($pattern, $start, $end - $start);
  4433.  
  4434.         // Fragment has a specifier
  4435.         if ( $pattern[$start] == '%' ) {
  4436.             // Find numbered arguments or take the next one in order
  4437.             if ( preg_match('/^%(\d+)\$/', $fragment, $matches) ) {
  4438.                 $arg = isset($args[$matches[1]]) ? $args[$matches[1]] : '';
  4439.                 $fragment = str_replace("%{$matches[1]}$", '%', $fragment);
  4440.             } else {
  4441.                 ++$arg_index;
  4442.                 $arg = isset($args[$arg_index]) ? $args[$arg_index] : '';
  4443.             }
  4444.  
  4445.             /**
  4446.              * Filters a fragment from the pattern passed to wp_sprintf().
  4447.              *
  4448.              * If the fragment is unchanged, then sprintf() will be run on the fragment.
  4449.              *
  4450.              * @since 2.5.0
  4451.              *
  4452.              * @param string $fragment A fragment from the pattern.
  4453.              * @param string $arg      The argument.
  4454.              */
  4455.             $_fragment = apply_filters( 'wp_sprintf', $fragment, $arg );
  4456.             if ( $_fragment != $fragment )
  4457.                 $fragment = $_fragment;
  4458.             else
  4459.                 $fragment = sprintf($fragment, strval($arg) );
  4460.         }
  4461.  
  4462.         // Append to result and move to next fragment
  4463.         $result .= $fragment;
  4464.         $start = $end;
  4465.     }
  4466.     return $result;
  4467. }
  4468.  
  4469. /**
  4470.  * Localize list items before the rest of the content.
  4471.  *
  4472.  * The '%l' must be at the first characters can then contain the rest of the
  4473.  * content. The list items will have ', ', ', and', and ' and ' added depending
  4474.  * on the amount of list items in the $args parameter.
  4475.  *
  4476.  * @since 2.5.0
  4477.  *
  4478.  * @param string $pattern Content containing '%l' at the beginning.
  4479.  * @param array  $args    List items to prepend to the content and replace '%l'.
  4480.  * @return string Localized list items and rest of the content.
  4481.  */
  4482. function wp_sprintf_l( $pattern, $args ) {
  4483.     // Not a match
  4484.     if ( substr($pattern, 0, 2) != '%l' )
  4485.         return $pattern;
  4486.  
  4487.     // Nothing to work with
  4488.     if ( empty($args) )
  4489.         return '';
  4490.  
  4491.     /**
  4492.      * Filters the translated delimiters used by wp_sprintf_l().
  4493.      * Placeholders (%s) are included to assist translators and then
  4494.      * removed before the array of strings reaches the filter.
  4495.      *
  4496.      * Please note: Ampersands and entities should be avoided here.
  4497.      *
  4498.      * @since 2.5.0
  4499.      *
  4500.      * @param array $delimiters An array of translated delimiters.
  4501.      */
  4502.     $l = apply_filters( 'wp_sprintf_l', array(
  4503.         /* translators: used to join items in a list with more than 2 items */
  4504.         'between'          => sprintf( __('%s, %s'), '', '' ),
  4505.         /* translators: used to join last two items in a list with more than 2 times */
  4506.         'between_last_two' => sprintf( __('%s, and %s'), '', '' ),
  4507.         /* translators: used to join items in a list with only 2 items */
  4508.         'between_only_two' => sprintf( __('%s and %s'), '', '' ),
  4509.     ) );
  4510.  
  4511.     $args = (array) $args;
  4512.     $result = array_shift($args);
  4513.     if ( count($args) == 1 )
  4514.         $result .= $l['between_only_two'] . array_shift($args);
  4515.     // Loop when more than two args
  4516.     $i = count($args);
  4517.     while ( $i ) {
  4518.         $arg = array_shift($args);
  4519.         $i--;
  4520.         if ( 0 == $i )
  4521.             $result .= $l['between_last_two'] . $arg;
  4522.         else
  4523.             $result .= $l['between'] . $arg;
  4524.     }
  4525.     return $result . substr($pattern, 2);
  4526. }
  4527.  
  4528. /**
  4529.  * Safely extracts not more than the first $count characters from html string.
  4530.  *
  4531.  * UTF-8, tags and entities safe prefix extraction. Entities inside will *NOT*
  4532.  * be counted as one character. For example & will be counted as 4, < as
  4533.  * 3, etc.
  4534.  *
  4535.  * @since 2.5.0
  4536.  *
  4537.  * @param string $str   String to get the excerpt from.
  4538.  * @param int    $count Maximum number of characters to take.
  4539.  * @param string $more  Optional. What to append if $str needs to be trimmed. Defaults to empty string.
  4540.  * @return string The excerpt.
  4541.  */
  4542. function wp_html_excerpt( $str, $count, $more = null ) {
  4543.     if ( null === $more )
  4544.         $more = '';
  4545.     $str = wp_strip_all_tags( $str, true );
  4546.     $excerpt = mb_substr( $str, 0, $count );
  4547.     // remove part of an entity at the end
  4548.     $excerpt = preg_replace( '/&[^;\s]{0,6}$/', '', $excerpt );
  4549.     if ( $str != $excerpt )
  4550.         $excerpt = trim( $excerpt ) . $more;
  4551.     return $excerpt;
  4552. }
  4553.  
  4554. /**
  4555.  * Add a Base url to relative links in passed content.
  4556.  *
  4557.  * By default it supports the 'src' and 'href' attributes. However this can be
  4558.  * changed via the 3rd param.
  4559.  *
  4560.  * @since 2.7.0
  4561.  *
  4562.  * @global string $_links_add_base
  4563.  *
  4564.  * @param string $content String to search for links in.
  4565.  * @param string $base    The base URL to prefix to links.
  4566.  * @param array  $attrs   The attributes which should be processed.
  4567.  * @return string The processed content.
  4568.  */
  4569. function links_add_base_url( $content, $base, $attrs = array('src', 'href') ) {
  4570.     global $_links_add_base;
  4571.     $_links_add_base = $base;
  4572.     $attrs = implode('|', (array)$attrs);
  4573.     return preg_replace_callback( "!($attrs)=(['\"])(.+?)\\2!i", '_links_add_base', $content );
  4574. }
  4575.  
  4576. /**
  4577.  * Callback to add a base url to relative links in passed content.
  4578.  *
  4579.  * @since 2.7.0
  4580.  * @access private
  4581.  *
  4582.  * @global string $_links_add_base
  4583.  *
  4584.  * @param string $m The matched link.
  4585.  * @return string The processed link.
  4586.  */
  4587. function _links_add_base( $m ) {
  4588.     global $_links_add_base;
  4589.     //1 = attribute name  2 = quotation mark  3 = URL
  4590.     return $m[1] . '=' . $m[2] .
  4591.         ( preg_match( '#^(\w{1,20}):#', $m[3], $protocol ) && in_array( $protocol[1], wp_allowed_protocols() ) ?
  4592.             $m[3] :
  4593.             WP_Http::make_absolute_url( $m[3], $_links_add_base )
  4594.         )
  4595.         . $m[2];
  4596. }
  4597.  
  4598. /**
  4599.  * Adds a Target attribute to all links in passed content.
  4600.  *
  4601.  * This function by default only applies to `<a>` tags, however this can be
  4602.  * modified by the 3rd param.
  4603.  *
  4604.  * *NOTE:* Any current target attributed will be stripped and replaced.
  4605.  *
  4606.  * @since 2.7.0
  4607.  *
  4608.  * @global string $_links_add_target
  4609.  *
  4610.  * @param string $content String to search for links in.
  4611.  * @param string $target  The Target to add to the links.
  4612.  * @param array  $tags    An array of tags to apply to.
  4613.  * @return string The processed content.
  4614.  */
  4615. function links_add_target( $content, $target = '_blank', $tags = array('a') ) {
  4616.     global $_links_add_target;
  4617.     $_links_add_target = $target;
  4618.     $tags = implode('|', (array)$tags);
  4619.     return preg_replace_callback( "!<($tags)([^>]*)>!i", '_links_add_target', $content );
  4620. }
  4621.  
  4622. /**
  4623.  * Callback to add a target attribute to all links in passed content.
  4624.  *
  4625.  * @since 2.7.0
  4626.  * @access private
  4627.  *
  4628.  * @global string $_links_add_target
  4629.  *
  4630.  * @param string $m The matched link.
  4631.  * @return string The processed link.
  4632.  */
  4633. function _links_add_target( $m ) {
  4634.     global $_links_add_target;
  4635.     $tag = $m[1];
  4636.     $link = preg_replace('|( target=([\'"])(.*?)\2)|i', '', $m[2]);
  4637.     return '<' . $tag . $link . ' target="' . esc_attr( $_links_add_target ) . '">';
  4638. }
  4639.  
  4640. /**
  4641.  * Normalize EOL characters and strip duplicate whitespace.
  4642.  *
  4643.  * @since 2.7.0
  4644.  *
  4645.  * @param string $str The string to normalize.
  4646.  * @return string The normalized string.
  4647.  */
  4648. function normalize_whitespace( $str ) {
  4649.     $str  = trim( $str );
  4650.     $str  = str_replace( "\r", "\n", $str );
  4651.     $str  = preg_replace( array( '/\n+/', '/[ \t]+/' ), array( "\n", ' ' ), $str );
  4652.     return $str;
  4653. }
  4654.  
  4655. /**
  4656.  * Properly strip all HTML tags including script and style
  4657.  *
  4658.  * This differs from strip_tags() because it removes the contents of
  4659.  * the `<script>` and `<style>` tags. E.g. `strip_tags( '<script>something</script>' )`
  4660.  * will return 'something'. wp_strip_all_tags will return ''
  4661.  *
  4662.  * @since 2.9.0
  4663.  *
  4664.  * @param string $string        String containing HTML tags
  4665.  * @param bool   $remove_breaks Optional. Whether to remove left over line breaks and white space chars
  4666.  * @return string The processed string.
  4667.  */
  4668. function wp_strip_all_tags($string, $remove_breaks = false) {
  4669.     $string = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $string );
  4670.     $string = strip_tags($string);
  4671.  
  4672.     if ( $remove_breaks )
  4673.         $string = preg_replace('/[\r\n\t ]+/', ' ', $string);
  4674.  
  4675.     return trim( $string );
  4676. }
  4677.  
  4678. /**
  4679.  * Sanitizes a string from user input or from the database.
  4680.  *
  4681.  * - Checks for invalid UTF-8,
  4682.  * - Converts single `<` characters to entities
  4683.  * - Strips all tags
  4684.  * - Removes line breaks, tabs, and extra whitespace
  4685.  * - Strips octets
  4686.  *
  4687.  * @since 2.9.0
  4688.  *
  4689.  * @see sanitize_textarea_field()
  4690.  * @see wp_check_invalid_utf8()
  4691.  * @see wp_strip_all_tags()
  4692.  *
  4693.  * @param string $str String to sanitize.
  4694.  * @return string Sanitized string.
  4695.  */
  4696. function sanitize_text_field( $str ) {
  4697.     $filtered = _sanitize_text_fields( $str, false );
  4698.  
  4699.     /**
  4700.      * Filters a sanitized text field string.
  4701.      *
  4702.      * @since 2.9.0
  4703.      *
  4704.      * @param string $filtered The sanitized string.
  4705.      * @param string $str      The string prior to being sanitized.
  4706.      */
  4707.     return apply_filters( 'sanitize_text_field', $filtered, $str );
  4708. }
  4709.  
  4710. /**
  4711.  * Sanitizes a multiline string from user input or from the database.
  4712.  *
  4713.  * The function is like sanitize_text_field(), but preserves
  4714.  * new lines (\n) and other whitespace, which are legitimate
  4715.  * input in textarea elements.
  4716.  *
  4717.  * @see sanitize_text_field()
  4718.  *
  4719.  * @since 4.7.0
  4720.  *
  4721.  * @param string $str String to sanitize.
  4722.  * @return string Sanitized string.
  4723.  */
  4724. function sanitize_textarea_field( $str ) {
  4725.     $filtered = _sanitize_text_fields( $str, true );
  4726.  
  4727.     /**
  4728.      * Filters a sanitized textarea field string.
  4729.      *
  4730.      * @since 4.7.0
  4731.      *
  4732.      * @param string $filtered The sanitized string.
  4733.      * @param string $str      The string prior to being sanitized.
  4734.      */
  4735.     return apply_filters( 'sanitize_textarea_field', $filtered, $str );
  4736. }
  4737.  
  4738. /**
  4739.  * Internal helper function to sanitize a string from user input or from the db
  4740.  *
  4741.  * @since 4.7.0
  4742.  * @access private
  4743.  *
  4744.  * @param string $str String to sanitize.
  4745.  * @param bool $keep_newlines optional Whether to keep newlines. Default: false.
  4746.  * @return string Sanitized string.
  4747.  */
  4748. function _sanitize_text_fields( $str, $keep_newlines = false ) {
  4749.     $filtered = wp_check_invalid_utf8( $str );
  4750.  
  4751.     if ( strpos($filtered, '<') !== false ) {
  4752.         $filtered = wp_pre_kses_less_than( $filtered );
  4753.         // This will strip extra whitespace for us.
  4754.         $filtered = wp_strip_all_tags( $filtered, false );
  4755.  
  4756.         // Use html entities in a special case to make sure no later
  4757.         // newline stripping stage could lead to a functional tag
  4758.         $filtered = str_replace("<\n", "<\n", $filtered);
  4759.     }
  4760.  
  4761.     if ( ! $keep_newlines ) {
  4762.         $filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered );
  4763.     }
  4764.     $filtered = trim( $filtered );
  4765.  
  4766.     $found = false;
  4767.     while ( preg_match('/%[a-f0-9]{2}/i', $filtered, $match) ) {
  4768.         $filtered = str_replace($match[0], '', $filtered);
  4769.         $found = true;
  4770.     }
  4771.  
  4772.     if ( $found ) {
  4773.         // Strip out the whitespace that may now exist after removing the octets.
  4774.         $filtered = trim( preg_replace('/ +/', ' ', $filtered) );
  4775.     }
  4776.  
  4777.     return $filtered;
  4778. }
  4779.  
  4780. /**
  4781.  * i18n friendly version of basename()
  4782.  *
  4783.  * @since 3.1.0
  4784.  *
  4785.  * @param string $path   A path.
  4786.  * @param string $suffix If the filename ends in suffix this will also be cut off.
  4787.  * @return string
  4788.  */
  4789. function wp_basename( $path, $suffix = '' ) {
  4790.     return urldecode( basename( str_replace( array( '%2F', '%5C' ), '/', urlencode( $path ) ), $suffix ) );
  4791. }
  4792.  
  4793. /**
  4794.  * Forever eliminate "Wordpress" from the planet (or at least the little bit we can influence).
  4795.  *
  4796.  * Violating our coding standards for a good function name.
  4797.  *
  4798.  * @since 3.0.0
  4799.  *
  4800.  * @staticvar string|false $dblq
  4801.  *
  4802.  * @param string $text The text to be modified.
  4803.  * @return string The modified text.
  4804.  */
  4805. function capital_P_dangit( $text ) {
  4806.     // Simple replacement for titles
  4807.     $current_filter = current_filter();
  4808.     if ( 'the_title' === $current_filter || 'wp_title' === $current_filter )
  4809.         return str_replace( 'Wordpress', 'WordPress', $text );
  4810.     // Still here? Use the more judicious replacement
  4811.     static $dblq = false;
  4812.     if ( false === $dblq ) {
  4813.         $dblq = _x( '“', 'opening curly double quote' );
  4814.     }
  4815.     return str_replace(
  4816.         array( ' Wordpress', '‘Wordpress', $dblq . 'Wordpress', '>Wordpress', '(Wordpress' ),
  4817.         array( ' WordPress', '‘WordPress', $dblq . 'WordPress', '>WordPress', '(WordPress' ),
  4818.     $text );
  4819. }
  4820.  
  4821. /**
  4822.  * Sanitize a mime type
  4823.  *
  4824.  * @since 3.1.3
  4825.  *
  4826.  * @param string $mime_type Mime type
  4827.  * @return string Sanitized mime type
  4828.  */
  4829. function sanitize_mime_type( $mime_type ) {
  4830.     $sani_mime_type = preg_replace( '/[^-+*.a-zA-Z0-9\/]/', '', $mime_type );
  4831.     /**
  4832.      * Filters a mime type following sanitization.
  4833.      *
  4834.      * @since 3.1.3
  4835.      *
  4836.      * @param string $sani_mime_type The sanitized mime type.
  4837.      * @param string $mime_type      The mime type prior to sanitization.
  4838.      */
  4839.     return apply_filters( 'sanitize_mime_type', $sani_mime_type, $mime_type );
  4840. }
  4841.  
  4842. /**
  4843.  * Sanitize space or carriage return separated URLs that are used to send trackbacks.
  4844.  *
  4845.  * @since 3.4.0
  4846.  *
  4847.  * @param string $to_ping Space or carriage return separated URLs
  4848.  * @return string URLs starting with the http or https protocol, separated by a carriage return.
  4849.  */
  4850. function sanitize_trackback_urls( $to_ping ) {
  4851.     $urls_to_ping = preg_split( '/[\r\n\t ]/', trim( $to_ping ), -1, PREG_SPLIT_NO_EMPTY );
  4852.     foreach ( $urls_to_ping as $k => $url ) {
  4853.         if ( !preg_match( '#^https?://.#i', $url ) )
  4854.             unset( $urls_to_ping[$k] );
  4855.     }
  4856.     $urls_to_ping = array_map( 'esc_url_raw', $urls_to_ping );
  4857.     $urls_to_ping = implode( "\n", $urls_to_ping );
  4858.     /**
  4859.      * Filters a list of trackback URLs following sanitization.
  4860.      *
  4861.      * The string returned here consists of a space or carriage return-delimited list
  4862.      * of trackback URLs.
  4863.      *
  4864.      * @since 3.4.0
  4865.      *
  4866.      * @param string $urls_to_ping Sanitized space or carriage return separated URLs.
  4867.      * @param string $to_ping      Space or carriage return separated URLs before sanitization.
  4868.      */
  4869.     return apply_filters( 'sanitize_trackback_urls', $urls_to_ping, $to_ping );
  4870. }
  4871.  
  4872. /**
  4873.  * Add slashes to a string or array of strings.
  4874.  *
  4875.  * This should be used when preparing data for core API that expects slashed data.
  4876.  * This should not be used to escape data going directly into an SQL query.
  4877.  *
  4878.  * @since 3.6.0
  4879.  *
  4880.  * @param string|array $value String or array of strings to slash.
  4881.  * @return string|array Slashed $value
  4882.  */
  4883. function wp_slash( $value ) {
  4884.     if ( is_array( $value ) ) {
  4885.         foreach ( $value as $k => $v ) {
  4886.             if ( is_array( $v ) ) {
  4887.                 $value[$k] = wp_slash( $v );
  4888.             } else {
  4889.                 $value[$k] = addslashes( $v );
  4890.             }
  4891.         }
  4892.     } else {
  4893.         $value = addslashes( $value );
  4894.     }
  4895.  
  4896.     return $value;
  4897. }
  4898.  
  4899. /**
  4900.  * Remove slashes from a string or array of strings.
  4901.  *
  4902.  * This should be used to remove slashes from data passed to core API that
  4903.  * expects data to be unslashed.
  4904.  *
  4905.  * @since 3.6.0
  4906.  *
  4907.  * @param string|array $value String or array of strings to unslash.
  4908.  * @return string|array Unslashed $value
  4909.  */
  4910. function wp_unslash( $value ) {
  4911.     return stripslashes_deep( $value );
  4912. }
  4913.  
  4914. /**
  4915.  * Extract and return the first URL from passed content.
  4916.  *
  4917.  * @since 3.6.0
  4918.  *
  4919.  * @param string $content A string which might contain a URL.
  4920.  * @return string|false The found URL.
  4921.  */
  4922. function get_url_in_content( $content ) {
  4923.     if ( empty( $content ) ) {
  4924.         return false;
  4925.     }
  4926.  
  4927.     if ( preg_match( '/<a\s[^>]*?href=([\'"])(.+?)\1/is', $content, $matches ) ) {
  4928.         return esc_url_raw( $matches[2] );
  4929.     }
  4930.  
  4931.     return false;
  4932. }
  4933.  
  4934. /**
  4935.  * Returns the regexp for common whitespace characters.
  4936.  *
  4937.  * By default, spaces include new lines, tabs, nbsp entities, and the UTF-8 nbsp.
  4938.  * This is designed to replace the PCRE \s sequence.  In ticket #22692, that
  4939.  * sequence was found to be unreliable due to random inclusion of the A0 byte.
  4940.  *
  4941.  * @since 4.0.0
  4942.  *
  4943.  * @staticvar string $spaces
  4944.  *
  4945.  * @return string The spaces regexp.
  4946.  */
  4947. function wp_spaces_regexp() {
  4948.     static $spaces = '';
  4949.  
  4950.     if ( empty( $spaces ) ) {
  4951.         /**
  4952.          * Filters the regexp for common whitespace characters.
  4953.          *
  4954.          * This string is substituted for the \s sequence as needed in regular
  4955.          * expressions. For websites not written in English, different characters
  4956.          * may represent whitespace. For websites not encoded in UTF-8, the 0xC2 0xA0
  4957.          * sequence may not be in use.
  4958.          *
  4959.          * @since 4.0.0
  4960.          *
  4961.          * @param string $spaces Regexp pattern for matching common whitespace characters.
  4962.          */
  4963.         $spaces = apply_filters( 'wp_spaces_regexp', '[\r\n\t ]|\xC2\xA0| ' );
  4964.     }
  4965.  
  4966.     return $spaces;
  4967. }
  4968.  
  4969. /**
  4970.  * Print the important emoji-related styles.
  4971.  *
  4972.  * @since 4.2.0
  4973.  *
  4974.  * @staticvar bool $printed
  4975.  */
  4976. function print_emoji_styles() {
  4977.     static $printed = false;
  4978.  
  4979.     if ( $printed ) {
  4980.         return;
  4981.     }
  4982.  
  4983.     $printed = true;
  4984. ?>
  4985. <style type="text/css">
  4986. img.wp-smiley,
  4987. img.emoji {
  4988.     display: inline !important;
  4989.     border: none !important;
  4990.     box-shadow: none !important;
  4991.     height: 1em !important;
  4992.     width: 1em !important;
  4993.     margin: 0 .07em !important;
  4994.     vertical-align: -0.1em !important;
  4995.     background: none !important;
  4996.     padding: 0 !important;
  4997. }
  4998. </style>
  4999. <?php
  5000. }
  5001.  
  5002. /**
  5003.  * Print the inline Emoji detection script if it is not already printed.
  5004.  *
  5005.  * @since 4.2.0
  5006.  * @staticvar bool $printed
  5007.  */
  5008. function print_emoji_detection_script() {
  5009.     static $printed = false;
  5010.  
  5011.     if ( $printed ) {
  5012.         return;
  5013.     }
  5014.  
  5015.     $printed = true;
  5016.  
  5017.     _print_emoji_detection_script();
  5018. }
  5019.  
  5020. /**
  5021.  * Prints inline Emoji dection script
  5022.  *
  5023.  * @ignore
  5024.  * @since 4.6.0
  5025.  * @access private
  5026.  */
  5027. function _print_emoji_detection_script() {
  5028.     $settings = array(
  5029.         /**
  5030.          * Filters the URL where emoji png images are hosted.
  5031.          *
  5032.          * @since 4.2.0
  5033.          *
  5034.          * @param string The emoji base URL for png images.
  5035.          */
  5036.         'baseUrl' => apply_filters( 'emoji_url', 'https://s.w.org/images/core/emoji/2.4/72x72/' ),
  5037.  
  5038.         /**
  5039.          * Filters the extension of the emoji png files.
  5040.          *
  5041.          * @since 4.2.0
  5042.          *
  5043.          * @param string The emoji extension for png files. Default .png.
  5044.          */
  5045.         'ext' => apply_filters( 'emoji_ext', '.png' ),
  5046.  
  5047.         /**
  5048.          * Filters the URL where emoji SVG images are hosted.
  5049.          *
  5050.          * @since 4.6.0
  5051.          *
  5052.          * @param string The emoji base URL for svg images.
  5053.          */
  5054.         'svgUrl' => apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/2.4/svg/' ),
  5055.  
  5056.         /**
  5057.          * Filters the extension of the emoji SVG files.
  5058.          *
  5059.          * @since 4.6.0
  5060.          *
  5061.          * @param string The emoji extension for svg files. Default .svg.
  5062.          */
  5063.         'svgExt' => apply_filters( 'emoji_svg_ext', '.svg' ),
  5064.     );
  5065.  
  5066.     $version = 'ver=' . get_bloginfo( 'version' );
  5067.  
  5068.     if ( SCRIPT_DEBUG ) {
  5069.         $settings['source'] = array(
  5070.             /** This filter is documented in wp-includes/class.wp-scripts.php */
  5071.             'wpemoji' => apply_filters( 'script_loader_src', includes_url( "js/wp-emoji.js?$version" ), 'wpemoji' ),
  5072.             /** This filter is documented in wp-includes/class.wp-scripts.php */
  5073.             'twemoji' => apply_filters( 'script_loader_src', includes_url( "js/twemoji.js?$version" ), 'twemoji' ),
  5074.         );
  5075.  
  5076.         ?>
  5077.         <script type="text/javascript">
  5078.             window._wpemojiSettings = <?php echo wp_json_encode( $settings ); ?>;
  5079.             <?php readfile( ABSPATH . WPINC . "/js/wp-emoji-loader.js" ); ?>
  5080.         </script>
  5081.         <?php
  5082.     } else {
  5083.         $settings['source'] = array(
  5084.             /** This filter is documented in wp-includes/class.wp-scripts.php */
  5085.             'concatemoji' => apply_filters( 'script_loader_src', includes_url( "js/wp-emoji-release.min.js?$version" ), 'concatemoji' ),
  5086.         );
  5087.  
  5088.         /*
  5089.          * If you're looking at a src version of this file, you'll see an "include"
  5090.          * statement below. This is used by the `grunt build` process to directly
  5091.          * include a minified version of wp-emoji-loader.js, instead of using the
  5092.          * readfile() method from above.
  5093.          *
  5094.          * If you're looking at a build version of this file, you'll see a string of
  5095.          * minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
  5096.          * and edit wp-emoji-loader.js directly.
  5097.          */
  5098.         ?>
  5099.         <script type="text/javascript">
  5100.             window._wpemojiSettings = <?php echo wp_json_encode( $settings ); ?>;
  5101.             !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,56692,8205,9792,65039],[55357,56692,8203,9792,65039]),!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);
  5102.         </script>
  5103.         <?php
  5104.     }
  5105. }
  5106.  
  5107. /**
  5108.  * Convert emoji characters to their equivalent HTML entity.
  5109.  *
  5110.  * This allows us to store emoji in a DB using the utf8 character set.
  5111.  *
  5112.  * @since 4.2.0
  5113.  *
  5114.  * @param string $content The content to encode.
  5115.  * @return string The encoded content.
  5116.  */
  5117. function wp_encode_emoji( $content ) {
  5118.     $emoji = _wp_emoji_list( 'partials' );
  5119.  
  5120.     foreach ( $emoji as $emojum ) {
  5121.         if ( version_compare( phpversion(), '5.4', '<' ) ) {
  5122.             $emoji_char = html_entity_decode( $emojum, ENT_COMPAT, 'UTF-8' );
  5123.         } else {
  5124.             $emoji_char = html_entity_decode( $emojum );
  5125.         }
  5126.         if ( false !== strpos( $content, $emoji_char ) ) {
  5127.             $content = preg_replace( "/$emoji_char/", $emojum, $content );
  5128.         }
  5129.     }
  5130.  
  5131.     return $content;
  5132. }
  5133.  
  5134. /**
  5135.  * Convert emoji to a static img element.
  5136.  *
  5137.  * @since 4.2.0
  5138.  *
  5139.  * @param string $text The content to encode.
  5140.  * @return string The encoded content.
  5141.  */
  5142. function wp_staticize_emoji( $text ) {
  5143.     if ( false === strpos( $text, '&#x' ) ) {
  5144.         if ( ( function_exists( 'mb_check_encoding' ) && mb_check_encoding( $text, 'ASCII' ) ) || ! preg_match( '/[^\x00-\x7F]/', $text ) ) {
  5145.             // The text doesn't contain anything that might be emoji, so we can return early.
  5146.             return $text;
  5147.         } else {
  5148.             $encoded_text = wp_encode_emoji( $text );
  5149.             if ( $encoded_text === $text ) {
  5150.                 return $encoded_text;
  5151.             }
  5152.  
  5153.             $text = $encoded_text;
  5154.         }
  5155.     }
  5156.  
  5157.     $emoji = _wp_emoji_list( 'entities' );
  5158.  
  5159.     // Quickly narrow down the list of emoji that might be in the text and need replacing.
  5160.     $possible_emoji = array();
  5161.     foreach( $emoji as $emojum ) {
  5162.         if ( false !== strpos( $text, $emojum ) ) {
  5163.             if ( version_compare( phpversion(), '5.4', '<' ) ) {
  5164.                 $possible_emoji[ $emojum ] = html_entity_decode( $emojum, ENT_COMPAT, 'UTF-8' );
  5165.             } else {
  5166.                 $possible_emoji[ $emojum ] = html_entity_decode( $emojum );
  5167.             }
  5168.         }
  5169.     }
  5170.  
  5171.     if ( ! $possible_emoji ) {
  5172.         return $text;
  5173.     }
  5174.  
  5175.     /** This filter is documented in wp-includes/formatting.php */
  5176.     $cdn_url = apply_filters( 'emoji_url', 'https://s.w.org/images/core/emoji/2.4/72x72/' );
  5177.  
  5178.     /** This filter is documented in wp-includes/formatting.php */
  5179.     $ext = apply_filters( 'emoji_ext', '.png' );
  5180.  
  5181.     $output = '';
  5182.     /*
  5183.      * HTML loop taken from smiley function, which was taken from texturize function.
  5184.      * It'll never be consolidated.
  5185.      *
  5186.      * First, capture the tags as well as in between.
  5187.      */
  5188.     $textarr = preg_split( '/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE );
  5189.     $stop = count( $textarr );
  5190.  
  5191.     // Ignore processing of specific tags.
  5192.     $tags_to_ignore = 'code|pre|style|script|textarea';
  5193.     $ignore_block_element = '';
  5194.  
  5195.     for ( $i = 0; $i < $stop; $i++ ) {
  5196.         $content = $textarr[$i];
  5197.  
  5198.         // If we're in an ignore block, wait until we find its closing tag.
  5199.         if ( '' == $ignore_block_element && preg_match( '/^<(' . $tags_to_ignore . ')>/', $content, $matches ) )  {
  5200.             $ignore_block_element = $matches[1];
  5201.         }
  5202.  
  5203.         // If it's not a tag and not in ignore block.
  5204.         if ( '' ==  $ignore_block_element && strlen( $content ) > 0 && '<' != $content[0] && false !== strpos( $content, '&#x' ) ) {
  5205.             foreach ( $possible_emoji as $emojum => $emoji_char ) {
  5206.                 if ( false === strpos( $content, $emojum ) ) {
  5207.                     continue;
  5208.                 }
  5209.  
  5210.                 $file = str_replace( ';&#x', '-', $emojum );
  5211.                 $file = str_replace( array( '&#x', ';'), '', $file );
  5212.  
  5213.                 $entity = sprintf( '<img src="%s" alt="%s" class="wp-smiley" style="height: 1em; max-height: 1em;" />', $cdn_url . $file . $ext, $emoji_char );
  5214.  
  5215.                 $content = str_replace( $emojum, $entity, $content );
  5216.             }
  5217.         }
  5218.  
  5219.         // Did we exit ignore block.
  5220.         if ( '' != $ignore_block_element && '</' . $ignore_block_element . '>' == $content )  {
  5221.             $ignore_block_element = '';
  5222.         }
  5223.  
  5224.         $output .= $content;
  5225.     }
  5226.  
  5227.     // Finally, remove any stray U+FE0F characters
  5228.     $output = str_replace( '️', '', $output );
  5229.  
  5230.     return $output;
  5231. }
  5232.  
  5233. /**
  5234.  * Convert emoji in emails into static images.
  5235.  *
  5236.  * @since 4.2.0
  5237.  *
  5238.  * @param array $mail The email data array.
  5239.  * @return array The email data array, with emoji in the message staticized.
  5240.  */
  5241. function wp_staticize_emoji_for_email( $mail ) {
  5242.     if ( ! isset( $mail['message'] ) ) {
  5243.         return $mail;
  5244.     }
  5245.  
  5246.     /*
  5247.      * We can only transform the emoji into images if it's a text/html email.
  5248.      * To do that, here's a cut down version of the same process that happens
  5249.      * in wp_mail() - get the Content-Type from the headers, if there is one,
  5250.      * then pass it through the wp_mail_content_type filter, in case a plugin
  5251.      * is handling changing the Content-Type.
  5252.      */
  5253.     $headers = array();
  5254.     if ( isset( $mail['headers'] ) ) {
  5255.         if ( is_array( $mail['headers'] ) ) {
  5256.             $headers = $mail['headers'];
  5257.         } else {
  5258.             $headers = explode( "\n", str_replace( "\r\n", "\n", $mail['headers'] ) );
  5259.         }
  5260.     }
  5261.  
  5262.     foreach ( $headers as $header ) {
  5263.         if ( strpos($header, ':') === false ) {
  5264.             continue;
  5265.         }
  5266.  
  5267.         // Explode them out.
  5268.         list( $name, $content ) = explode( ':', trim( $header ), 2 );
  5269.  
  5270.         // Cleanup crew.
  5271.         $name    = trim( $name    );
  5272.         $content = trim( $content );
  5273.  
  5274.         if ( 'content-type' === strtolower( $name ) ) {
  5275.             if ( strpos( $content, ';' ) !== false ) {
  5276.                 list( $type, $charset ) = explode( ';', $content );
  5277.                 $content_type = trim( $type );
  5278.             } else {
  5279.                 $content_type = trim( $content );
  5280.             }
  5281.             break;
  5282.         }
  5283.     }
  5284.  
  5285.     // Set Content-Type if we don't have a content-type from the input headers.
  5286.     if ( ! isset( $content_type ) ) {
  5287.         $content_type = 'text/plain';
  5288.     }
  5289.  
  5290.     /** This filter is documented in wp-includes/pluggable.php */
  5291.     $content_type = apply_filters( 'wp_mail_content_type', $content_type );
  5292.  
  5293.     if ( 'text/html' === $content_type ) {
  5294.         $mail['message'] = wp_staticize_emoji( $mail['message'] );
  5295.     }
  5296.  
  5297.     return $mail;
  5298. }
  5299.  
  5300. /**
  5301.  * Returns a arrays of emoji data.
  5302.  *
  5303.  * These arrays automatically built from the regex in twemoji.js - if they need to be updated,
  5304.  * you should update the regex there, then run the `grunt precommit:emoji` job.
  5305.  *
  5306.  * @since 4.9.0
  5307.  * @access private
  5308.  *
  5309.  * @param string $type Optional. Which array type to return. Accepts 'partials' or 'entities', default 'entities'.
  5310.  * @return array An array to match all emoji that WordPress recognises.
  5311.  */
  5312. function _wp_emoji_list( $type = 'entities' ) {
  5313.     // Do not remove the START/END comments - they're used to find where to insert the arrays.
  5314.  
  5315.     // START: emoji arrays
  5316.     $entities = array('👩‍❤️‍💋‍👩','👩‍❤️‍💋‍👨','👨‍❤️‍💋‍👨','🏴󠁧󠁢󠁳󠁣󠁴󠁿','🏴󠁧󠁢󠁷󠁬󠁳󠁿','🏴󠁧󠁢󠁥󠁮󠁧󠁿','👩‍👩‍👧‍👦','👨‍👨‍👦‍👦','👩‍👩‍👦‍👦','👨‍👨‍👧‍👦','👨‍👨‍👧‍👧','👨‍👩‍👧‍👧','👨‍👩‍👦‍👦','👩‍👩‍👧‍👧','👨‍👩‍👧‍👦','👨‍❤️‍👨','👩‍❤️‍👨','👩‍❤️‍👩','👩‍👩‍👦','👩‍👦‍👦','👩‍👧‍👦','👩‍👧‍👧','👨‍👨‍👦','👨‍👩‍👧','👨‍👧‍👧','👨‍👧‍👦','👩‍👩‍👧','👨‍👩‍👦','👨‍👨‍👧','👨‍👦‍👦','👩🏾‍✈️','🏋🏻‍♂️','🏋🏼‍♀️','🏋🏼‍♂️','🏋🏽‍♀️','🏋🏽‍♂️','🏋🏾‍♀️','🏋🏾‍♂️','🏋🏿‍♀️','🏋🏿‍♂️','🏌🏻‍♀️','🏌🏻‍♂️','🏌🏼‍♀️','🏌🏼‍♂️','🏌🏽‍♀️','🏌🏽‍♂️','🏌🏾‍♀️','🏌🏾‍♂️','🏌🏿‍♀️','🏌🏿‍♂️','💆🏻‍♀️','🏃🏼‍♀️','🏃🏼‍♂️','🧝🏿‍♂️','🧝🏿‍♀️','🧝🏾‍♂️','🧝🏾‍♀️','🧝🏽‍♂️','🧝🏽‍♀️','🧝🏼‍♂️','🧝🏼‍♀️','🧝🏻‍♂️','🧝🏻‍♀️','🧜🏿‍♂️','🧜🏿‍♀️','🧜🏾‍♂️','🧜🏾‍♀️','👨🏻‍⚕️','👨🏻‍⚖️','👨🏻‍✈️','🧜🏽‍♂️','🧜🏽‍♀️','🧜🏼‍♂️','🧜🏼‍♀️','🧜🏻‍♂️','🧜🏻‍♀️','🧛🏿‍♂️','🧛🏿‍♀️','🧛🏾‍♂️','🧛🏾‍♀️','🧛🏽‍♂️','🧛🏽‍♀️','🧛🏼‍♂️','👨🏼‍⚕️','👨🏼‍⚖️','👨🏼‍✈️','🧛🏼‍♀️','🧛🏻‍♂️','🧛🏻‍♀️','🧚🏿‍♂️','🧚🏿‍♀️','🧚🏾‍♂️','🧚🏾‍♀️','🧚🏽‍♂️','🧚🏽‍♀️','🧚🏼‍♂️','🧚🏼‍♀️','🧚🏻‍♂️','🧚🏻‍♀️','👨🏽‍⚕️','👨🏽‍⚖️','👨🏽‍✈️','🧙🏿‍♂️','🧙🏿‍♀️','🧙🏾‍♂️','🧙🏾‍♀️','🧙🏽‍♂️','🧙🏽‍♀️','🧙🏼‍♂️','🧙🏼‍♀️','🧙🏻‍♂️','🧙🏻‍♀️','🧘🏿‍♂️','🧘🏿‍♀️','🧘🏾‍♂️','👨🏾‍⚕️','👨🏾‍⚖️','👨🏾‍✈️','🧘🏾‍♀️','🧘🏽‍♂️','🧘🏽‍♀️','🧘🏼‍♂️','🧘🏼‍♀️','🧘🏻‍♂️','🧘🏻‍♀️','🧗🏿‍♂️','🧗🏿‍♀️','🧗🏾‍♂️','🧗🏾‍♀️','🧗🏽‍♂️','🧗🏽‍♀️','👨🏿‍⚕️','👨🏿‍⚖️','👨🏿‍✈️','🧗🏼‍♂️','🧗🏼‍♀️','🧗🏻‍♂️','🧗🏻‍♀️','🧖🏿‍♂️','🧖🏿‍♀️','🧖🏾‍♂️','🏃🏽‍♀️','🧖🏾‍♀️','🏃🏽‍♂️','🏃🏾‍♀️','🧖🏽‍♂️','🏃🏾‍♂️','🏃🏿‍♀️','🏃🏿‍♂️','🏄🏻‍♀️','🏄🏻‍♂️','🏄🏼‍♀️','🏄🏼‍♂️','🏄🏽‍♀️','🏄🏽‍♂️','🏄🏾‍♀️','🧖🏽‍♀️','🧖🏼‍♂️','🧖🏼‍♀️','🧖🏻‍♂️','🧖🏻‍♀️','🤾🏿‍♂️','🤾🏿‍♀️','🤾🏾‍♂️','🤾🏾‍♀️','🏄🏾‍♂️','🏄🏿‍♀️','🤾🏽‍♂️','🤾🏽‍♀️','🤾🏼‍♂️','🤾🏼‍♀️','🤾🏻‍♂️','🤾🏻‍♀️','🤽🏿‍♂️','🤽🏿‍♀️','🤽🏾‍♂️','🤽🏾‍♀️','🤽🏽‍♂️','🤽🏽‍♀️','🤽🏼‍♂️','👩🏻‍⚕️','👩🏻‍⚖️','👩🏻‍✈️','🤽🏼‍♀️','🤽🏻‍♂️','🤽🏻‍♀️','🤹🏿‍♂️','🤹🏿‍♀️','🤹🏾‍♂️','🤹🏾‍♀️','🤹🏽‍♂️','🤹🏽‍♀️','🤹🏼‍♂️','🤹🏼‍♀️','🤹🏻‍♂️','🤹🏻‍♀️','👩🏼‍⚕️','👩🏼‍⚖️','👩🏼‍✈️','🤸🏿‍♂️','🤸🏿‍♀️','🤸🏾‍♂️','🤸🏾‍♀️','🤸🏽‍♂️','🤸🏽‍♀️','🤸🏼‍♂️','🤸🏼‍♀️','🤸🏻‍♂️','🤸🏻‍♀️','🤷🏿‍♂️','🤷🏿‍♀️','🤷🏾‍♂️','👩🏽‍⚕️','👩🏽‍⚖️','👩🏽‍✈️','🤷🏾‍♀️','🤷🏽‍♂️','🤷🏽‍♀️','🤷🏼‍♂️','🤷🏼‍♀️','🤷🏻‍♂️','🤷🏻‍♀️','🤵🏿‍♂️','🤵🏿‍♀️','🤵🏾‍♂️','🤵🏾‍♀️','🤵🏽‍♂️','🤵🏽‍♀️','👩🏾‍⚕️','👩🏾‍⚖️','🏃🏻‍♂️','🤵🏼‍♂️','🤵🏼‍♀️','🤵🏻‍♂️','🤵🏻‍♀️','🤦🏿‍♂️','🤦🏿‍♀️','🤦🏾‍♂️','🤦🏾‍♀️','🤦🏽‍♂️','🤦🏽‍♀️','🤦🏼‍♂️','🤦🏼‍♀️','🤦🏻‍♂️','👩🏿‍⚕️','👩🏿‍⚖️','👩🏿‍✈️','🤦🏻‍♀️','🚶🏿‍♂️','🚶🏿‍♀️','🚶🏾‍♂️','🚶🏾‍♀️','🚶🏽‍♂️','🚶🏽‍♀️','🏄🏿‍♂️','🚶🏼‍♂️','🏊🏻‍♀️','🏊🏻‍♂️','🚶🏼‍♀️','🏊🏼‍♀️','🏊🏼‍♂️','🏊🏽‍♀️','🏊🏽‍♂️','🏊🏾‍♀️','🚶🏻‍♂️','🚶🏻‍♀️','🚵🏿‍♂️','🚵🏿‍♀️','🚵🏾‍♂️','🚵🏾‍♀️','🚵🏽‍♂️','🚵🏽‍♀️','🚵🏼‍♂️','🏊🏾‍♂️','🏊🏿‍♀️','🏊🏿‍♂️','🏋🏻‍♀️','👮🏻‍♀️','👮🏻‍♂️','👮🏼‍♀️','👮🏼‍♂️','👮🏽‍♀️','👮🏽‍♂️','👮🏾‍♀️','👮🏾‍♂️','👮🏿‍♀️','👮🏿‍♂️','🚵🏼‍♀️','🚵🏻‍♂️','🚵🏻‍♀️','🚴🏿‍♂️','👱🏻‍♀️','👱🏻‍♂️','👱🏼‍♀️','👱🏼‍♂️','👱🏽‍♀️','👱🏽‍♂️','👱🏾‍♀️','👱🏾‍♂️','👱🏿‍♀️','👱🏿‍♂️','🚴🏿‍♀️','🚴🏾‍♂️','👳🏻‍♀️','👳🏻‍♂️','👳🏼‍♀️','👳🏼‍♂️','👳🏽‍♀️','👳🏽‍♂️','👳🏾‍♀️','👳🏾‍♂️','👳🏿‍♀️','👳🏿‍♂️','🚴🏾‍♀️','🚴🏽‍♂️','👷🏻‍♀️','👷🏻‍♂️','👷🏼‍♀️','👷🏼‍♂️','👷🏽‍♀️','👷🏽‍♂️','👷🏾‍♀️','👷🏾‍♂️','👷🏿‍♀️','👷🏿‍♂️','🚴🏽‍♀️','🚴🏼‍♂️','💁🏻‍♀️','💁🏻‍♂️','💁🏼‍♀️','💁🏼‍♂️','💁🏽‍♀️','💁🏽‍♂️','💁🏾‍♀️','💁🏾‍♂️','💁🏿‍♀️','💁🏿‍♂️','🚴🏼‍♀️','🚴🏻‍♂️','💂🏻‍♀️','💂🏻‍♂️','💂🏼‍♀️','💂🏼‍♂️','💂🏽‍♀️','💂🏽‍♂️','💂🏾‍♀️','💂🏾‍♂️','💂🏿‍♀️','💂🏿‍♂️','🚴🏻‍♀️','🚣🏿‍♂️','🏃🏻‍♀️','💆🏻‍♂️','💆🏼‍♀️','💆🏼‍♂️','💆🏽‍♀️','💆🏽‍♂️','💆🏾‍♀️','💆🏾‍♂️','💆🏿‍♀️','💆🏿‍♂️','🚣🏿‍♀️','🚣🏾‍♂️','💇🏻‍♀️','💇🏻‍♂️','💇🏼‍♀️','💇🏼‍♂️','💇🏽‍♀️','💇🏽‍♂️','💇🏾‍♀️','💇🏾‍♂️','💇🏿‍♀️','💇🏿‍♂️','🚣🏾‍♀️','🚣🏽‍♂️','🕴🏻‍♀️','🕴🏻‍♂️','🕴🏼‍♀️','🕴🏼‍♂️','🕴🏽‍♀️','🕴🏽‍♂️','🕴🏾‍♀️','🕴🏾‍♂️','🕴🏿‍♀️','🕴🏿‍♂️','🕵🏻‍♀️','🕵🏻‍♂️','🕵🏼‍♀️','🕵🏼‍♂️','🕵🏽‍♀️','🕵🏽‍♂️','🕵🏾‍♀️','🕵🏾‍♂️','🕵🏿‍♀️','🕵🏿‍♂️','🙅🏻‍♀️','🙅🏻‍♂️','🙅🏼‍♀️','🙅🏼‍♂️','🙅🏽‍♀️','🙅🏽‍♂️','🙅🏾‍♀️','🙅🏾‍♂️','🙅🏿‍♀️','🙅🏿‍♂️','🚣🏽‍♀️','🚣🏼‍♂️','🙆🏻‍♀️','🙆🏻‍♂️','🙆🏼‍♀️','🙆🏼‍♂️','🙆🏽‍♀️','🙆🏽‍♂️','🙆🏾‍♀️','🙆🏾‍♂️','🙆🏿‍♀️','🙆🏿‍♂️','🚣🏼‍♀️','🚣🏻‍♂️','🙇🏻‍♀️','🙇🏻‍♂️','🙇🏼‍♀️','🙇🏼‍♂️','🙇🏽‍♀️','🙇🏽‍♂️','🙇🏾‍♀️','🙇🏾‍♂️','🙇🏿‍♀️','🙇🏿‍♂️','🚣🏻‍♀️','🙎🏿‍♂️','🙋🏻‍♀️','🙋🏻‍♂️','🙋🏼‍♀️','🙋🏼‍♂️','🙋🏽‍♀️','🙋🏽‍♂️','🙋🏾‍♀️','🙋🏾‍♂️','🙋🏿‍♀️','🙋🏿‍♂️','🙎🏿‍♀️','🙎🏾‍♂️','🙍🏻‍♀️','🙍🏻‍♂️','🙍🏼‍♀️','🙍🏼‍♂️','🙍🏽‍♀️','🙍🏽‍♂️','🙍🏾‍♀️','🙍🏾‍♂️','🙍🏿‍♀️','🙍🏿‍♂️','🙎🏾‍♀️','🙎🏽‍♂️','🙎🏻‍♀️','🙎🏻‍♂️','🙎🏼‍♀️','🙎🏼‍♂️','🙎🏽‍♀️','🏋️‍♀️','🕵️‍♀️','🕵️‍♂️','🏋️‍♂️','⛹🏾‍♀️','🏌️‍♀️','🕴️‍♀️','🕴️‍♂️','🏌️‍♂️','⛹🏻‍♂️','⛹🏻‍♀️','⛹🏾‍♂️','⛹🏿‍♀️','⛹🏿‍♂️','⛹🏽‍♀️','⛹🏽‍♂️','⛹🏼‍♀️','⛹🏼‍♂️','⛹️‍♀️','⛹️‍♂️','👩🏻‍🏭','👨🏻‍🌾','👨🏻‍🍳','👨🏻‍🎓','👨🏻‍🎤','👨🏻‍🎨','👨🏻‍🏫','👨🏻‍🏭','👨🏻‍💻','👨🏻‍💼','👨🏻‍🔧','👨🏻‍🔬','👨🏻‍🚀','👨🏻‍🚒','👨🏼‍🌾','👨🏼‍🍳','👨🏼‍🎓','👨🏼‍🎤','👨🏼‍🎨','👨🏼‍🏫','👨🏼‍🏭','👨🏼‍💻','👨🏼‍💼','👨🏼‍🔧','👨🏼‍🔬','👨🏼‍🚀','👨🏼‍🚒','👨🏽‍🌾','👨🏽‍🍳','👨🏽‍🎓','👨🏽‍🎤','👨🏽‍🎨','👨🏽‍🏫','👨🏽‍🏭','👨🏽‍💻','👨🏽‍💼','👨🏽‍🔧','👨🏽‍🔬','👨🏽‍🚀','👨🏽‍🚒','👨🏾‍🌾','👨🏾‍🍳','👨🏾‍🎓','👨🏾‍🎤','👨🏾‍🎨','👨🏾‍🏫','👨🏾‍🏭','👨🏾‍💻','👨🏾‍💼','👨🏾‍🔧','👨🏾‍🔬','👨🏾‍🚀','👨🏾‍🚒','👩🏿‍🚒','👩🏿‍🚀','👩🏿‍🔬','👩🏿‍🔧','👩🏿‍💼','👩🏿‍💻','👩🏿‍🏭','👩🏿‍🏫','👩🏿‍🎨','👨🏿‍🌾','👨🏿‍🍳','👩🏿‍🎤','👩🏿‍🎓','👩🏿‍🍳','👩🏿‍🌾','👩🏾‍🚒','👩🏾‍🚀','👩🏾‍🔬','👩🏾‍🔧','👩🏾‍💼','👩🏾‍💻','👨🏿‍🎓','👨🏿‍🎤','👩🏾‍🏭','👩🏾‍🏫','👩🏾‍🎨','👩🏾‍🎤','👩🏾‍🎓','👩🏾‍🍳','👩🏾‍🌾','👩🏽‍🚒','👩🏽‍🚀','👩🏽‍🔬','👨🏿‍🎨','👨🏿‍🏫','👩🏽‍🔧','👩🏽‍💼','👩🏽‍💻','👩🏽‍🏭','👩🏽‍🏫','👩🏽‍🎨','👩🏽‍🎤','👩🏽‍🎓','👩🏽‍🍳','👩🏽‍🌾','👨🏿‍🏭','👨🏿‍💻','👩🏼‍🚒','👩🏼‍🚀','👩🏼‍🔬','👩🏼‍🔧','👩🏼‍💼','👩🏼‍💻','👩🏼‍🏭','👩🏼‍🏫','👩🏼‍🎨','👩🏼‍🎤','👨🏿‍💼','👨🏿‍🔧','👨🏿‍🔬','👨🏿‍🚀','👩🏼‍🎓','👩🏼‍🍳','👩🏼‍🌾','👩🏻‍🚒','👩🏻‍🚀','👩🏻‍🔬','👩🏻‍🔧','👩🏻‍💼','👩🏻‍💻','👨🏿‍🚒','👩🏻‍🌾','👩🏻‍🍳','👩🏻‍🏫','👩🏻‍🎨','👩🏻‍🎤','👩🏻‍🎓','🏳️‍🌈','🤽‍♂️','👨‍✈️','👨‍⚖️','👨‍⚕️','🏃‍♀️','🤾‍♀️','🤾‍♂️','🏃‍♂️','🏄‍♀️','🏄‍♂️','🏊‍♀️','🏊‍♂️','🙋‍♂️','🙋‍♀️','🙍‍♂️','🏴‍☠️','🧟‍♂️','🧖‍♀️','🧖‍♂️','🧟‍♀️','🧞‍♂️','🧞‍♀️','🧝‍♂️','🙍‍♀️','🤼‍♂️','🤼‍♀️','🤹‍♂️','🤹‍♀️','🤸‍♂️','🧗‍♀️','🧗‍♂️','🤸‍♀️','🤷‍♂️','🤷‍♀️','🤵‍♂️','🤵‍♀️','🤦‍♂️','🤦‍♀️','🧝‍♀️','🚶‍♂️','🚶‍♀️','🧘‍♀️','🧘‍♂️','🙇‍♂️','🙎‍♀️','🙎‍♂️','🙇‍♀️','🙆‍♂️','🙆‍♀️','🙅‍♂️','🙅‍♀️','💇‍♂️','🧜‍♂️','🧙‍♀️','🧙‍♂️','🚵‍♂️','🚵‍♀️','🧜‍♀️','🤽‍♀️','💇‍♀️','💆‍♂️','👩‍⚕️','👩‍⚖️','👩‍✈️','👮‍♀️','🧚‍♀️','🧚‍♂️','👮‍♂️','👯‍♀️','🚴‍♂️','🚴‍♀️','👯‍♂️','👱‍♀️','👱‍♂️','👳‍♀️','👳‍♂️','👷‍♀️','🧛‍♀️','🧛‍♂️','👷‍♂️','💁‍♀️','💁‍♂️','💂‍♀️','🚣‍♂️','🚣‍♀️','💂‍♂️','💆‍♀️','👨‍🌾','👩‍🚒','👩‍🔧','👩‍💼','👩‍💻','👩‍👧','👩‍👦','👩‍🏭','👩‍🏫','👩‍🎨','👩‍🎤','👩‍🎓','👩‍🍳','👁‍🗨','👩‍🌾','👩‍🚀','👨‍🍳','👨‍🎓','👨‍🎤','👨‍🎨','👨‍🏫','👨‍🏭','👨‍👦','👨‍👧','👨‍💻','👨‍💼','👨‍🔧','👨‍🔬','👨‍🚀','👨‍🚒','👩‍🔬','👳🏾','🇧🇿','🇨🇦','👳🏿','🏋🏻','🇨🇨','👴🏻','👴🏼','👴🏽','👴🏾','👴🏿','👵🏻','👵🏼','👵🏽','👵🏾','👵🏿','👶🏻','👶🏼','👶🏽','👶🏾','👶🏿','🇨🇩','🏋🏼','👷🏻','🇨🇫','🇨🇬','👷🏼','🏋🏽','🇨🇭','👷🏽','🇨🇮','🏋🏾','👷🏾','🇨🇰','🇨🇱','👷🏿','🏋🏿','🇨🇲','👸🏻','👸🏼','👸🏽','👸🏾','👸🏿','👼🏻','👼🏼','👼🏽','👼🏾','👼🏿','🇨🇳','🇨🇴','💁🏻','🇨🇵','🏌🏻','💁🏼','🇨🇷','🇨🇺','💁🏽','🏌🏼','🇨🇻','💁🏾','🇨🇼','🏌🏽','💁🏿','🇨🇽','🇨🇾','🏌🏾','🇨🇿','💂🏻','🇩🇪','🏌🏿','💂🏼','🇩🇬','🇩🇯','💂🏽','🇩🇰','🇩🇲','💂🏾','🇩🇴','🇩🇿','💂🏿','🇪🇦','🇪🇨','💃🏻','💃🏼','💃🏽','💃🏾','💃🏿','💅🏻','💅🏼','💅🏽','💅🏾','💅🏿','👂🏻','👂🏼','💆🏻','👂🏽','👂🏾','💆🏼','👂🏿','👃🏻','💆🏽','👃🏼','👃🏽','💆🏾','👃🏾','👃🏿','💆🏿','👆🏻','👆🏼','👆🏽','👆🏾','💇🏻','👆🏿','👇🏻','💇🏼','👇🏼','👇🏽','💇🏽','👇🏾','👇🏿','💇🏾','👈🏻','👈🏼','💇🏿','👈🏽','👈🏾','💪🏻','💪🏼','💪🏽','💪🏾','💪🏿','👈🏿','👉🏻','🕴🏻','👉🏼','👉🏽','🕴🏼','👉🏾','👉🏿','🕴🏽','👊🏻','👊🏼','🕴🏾','👊🏽','👊🏾','🕴🏿','👊🏿','👋🏻','👋🏼','👋🏽','🕵🏻','👋🏾','👋🏿','🕵🏼','👌🏻','👌🏼','🕵🏽','👌🏽','👌🏾','🕵🏾','👌🏿','👍🏻','🕵🏿','👍🏼','👍🏽','🕺🏻','🕺🏼','🕺🏽','🕺🏾','🕺🏿','🖐🏻','🖐🏼','🖐🏽','🖐🏾','🖐🏿','🖕🏻','🖕🏼','🖕🏽','🖕🏾','🖕🏿','🖖🏻','🖖🏼','🖖🏽','🖖🏾','🖖🏿','👍🏾','👍🏿','🙅🏻','👎🏻','👎🏼','🙅🏼','👎🏽','👎🏾','🙅🏽','👎🏿','👏🏻','🙅🏾','👏🏼','👏🏽','🙅🏿','👏🏾','👏🏿','👐🏻','👐🏼','🙆🏻','👐🏽','👐🏾','🙆🏼','👐🏿','👦🏻','🙆🏽','👦🏼','👦🏽','🙆🏾','👦🏾','👦🏿','🙆🏿','👧🏻','👧🏼','👧🏽','👧🏾','🙇🏻','👧🏿','🇪🇪','🙇🏼','🇪🇬','🇪🇭','🙇🏽','🇪🇷','🇪🇸','🙇🏾','🇪🇹','🇪🇺','🙇🏿','🇫🇮','🇫🇯','🇫🇰','🇫🇲','🙋🏻','🇫🇴','🇫🇷','🙋🏼','🇬🇦','🇬🇧','🙋🏽','🇬🇩','👨🏻','🙋🏾','🇬🇪','🇬🇫','🙋🏿','🇬🇬','🇬🇭','🙌🏻','🙌🏼','🙌🏽','🙌🏾','🙌🏿','🇬🇮','🇬🇱','🙍🏻','🇬🇲','🇬🇳','🙍🏼','🇬🇵','🇬🇶','🙍🏽','🇬🇷','🇬🇸','🙍🏾','🇬🇹','🇬🇺','🙍🏿','🇬🇼','🇬🇾','👨🏼','🇭🇰','🙎🏻','🇭🇲','🇭🇳','🙎🏼','🇭🇷','🇭🇹','🙎🏽','🇭🇺','🇮🇨','🙎🏾','🇮🇩','🇮🇪','🙎🏿','🇮🇱','🇮🇲','🙏🏻','🙏🏼','🙏🏽','🙏🏾','🙏🏿','🇮🇳','🇮🇴','🚣🏻','🇮🇶','🇮🇷','🚣🏼','🇮🇸','👨🏽','🚣🏽','🇮🇹','🇯🇪','🚣🏾','🇯🇲','🇯🇴','🚣🏿','🇯🇵','🇰🇪','🇰🇬','🇰🇭','🚴🏻','🇰🇮','🇰🇲','🚴🏼','🇰🇳','🇰🇵','🚴🏽','🇰🇷','🇰🇼','🚴🏾','🇰🇾','🇰🇿','🚴🏿','👨🏾','🇱🇦','🇱🇧','🇱🇨','🚵🏻','🇱🇮','🇱🇰','🚵🏼','🇱🇷','🇱🇸','🚵🏽','🇱🇹','🇱🇺','🚵🏾','🇱🇻','🇱🇾','🚵🏿','🇲🇦','🇲🇨','🇲🇩','🇲🇪','🚶🏻','🇲🇫','👨🏿','🚶🏼','🇲🇬','🇲🇭','🚶🏽','🇲🇰','🇲🇱','🚶🏾','🇲🇲','🇲🇳','🚶🏿','🇲🇴','🇲🇵','🛀🏻','🛀🏼','🛀🏽','🛀🏾','🛀🏿','🛌🏻','🛌🏼','🛌🏽','🛌🏾','🛌🏿','🤘🏻','🤘🏼','🤘🏽','🤘🏾','🤘🏿','🤙🏻','🤙🏼','🤙🏽','🤙🏾','🤙🏿','🤚🏻','🤚🏼','🤚🏽','🤚🏾','🤚🏿','🤛🏻','🤛🏼','🤛🏽','🤛🏾','🤛🏿','🤜🏻','🤜🏼','🤜🏽','🤜🏾','🤜🏿','🤞🏻','🤞🏼','🤞🏽','🤞🏾','🤞🏿','🤟🏻','🤟🏼','🤟🏽','🤟🏾','🤟🏿','🇲🇶','🇲🇷','🤦🏻','🇲🇸','🇲🇹','🤦🏼','🇲🇺','🇲🇻','🤦🏽','🇲🇼','🇲🇽','🤦🏾','🇲🇾','🇲🇿','🤦🏿','🇳🇦','🇳🇨','🤰🏻','🤰🏼','🤰🏽','🤰🏾','🤰🏿','🤱🏻','🤱🏼','🤱🏽','🤱🏾','🤱🏿','🤲🏻','🤲🏼','🤲🏽','🤲🏾','🤲🏿','🤳🏻','🤳🏼','🤳🏽','🤳🏾','🤳🏿','🤴🏻','🤴🏼','🤴🏽','🤴🏾','🤴🏿','🇳🇪','🇳🇫','🤵🏻','🇳🇬','🇳🇮','🤵🏼','🇳🇱','🇳🇴','🤵🏽','🇳🇵','🇳🇷','🤵🏾','🇳🇺','🇳🇿','🤵🏿','🇴🇲','🇵🇦','🤶🏻','🤶🏼','🤶🏽','🤶🏾','🤶🏿','🇵🇪','🇵🇫','🤷🏻','🇵🇬','🇵🇭','🤷🏼','🇵🇰','🇵🇱','🤷🏽','🇵🇲','🇵🇳','🤷🏾','🇵🇷','🇵🇸','🤷🏿','🇵🇹','🇵🇼','🇵🇾','🇶🇦','🤸🏻','🇷🇪','🇷🇴','🤸🏼','🇷🇸','👩🏻','🤸🏽','🇷🇺','🇷🇼','🤸🏾','🇸🇦','🇸🇧','🤸🏿','🇸🇨','🇸🇩','🇸🇪','🇸🇬','🤹🏻','🇸🇭','🇸🇮','🤹🏼','🇸🇯','🇸🇰','🤹🏽','🇸🇱','🇸🇲','🤹🏾','🇸🇳','🇸🇴','🤹🏿','👩🏼','🇸🇷','🇸🇸','🇸🇹','🇸🇻','🇸🇽','🤽🏻','🇸🇾','🇸🇿','🤽🏼','🇹🇦','🇹🇨','🤽🏽','🇹🇩','🇹🇫','🤽🏾','🇹🇬','🇹🇭','🤽🏿','🇹🇯','🇹🇰','🇹🇱','👩🏽','🤾🏻','🇹🇲','🇹🇳','🤾🏼','🇹🇴','🇹🇷','🤾🏽','🇹🇹','🇹🇻','🤾🏾','🇹🇼','🇹🇿','🤾🏿','🇺🇦','🇺🇬','🧑🏻','🧑🏼','🧑🏽','🧑🏾','🧑🏿','🧒🏻','🧒🏼','🧒🏽','🧒🏾','🧒🏿','🧓🏻','🧓🏼','🧓🏽','🧓🏾','🧓🏿','🧔🏻','🧔🏼','🧔🏽','🧔🏾','🧔🏿','🧕🏻','🧕🏼','🧕🏽','🧕🏾','🧕🏿','🇺🇲','🇺🇳','🧖🏻','🇺🇸','🇺🇾','🧖🏼','🇺🇿','🇻🇦','🧖🏽','👩🏾','🇻🇨','🧖🏾','🇻🇪','🇻🇬','🧖🏿','🇻🇮','🇻🇳','🇻🇺','🇼🇫','🧗🏻','🇼🇸','🇽🇰','🧗🏼','🇾🇪','🇾🇹','🧗🏽','🇿🇦','🇿🇲','🧗🏾','🇿🇼','🎅🏻','🧗🏿','🎅🏼','👩🏿','🎅🏽','🎅🏾','🧘🏻','🎅🏿','🏂🏻','🧘🏼','🏂🏼','🏂🏽','🧘🏽','🏂🏾','🏂🏿','🧘🏾','🇦🇨','🇦🇪','🧘🏿','🏃🏻','🇦🇫','🇦🇬','🏃🏼','🧙🏻','🇦🇮','🇦🇱','🧙🏼','🏃🏽','🇦🇲','🧙🏽','🇦🇴','🏃🏾','🧙🏾','🇦🇶','🇦🇷','🧙🏿','🏃🏿','🇦🇸','🇦🇹','🇦🇺','🧚🏻','🇦🇼','🏄🏻','🧚🏼','🇦🇽','🇦🇿','🧚🏽','🏄🏼','🇧🇦','🧚🏾','👮🏻','🇧🇧','🧚🏿','🏄🏽','👮🏼','🇧🇩','🇧🇪','🧛🏻','👮🏽','🏄🏾','🧛🏼','🇧🇫','👮🏾','🧛🏽','🇧🇬','🏄🏿','🧛🏾','👮🏿','🇧🇭','🧛🏿','🇧🇮','🏇🏻','🏇🏼','👰🏻','🧜🏻','👰🏼','👰🏽','🧜🏼','👰🏾','👰🏿','🧜🏽','🏇🏽','🏇🏾','🧜🏾','👱🏻','🏇🏿','🧜🏿','🇧🇯','👱🏼','🇧🇱','🏊🏻','🧝🏻','👱🏽','🇧🇲','🧝🏼','🇧🇳','👱🏾','🧝🏽','🏊🏼','🇧🇴','🧝🏾','👱🏿','🇧🇶','🧝🏿','🏊🏽','👲🏻','👲🏼','👲🏽','👲🏾','👲🏿','🇧🇷','🇧🇸','👳🏻','🏊🏾','🇧🇹','👳🏼','🇧🇻','🏊🏿','👳🏽','🇧🇼','🇧🇾','🇦🇩','✍🏿','⛹🏻','✍🏾','✍🏽','✍🏼','✍🏻','✌🏿','✌🏾','✌🏽','✌🏼','✌🏻','✋🏿','✋🏾','✋🏽','✋🏼','✋🏻','✊🏿','✊🏾','✊🏽','✊🏼','✊🏻','⛷🏽','⛷🏾','⛹🏿','☝🏿','☝🏾','⛹🏾','☝🏽','☝🏼','⛹🏽','☝🏻','⛷🏿','⛹🏼','⛷🏻','⛷🏼','4⃣','#⃣','0⃣','1⃣','2⃣','3⃣','*⃣','5⃣','6⃣','7⃣','8⃣','9⃣','🏪','🎈','🎉','🎊','🎋','🎌','🎍','🎎','🎏','🎐','🎑','🎒','🎓','🎖','🎗','🎙','🎚','🕴','🎛','🎞','🎟','🎠','🎡','🎢','🎣','🎤','🎥','🎦','🎧','🎨','🎩','🎪','🎫','🎬','🎭','🕵','🕶','🕷','🕸','🕹','🎮','🎯','🎰','🎱','🎲','🕺','🖇','🖊','🖋','🖌','🖍','🎳','🎴','🎵','🎶','🎷','🖐','🎸','🎹','🎺','🎻','🎼','🖕','🎽','🎾','🎿','🏀','🏁','🖖','🖤','🖥','🖨','🖱','🖲','🖼','🗂','🗃','🗄','🗑','🗒','🗓','🗜','🗝','🗞','🗡','🗣','🗨','🗯','🗳','🗺','🗻','🗼','🗽','🗾','🗿','😀','😁','😂','😃','😄','😅','😆','😇','😈','😉','😊','😋','😌','😍','😎','😏','😐','😑','😒','😓','😔','😕','😖','😗','😘','😙','😚','😛','😜','😝','😞','😟','😠','😡','😢','😣','😤','😥','😦','😧','😨','😩','😪','😫','😬','😭','😮','😯','😰','😱','😲','😳','😴','😵','😶','😷','😸','😹','😺','😻','😼','😽','😾','😿','🙀','🙁','🙂','🙃','🙄','🇧','🇮','🇪','🇷','🇱','🏂','🆎','🆑','🇨','🇹','🇯','🆒','🇬','🆓','🇳','🆔','🇴','🙅','🇺','🇫','🆕','🆖','🆗','🇭','🏃','🆘','🇩','🇻','🇰','🆙','🇼','🆚','🇽','🇸','🀄','🙆','🇾','🇦','🅰','🅱','🇿','🈁','🈂','🏄','🏅','🏆','🈚','🈯','🈲','🈳','🈴','🏇','👨','🙇','🙈','🙉','🙊','🏈','🏉','🈵','🈶','🈷','🈸','🈹','🈺','🉐','🉑','🌀','🌁','🌂','🌃','🌄','🌅','🌆','🙋','🌇','🌈','🏊','🌉','🌊','🙌','🌋','🌌','🌍','🌎','🌏','🌐','🌑','🌒','🌓','🌔','🌕','🌖','🌗','🌘','🌙','🏋','🌚','🙍','🌛','🌜','🌝','🌞','🌟','🌠','🌡','🌤','🌥','🌦','🌧','🌨','🌩','🌪','🌫','🌬','🏌','🙎','🏍','🏎','🏏','🏐','🏑','🙏','🚀','🚁','🚂','🚃','🚄','🚅','🚆','🚇','🚈','🚉','🚊','🚋','🚌','🚍','🚎','🚏','🚐','🚑','🚒','🚓','🚔','🚕','🚖','🚗','🚘','🚙','🚚','🚛','🚜','🚝','🚞','🚟','🚠','🚡','🚢','🏒','🏓','🏔','🏕','🏖','🏗','🏘','🏙','🏚','🏛','🏜','🏝','🏞','🏟','🏠','🏡','🏢','🚣','🚤','🚥','🚦','🚧','🚨','🚩','🚪','🚫','🚬','🚭','🚮','🚯','🚰','🚱','🚲','🚳','🏣','🏤','🏥','🏦','🏧','🏨','🏩','🃏','🏫','🏬','🏭','🏮','🏯','🏰','🌭','🏳','🌮','🚴','🌯','🌰','🌱','🏴','🏵','🏷','🏸','🏹','🏺','🏻','🏼','🏽','🏾','🏿','🐀','🐁','🐂','🚵','🐃','🐄','🐅','👩','👪','👫','👬','👭','🐆','🐇','🐈','🐉','🐊','🐋','🐌','🐍','🐎','🚶','🚷','🚸','🚹','🚺','🚻','🚼','🚽','🚾','🚿','🐏','🐐','🐑','🐒','🐓','🛀','🛁','🛂','🛃','🛄','🛅','🛋','🐔','🐕','🐖','👮','🐗','🛌','🛍','🛎','🛏','🛐','🛑','🛒','🛠','🛡','🛢','🛣','🛤','🛥','🛩','🛫','🛬','🛰','🛳','🛴','🛵','🛶','🛷','🛸','🤐','🤑','🤒','🤓','🤔','🤕','🤖','🤗','🐘','👯','🐙','🐚','🐛','🤘','🐜','🐝','👰','🐞','🐟','🤙','🐠','🐡','🐢','🐣','🐤','🤚','🐥','🐦','🐧','🐨','🐩','🤛','🐪','🐫','🐬','🐭','🐮','🤜','🤝','👱','🐯','🐰','🐱','🐲','🤞','🐳','👲','🐴','🐵','🐶','🤟','🤠','🤡','🤢','🤣','🤤','🤥','🐷','🐸','🐹','🐺','🐻','🐼','🐽','🐾','🐿','👀','🌲','👁','🌳','🌴','👳','🌵','🌶','🤦','🤧','🤨','🤩','🤪','🤫','🤬','🤭','🤮','🤯','🌷','👂','🌸','👴','🌹','🤰','🌺','🌻','🌼','👃','👵','🤱','👄','👅','🌽','🌾','🌿','🤲','👶','🍀','🍁','👆','🍂','🤳','🍃','🍄','🍅','🍆','👇','🤴','🍇','🍈','🍉','🍊','🍋','👈','🍌','🍍','👷','🍎','🍏','🍐','👉','🍑','👸','👹','👺','🤵','👻','🍒','🍓','🍔','🍕','🤶','👊','👼','👽','👾','👿','💀','🍖','🍗','🍘','🍙','🍚','👋','🍛','🍜','🍝','🍞','🍟','🤷','👌','🍠','🍡','🍢','🍣','🍤','💁','👍','🍥','🍦','🍧','🍨','🍩','👎','🍪','🍫','🍬','🤸','🍭','🍮','👏','🍯','🍰','🍱','🍲','💂','🍳','👐','👑','👒','👓','💃','💄','👔','👕','🤹','🤺','👖','👗','🤼','👘','💅','👙','👚','👛','👜','👝','👞','👟','👠','👡','👢','👣','👤','👥','🍴','🍵','🤽','🍶','🍷','💆','🍸','👦','🍹','🍺','🍻','🍼','🍽','👧','🍾','🍿','🎀','🎁','🎂','🎃','🤾','🥀','🥁','🥂','🥃','🥄','🥅','🥇','🥈','🥉','🥊','🥋','🥌','🥐','🥑','🥒','🥓','🥔','🥕','🥖','🥗','🥘','🥙','🥚','🥛','🥜','🥝','🥞','🥟','🥠','🥡','🥢','🥣','🥤','🥥','🥦','🥧','🥨','🥩','🥪','🥫','🦀','🦁','🦂','🦃','🦄','🦅','🦆','🦇','🦈','🦉','🦊','🦋','🦌','🦍','🦎','🦏','🦐','🦑','🦒','🦓','🦔','🦕','🦖','🦗','🧀','🧐','🎄','🇵','🅾','💇','💈','🧑','💉','💊','💋','💌','💍','🧒','💎','💏','💐','💑','💒','🧓','💓','💔','💕','💖','💗','🧔','💘','💙','💚','💛','💜','🧕','💝','💞','💟','💠','💡','💢','💣','💤','💥','💦','💧','💨','💩','🇶','🇲','🅿','🎅','🧖','🎆','💪','💫','💬','💭','💮','💯','💰','💱','💲','💳','💴','💵','💶','💷','💸','💹','🧗','💺','💻','💼','💽','💾','💿','📀','📁','📂','📃','📄','📅','📆','📇','📈','📉','📊','🧘','📋','📌','📍','📎','📏','📐','📑','📒','📓','📔','📕','📖','📗','📘','📙','📚','📛','🧙','📜','📝','📞','📟','📠','📡','📢','📣','📤','📥','📦','📧','📨','📩','📪','📫','📬','🧚','📭','📮','📯','📰','📱','📲','📳','📴','📵','📶','📷','📸','📹','📺','📻','📼','📽','🧛','📿','🔀','🔁','🔂','🔃','🔄','🔅','🔆','🔇','🔈','🔉','🔊','🔋','🔌','🔍','🔎','🔏','🧜','🔐','🔑','🔒','🔓','🔔','🔕','🔖','🔗','🔘','🔙','🔚','🔛','🔜','🔝','🔞','🔟','🔠','🧝','🔡','🔢','🧞','🔣','🔤','🧟','🧠','🧡','🧢','🧣','🧤','🧥','🧦','🔥','🔦','🔧','🔨','🔩','🔪','🔫','🔬','🔭','🔮','🔯','🔰','🔱','🔲','🔳','🔴','🔵','🔶','🔷','🔸','🔹','🔺','🔻','🔼','🔽','🕉','🕊','🕋','🕌','🕍','🕎','🕐','🕑','🕒','🕓','🕔','🕕','🕖','🕗','🕘','🕙','🕚','🕛','🕜','🕝','🕞','🕟','🕠','🕡','🕢','🕣','🕤','🕥','🕦','🕧','🕯','🕰','🕳','🎇','▪','☦','☮','☯','☸','☹','☺','♀','♂','♈','♉','♊','♋','♌','♍','♎','♏','♐','♑','♒','♓','♠','♣','♥','♦','♨','♻','♿','⚒','⚓','⚔','⚕','⚖','⚗','⚙','⚛','⚜','⚠','⚡','⚪','⚫','⚰','⚱','⚽','⚾','⛄','⛅','⛈','⛎','⛏','⛑','⛓','⛔','⛩','⛪','⛰','⛱','⛲','⛳','⛴','⛵','☣','☢','☠','☝','☘','⛷','⛸','☕','☔','☑','☎','☄','☃','☂','☁','☀','◾','◽','◼','◻','◀','▶','▫','☪','⛹','⛺','⛽','✂','✅','✈','✉','Ⓜ','⏺','⏹','⏸','⏳','✊','⏲','⏱','⏰','⏯','⏮','✋','⏭','⏬','⏫','⏪','⏩','✌','⏏','⌨','⌛','⌚','↪','✍','✏','✒','✔','✖','✝','✡','✨','✳','✴','❄','❇','❌','❎','❓','❔','❕','❗','❣','❤','➕','➖','➗','➡','➰','➿','⤴','⤵','↩','⬅','⬆','⬇','⬛','⬜','⭐','⭕','↙','〰','〽','↘','↗','㊗','㊙','↖','↕','↔','ℹ','™','⁉','‼','');
  5317.     $partials = array('🀄','🃏','🅰','🅱','🅾','🅿','🆎','🆑','🆒','🆓','🆔','🆕','🆖','🆗','🆘','🆙','🆚','🇦','🇨','🇩','🇪','🇫','🇬','🇮','🇱','🇲','🇴','🇶','🇷','🇸','🇹','🇺','🇼','🇽','🇿','🇧','🇭','🇯','🇳','🇻','🇾','🇰','🇵','🈁','🈂','🈚','🈯','🈲','🈳','🈴','🈵','🈶','🈷','🈸','🈹','🈺','🉐','🉑','🌀','🌁','🌂','🌃','🌄','🌅','🌆','🌇','🌈','🌉','🌊','🌋','🌌','🌍','🌎','🌏','🌐','🌑','🌒','🌓','🌔','🌕','🌖','🌗','🌘','🌙','🌚','🌛','🌜','🌝','🌞','🌟','🌠','🌡','🌤','🌥','🌦','🌧','🌨','🌩','🌪','🌫','🌬','🌭','🌮','🌯','🌰','🌱','🌲','🌳','🌴','🌵','🌶','🌷','🌸','🌹','🌺','🌻','🌼','🌽','🌾','🌿','🍀','🍁','🍂','🍃','🍄','🍅','🍆','🍇','🍈','🍉','🍊','🍋','🍌','🍍','🍎','🍏','🍐','🍑','🍒','🍓','🍔','🍕','🍖','🍗','🍘','🍙','🍚','🍛','🍜','🍝','🍞','🍟','🍠','🍡','🍢','🍣','🍤','🍥','🍦','🍧','🍨','🍩','🍪','🍫','🍬','🍭','🍮','🍯','🍰','🍱','🍲','🍳','🍴','🍵','🍶','🍷','🍸','🍹','🍺','🍻','🍼','🍽','🍾','🍿','🎀','🎁','🎂','🎃','🎄','🎅','🏻','🏼','🏽','🏾','🏿','🎆','🎇','🎈','🎉','🎊','🎋','🎌','🎍','🎎','🎏','🎐','🎑','🎒','🎓','🎖','🎗','🎙','🎚','🎛','🎞','🎟','🎠','🎡','🎢','🎣','🎤','🎥','🎦','🎧','🎨','🎩','🎪','🎫','🎬','🎭','🎮','🎯','🎰','🎱','🎲','🎳','🎴','🎵','🎶','🎷','🎸','🎹','🎺','🎻','🎼','🎽','🎾','🎿','🏀','🏁','🏂','🏃','‍','♀','️','♂','🏄','🏅','🏆','🏇','🏈','🏉','🏊','🏋','🏌','🏍','🏎','🏏','🏐','🏑','🏒','🏓','🏔','🏕','🏖','🏗','🏘','🏙','🏚','🏛','🏜','🏝','🏞','🏟','🏠','🏡','🏢','🏣','🏤','🏥','🏦','🏧','🏨','🏩','🏪','🏫','🏬','🏭','🏮','🏯','🏰','🏳','🏴','☠','󠁧','󠁢','󠁥','󠁮','󠁿','󠁳','󠁣','󠁴','󠁷','󠁬','🏵','🏷','🏸','🏹','🏺','🐀','🐁','🐂','🐃','🐄','🐅','🐆','🐇','🐈','🐉','🐊','🐋','🐌','🐍','🐎','🐏','🐐','🐑','🐒','🐓','🐔','🐕','🐖','🐗','🐘','🐙','🐚','🐛','🐜','🐝','🐞','🐟','🐠','🐡','🐢','🐣','🐤','🐥','🐦','🐧','🐨','🐩','🐪','🐫','🐬','🐭','🐮','🐯','🐰','🐱','🐲','🐳','🐴','🐵','🐶','🐷','🐸','🐹','🐺','🐻','🐼','🐽','🐾','🐿','👀','👁','🗨','👂','👃','👄','👅','👆','👇','👈','👉','👊','👋','👌','👍','👎','👏','👐','👑','👒','👓','👔','👕','👖','👗','👘','👙','👚','👛','👜','👝','👞','👟','👠','👡','👢','👣','👤','👥','👦','👧','👨','💻','💼','🔧','🔬','🚀','🚒','⚕','⚖','✈','👩','❤','💋','👪','👫','👬','👭','👮','👯','👰','👱','👲','👳','👴','👵','👶','👷','👸','👹','👺','👻','👼','👽','👾','👿','💀','💁','💂','💃','💄','💅','💆','💇','💈','💉','💊','💌','💍','💎','💏','💐','💑','💒','💓','💔','💕','💖','💗','💘','💙','💚','💛','💜','💝','💞','💟','💠','💡','💢','💣','💤','💥','💦','💧','💨','💩','💪','💫','💬','💭','💮','💯','💰','💱','💲','💳','💴','💵','💶','💷','💸','💹','💺','💽','💾','💿','📀','📁','📂','📃','📄','📅','📆','📇','📈','📉','📊','📋','📌','📍','📎','📏','📐','📑','📒','📓','📔','📕','📖','📗','📘','📙','📚','📛','📜','📝','📞','📟','📠','📡','📢','📣','📤','📥','📦','📧','📨','📩','📪','📫','📬','📭','📮','📯','📰','📱','📲','📳','📴','📵','📶','📷','📸','📹','📺','📻','📼','📽','📿','🔀','🔁','🔂','🔃','🔄','🔅','🔆','🔇','🔈','🔉','🔊','🔋','🔌','🔍','🔎','🔏','🔐','🔑','🔒','🔓','🔔','🔕','🔖','🔗','🔘','🔙','🔚','🔛','🔜','🔝','🔞','🔟','🔠','🔡','🔢','🔣','🔤','🔥','🔦','🔨','🔩','🔪','🔫','🔭','🔮','🔯','🔰','🔱','🔲','🔳','🔴','🔵','🔶','🔷','🔸','🔹','🔺','🔻','🔼','🔽','🕉','🕊','🕋','🕌','🕍','🕎','🕐','🕑','🕒','🕓','🕔','🕕','🕖','🕗','🕘','🕙','🕚','🕛','🕜','🕝','🕞','🕟','🕠','🕡','🕢','🕣','🕤','🕥','🕦','🕧','🕯','🕰','🕳','🕴','🕵','🕶','🕷','🕸','🕹','🕺','🖇','🖊','🖋','🖌','🖍','🖐','🖕','🖖','🖤','🖥','🖨','🖱','🖲','🖼','🗂','🗃','🗄','🗑','🗒','🗓','🗜','🗝','🗞','🗡','🗣','🗯','🗳','🗺','🗻','🗼','🗽','🗾','🗿','😀','😁','😂','😃','😄','😅','😆','😇','😈','😉','😊','😋','😌','😍','😎','😏','😐','😑','😒','😓','😔','😕','😖','😗','😘','😙','😚','😛','😜','😝','😞','😟','😠','😡','😢','😣','😤','😥','😦','😧','😨','😩','😪','😫','😬','😭','😮','😯','😰','😱','😲','😳','😴','😵','😶','😷','😸','😹','😺','😻','😼','😽','😾','😿','🙀','🙁','🙂','🙃','🙄','🙅','🙆','🙇','🙈','🙉','🙊','🙋','🙌','🙍','🙎','🙏','🚁','🚂','🚃','🚄','🚅','🚆','🚇','🚈','🚉','🚊','🚋','🚌','🚍','🚎','🚏','🚐','🚑','🚓','🚔','🚕','🚖','🚗','🚘','🚙','🚚','🚛','🚜','🚝','🚞','🚟','🚠','🚡','🚢','🚣','🚤','🚥','🚦','🚧','🚨','🚩','🚪','🚫','🚬','🚭','🚮','🚯','🚰','🚱','🚲','🚳','🚴','🚵','🚶','🚷','🚸','🚹','🚺','🚻','🚼','🚽','🚾','🚿','🛀','🛁','🛂','🛃','🛄','🛅','🛋','🛌','🛍','🛎','🛏','🛐','🛑','🛒','🛠','🛡','🛢','🛣','🛤','🛥','🛩','🛫','🛬','🛰','🛳','🛴','🛵','🛶','🛷','🛸','🤐','🤑','🤒','🤓','🤔','🤕','🤖','🤗','🤘','🤙','🤚','🤛','🤜','🤝','🤞','🤟','🤠','🤡','🤢','🤣','🤤','🤥','🤦','🤧','🤨','🤩','🤪','🤫','🤬','🤭','🤮','🤯','🤰','🤱','🤲','🤳','🤴','🤵','🤶','🤷','🤸','🤹','🤺','🤼','🤽','🤾','🥀','🥁','🥂','🥃','🥄','🥅','🥇','🥈','🥉','🥊','🥋','🥌','🥐','🥑','🥒','🥓','🥔','🥕','🥖','🥗','🥘','🥙','🥚','🥛','🥜','🥝','🥞','🥟','🥠','🥡','🥢','🥣','🥤','🥥','🥦','🥧','🥨','🥩','🥪','🥫','🦀','🦁','🦂','🦃','🦄','🦅','🦆','🦇','🦈','🦉','🦊','🦋','🦌','🦍','🦎','🦏','🦐','🦑','🦒','🦓','🦔','🦕','🦖','🦗','🧀','🧐','🧑','🧒','🧓','🧔','🧕','🧖','🧗','🧘','🧙','🧚','🧛','🧜','🧝','🧞','🧟','🧠','🧡','🧢','🧣','🧤','🧥','🧦','‼','⁉','™','ℹ','↔','↕','↖','↗','↘','↙','↩','↪','⃣','⌚','⌛','⌨','⏏','⏩','⏪','⏫','⏬','⏭','⏮','⏯','⏰','⏱','⏲','⏳','⏸','⏹','⏺','Ⓜ','▪','▫','▶','◀','◻','◼','◽','◾','☀','☁','☂','☃','☄','☎','☑','☔','☕','☘','☝','☢','☣','☦','☪','☮','☯','☸','☹','☺','♈','♉','♊','♋','♌','♍','♎','♏','♐','♑','♒','♓','♠','♣','♥','♦','♨','♻','♿','⚒','⚓','⚔','⚗','⚙','⚛','⚜','⚠','⚡','⚪','⚫','⚰','⚱','⚽','⚾','⛄','⛅','⛈','⛎','⛏','⛑','⛓','⛔','⛩','⛪','⛰','⛱','⛲','⛳','⛴','⛵','⛷','⛸','⛹','⛺','⛽','✂','✅','✉','✊','✋','✌','✍','✏','✒','✔','✖','✝','✡','✨','✳','✴','❄','❇','❌','❎','❓','❔','❕','❗','❣','➕','➖','➗','➡','➰','➿','⤴','⤵','⬅','⬆','⬇','⬛','⬜','⭐','⭕','〰','〽','㊗','㊙','');
  5318.     // END: emoji arrays
  5319.  
  5320.     if ( 'entities' === $type ) {
  5321.         return $entities;
  5322.     }
  5323.  
  5324.     return $partials;
  5325. }
  5326.  
  5327. /**
  5328.  * Shorten a URL, to be used as link text.
  5329.  *
  5330.  * @since 1.2.0
  5331.  * @since 4.4.0 Moved to wp-includes/formatting.php from wp-admin/includes/misc.php and added $length param.
  5332.  *
  5333.  * @param string $url    URL to shorten.
  5334.  * @param int    $length Optional. Maximum length of the shortened URL. Default 35 characters.
  5335.  * @return string Shortened URL.
  5336.  */
  5337. function url_shorten( $url, $length = 35 ) {
  5338.     $stripped = str_replace( array( 'https://', 'http://', 'www.' ), '', $url );
  5339.     $short_url = untrailingslashit( $stripped );
  5340.  
  5341.     if ( strlen( $short_url ) > $length ) {
  5342.         $short_url = substr( $short_url, 0, $length - 3 ) . '…';
  5343.     }
  5344.     return $short_url;
  5345. }
  5346.  
  5347. /**
  5348.  * Sanitizes a hex color.
  5349.  *
  5350.  * Returns either '', a 3 or 6 digit hex color (with #), or nothing.
  5351.  * For sanitizing values without a #, see sanitize_hex_color_no_hash().
  5352.  *
  5353.  * @since 3.4.0
  5354.  *
  5355.  * @param string $color
  5356.  * @return string|void
  5357.  */
  5358. function sanitize_hex_color( $color ) {
  5359.     if ( '' === $color ) {
  5360.         return '';
  5361.     }
  5362.  
  5363.     // 3 or 6 hex digits, or the empty string.
  5364.     if ( preg_match('|^#([A-Fa-f0-9]{3}){1,2}$|', $color ) ) {
  5365.         return $color;
  5366.     }
  5367. }
  5368.  
  5369. /**
  5370.  * Sanitizes a hex color without a hash. Use sanitize_hex_color() when possible.
  5371.  *
  5372.  * Saving hex colors without a hash puts the burden of adding the hash on the
  5373.  * UI, which makes it difficult to use or upgrade to other color types such as
  5374.  * rgba, hsl, rgb, and html color names.
  5375.  *
  5376.  * Returns either '', a 3 or 6 digit hex color (without a #), or null.
  5377.  *
  5378.  * @since 3.4.0
  5379.  *
  5380.  * @param string $color
  5381.  * @return string|null
  5382.  */
  5383. function sanitize_hex_color_no_hash( $color ) {
  5384.     $color = ltrim( $color, '#' );
  5385.  
  5386.     if ( '' === $color ) {
  5387.         return '';
  5388.     }
  5389.  
  5390.     return sanitize_hex_color( '#' . $color ) ? $color : null;
  5391. }
  5392.  
  5393. /**
  5394.  * Ensures that any hex color is properly hashed.
  5395.  * Otherwise, returns value untouched.
  5396.  *
  5397.  * This method should only be necessary if using sanitize_hex_color_no_hash().
  5398.  *
  5399.  * @since 3.4.0
  5400.  *
  5401.  * @param string $color
  5402.  * @return string
  5403.  */
  5404. function maybe_hash_hex_color( $color ) {
  5405.     if ( $unhashed = sanitize_hex_color_no_hash( $color ) ) {
  5406.         return '#' . $unhashed;
  5407.     }
  5408.  
  5409.     return $color;
  5410. }
  5411.