Ticket #35022: 35022.6.patch
File 35022.6.patch, 13.0 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 ); … … 702 700 */ 703 701 function _get_wptexturize_shortcode_regex( $tagnames ) { 704 702 $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) ); 705 $tagregexp = "(?:$tagregexp)(?= [\\s\\]\\/])"; // Excerpt of get_shortcode_regex().703 $tagregexp = "(?:$tagregexp)(?=" . shortcode_name_terminators() . ")"; // Excerpt of get_shortcode_regex(). 706 704 $regex = 707 705 '\[' // Find start of shortcode. 708 706 . '[\/\[]?' // Shortcodes may begin with [/ or [[ … … 788 786 * 789 787 * @since 2.9.0 790 788 * 791 * @global array $shortcode_tags792 *793 789 * @param string $pee The content. 794 790 * @return string The filtered content. 795 791 */ 796 792 function shortcode_unautop( $pee ) { 797 global $shortcode_tags;798 793 799 if ( empty( $shortcode_tags ) || !is_array( $shortcode_tags ) ) { 794 $tagnames = get_shortcode_tagnames( $pee ); 795 if ( empty( $tagnames ) ) { 800 796 return $pee; 801 797 } 802 798 803 $tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags )) );799 $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) ); 804 800 $spaces = wp_spaces_regexp(); 805 801 806 802 $pattern = … … 810 806 . '(' // 1: The shortcode 811 807 . '\\[' // Opening bracket 812 808 . "($tagregexp)" // 2: Shortcode name 813 . '(? ![\\w-])' // Not followed by word character or hyphen809 . '(?=' . shortcode_name_terminators() . ')' // Followed by a shortcode name terminator. 814 810 // Unroll the loop: Inside the opening shortcode tag 815 811 . '[^\\]\\/]*' // Not a closing bracket or forward slash 816 812 . '(?:' -
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; … … 246 233 * @since 2.5.0 247 234 * @since 4.4.0 Added the `$tagnames` parameter. 248 235 * 249 * @global array $shortcode_tags250 *251 236 * @param array $tagnames Optional. List of shortcodes to find. Defaults to all registered shortcodes. 252 237 * @return string The shortcode search regular expression 253 238 */ 254 239 function get_shortcode_regex( $tagnames = null ) { 255 global $shortcode_tags;256 240 257 241 if ( empty( $tagnames ) ) { 258 $tagnames = array_keys( $shortcode_tags);242 $tagnames = get_shortcode_tagnames(); 259 243 } 260 244 $tagregexp = join( '|', array_map('preg_quote', $tagnames) ); 261 245 … … 265 249 '\\[' // Opening bracket 266 250 . '(\\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]] 267 251 . "($tagregexp)" // 2: Shortcode name 268 . '(? ![\\w-])' // Not followed by word character or hyphen252 . '(?=' . shortcode_name_terminators() . ')' // Followed by a shortcode name terminator. 269 253 . '(' // 3: Unroll the loop: Inside the opening shortcode tag 270 254 . '[^\\]\\/]*' // Not a closing bracket or forward slash 271 255 . '(?:' … … 293 277 } 294 278 295 279 /** 280 * Return regular expression of characters that terminate the name of a shortcode. 281 * Dependent on charset of blog. 282 * 283 * @since x.x.x 284 * 285 * @return string Regular expression of terminating characters. 286 */ 287 function shortcode_name_terminators() { 288 // Needs to be synced with get_shortcode_tagnames() expression below. 289 if ( 'UTF-8' === _canonical_charset( get_option( 'blog_charset' ) ) ) { 290 return '(?:[<>&\/\[\]\x00-\x20=]|\xc2\xa0)'; 291 } 292 return '[<>&\/\[\]\x00-\x20=]'; 293 } 294 295 /** 296 * Return registered shortcode tagnames, reduced to those in $text if given. 297 * 298 * @since x.x.x 299 * 300 * @global array $shortcode_tags 301 * 302 * @param string $text Optional. If given, only those registered shortcodes that appear in $text are returned. 303 * @return array Array of shortcode names. 304 */ 305 function get_shortcode_tagnames( $text = null ) { 306 global $shortcode_tags; 307 308 if ( ! $shortcode_tags || ! is_array( $shortcode_tags ) ) { 309 return array(); 310 } 311 if ( null === $text ) { 312 return array_keys( $shortcode_tags ); 313 } 314 if ( false === strpos( $text, '[' ) ) { 315 return array(); 316 } 317 318 // 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. 319 if ( ! preg_match_all( '/\[(?!\[)\/?\K[^<>&\/\[\]\x00-\x20=]+/', $text, $matches ) ) { // Needs to be synced with shortcode_name_terminators() expression above. 320 return array(); 321 } 322 if ( false !== strpos( $text, "\xc2\xa0" ) && 'UTF-8' === _canonical_charset( get_option( 'blog_charset' ) ) ) { 323 $matches[0] = array_map( '_shortcode_name_terminator_chop_cb', $matches[0] ); 324 } 325 326 return array_values( array_intersect( array_keys( $shortcode_tags ), $matches[0] ) ); 327 } 328 329 /** 330 * Callback for array_map in {@see get_shortcode_tagnames()} to chop off UTF-8 no-break space from potential shortcode name. 331 * 332 * @since x.x.x 333 * @access private 334 * 335 * @param string $entry The potential shortcode name match. 336 * @return string The potential shortcode name chopped down if necessary. 337 */ 338 function _shortcode_name_terminator_chop_cb( $entry ) { 339 if ( false !== ( $pos = strpos( $entry, "\xc2\xa0" ) ) ) { 340 $entry = substr( $entry, 0, $pos ); 341 } 342 return $entry; 343 } 344 345 /** 296 346 * Regular Expression callable for do_shortcode() for calling shortcode hook. 297 347 * @see get_shortcode_regex for details of the match array contents. 298 348 * … … 589 639 * 590 640 * @since 2.5.0 591 641 * 592 * @global array $shortcode_tags593 *594 642 * @param string $content Content to remove shortcode tags. 595 643 * @return string Content without shortcode tags. 596 644 */ 597 645 function strip_shortcodes( $content ) { 598 global $shortcode_tags;599 646 600 if ( false === strpos( $content, '[' ) ) {601 return $content;602 }603 604 if (empty($shortcode_tags) || !is_array($shortcode_tags))605 return $content;606 607 647 // Find all registered tag names in $content. 608 preg_match_all( '@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches);648 $tagnames = get_shortcode_tagnames( $content ); 609 649 610 $tags_to_remove = array_keys( $shortcode_tags );611 612 650 /** 613 651 * Filters the list of shortcode tags to remove from the content. 614 652 * 615 653 * @since 4.7.0 616 654 * 617 * @param array $tag _arrayArray of shortcode tags to remove.655 * @param array $tagnames Array of shortcode tags to remove. 618 656 * @param string $content Content shortcodes are being removed from. 619 657 */ 620 $tag s_to_remove = apply_filters( 'strip_shortcodes_tagnames', $tags_to_remove, $content );658 $tagnames = apply_filters( 'strip_shortcodes_tagnames', $tagnames, $content ); 621 659 622 $tagnames = array_intersect( $tags_to_remove, $matches[1] );623 624 660 if ( empty( $tagnames ) ) { 625 661 return $content; 626 662 } -
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() { … … 638 683 '', 639 684 false, 640 685 ), 686 array( 687 "bad\xc2\xa0space", 688 false, 689 ), 641 690 ); 642 691 } 643 692 … … 655 704 'unreserved!#$%()*+,-.;?@^_{|}~chars', 656 705 true, 657 706 ), 707 array( 708 "unreservedutf8\xc2\xa1\xe0\xa0\x80\xf0\xa0\x80\x80\xc2\xa2chars", 709 true, 710 ), 658 711 ); 659 712 } 660 713 -
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