3 * Main Wordpress Formatting API.
5 * Handles many functions for formatting output.
11 * Replaces common plain text characters into formatted entities
15 * 'cause today's effort makes it worth tomorrow's "holiday"...
19 * ’cause today’s effort makes it worth tomorrow’s “holiday”…
21 * Code within certain html blocks are skipped.
24 * @uses $wp_cockneyreplace Array of formatted entities for certain common phrases
26 * @param string $text The text to be formatted
27 * @return string The string replaced with html entities
29 function wptexturize($text) {
30 global $wp_cockneyreplace;
32 $has_pre_parent = false;
35 $textarr = preg_split('/(<.*>|\[.*\])/Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
36 $stop = count($textarr);
38 // if a plugin has provided an autocorrect array, use it
39 if ( isset($wp_cockneyreplace) ) {
40 $cockney = array_keys($wp_cockneyreplace);
41 $cockneyreplace = array_values($wp_cockneyreplace);
43 $cockney = array("'tain't","'twere","'twas","'tis","'twill","'til","'bout","'nuff","'round","'cause");
44 $cockneyreplace = array("’tain’t","’twere","’twas","’tis","’twill","’til","’bout","’nuff","’round","’cause");
47 $static_characters = array_merge(array('---', ' -- ', '--', 'xn–', '...', '``', '\'s', '\'\'', ' (tm)'), $cockney);
48 $static_replacements = array_merge(array('—', ' — ', '–', 'xn--', '…', '“', '’s', '”', ' ™'), $cockneyreplace);
50 $dynamic_characters = array('/\'(\d\d(?:’|\')?s)/', '/(\s|\A|")\'/', '/(\d+)"/', '/(\d+)\'/', '/(\S)\'([^\'\s])/', '/(\s|\A)"(?!\s)/', '/"(\s|\S|\Z)/', '/\'([\s.]|\Z)/', '/(\d+)x(\d+)/');
51 $dynamic_replacements = array('’$1','$1‘', '$1″', '$1′', '$1’$2', '$1“$2', '”$1', '’$1', '$1×$2');
53 for ( $i = 0; $i < $stop; $i++ ) {
56 if ( !empty($curl) && '<' != $curl{0} && '[' != $curl{0} && $next && !$has_pre_parent) { // If it's not a tag
58 $curl = str_replace($static_characters, $static_replacements, $curl);
59 // regular expressions
60 $curl = preg_replace($dynamic_characters, $dynamic_replacements, $curl);
61 } elseif (strpos($curl, '<code') !== false || strpos($curl, '<kbd') !== false || strpos($curl, '<style') !== false || strpos($curl, '<script') !== false) {
63 } elseif (strpos($curl, '<pre') !== false) {
64 $has_pre_parent = true;
65 } elseif (strpos($curl, '</pre>') !== false) {
66 $has_pre_parent = false;
71 $curl = preg_replace('/&([^#])(?![a-zA-Z1-4]{1,8};)/', '&$1', $curl);
79 * Accepts matches array from preg_replace_callback in wpautop() or a string.
81 * Ensures that the contents of a <<pre>>...<</pre>> HTML block are not
82 * converted into paragraphs or line-breaks.
86 * @param array|string $matches The array or string
87 * @return string The pre block without paragraph/line-break conversion.
89 function clean_pre($matches) {
90 if ( is_array($matches) )
91 $text = $matches[1] . $matches[2] . "</pre>";
95 $text = str_replace('<br />', '', $text);
96 $text = str_replace('<p>', "\n", $text);
97 $text = str_replace('</p>', '', $text);
103 * Replaces double line-breaks with paragraph elements.
105 * A group of regex replaces used to identify text formatted with newlines and
106 * replace double line-breaks with HTML paragraph tags. The remaining
107 * line-breaks after conversion become <<br />> tags, unless $br is set to '0'
112 * @param string $pee The text which has to be formatted.
113 * @param int|bool $br Optional. If set, this will convert all remaining line-breaks after paragraphing. Default true.
114 * @return string Text which has been converted into correct paragraph tags.
116 function wpautop($pee, $br = 1) {
117 $pee = $pee . "\n"; // just to make things a little easier, pad the end
118 $pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
119 // Space things out a little
120 $allblocks = '(?:table|thead|tfoot|caption|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|map|area|blockquote|address|math|style|input|p|h[1-6]|hr)';
121 $pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
122 $pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
123 $pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
124 if ( strpos($pee, '<object') !== false ) {
125 $pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // no pee inside object/embed
126 $pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee);
128 $pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates
129 // make paragraphs, including one at the end
130 $pees = preg_split('/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY);
132 foreach ( $pees as $tinkle )
133 $pee .= '<p>' . trim($tinkle, "\n") . "</p>\n";
134 $pee = preg_replace('|<p>\s*?</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace
135 $pee = preg_replace('!<p>([^<]+)\s*?(</(?:div|address|form)[^>]*>)!', "<p>$1</p>$2", $pee);
136 $pee = preg_replace( '|<p>|', "$1<p>", $pee );
137 $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); // don't pee all over a tag
138 $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
139 $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
140 $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
141 $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
142 $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
144 $pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', create_function('$matches', 'return str_replace("\n", "<WPPreserveNewline />", $matches[0]);'), $pee);
145 $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // optionally make line breaks
146 $pee = str_replace('<WPPreserveNewline />', "\n", $pee);
148 $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
149 $pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
150 if (strpos($pee, '<pre') !== false)
151 $pee = preg_replace_callback('!(<pre.*?>)(.*?)</pre>!is', 'clean_pre', $pee );
152 $pee = preg_replace( "|\n</p>$|", '</p>', $pee );
153 $pee = preg_replace('/<p>\s*?(' . get_shortcode_regex() . ')\s*<\/p>/s', '$1', $pee); // don't auto-p wrap shortcodes that stand alone
159 * Checks to see if a string is utf8 encoded.
161 * @author bmorel at ssi dot fr
165 * @param string $Str The string to be checked
166 * @return bool True if $Str fits a UTF-8 model, false otherwise.
168 function seems_utf8($Str) { # by bmorel at ssi dot fr
169 $length = strlen($Str);
170 for ($i=0; $i < $length; $i++) {
171 if (ord($Str[$i]) < 0x80) continue; # 0bbbbbbb
172 elseif ((ord($Str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
173 elseif ((ord($Str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
174 elseif ((ord($Str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
175 elseif ((ord($Str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
176 elseif ((ord($Str[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b
177 else return false; # Does not match any model
178 for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
179 if ((++$i == $length) || ((ord($Str[$i]) & 0xC0) != 0x80))
187 * Converts a number of special characters into their HTML entities.
189 * Specifically deals with: &, <, >, ", and '.
191 * $quote_style can be set to ENT_COMPAT to encode " to
192 * ", or ENT_QUOTES to do both. Default is ENT_NOQUOTES where no quotes are encoded.
196 * @param string $string The text which is to be encoded.
197 * @param mixed $quote_style Optional. Converts double quotes if set to ENT_COMPAT, both single and double if set to ENT_QUOTES or none if set to ENT_NOQUOTES. Also compatible with old values; converting single quotes if set to 'single', double if set to 'double' or both if otherwise set. Default is ENT_NOQUOTES.
198 * @param string $charset Optional. The character encoding of the string. Default is false.
199 * @param boolean $double_encode Optional. Whether or not to encode existing html entities. Default is false.
200 * @return string The encoded text with HTML entities.
202 function wp_specialchars( $string, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false )
204 $string = (string) $string;
206 if ( 0 === strlen( $string ) ) {
210 // Don't bother if there are no specialchars - saves some processing
211 if ( !preg_match( '/[&<>"\']/', $string ) ) {
215 // Account for the previous behaviour of the function when the $quote_style is not an accepted value
216 if ( empty( $quote_style ) ) {
217 $quote_style = ENT_NOQUOTES;
218 } elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) {
219 $quote_style = ENT_QUOTES;
222 // Store the site charset as a static to avoid multiple calls to wp_load_alloptions()
225 if ( !isset( $_charset ) ) {
226 $alloptions = wp_load_alloptions();
227 $_charset = isset( $alloptions['blog_charset'] ) ? $alloptions['blog_charset'] : '';
229 $charset = $_charset;
231 if ( in_array( $charset, array( 'utf8', 'utf-8', 'UTF8' ) ) ) {
235 $_quote_style = $quote_style;
237 if ( $quote_style === 'double' ) {
238 $quote_style = ENT_COMPAT;
239 $_quote_style = ENT_COMPAT;
240 } elseif ( $quote_style === 'single' ) {
241 $quote_style = ENT_NOQUOTES;
244 // Handle double encoding ourselves
245 if ( !$double_encode ) {
246 $string = wp_specialchars_decode( $string, $_quote_style );
247 $string = preg_replace( '/&(#?x?[0-9]+|[a-z]+);/i', '|wp_entity|$1|/wp_entity|', $string );
250 $string = @htmlspecialchars( $string, $quote_style, $charset );
252 // Handle double encoding ourselves
253 if ( !$double_encode ) {
254 $string = str_replace( array( '|wp_entity|', '|/wp_entity|' ), array( '&', ';' ), $string );
257 // Backwards compatibility
258 if ( 'single' === $_quote_style ) {
259 $string = str_replace( "'", ''', $string );
266 * Converts a number of HTML entities into their special characters.
268 * Specifically deals with: &, <, >, ", and '.
270 * $quote_style can be set to ENT_COMPAT to decode " entities,
271 * or ENT_QUOTES to do both " and '. Default is ENT_NOQUOTES where no quotes are decoded.
275 * @param string $string The text which is to be decoded.
276 * @param mixed $quote_style Optional. Converts double quotes if set to ENT_COMPAT, both single and double if set to ENT_QUOTES or none if set to ENT_NOQUOTES. Also compatible with old wp_specialchars() values; converting single quotes if set to 'single', double if set to 'double' or both if otherwise set. Default is ENT_NOQUOTES.
277 * @return string The decoded text without HTML entities.
279 function wp_specialchars_decode( $string, $quote_style = ENT_NOQUOTES )
281 $string = (string) $string;
283 if ( 0 === strlen( $string ) ) {
287 // Don't bother if there are no entities - saves a lot of processing
288 if ( strpos( $string, '&' ) === false ) {
292 // Match the previous behaviour of wp_specialchars() when the $quote_style is not an accepted value
293 if ( empty( $quote_style ) ) {
294 $quote_style = ENT_NOQUOTES;
295 } elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) {
296 $quote_style = ENT_QUOTES;
299 // More complete than get_html_translation_table( HTML_SPECIALCHARS )
300 $single = array( ''' => '\'', ''' => '\'' );
301 $single_preg = array( '/�*39;/' => ''', '/�*27;/i' => ''' );
302 $double = array( '"' => '"', '"' => '"', '"' => '"' );
303 $double_preg = array( '/�*34;/' => '"', '/�*22;/i' => '"' );
304 $others = array( '<' => '<', '<' => '<', '>' => '>', '>' => '>', '&' => '&', '&' => '&', '&' => '&' );
305 $others_preg = array( '/�*60;/' => '<', '/�*62;/' => '>', '/�*38;/' => '&', '/�*26;/i' => '&' );
307 if ( $quote_style === ENT_QUOTES ) {
308 $translation = array_merge( $single, $double, $others );
309 $translation_preg = array_merge( $single_preg, $double_preg, $others_preg );
310 } elseif ( $quote_style === ENT_COMPAT || $quote_style === 'double' ) {
311 $translation = array_merge( $double, $others );
312 $translation_preg = array_merge( $double_preg, $others_preg );
313 } elseif ( $quote_style === 'single' ) {
314 $translation = array_merge( $single, $others );
315 $translation_preg = array_merge( $single_preg, $others_preg );
316 } elseif ( $quote_style === ENT_NOQUOTES ) {
317 $translation = $others;
318 $translation_preg = $others_preg;
321 // Remove zero padding on numeric entities
322 $string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string );
324 // Replace characters according to translation table
325 return strtr( $string, $translation );
329 * Checks for invalid UTF8 in a string.
333 * @param string $string The text which is to be checked.
334 * @param boolean $strip Optional. Whether to attempt to strip out invalid UTF8. Default is false.
335 * @return string The checked text.
337 function wp_check_invalid_utf8( $string, $strip = false )
339 $string = (string) $string;
341 if ( 0 === strlen( $string ) ) {
345 // Store the site charset as a static to avoid multiple calls to get_option()
347 if ( !isset( $is_utf8 ) ) {
348 $is_utf8 = in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) );
354 // Check for support for utf8 in the installed PCRE library once and store the result in a static
356 if ( !isset( $utf8_pcre ) ) {
357 $utf8_pcre = @preg_match( '/^./u', 'a' );
359 // We can't demand utf8 in the PCRE installation, so just return the string in those cases
364 // preg_match fails when it encounters invalid UTF8 in $string
365 if ( 1 === @preg_match( '/^./us', $string ) ) {
369 // Attempt to strip the bad chars if requested (not recommended)
370 if ( $strip && function_exists( 'iconv' ) ) {
371 return iconv( 'utf-8', 'utf-8', $string );
378 * Encode the Unicode values to be used in the URI.
382 * @param string $utf8_string
383 * @param int $length Max length of the string
384 * @return string String with Unicode encoded for URI.
386 function utf8_uri_encode( $utf8_string, $length = 0 ) {
392 $string_length = strlen( $utf8_string );
393 for ($i = 0; $i < $string_length; $i++ ) {
395 $value = ord( $utf8_string[ $i ] );
397 if ( $value < 128 ) {
398 if ( $length && ( $unicode_length >= $length ) )
400 $unicode .= chr($value);
403 if ( count( $values ) == 0 ) $num_octets = ( $value < 224 ) ? 2 : 3;
407 if ( $length && ( $unicode_length + ($num_octets * 3) ) > $length )
409 if ( count( $values ) == $num_octets ) {
410 if ($num_octets == 3) {
411 $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]) . '%' . dechex($values[2]);
412 $unicode_length += 9;
414 $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]);
415 $unicode_length += 6;
428 * Converts all accent characters to ASCII characters.
430 * If there are no accent characters, then the string given is just returned.
434 * @param string $string Text that might have accent characters
435 * @return string Filtered string with replaced "nice" characters.
437 function remove_accents($string) {
438 if ( !preg_match('/[\x80-\xff]/', $string) )
441 if (seems_utf8($string)) {
443 // Decompositions for Latin-1 Supplement
444 chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
445 chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
446 chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
447 chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
448 chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
449 chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
450 chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
451 chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
452 chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
453 chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
454 chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
455 chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
456 chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
457 chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
458 chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
459 chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
460 chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
461 chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
462 chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
463 chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
464 chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
465 chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
466 chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
467 chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
468 chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
469 chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
470 chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
471 chr(195).chr(191) => 'y',
472 // Decompositions for Latin Extended-A
473 chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
474 chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
475 chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
476 chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
477 chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
478 chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
479 chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
480 chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
481 chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
482 chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
483 chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
484 chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
485 chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
486 chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
487 chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
488 chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
489 chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
490 chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
491 chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
492 chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
493 chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
494 chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
495 chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
496 chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
497 chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
498 chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
499 chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
500 chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
501 chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
502 chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
503 chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
504 chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
505 chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
506 chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
507 chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
508 chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
509 chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
510 chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
511 chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
512 chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
513 chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
514 chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
515 chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
516 chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
517 chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
518 chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
519 chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
520 chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
521 chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
522 chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
523 chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
524 chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
525 chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
526 chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
527 chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
528 chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
529 chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
530 chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
531 chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
532 chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
533 chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
534 chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
535 chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
536 chr(197).chr(190) => 'z', chr(197).chr(191) => 's',
538 chr(226).chr(130).chr(172) => 'E',
540 chr(194).chr(163) => '');
542 $string = strtr($string, $chars);
544 // Assume ISO-8859-1 if not UTF-8
545 $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
546 .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194)
547 .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202)
548 .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
549 .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218)
550 .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227)
551 .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235)
552 .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243)
553 .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251)
554 .chr(252).chr(253).chr(255);
556 $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
558 $string = strtr($string, $chars['in'], $chars['out']);
559 $double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
560 $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
561 $string = str_replace($double_chars['in'], $double_chars['out'], $string);
568 * Filters certain characters from the file name.
570 * Turns all strings to lowercase removing most characters except alphanumeric
571 * with spaces, dashes and periods. All spaces and underscores are converted to
572 * dashes. Multiple dashes are converted to a single dash. Finally, if the file
573 * name ends with a dash, it is removed.
577 * @param string $name The file name
578 * @return string Sanitized file name
580 function sanitize_file_name( $name ) { // Like sanitize_title, but with periods
581 $name = strtolower( $name );
582 $name = preg_replace('/&.+?;/', '', $name); // kill entities
583 $name = str_replace( '_', '-', $name );
584 $name = preg_replace('/[^a-z0-9\s-.]/', '', $name);
585 $name = preg_replace('/\s+/', '-', $name);
586 $name = preg_replace('|-+|', '-', $name);
587 $name = trim($name, '-');
592 * Sanitize username stripping out unsafe characters.
594 * If $strict is true, only alphanumeric characters (as well as _, space, ., -,
596 * Removes tags, octets, entities, and if strict is enabled, will remove all
597 * non-ASCII characters. After sanitizing, it passes the username, raw username
598 * (the username in the parameter), and the strict parameter as parameters for
602 * @uses apply_filters() Calls 'sanitize_user' hook on username, raw username,
603 * and $strict parameter.
605 * @param string $username The username to be sanitized.
606 * @param bool $strict If set limits $username to specific characters. Default false.
607 * @return string The sanitized username, after passing through filters.
609 function sanitize_user( $username, $strict = false ) {
610 $raw_username = $username;
611 $username = strip_tags($username);
613 $username = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '', $username);
614 $username = preg_replace('/&.+?;/', '', $username); // Kill entities
616 // If strict, reduce to ASCII for max portability.
618 $username = preg_replace('|[^a-z0-9 _.\-@]|i', '', $username);
620 // Consolidate contiguous whitespace
621 $username = preg_replace('|\s+|', ' ', $username);
623 return apply_filters('sanitize_user', $username, $raw_username, $strict);
627 * Sanitizes title or use fallback title.
629 * Specifically, HTML and PHP tags are stripped. Further actions can be added
630 * via the plugin API. If $title is empty and $fallback_title is set, the latter
635 * @param string $title The string to be sanitized.
636 * @param string $fallback_title Optional. A title to use if $title is empty.
637 * @return string The sanitized string.
639 function sanitize_title($title, $fallback_title = '') {
640 $title = strip_tags($title);
641 $title = apply_filters('sanitize_title', $title);
643 if ( '' === $title || false === $title )
644 $title = $fallback_title;
650 * Sanitizes title, replacing whitespace with dashes.
652 * Limits the output to alphanumeric characters, underscore (_) and dash (-).
653 * Whitespace becomes a dash.
657 * @param string $title The title to be sanitized.
658 * @return string The sanitized title.
660 function sanitize_title_with_dashes($title) {
661 $title = strip_tags($title);
662 // Preserve escaped octets.
663 $title = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $title);
664 // Remove percent signs that are not part of an octet.
665 $title = str_replace('%', '', $title);
667 $title = preg_replace('|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $title);
669 $title = remove_accents($title);
670 if (seems_utf8($title)) {
671 if (function_exists('mb_strtolower')) {
672 $title = mb_strtolower($title, 'UTF-8');
674 $title = utf8_uri_encode($title, 200);
677 $title = strtolower($title);
678 $title = preg_replace('/&.+?;/', '', $title); // kill entities
679 $title = preg_replace('/[^%a-z0-9 _-]/', '', $title);
680 $title = preg_replace('/\s+/', '-', $title);
681 $title = preg_replace('|-+|', '-', $title);
682 $title = trim($title, '-');
688 * Ensures a string is a valid SQL order by clause.
690 * Accepts one or more columns, with or without ASC/DESC, and also accepts
695 * @param string $orderby Order by string to be checked.
696 * @return string|false Returns the order by clause if it is a match, false otherwise.
698 function sanitize_sql_orderby( $orderby ){
699 preg_match('/^\s*([a-z0-9_]+(\s+(ASC|DESC))?(\s*,\s*|\s*$))+|^\s*RAND\(\s*\)\s*$/i', $orderby, $obmatches);
706 * Converts a number of characters from a string.
708 * Metadata tags <<title>> and <<category>> are removed, <<br>> and <<hr>> are
709 * converted into correct XHTML and Unicode characters are converted to the
714 * @param string $content String of characters to be converted.
715 * @param string $deprecated Not used.
716 * @return string Converted string.
718 function convert_chars($content, $deprecated = '') {
719 // Translation of invalid Unicode references range to valid range
720 $wp_htmltranswinuni = array(
721 '€' => '€', // the Euro sign
723 '‚' => '‚', // these are Windows CP1252 specific characters
724 'ƒ' => 'ƒ', // they would look weird on non-Windows browsers
725 '„' => '„',
726 '…' => '…',
727 '†' => '†',
728 '‡' => '‡',
729 'ˆ' => 'ˆ',
730 '‰' => '‰',
731 'Š' => 'Š',
732 '‹' => '‹',
733 'Œ' => 'Œ',
735 'Ž' => 'ž',
738 '‘' => '‘',
739 '’' => '’',
740 '“' => '“',
741 '”' => '”',
742 '•' => '•',
743 '–' => '–',
744 '—' => '—',
745 '˜' => '˜',
746 '™' => '™',
747 'š' => 'š',
748 '›' => '›',
749 'œ' => 'œ',
755 // Remove metadata tags
756 $content = preg_replace('/<title>(.+?)<\/title>/','',$content);
757 $content = preg_replace('/<category>(.+?)<\/category>/','',$content);
759 // Converts lone & characters into & (a.k.a. &)
760 $content = preg_replace('/&([^#])(?![a-z1-4]{1,8};)/i', '&$1', $content);
763 $content = strtr($content, $wp_htmltranswinuni);
765 // Just a little XHTML help
766 $content = str_replace('<br>', '<br />', $content);
767 $content = str_replace('<hr>', '<hr />', $content);
773 * Fixes javascript bugs in browsers.
775 * Converts unicode characters to HTML numbered entities.
781 * @param string $text Text to be made safe.
782 * @return string Fixed text.
784 function funky_javascript_fix($text) {
785 // Fixes for browsers' javascript bugs
786 global $is_macIE, $is_winIE;
788 /** @todo use preg_replace_callback() instead */
789 if ( $is_winIE || $is_macIE )
790 $text = preg_replace("/\%u([0-9A-F]{4,4})/e", "'&#'.base_convert('\\1',16,10).';'", $text);
796 * Will only balance the tags if forced to and the option is set to balance tags.
798 * The option 'use_balanceTags' is used for whether the tags will be balanced.
799 * Both the $force parameter and 'use_balanceTags' option will have to be true
800 * before the tags will be balanced.
804 * @param string $text Text to be balanced
805 * @param bool $force Forces balancing, ignoring the value of the option. Default false.
806 * @return string Balanced text
808 function balanceTags( $text, $force = false ) {
809 if ( !$force && get_option('use_balanceTags') == 0 )
811 return force_balance_tags( $text );
815 * Balances tags of string using a modified stack.
819 * @author Leonard Lin <leonard@acm.org>
821 * @copyright November 4, 2001
823 * @todo Make better - change loop condition to $text in 1.2
824 * @internal Modified by Scott Reilly (coffee2code) 02 Aug 2004
825 * 1.1 Fixed handling of append/stack pop order of end text
826 * Added Cleaning Hooks
829 * @param string $text Text to be balanced.
830 * @return string Balanced text.
832 function force_balance_tags( $text ) {
833 $tagstack = array(); $stacksize = 0; $tagqueue = ''; $newtext = '';
834 $single_tags = array('br', 'hr', 'img', 'input'); //Known single-entity/self-closing tags
835 $nestable_tags = array('blockquote', 'div', 'span'); //Tags that can be immediately nested within themselves
837 # WP bug fix for comments - in case you REALLY meant to type '< !--'
838 $text = str_replace('< !--', '< !--', $text);
839 # WP bug fix for LOVE <3 (and other situations with '<' before a number)
840 $text = preg_replace('#<([0-9]{1})#', '<$1', $text);
842 while (preg_match("/<(\/?\w*)\s*([^>]*)>/",$text,$regex)) {
843 $newtext .= $tagqueue;
845 $i = strpos($text,$regex[0]);
846 $l = strlen($regex[0]);
851 if ($regex[1][0] == "/") { // End Tag
852 $tag = strtolower(substr($regex[1],1));
853 // if too many closing tags
854 if($stacksize <= 0) {
856 //or close to be safe $tag = '/' . $tag;
858 // if stacktop value = tag close value then pop
859 else if ($tagstack[$stacksize - 1] == $tag) { // found closing tag
860 $tag = '</' . $tag . '>'; // Close Tag
862 array_pop ($tagstack);
864 } else { // closing tag not at top, search for it
865 for ($j=$stacksize-1;$j>=0;$j--) {
866 if ($tagstack[$j] == $tag) {
867 // add tag to tagqueue
868 for ($k=$stacksize-1;$k>=$j;$k--){
869 $tagqueue .= '</' . array_pop ($tagstack) . '>';
877 } else { // Begin Tag
878 $tag = strtolower($regex[1]);
882 // If self-closing or '', don't do anything.
883 if((substr($regex[2],-1) == '/') || ($tag == '')) {
885 // ElseIf it's a known single-entity tag but it doesn't close itself, do so
886 elseif ( in_array($tag, $single_tags) ) {
888 } else { // Push the tag onto the stack
889 // If the top of the stack is the same as the tag we want to push, close previous tag
890 if (($stacksize > 0) && !in_array($tag, $nestable_tags) && ($tagstack[$stacksize - 1] == $tag)) {
891 $tagqueue = '</' . array_pop ($tagstack) . '>';
894 $stacksize = array_push ($tagstack, $tag);
898 $attributes = $regex[2];
900 $attributes = ' '.$attributes;
902 $tag = '<'.$tag.$attributes.'>';
903 //If already queuing a close tag, then put this tag on, too
909 $newtext .= substr($text,0,$i) . $tag;
910 $text = substr($text,$i+$l);
914 $newtext .= $tagqueue;
916 // Add Remaining text
920 while($x = array_pop($tagstack)) {
921 $newtext .= '</' . $x . '>'; // Add remaining tags to close
924 // WP fix for the bug with HTML comments
925 $newtext = str_replace("< !--","<!--",$newtext);
926 $newtext = str_replace("< !--","< !--",$newtext);
932 * Acts on text which is about to be edited.
934 * Unless $richedit is set, it is simply a holder for the 'format_to_edit'
935 * filter. If $richedit is set true htmlspecialchars() will be run on the
936 * content, converting special characters to HTMl entities.
940 * @param string $content The text about to be edited.
941 * @param bool $richedit Whether or not the $content should pass through htmlspecialchars(). Default false.
942 * @return string The text after the filter (and possibly htmlspecialchars()) has been run.
944 function format_to_edit($content, $richedit = false) {
945 $content = apply_filters('format_to_edit', $content);
947 $content = htmlspecialchars($content);
952 * Holder for the 'format_to_post' filter.
956 * @param string $content The text to pass through the filter.
957 * @return string Text returned from the 'format_to_post' filter.
959 function format_to_post($content) {
960 $content = apply_filters('format_to_post', $content);
965 * Add leading zeros when necessary.
967 * If you set the threshold to '4' and the number is '10', then you will get
968 * back '0010'. If you set the number to '4' and the number is '5000', then you
969 * will get back '5000'.
971 * Uses sprintf to append the amount of zeros based on the $threshold parameter
972 * and the size of the number. If the number is large enough, then no zeros will
977 * @param mixed $number Number to append zeros to if not greater than threshold.
978 * @param int $threshold Digit places number needs to be to not have zeros added.
979 * @return string Adds leading zeros to number if needed.
981 function zeroise($number, $threshold) {
982 return sprintf('%0'.$threshold.'s', $number);
986 * Adds backslashes before letters and before a number at the start of a string.
990 * @param string $string Value to which backslashes will be added.
991 * @return string String with backslashes inserted.
993 function backslashit($string) {
994 $string = preg_replace('/^([0-9])/', '\\\\\\\\\1', $string);
995 $string = preg_replace('/([a-z])/i', '\\\\\1', $string);
1000 * Appends a trailing slash.
1002 * Will remove trailing slash if it exists already before adding a trailing
1003 * slash. This prevents double slashing a string or path.
1005 * The primary use of this is for paths and thus should be used for paths. It is
1006 * not restricted to paths and offers no specific path support.
1009 * @uses untrailingslashit() Unslashes string if it was slashed already.
1011 * @param string $string What to add the trailing slash to.
1012 * @return string String with trailing slash added.
1014 function trailingslashit($string) {
1015 return untrailingslashit($string) . '/';
1019 * Removes trailing slash if it exists.
1021 * The primary use of this is for paths and thus should be used for paths. It is
1022 * not restricted to paths and offers no specific path support.
1026 * @param string $string What to remove the trailing slash from.
1027 * @return string String without the trailing slash.
1029 function untrailingslashit($string) {
1030 return rtrim($string, '/');
1034 * Adds slashes to escape strings.
1036 * Slashes will first be removed if magic_quotes_gpc is set, see {@link
1037 * http://www.php.net/magic_quotes} for more details.
1041 * @param string $gpc The string returned from HTTP request data.
1042 * @return string Returns a string escaped with slashes.
1044 function addslashes_gpc($gpc) {
1047 if (get_magic_quotes_gpc()) {
1048 $gpc = stripslashes($gpc);
1051 return $wpdb->escape($gpc);
1055 * Navigates through an array and removes slashes from the values.
1057 * If an array is passed, the array_map() function causes a callback to pass the
1058 * value back to the function. The slashes from this value will removed.
1062 * @param array|string $value The array or string to be striped.
1063 * @return array|string Stripped array (or string in the callback).
1065 function stripslashes_deep($value) {
1066 $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value);
1071 * Navigates through an array and encodes the values to be used in a URL.
1073 * Uses a callback to pass the value of the array back to the function as a
1078 * @param array|string $value The array or string to be encoded.
1079 * @return array|string $value The encoded array (or string from the callback).
1081 function urlencode_deep($value) {
1082 $value = is_array($value) ? array_map('urlencode_deep', $value) : urlencode($value);
1087 * Converts email addresses characters to HTML entities to block spam bots.
1091 * @param string $emailaddy Email address.
1092 * @param int $mailto Optional. Range from 0 to 1. Used for encoding.
1093 * @return string Converted email address.
1095 function antispambot($emailaddy, $mailto=0) {
1096 $emailNOSPAMaddy = '';
1097 srand ((float) microtime() * 1000000);
1098 for ($i = 0; $i < strlen($emailaddy); $i = $i + 1) {
1099 $j = floor(rand(0, 1+$mailto));
1101 $emailNOSPAMaddy .= '&#'.ord(substr($emailaddy,$i,1)).';';
1103 $emailNOSPAMaddy .= substr($emailaddy,$i,1);
1105 $emailNOSPAMaddy .= '%'.zeroise(dechex(ord(substr($emailaddy, $i, 1))), 2);
1108 $emailNOSPAMaddy = str_replace('@','@',$emailNOSPAMaddy);
1109 return $emailNOSPAMaddy;
1113 * Callback to convert URI match to HTML A element.
1115 * This function was backported from 2.5.0 to 2.3.2. Regex callback for {@link
1116 * make_clickable()}.
1121 * @param array $matches Single Regex Match.
1122 * @return string HTML A element with URI address.
1124 function _make_url_clickable_cb($matches) {
1127 $url = clean_url($url);
1130 // removed trailing [.,;:] from URL
1131 if ( in_array(substr($url, -1), array('.', ',', ';', ':')) === true ) {
1132 $ret = substr($url, -1);
1133 $url = substr($url, 0, strlen($url)-1);
1135 return $matches[1] . "<a href=\"$url\" rel=\"nofollow\">$url</a>" . $ret;
1139 * Callback to convert URL match to HTML A element.
1141 * This function was backported from 2.5.0 to 2.3.2. Regex callback for {@link
1142 * make_clickable()}.
1147 * @param array $matches Single Regex Match.
1148 * @return string HTML A element with URL address.
1150 function _make_web_ftp_clickable_cb($matches) {
1152 $dest = $matches[2];
1153 $dest = 'http://' . $dest;
1154 $dest = clean_url($dest);
1157 // removed trailing [,;:] from URL
1158 if ( in_array(substr($dest, -1), array('.', ',', ';', ':')) === true ) {
1159 $ret = substr($dest, -1);
1160 $dest = substr($dest, 0, strlen($dest)-1);
1162 return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>" . $ret;
1166 * Callback to convert email address match to HTML A element.
1168 * This function was backported from 2.5.0 to 2.3.2. Regex callback for {@link
1169 * make_clickable()}.
1174 * @param array $matches Single Regex Match.
1175 * @return string HTML A element with email address.
1177 function _make_email_clickable_cb($matches) {
1178 $email = $matches[2] . '@' . $matches[3];
1179 return $matches[1] . "<a href=\"mailto:$email\">$email</a>";
1183 * Convert plaintext URI to HTML links.
1185 * Converts URI, www and ftp, and email addresses. Finishes by fixing links
1190 * @param string $ret Content to convert URIs.
1191 * @return string Content with converted URIs.
1193 function make_clickable($ret) {
1195 // in testing, using arrays here was found to be faster
1196 $ret = preg_replace_callback('#([\s>])([\w]+?://[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]*)#is', '_make_url_clickable_cb', $ret);
1197 $ret = preg_replace_callback('#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]*)#is', '_make_web_ftp_clickable_cb', $ret);
1198 $ret = preg_replace_callback('#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret);
1199 // this one is not in an array because we need it to run last, for cleanup of accidental links within links
1200 $ret = preg_replace("#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i", "$1$3</a>", $ret);
1206 * Adds rel nofollow string to all HTML A elements in content.
1210 * @param string $text Content that may contain HTML A elements.
1211 * @return string Converted content.
1213 function wp_rel_nofollow( $text ) {
1215 // This is a pre save filter, so text is already escaped.
1216 $text = stripslashes($text);
1217 $text = preg_replace_callback('|<a (.+?)>|i', 'wp_rel_nofollow_callback', $text);
1218 $text = $wpdb->escape($text);
1223 * Callback to used to add rel=nofollow string to HTML A element.
1225 * Will remove already existing rel="nofollow" and rel='nofollow' from the
1226 * string to prevent from invalidating (X)HTML.
1230 * @param array $matches Single Match
1231 * @return string HTML A Element with rel nofollow.
1233 function wp_rel_nofollow_callback( $matches ) {
1234 $text = $matches[1];
1235 $text = str_replace(array(' rel="nofollow"', " rel='nofollow'"), '', $text);
1236 return "<a $text rel=\"nofollow\">";
1240 * Convert text equivalent of smilies to images.
1242 * Will only convert smilies if the option 'use_smilies' is true and the globals
1243 * used in the function aren't empty.
1246 * @uses $wp_smiliessearch, $wp_smiliesreplace Smiley replacement arrays.
1248 * @param string $text Content to convert smilies from text.
1249 * @return string Converted content with text smilies replaced with images.
1251 function convert_smilies($text) {
1252 global $wp_smiliessearch, $wp_smiliesreplace;
1254 if ( get_option('use_smilies') && !empty($wp_smiliessearch) && !empty($wp_smiliesreplace) ) {
1255 // HTML loop taken from texturize function, could possible be consolidated
1256 $textarr = preg_split("/(<.*>)/U", $text, -1, PREG_SPLIT_DELIM_CAPTURE); // capture the tags as well as in between
1257 $stop = count($textarr);// loop stuff
1258 for ($i = 0; $i < $stop; $i++) {
1259 $content = $textarr[$i];
1260 if ((strlen($content) > 0) && ('<' != $content{0})) { // If it's not a tag
1261 $content = preg_replace($wp_smiliessearch, $wp_smiliesreplace, $content);
1263 $output .= $content;
1266 // return default text.
1273 * Checks to see if the text is a valid email address.
1277 * @param string $user_email The email address to be checked.
1278 * @return bool Returns true if valid, otherwise false.
1280 function is_email($user_email) {
1281 $chars = "/^([a-z0-9+_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,6}\$/i";
1282 if (strpos($user_email, '@') !== false && strpos($user_email, '.') !== false) {
1283 if (preg_match($chars, $user_email)) {
1294 * Convert to ASCII from email subjects.
1297 * @usedby wp_mail() handles charsets in email subjects
1299 * @param string $string Subject line
1300 * @return string Converted string to ASCII
1302 function wp_iso_descrambler($string) {
1303 /* this may only work with iso-8859-1, I'm afraid */
1304 if (!preg_match('#\=\?(.+)\?Q\?(.+)\?\=#i', $string, $matches)) {
1307 $subject = str_replace('_', ' ', $matches[2]);
1308 $subject = preg_replace_callback('#\=([0-9a-f]{2})#i', create_function('$match', 'return chr(hexdec(strtolower($match[1])));'), $subject);
1314 * Returns a date in the GMT equivalent.
1316 * Requires and returns a date in the Y-m-d H:i:s format. Simply subtracts the
1317 * value of the 'gmt_offset' option.
1321 * @uses get_option() to retrieve the the value of 'gmt_offset'.
1322 * @param string $string The date to be converted.
1323 * @return string GMT version of the date provided.
1325 function get_gmt_from_date($string) {
1326 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);
1327 $string_time = gmmktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
1328 $string_gmt = gmdate('Y-m-d H:i:s', $string_time - get_option('gmt_offset') * 3600);
1333 * Converts a GMT date into the correct format for the blog.
1335 * Requires and returns in the Y-m-d H:i:s format. Simply adds the value of
1340 * @param string $string The date to be converted.
1341 * @return string Formatted date relative to the GMT offset.
1343 function get_date_from_gmt($string) {
1344 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);
1345 $string_time = gmmktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
1346 $string_localtime = gmdate('Y-m-d H:i:s', $string_time + get_option('gmt_offset')*3600);
1347 return $string_localtime;
1351 * Computes an offset in seconds from an iso8601 timezone.
1355 * @param string $timezone Either 'Z' for 0 offset or '±hhmm'.
1356 * @return int|float The offset in seconds.
1358 function iso8601_timezone_to_offset($timezone) {
1359 // $timezone is either 'Z' or '[+|-]hhmm'
1360 if ($timezone == 'Z') {
1363 $sign = (substr($timezone, 0, 1) == '+') ? 1 : -1;
1364 $hours = intval(substr($timezone, 1, 2));
1365 $minutes = intval(substr($timezone, 3, 4)) / 60;
1366 $offset = $sign * 3600 * ($hours + $minutes);
1372 * Converts an iso8601 date to MySQL DateTime format used by post_date[_gmt].
1376 * @param string $date_string Date and time in ISO 8601 format {@link http://en.wikipedia.org/wiki/ISO_8601}.
1377 * @param string $timezone Optional. If set to GMT returns the time minus gmt_offset. Default is 'user'.
1378 * @return string The date and time in MySQL DateTime format - Y-m-d H:i:s.
1380 function iso8601_to_datetime($date_string, $timezone = 'user') {
1381 $timezone = strtolower($timezone);
1383 if ($timezone == 'gmt') {
1385 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);
1387 if (!empty($date_bits[7])) { // we have a timezone, so let's compute an offset
1388 $offset = iso8601_timezone_to_offset($date_bits[7]);
1389 } else { // we don't have a timezone, so we assume user local timezone (not server's!)
1390 $offset = 3600 * get_option('gmt_offset');
1393 $timestamp = gmmktime($date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1]);
1394 $timestamp -= $offset;
1396 return gmdate('Y-m-d H:i:s', $timestamp);
1398 } else if ($timezone == 'user') {
1399 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);
1404 * Adds a element attributes to open links in new windows.
1406 * Comment text in popup windows should be filtered through this. Right now it's
1407 * a moderately dumb function, ideally it would detect whether a target or rel
1408 * attribute was already there and adjust its actions accordingly.
1412 * @param string $text Content to replace links to open in a new window.
1413 * @return string Content that has filtered links.
1415 function popuplinks($text) {
1416 $text = preg_replace('/<a (.+?)>/i', "<a $1 target='_blank' rel='external'>", $text);
1421 * Strips out all characters that are not allowable in an email.
1425 * @param string $email Email address to filter.
1426 * @return string Filtered email address.
1428 function sanitize_email($email) {
1429 return preg_replace('/[^a-z0-9+_.@-]/i', '', $email);
1433 * Determines the difference between two timestamps.
1435 * The difference is returned in a human readable format such as "1 hour",
1436 * "5 mins", "2 days".
1440 * @param int $from Unix timestamp from which the difference begins.
1441 * @param int $to Optional. Unix timestamp to end the time difference. Default becomes time() if not set.
1442 * @return string Human readable time difference.
1444 function human_time_diff( $from, $to = '' ) {
1447 $diff = (int) abs($to - $from);
1448 if ($diff <= 3600) {
1449 $mins = round($diff / 60);
1453 $since = sprintf(__ngettext('%s min', '%s mins', $mins), $mins);
1454 } else if (($diff <= 86400) && ($diff > 3600)) {
1455 $hours = round($diff / 3600);
1459 $since = sprintf(__ngettext('%s hour', '%s hours', $hours), $hours);
1460 } elseif ($diff >= 86400) {
1461 $days = round($diff / 86400);
1465 $since = sprintf(__ngettext('%s day', '%s days', $days), $days);
1471 * Generates an excerpt from the content, if needed.
1473 * The excerpt word amount will be 55 words and if the amount is greater than
1474 * that, then the string '[...]' will be appended to the excerpt. If the string
1475 * is less than 55 words, then the content will be returned as is.
1479 * @param string $text The exerpt. If set to empty an excerpt is generated.
1480 * @return string The excerpt.
1482 function wp_trim_excerpt($text) {
1483 if ( '' == $text ) {
1484 $text = get_the_content('');
1486 $text = strip_shortcodes( $text );
1488 $text = apply_filters('the_content', $text);
1489 $text = str_replace(']]>', ']]>', $text);
1490 $text = strip_tags($text);
1491 $excerpt_length = apply_filters('excerpt_length', 55);
1492 $words = explode(' ', $text, $excerpt_length + 1);
1493 if (count($words) > $excerpt_length) {
1495 array_push($words, '[...]');
1496 $text = implode(' ', $words);
1503 * Converts named entities into numbered entities.
1507 * @param string $text The text within which entities will be converted.
1508 * @return string Text with converted entities.
1510 function ent2ncr($text) {
1512 '"' => '"',
1514 '⁄' => '/',
1518 ' ' => ' ',
1519 '¡' => '¡',
1520 '¢' => '¢',
1521 '£' => '£',
1522 '¤' => '¤',
1523 '¥' => '¥',
1524 '¦' => '¦',
1525 '&brkbar;' => '¦',
1526 '§' => '§',
1527 '¨' => '¨',
1528 '¨' => '¨',
1529 '©' => '©',
1530 'ª' => 'ª',
1531 '«' => '«',
1532 '¬' => '¬',
1533 '­' => '­',
1534 '®' => '®',
1535 '¯' => '¯',
1536 '&hibar;' => '¯',
1537 '°' => '°',
1538 '±' => '±',
1539 '²' => '²',
1540 '³' => '³',
1541 '´' => '´',
1542 'µ' => 'µ',
1543 '¶' => '¶',
1544 '·' => '·',
1545 '¸' => '¸',
1546 '¹' => '¹',
1547 'º' => 'º',
1548 '»' => '»',
1549 '¼' => '¼',
1550 '½' => '½',
1551 '¾' => '¾',
1552 '¿' => '¿',
1553 'À' => 'À',
1554 'Á' => 'Á',
1555 'Â' => 'Â',
1556 'Ã' => 'Ã',
1557 'Ä' => 'Ä',
1558 'Å' => 'Å',
1559 'Æ' => 'Æ',
1560 'Ç' => 'Ç',
1561 'È' => 'È',
1562 'É' => 'É',
1563 'Ê' => 'Ê',
1564 'Ë' => 'Ë',
1565 'Ì' => 'Ì',
1566 'Í' => 'Í',
1567 'Î' => 'Î',
1568 'Ï' => 'Ï',
1569 'Ð' => 'Ð',
1570 'Ñ' => 'Ñ',
1571 'Ò' => 'Ò',
1572 'Ó' => 'Ó',
1573 'Ô' => 'Ô',
1574 'Õ' => 'Õ',
1575 'Ö' => 'Ö',
1576 '×' => '×',
1577 'Ø' => 'Ø',
1578 'Ù' => 'Ù',
1579 'Ú' => 'Ú',
1580 'Û' => 'Û',
1581 'Ü' => 'Ü',
1582 'Ý' => 'Ý',
1583 'Þ' => 'Þ',
1584 'ß' => 'ß',
1585 'à' => 'à',
1586 'á' => 'á',
1587 'â' => 'â',
1588 'ã' => 'ã',
1589 'ä' => 'ä',
1590 'å' => 'å',
1591 'æ' => 'æ',
1592 'ç' => 'ç',
1593 'è' => 'è',
1594 'é' => 'é',
1595 'ê' => 'ê',
1596 'ë' => 'ë',
1597 'ì' => 'ì',
1598 'í' => 'í',
1599 'î' => 'î',
1600 'ï' => 'ï',
1601 'ð' => 'ð',
1602 'ñ' => 'ñ',
1603 'ò' => 'ò',
1604 'ó' => 'ó',
1605 'ô' => 'ô',
1606 'õ' => 'õ',
1607 'ö' => 'ö',
1608 '÷' => '÷',
1609 'ø' => 'ø',
1610 'ù' => 'ù',
1611 'ú' => 'ú',
1612 'û' => 'û',
1613 'ü' => 'ü',
1614 'ý' => 'ý',
1615 'þ' => 'þ',
1616 'ÿ' => 'ÿ',
1617 'Œ' => 'Œ',
1618 'œ' => 'œ',
1619 'Š' => 'Š',
1620 'š' => 'š',
1621 'Ÿ' => 'Ÿ',
1622 'ƒ' => 'ƒ',
1623 'ˆ' => 'ˆ',
1624 '˜' => '˜',
1625 'Α' => 'Α',
1626 'Β' => 'Β',
1627 'Γ' => 'Γ',
1628 'Δ' => 'Δ',
1629 'Ε' => 'Ε',
1630 'Ζ' => 'Ζ',
1631 'Η' => 'Η',
1632 'Θ' => 'Θ',
1633 'Ι' => 'Ι',
1634 'Κ' => 'Κ',
1635 'Λ' => 'Λ',
1639 'Ο' => 'Ο',
1641 'Ρ' => 'Ρ',
1642 'Σ' => 'Σ',
1643 'Τ' => 'Τ',
1644 'Υ' => 'Υ',
1645 'Φ' => 'Φ',
1646 'Χ' => 'Χ',
1647 'Ψ' => 'Ψ',
1648 'Ω' => 'Ω',
1649 'α' => 'α',
1650 'β' => 'β',
1651 'γ' => 'γ',
1652 'δ' => 'δ',
1653 'ε' => 'ε',
1654 'ζ' => 'ζ',
1655 'η' => 'η',
1656 'θ' => 'θ',
1657 'ι' => 'ι',
1658 'κ' => 'κ',
1659 'λ' => 'λ',
1663 'ο' => 'ο',
1665 'ρ' => 'ρ',
1666 'ς' => 'ς',
1667 'σ' => 'σ',
1668 'τ' => 'τ',
1669 'υ' => 'υ',
1670 'φ' => 'φ',
1671 'χ' => 'χ',
1672 'ψ' => 'ψ',
1673 'ω' => 'ω',
1674 'ϑ' => 'ϑ',
1675 'ϒ' => 'ϒ',
1676 'ϖ' => 'ϖ',
1677 ' ' => ' ',
1678 ' ' => ' ',
1679 ' ' => ' ',
1680 '‌' => '‌',
1681 '‍' => '‍',
1682 '‎' => '‎',
1683 '‏' => '‏',
1684 '–' => '–',
1685 '—' => '—',
1686 '‘' => '‘',
1687 '’' => '’',
1688 '‚' => '‚',
1689 '“' => '“',
1690 '”' => '”',
1691 '„' => '„',
1692 '†' => '†',
1693 '‡' => '‡',
1694 '•' => '•',
1695 '…' => '…',
1696 '‰' => '‰',
1697 '′' => '′',
1698 '″' => '″',
1699 '‹' => '‹',
1700 '›' => '›',
1701 '‾' => '‾',
1702 '⁄' => '⁄',
1703 '€' => '€',
1704 'ℑ' => 'ℑ',
1705 '℘' => '℘',
1706 'ℜ' => 'ℜ',
1707 '™' => '™',
1708 'ℵ' => 'ℵ',
1709 '↵' => '↵',
1710 '⇐' => '⇐',
1711 '⇑' => '⇑',
1712 '⇒' => '⇒',
1713 '⇓' => '⇓',
1714 '⇔' => '⇔',
1715 '∀' => '∀',
1716 '∂' => '∂',
1717 '∃' => '∃',
1718 '∅' => '∅',
1719 '∇' => '∇',
1720 '∈' => '∈',
1721 '∉' => '∉',
1722 '∋' => '∋',
1723 '∏' => '∏',
1724 '∑' => '∑',
1725 '−' => '−',
1726 '∗' => '∗',
1727 '√' => '√',
1728 '∝' => '∝',
1729 '∞' => '∞',
1730 '∠' => '∠',
1731 '∧' => '∧',
1732 '∨' => '∨',
1733 '∩' => '∩',
1734 '∪' => '∪',
1735 '∫' => '∫',
1736 '∴' => '∴',
1737 '∼' => '∼',
1738 '≅' => '≅',
1739 '≈' => '≈',
1740 '≠' => '≠',
1741 '≡' => '≡',
1742 '≤' => '≤',
1743 '≥' => '≥',
1744 '⊂' => '⊂',
1745 '⊃' => '⊃',
1746 '⊄' => '⊄',
1747 '⊆' => '⊆',
1748 '⊇' => '⊇',
1749 '⊕' => '⊕',
1750 '⊗' => '⊗',
1751 '⊥' => '⊥',
1752 '⋅' => '⋅',
1753 '⌈' => '⌈',
1754 '⌉' => '⌉',
1755 '⌊' => '⌊',
1756 '⌋' => '⌋',
1757 '⟨' => '〈',
1758 '⟩' => '〉',
1759 '←' => '←',
1760 '↑' => '↑',
1761 '→' => '→',
1762 '↓' => '↓',
1763 '↔' => '↔',
1764 '◊' => '◊',
1765 '♠' => '♠',
1766 '♣' => '♣',
1767 '♥' => '♥',
1768 '♦' => '♦'
1771 return str_replace( array_keys($to_ncr), array_values($to_ncr), $text );
1775 * Formats text for the rich text editor.
1777 * The filter 'richedit_pre' is applied here. If $text is empty the filter will
1778 * be applied to an empty string.
1782 * @param string $text The text to be formatted.
1783 * @return string The formatted text after filter is applied.
1785 function wp_richedit_pre($text) {
1786 // Filtering a blank results in an annoying <br />\n
1787 if ( empty($text) ) return apply_filters('richedit_pre', '');
1789 $output = convert_chars($text);
1790 $output = wpautop($output);
1791 $output = htmlspecialchars($output, ENT_NOQUOTES);
1793 return apply_filters('richedit_pre', $output);
1797 * Formats text for the HTML editor.
1799 * Unless $output is empty it will pass through htmlspecialchars before the
1800 * 'htmledit_pre' filter is applied.
1804 * @param string $output The text to be formatted.
1805 * @return string Formatted text after filter applied.
1807 function wp_htmledit_pre($output) {
1808 if ( !empty($output) )
1809 $output = htmlspecialchars($output, ENT_NOQUOTES); // convert only < > &
1811 return apply_filters('htmledit_pre', $output);
1815 * Checks and cleans a URL.
1817 * A number of characters are removed from the URL. If the URL is for displaying
1818 * (the default behaviour) amperstands are also replaced. The 'clean_url' filter
1819 * is applied to the returned cleaned URL.
1822 * @uses wp_kses_bad_protocol() To only permit protocols in the URL set
1823 * via $protocols or the common ones set in the function.
1825 * @param string $url The URL to be cleaned.
1826 * @param array $protocols Optional. An array of acceptable protocols.
1827 * Defaults to 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet' if not set.
1828 * @param string $context Optional. How the URL will be used. Default is 'display'.
1829 * @return string The cleaned $url after the 'cleaned_url' filter is applied.
1831 function clean_url( $url, $protocols = null, $context = 'display' ) {
1832 $original_url = $url;
1834 if ('' == $url) return $url;
1835 $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$*\'()\\x80-\\xff]|i', '', $url);
1836 $strip = array('%0d', '%0a');
1837 $url = str_replace($strip, '', $url);
1838 $url = str_replace(';//', '://', $url);
1839 /* If the URL doesn't appear to contain a scheme, we
1840 * presume it needs http:// appended (unless a relative
1841 * link starting with / or a php file).
1843 if ( strpos($url, ':') === false &&
1844 substr( $url, 0, 1 ) != '/' && !preg_match('/^[a-z0-9-]+?\.php/i', $url) )
1845 $url = 'http://' . $url;
1847 // Replace ampersands and single quotes only when displaying.
1848 if ( 'display' == $context ) {
1849 $url = preg_replace('/&([^#])(?![a-z]{2,8};)/', '&$1', $url);
1850 $url = str_replace( "'", ''', $url );
1853 if ( !is_array($protocols) )
1854 $protocols = array('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet');
1855 if ( wp_kses_bad_protocol( $url, $protocols ) != $url )
1858 return apply_filters('clean_url', $url, $original_url, $context);
1862 * Performs clean_url() for database usage.
1868 * @param string $url The URL to be cleaned.
1869 * @param array $protocols An array of acceptable protocols.
1870 * @return string The cleaned URL.
1872 function sanitize_url( $url, $protocols = null ) {
1873 return clean_url( $url, $protocols, 'db' );
1877 * Convert entities, while preserving already-encoded entities.
1879 * @link http://www.php.net/htmlentities Borrowed from the PHP Manual user notes.
1883 * @param string $myHTML The text to be converted.
1884 * @return string Converted text.
1886 function htmlentities2($myHTML) {
1887 $translation_table = get_html_translation_table( HTML_ENTITIES, ENT_QUOTES );
1888 $translation_table[chr(38)] = '&';
1889 return preg_replace( "/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/", "&", strtr($myHTML, $translation_table) );
1893 * Escape single quotes, specialchar double quotes, and fix line endings.
1895 * The filter 'js_escape' is also applied here.
1899 * @param string $text The text to be escaped.
1900 * @return string Escaped text.
1902 function js_escape($text) {
1903 $safe_text = wp_check_invalid_utf8( $text );
1904 $safe_text = wp_specialchars( $safe_text, ENT_COMPAT );
1905 $safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) );
1906 $safe_text = preg_replace( "/\r?\n/", "\\n", addslashes( $safe_text ) );
1907 return apply_filters( 'js_escape', $safe_text, $text );
1911 * Escaping for HTML attributes.
1915 * @param string $text
1918 function attribute_escape( $text ) {
1919 $safe_text = wp_check_invalid_utf8( $text );
1920 $safe_text = wp_specialchars( $safe_text, ENT_QUOTES );
1921 return apply_filters( 'attribute_escape', $safe_text, $text );
1925 * Escape a HTML tag name.
1929 * @param string $tag_name
1932 function tag_escape($tag_name) {
1933 $safe_tag = strtolower( preg_replace('/[^a-zA-Z_:]/', '', $tag_name) );
1934 return apply_filters('tag_escape', $safe_tag, $tag_name);
1938 * Escapes text for SQL LIKE special characters % and _.
1942 * @param string $text The text to be escaped.
1943 * @return string text, safe for inclusion in LIKE query.
1945 function like_escape($text) {
1946 return str_replace(array("%", "_"), array("\\%", "\\_"), $text);
1950 * Convert full URL paths to absolute paths.
1952 * Removes the http or https protocols and the domain. Keeps the path '/' at the
1953 * beginning, so it isn't a true relative link, but from the web root base.
1957 * @param string $link Full URL path.
1958 * @return string Absolute path.
1960 function wp_make_link_relative( $link ) {
1961 return preg_replace( '|https?://[^/]+(/.*)|i', '$1', $link );
1965 * Sanitises various option values based on the nature of the option.
1967 * This is basically a switch statement which will pass $value through a number
1968 * of functions depending on the $option.
1972 * @param string $option The name of the option.
1973 * @param string $value The unsanitised value.
1974 * @return string Sanitized value.
1976 function sanitize_option($option, $value) {
1980 $value = sanitize_email($value);
1983 case 'thumbnail_size_w':
1984 case 'thumbnail_size_h':
1985 case 'medium_size_w':
1986 case 'medium_size_h':
1987 case 'large_size_w':
1988 case 'large_size_h':
1989 case 'default_post_edit_rows':
1990 case 'mailserver_port':
1991 case 'comment_max_links':
1992 case 'page_on_front':
1993 case 'rss_excerpt_length':
1994 case 'default_category':
1995 case 'default_email_category':
1996 case 'default_link_category':
1997 case 'close_comments_days_old':
1998 case 'comments_per_page':
1999 case 'thread_comments_depth':
2000 $value = abs((int) $value);
2003 case 'posts_per_page':
2004 case 'posts_per_rss':
2005 $value = (int) $value;
2006 if ( empty($value) ) $value = 1;
2007 if ( $value < -1 ) $value = abs($value);
2010 case 'default_ping_status':
2011 case 'default_comment_status':
2012 // Options that if not there have 0 value but need to be something like "closed"
2013 if ( $value == '0' || $value == '')
2017 case 'blogdescription':
2019 $value = addslashes($value);
2020 $value = wp_filter_post_kses( $value ); // calls stripslashes then addslashes
2021 $value = stripslashes($value);
2022 $value = wp_specialchars( $value );
2025 case 'blog_charset':
2026 $value = preg_replace('/[^a-zA-Z0-9_-]/', '', $value); // strips slashes
2031 case 'mailserver_url':
2032 case 'mailserver_login':
2033 case 'mailserver_pass':
2036 $value = strip_tags($value);
2037 $value = addslashes($value);
2038 $value = wp_filter_kses($value); // calls stripslashes then addslashes
2039 $value = stripslashes($value);
2043 $value = preg_replace('/[^0-9:.-]/', '', $value); // strips slashes
2048 $value = stripslashes($value);
2049 $value = clean_url($value);
2052 $value = apply_filters("sanitize_option_{$option}", $value, $option);
2060 * Parses a string into variables to be stored in an array.
2062 * Uses {@link http://www.php.net/parse_str parse_str()} and stripslashes if
2063 * {@link http://www.php.net/magic_quotes magic_quotes_gpc} is on.
2066 * @uses apply_filters() for the 'wp_parse_str' filter.
2068 * @param string $string The string to be parsed.
2069 * @param array $array Variables will be stored in this array.
2071 function wp_parse_str( $string, &$array ) {
2072 parse_str( $string, $array );
2073 if ( get_magic_quotes_gpc() )
2074 $array = stripslashes_deep( $array );
2075 $array = apply_filters( 'wp_parse_str', $array );
2079 * Convert lone less than signs.
2081 * KSES already converts lone greater than signs.
2083 * @uses wp_pre_kses_less_than_callback in the callback function.
2086 * @param string $text Text to be converted.
2087 * @return string Converted text.
2089 function wp_pre_kses_less_than( $text ) {
2090 return preg_replace_callback('%<[^>]*?((?=<)|>|$)%', 'wp_pre_kses_less_than_callback', $text);
2094 * Callback function used by preg_replace.
2096 * @uses wp_specialchars to format the $matches text.
2099 * @param array $matches Populated by matches to preg_replace.
2100 * @return string The text returned after wp_specialchars if needed.
2102 function wp_pre_kses_less_than_callback( $matches ) {
2103 if ( false === strpos($matches[0], '>') )
2104 return wp_specialchars($matches[0]);
2109 * WordPress implementation of PHP sprintf() with filters.
2112 * @link http://www.php.net/sprintf
2114 * @param string $pattern The string which formatted args are inserted.
2115 * @param mixed $args,... Arguments to be formatted into the $pattern string.
2116 * @return string The formatted string.
2118 function wp_sprintf( $pattern ) {
2119 $args = func_get_args( );
2120 $len = strlen($pattern);
2124 while ( $len > $start ) {
2125 // Last character: append and break
2126 if ( strlen($pattern) - 1 == $start ) {
2127 $result .= substr($pattern, -1);
2131 // Literal %: append and continue
2132 if ( substr($pattern, $start, 2) == '%%' ) {
2138 // Get fragment before next %
2139 $end = strpos($pattern, '%', $start + 1);
2140 if ( false === $end )
2142 $fragment = substr($pattern, $start, $end - $start);
2144 // Fragment has a specifier
2145 if ( $pattern{$start} == '%' ) {
2146 // Find numbered arguments or take the next one in order
2147 if ( preg_match('/^%(\d+)\$/', $fragment, $matches) ) {
2148 $arg = isset($args[$matches[1]]) ? $args[$matches[1]] : '';
2149 $fragment = str_replace("%{$matches[1]}$", '%', $fragment);
2152 $arg = isset($args[$arg_index]) ? $args[$arg_index] : '';
2155 // Apply filters OR sprintf
2156 $_fragment = apply_filters( 'wp_sprintf', $fragment, $arg );
2157 if ( $_fragment != $fragment )
2158 $fragment = $_fragment;
2160 $fragment = sprintf($fragment, strval($arg) );
2163 // Append to result and move to next fragment
2164 $result .= $fragment;
2171 * Localize list items before the rest of the content.
2173 * The '%l' must be at the first characters can then contain the rest of the
2174 * content. The list items will have ', ', ', and', and ' and ' added depending
2175 * on the amount of list items in the $args parameter.
2179 * @param string $pattern Content containing '%l' at the beginning.
2180 * @param array $args List items to prepend to the content and replace '%l'.
2181 * @return string Localized list items and rest of the content.
2183 function wp_sprintf_l($pattern, $args) {
2185 if ( substr($pattern, 0, 2) != '%l' )
2188 // Nothing to work with
2192 // Translate and filter the delimiter set (avoid ampersands and entities here)
2193 $l = apply_filters('wp_sprintf_l', array(
2194 'between' => _c(', |between list items'),
2195 'between_last_two' => _c(', and |between last two list items'),
2196 'between_only_two' => _c(' and |between only two list items'),
2199 $args = (array) $args;
2200 $result = array_shift($args);
2201 if ( count($args) == 1 )
2202 $result .= $l['between_only_two'] . array_shift($args);
2203 // Loop when more than two args
2206 $arg = array_shift($args);
2209 $result .= $l['between_last_two'] . $arg;
2211 $result .= $l['between'] . $arg;
2213 return $result . substr($pattern, 2);
2217 * Safely extracts not more than the first $count characters from html string.
2219 * UTF-8, tags and entities safe prefix extraction. Entities inside will *NOT*
2220 * be counted as one character. For example & will be counted as 4, < as
2225 * @param integer $str String to get the excerpt from.
2226 * @param integer $count Maximum number of characters to take.
2227 * @return string The excerpt.
2229 function wp_html_excerpt( $str, $count ) {
2230 $str = strip_tags( $str );
2231 $str = mb_strcut( $str, 0, $count );
2232 // remove part of an entity at the end
2233 $str = preg_replace( '/&[^;\s]{0,6}$/', '', $str );
2238 * Add a Base url to relative links in passed content.
2240 * By default it supports the 'src' and 'href' attributes. However this can be
2241 * changed via the 3rd param.
2245 * @param string $content String to search for links in.
2246 * @param string $base The base URL to prefix to links.
2247 * @param array $attrs The attributes which should be processed.
2248 * @return string The processed content.
2250 function links_add_base_url( $content, $base, $attrs = array('src', 'href') ) {
2251 $attrs = implode('|', (array)$attrs);
2252 return preg_replace_callback("!($attrs)=(['\"])(.+?)\\2!i",
2253 create_function('$m', 'return _links_add_base($m, "' . $base . '");'),
2258 * Callback to add a base url to relative links in passed content.
2263 * @param string $m The matched link.
2264 * @param string $base The base URL to prefix to links.
2265 * @return string The processed link.
2267 function _links_add_base($m, $base) {
2268 //1 = attribute name 2 = quotation mark 3 = URL
2269 return $m[1] . '=' . $m[2] .
2270 (strpos($m[3], 'http://') === false ?
2271 path_join($base, $m[3]) :
2277 * Adds a Target attribute to all links in passed content.
2279 * This function by default only applies to <a> tags, however this can be
2280 * modified by the 3rd param.
2282 * <b>NOTE:</b> Any current target attributed will be striped and replaced.
2286 * @param string $content String to search for links in.
2287 * @param string $target The Target to add to the links.
2288 * @param array $tags An array of tags to apply to.
2289 * @return string The processed content.
2291 function links_add_target( $content, $target = '_blank', $tags = array('a') ) {
2292 $tags = implode('|', (array)$tags);
2293 return preg_replace_callback("!<($tags)(.+?)>!i",
2294 create_function('$m', 'return _links_add_target($m, "' . $target . '");'),
2298 * Callback to add a target attribute to all links in passed content.
2303 * @param string $m The matched link.
2304 * @param string $target The Target to add to the links.
2305 * @return string The processed link.
2307 function _links_add_target( $m, $target ) {
2309 $link = preg_replace('|(target=[\'"](.*?)[\'"])|i', '', $m[2]);
2310 return '<' . $tag . $link . ' target="' . $target . '">';
2313 // normalize EOL characters and strip duplicate whitespace
2314 function normalize_whitespace( $str ) {
2316 $str = str_replace("\r", "\n", $str);
2317 $str = preg_replace( array( '/\n+/', '/[ \t]+/' ), array( "\n", ' ' ), $str );