Ticket #35022: 35022.4.patch
File 35022.4.patch, 12.4 KB (added by , 8 years ago) |
---|
-
src/wp-includes/formatting.php
25 25 * @since 0.71 26 26 * 27 27 * @global array $wp_cockneyreplace Array of formatted entities for certain common phrases 28 * @global array $shortcode_tags29 28 * @staticvar array $static_characters 30 29 * @staticvar array $static_replacements 31 30 * @staticvar array $dynamic_characters … … 39 38 * @return string The string replaced with html entities 40 39 */ 41 40 function wptexturize( $text, $reset = false ) { 42 global $wp_cockneyreplace , $shortcode_tags;41 global $wp_cockneyreplace; 43 42 static $static_characters = null, 44 43 $static_replacements = null, 45 44 $dynamic_characters = null, … … 216 215 217 216 // Look for shortcodes and HTML elements. 218 217 219 preg_match_all( '@\[/?([^<>&/\[\]\x00-\x20=]++)@', $text, $matches ); 220 $tagnames = array_intersect( array_keys( $shortcode_tags ), $matches[1] ); 218 $tagnames = get_shortcode_tagnames( $text ); 221 219 $found_shortcodes = ! empty( $tagnames ); 222 220 $shortcode_regex = $found_shortcodes ? _get_wptexturize_shortcode_regex( $tagnames ) : ''; 223 221 $regex = _get_wptexturize_split_regex( $shortcode_regex ); … … 696 694 */ 697 695 function _get_wptexturize_shortcode_regex( $tagnames ) { 698 696 $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) ); 699 $tagregexp = "(?:$tagregexp)(?= [\\s\\]\\/])"; // Excerpt of get_shortcode_regex().697 $tagregexp = "(?:$tagregexp)(?=" . shortcode_name_terminators() . ")"; // Excerpt of get_shortcode_regex(). 700 698 $regex = 701 699 '\[' // Find start of shortcode. 702 700 . '[\/\[]?' // Shortcodes may begin with [/ or [[ … … 782 780 * 783 781 * @since 2.9.0 784 782 * 785 * @global array $shortcode_tags786 *787 783 * @param string $pee The content. 788 784 * @return string The filtered content. 789 785 */ 790 786 function shortcode_unautop( $pee ) { 791 global $shortcode_tags;792 787 793 if ( empty( $shortcode_tags ) || !is_array( $shortcode_tags ) ) { 788 $tagnames = get_shortcode_tagnames( $pee ); 789 if ( empty( $tagnames ) ) { 794 790 return $pee; 795 791 } 796 792 797 $tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags )) );793 $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) ); 798 794 $spaces = wp_spaces_regexp(); 799 795 800 796 $pattern = … … 804 800 . '(' // 1: The shortcode 805 801 . '\\[' // Opening bracket 806 802 . "($tagregexp)" // 2: Shortcode name 807 . '(? ![\\w-])' // Not followed by word character or hyphen803 . '(?=' . shortcode_name_terminators() . ')' // Followed by a shortcode name terminator. 808 804 // Unroll the loop: Inside the opening shortcode tag 809 805 . '[^\\]\\/]*' // Not a closing bracket or forward slash 810 806 . '(?:' -
src/wp-includes/js/shortcode.js
102 102 // 6. The closing tag. 103 103 // 7. An extra `]` to allow for escaping shortcodes with double `[[]]` 104 104 regexp: _.memoize( function( tag ) { 105 return new RegExp( '\\[(\\[?)(' + tag + ')(?![\\w-])([^\\]\\/]*(?:\\/(?!\\])[^\\]\\/]*)*?)(?:(\\/)\\]|\\](?:([^\\[]*(?:\\[(?!\\/\\2\\])[^\\[]*)*)(\\[\\/\\2\\]))?)(\\]?)', 'g' ); 105 var shortcode_name_terminators = '[<>&\\/\\[\\]\x00-\x20=\u00a0]'; 106 return new RegExp( '\\[(\\[?)(' + tag + ')(?=' + shortcode_name_terminators + ')([^\\]\\/]*(?:\\/(?!\\])[^\\]\\/]*)*?)(?:(\\/)\\]|\\](?:([^\\[]*(?:\\[(?!\\/\\2\\])[^\\[]*)*)(\\[\\/\\2\\]))?)(\\]?)', 'g' ); 106 107 }), 107 108 108 109 -
src/wp-includes/shortcodes.php
95 95 return; 96 96 } 97 97 98 if ( 0 !== preg_match( '@ [<>&/\[\]\x00-\x20=]@', $tag ) ) {98 if ( 0 !== preg_match( '@' . shortcode_name_terminators() . '@', $tag ) ) { 99 99 /* translators: 1: shortcode name, 2: space separated list of reserved characters */ 100 100 $message = sprintf( __( 'Invalid shortcode name: %1$s. Do not use spaces or reserved characters: %2$s' ), $tag, '& / < > [ ] =' ); 101 101 _doing_it_wrong( __FUNCTION__, $message, '4.4.0' ); … … 157 157 * 158 158 * @since 3.6.0 159 159 * 160 * @global array $shortcode_tags161 *162 160 * @param string $content Content to search for shortcodes. 163 161 * @param string $tag Shortcode tag to check. 164 162 * @return bool Whether the passed content contains the given shortcode. … … 193 191 * 194 192 * @since 2.5.0 195 193 * 196 * @global array $shortcode_tags List of shortcode tags and their callback hooks.197 *198 194 * @param string $content Content to search for shortcodes. 199 195 * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped. 200 196 * @return string Content with shortcodes filtered out. 201 197 */ 202 198 function do_shortcode( $content, $ignore_html = false ) { 203 global $shortcode_tags;204 199 205 if ( false === strpos( $content, '[' ) ) {206 return $content;207 }208 209 if (empty($shortcode_tags) || !is_array($shortcode_tags))210 return $content;211 212 200 // Find all registered tag names in $content. 213 preg_match_all( '@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches ); 214 $tagnames = array_intersect( array_keys( $shortcode_tags ), $matches[1] ); 201 $tagnames = get_shortcode_tagnames( $content ); 215 202 216 203 if ( empty( $tagnames ) ) { 217 204 return $content; … … 245 232 * 246 233 * @since 2.5.0 247 234 * 248 * @global array $shortcode_tags249 *250 235 * @param array $tagnames List of shortcodes to find. Optional. Defaults to all registered shortcodes. 251 236 * @return string The shortcode search regular expression 252 237 */ 253 238 function get_shortcode_regex( $tagnames = null ) { 254 global $shortcode_tags;255 239 256 240 if ( empty( $tagnames ) ) { 257 $tagnames = array_keys( $shortcode_tags);241 $tagnames = get_shortcode_tagnames(); 258 242 } 259 243 $tagregexp = join( '|', array_map('preg_quote', $tagnames) ); 260 244 … … 264 248 '\\[' // Opening bracket 265 249 . '(\\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]] 266 250 . "($tagregexp)" // 2: Shortcode name 267 . '(? ![\\w-])' // Not followed by word character or hyphen251 . '(?=' . shortcode_name_terminators() . ')' // Followed by a shortcode name terminator. 268 252 . '(' // 3: Unroll the loop: Inside the opening shortcode tag 269 253 . '[^\\]\\/]*' // Not a closing bracket or forward slash 270 254 . '(?:' … … 292 276 } 293 277 294 278 /** 279 * Return regular expression of characters that terminate the name of a shortcode. 280 * Dependent on charset of blog. 281 * 282 * @since 4.7.0 283 * 284 * @return string Regular expression of terminating characters. 285 */ 286 function shortcode_name_terminators() { 287 // Needs to be synced with get_shortcode_tagnames() expression below. 288 if ( 'UTF-8' === _canonical_charset( get_option( 'blog_charset' ) ) ) { 289 return '(?:[<>&\/\[\]\x00-\x20=]|\xc2\xa0)'; 290 } 291 return '[<>&\/\[\]\x00-\x20=]'; 292 } 293 294 /** 295 * Return registered shortcode tagnames, reduced to those in $text if given. 296 * 297 * @since 4.7.0 298 * 299 * @global array $shortcode_tags 300 * 301 * @param string $text Optional. If given, only those registered shortcodes that appear in $text are returned. 302 * @return array Array of shortcode names. 303 */ 304 function get_shortcode_tagnames( $text = null ) { 305 global $shortcode_tags; 306 307 if ( ! $shortcode_tags || ! is_array( $shortcode_tags ) ) { 308 return array(); 309 } 310 if ( null === $text ) { 311 return array_keys( $shortcode_tags ); 312 } 313 if ( false === strpos( $text, '[' ) ) { 314 return array(); 315 } 316 317 // Grouped expressions with unlimited repetition cause seg faults or match failures in PCRE <= 8.12 so use simple character class first and then post-process the matches. 318 if ( ! preg_match_all( '/\[(?!\[)\/?\K[^<>&\/\[\]\x00-\x20=]+/', $text, $matches ) ) { // Needs to be synced with shortcode_name_terminators() expression above. 319 return array(); 320 } 321 if ( false !== strpos( $text, "\xc2\xa0" ) && 'UTF-8' === _canonical_charset( get_option( 'blog_charset' ) ) ) { 322 $matches[0] = array_map( '_shortcode_name_terminator_chop_cb', $matches[0] ); 323 } 324 325 return array_values( array_intersect( array_keys( $shortcode_tags ), $matches[0] ) ); 326 } 327 328 /** 329 * Callback for array_map in {@see get_shortcode_tagnames()} to chop off UTF-8 no-break space from potential shortcode name. 330 * 331 * @since 4.7.0 332 * @access private 333 * 334 * @param string $entry The potential shortcode name match. 335 * @return string The potential shortcode name chopped down if necessary. 336 */ 337 function _shortcode_name_terminator_chop_cb( $entry ) { 338 if ( false !== ( $pos = strpos( $entry, "\xc2\xa0" ) ) ) { 339 $entry = substr( $entry, 0, $pos ); 340 } 341 return $entry; 342 } 343 344 /** 295 345 * Regular Expression callable for do_shortcode() for calling shortcode hook. 296 346 * @see get_shortcode_regex for details of the match array contents. 297 347 * … … 580 630 * 581 631 * @since 2.5.0 582 632 * 583 * @global array $shortcode_tags584 *585 633 * @param string $content Content to remove shortcode tags. 586 634 * @return string Content without shortcode tags. 587 635 */ 588 636 function strip_shortcodes( $content ) { 589 global $shortcode_tags;590 637 591 if ( false === strpos( $content, '[' ) ) {592 return $content;593 }594 595 if (empty($shortcode_tags) || !is_array($shortcode_tags))596 return $content;597 598 638 // Find all registered tag names in $content. 599 preg_match_all( '@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches ); 600 $tagnames = array_intersect( array_keys( $shortcode_tags ), $matches[1] ); 639 $tagnames = get_shortcode_tagnames( $content ); 601 640 602 641 if ( empty( $tagnames ) ) { 603 642 return $content; -
tests/phpunit/tests/shortcode.php
332 332 } 333 333 334 334 /** 335 * @ticket 35022 336 */ 337 function test_no_break_space_following_shortcode_tag() { 338 do_shortcode( "[test-shortcode-tag\xC2\xA0foo=\"bar\"]" ); 339 $this->assertSame( 'test-shortcode-tag', $this->tagname ); 340 $this->assertSame( array( 'foo' => 'bar' ), $this->atts ); 341 } 342 343 /** 344 * @ticket 35022 345 */ 346 function test_non_no_break_space_following_shortcode_tag() { 347 do_shortcode( "[test-shortcode-tag\xC2\xA1foo=\"bar\"]" ); 348 $this->assertNull( $this->tagname ); 349 $this->assertNull( $this->atts ); 350 } 351 352 function _charset_iso_8859_1() { 353 return 'iso-8859-1'; 354 } 355 356 /** 357 * @ticket 35022 358 */ 359 function test_no_break_space_following_shortcode_tag_iso_8859_1() { 360 add_filter( 'pre_option_blog_charset', array( $this, '_charset_iso_8859_1' ) ); 361 362 do_shortcode( "[test-shortcode-tag foo=\"bar\"]" ); 363 $this->assertSame( 'test-shortcode-tag', $this->tagname ); 364 $this->assertSame( array( 'foo' => 'bar' ), $this->atts ); 365 366 $this->atts = $this->content = $this->tagname = null; 367 do_shortcode( "[test-shortcode-tag\xA0foo=\"bar\"]" ); // ISO-8859-1 no-break space not supported currently. 368 $this->assertNull( $this->tagname ); 369 $this->assertNull( $this->atts ); 370 371 $this->atts = $this->content = $this->tagname = null; 372 do_shortcode( "[test-shortcode-tag\xC2\xA0foo=\"bar\"]" ); 373 $this->assertNull( $this->tagname ); 374 $this->assertNull( $this->atts ); 375 376 remove_filter( 'pre_option_blog_charset', array( $this, '_charset_iso_8859_1' ) ); 377 } 378 379 /** 335 380 * @ticket 14050 336 381 */ 337 382 function test_shortcode_unautop() { … … 608 653 '', 609 654 false, 610 655 ), 656 array( 657 "bad\xc2\xa0space", 658 false, 659 ), 611 660 ); 612 661 } 613 662 … … 625 674 'unreserved!#$%()*+,-.;?@^_{|}~chars', 626 675 true, 627 676 ), 677 array( 678 "unreservedutf8\xc2\xa1\xe0\xa0\x80\xf0\xa0\x80\x80\xc2\xa2chars", 679 true, 680 ), 628 681 ); 629 682 } 630 683 -
tests/qunit/wp-includes/js/shortcode.js
96 96 equal( result, undefined, 'stub does not trigger match' ); 97 97 }); 98 98 99 test( 'next() should find the shortcode delimited by no-break space (U+00A0)', function() { 100 var result; 101 102 103 result = wp.shortcode.next( 'foo', 'this has a no-break space delimited [foo\u00a0param="foo"] shortcode' ); 104 equal( result.index, 36, 'no-break space delimited foo shortcode found at index 36' ); 105 }); 106 99 107 test( 'replace() should replace the shortcode', function() { 100 108 var result; 101 109