WordPress.org

Make WordPress Core

Ticket #22692: miqro-22692.9.patch

File miqro-22692.9.patch, 10.3 KB (added by miqrogroove, 7 years ago)

Src and tests merge, take 2.

  • src/wp-includes/formatting.php

     
    7373                $static_characters = array_merge( array( '---', ' -- ', '--', ' - ', 'xn–', '...', '``', '\'\'', ' (tm)' ), $cockney );
    7474                $static_replacements = array_merge( array( $em_dash, ' ' . $em_dash . ' ', $en_dash, ' ' . $en_dash . ' ', 'xn--', '…', $opening_quote, $closing_quote, ' ™' ), $cockneyreplace );
    7575
     76                // Pattern-based replacements of characters.
    7677                $dynamic = array();
    77                 if ( "'" != $apos ) {
    78                         $dynamic[ '/\'(\d\d(?:’|\')?s)/' ] = $apos . '$1'; // '99's
    79                         $dynamic[ '/\'(\d)/'                   ] = $apos . '$1'; // '99
    80                 }
     78                $spaces = wp_spaces_regexp();
     79
     80                // '99s (apostrophe)
     81                if ( "'" != $apos )
     82                        $dynamic[ '/\'(?=\d)/' ] = $apos;
     83
     84                // Single quote at start, or preceded by (, {, <, [, ", or spaces.
    8185                if ( "'" != $opening_single_quote )
    82                         $dynamic[ '/(\s|\A|[([{<]|")\'/'       ] = '$1' . $opening_single_quote; // opening single quote, even after (, {, <, [
     86                        $dynamic[ '/(?<=\A|[([{<"]|' . $spaces . ')\'/' ] = $opening_single_quote;
     87
     88                // 9" (double prime)
    8389                if ( '"' != $double_prime )
    84                         $dynamic[ '/(\d)"/'                    ] = '$1' . $double_prime; // 9" (double prime)
     90                        $dynamic[ '/(?<=\d)"/' ] = $double_prime;
     91
     92                // 9' (prime)
    8593                if ( "'" != $prime )
    86                         $dynamic[ '/(\d)\'/'                   ] = '$1' . $prime; // 9' (prime)
     94                        $dynamic[ '/(?<=\d)\'/' ] = $prime;
     95
     96                // Apostrophe in a word.  No spaces or double primes.
    8797                if ( "'" != $apos )
    88                         $dynamic[ '/(\S)\'([^\'\s])/'          ] = '$1' . $apos . '$2'; // apostrophe in a word
     98                        $dynamic[ '/(?<!' . $spaces . ')\'(?!\'|' . $spaces . ')/' ] = $apos;
     99
     100                // Double quote at start, or preceded by (, {, <, [, or spaces, and not followed by spaces.
    89101                if ( '"' != $opening_quote )
    90                         $dynamic[ '/(\s|\A|[([{<])"(?!\s)/'    ] = '$1' . $opening_quote . '$2'; // opening double quote, even after (, {, <, [
     102                        $dynamic[ '/(?<=\A|[([{<]|' . $spaces . ')"(?!' . $spaces . ')/' ] = $opening_quote;
     103
     104                // Any remaining double quotes.
    91105                if ( '"' != $closing_quote )
    92                         $dynamic[ '/"(\s|\S|\Z)/'              ] = $closing_quote . '$1'; // closing double quote
     106                        $dynamic[ '/"/' ] = $closing_quote;
     107
     108                // Single quotes followed by spaces or a period.
    93109                if ( "'" != $closing_single_quote )
    94                         $dynamic[ '/\'([\s.]|\Z)/'             ] = $closing_single_quote . '$1'; // closing single quote
     110                        $dynamic[ '/\'(?=\Z|\.|' . $spaces . ')/' ] = $closing_single_quote;
    95111
    96                 $dynamic[ '/\b(\d+)x(\d+)\b/'              ] = '$1&#215;$2'; // 9x9 (times)
     112                // 9x9 (times)
     113                $dynamic[ '/\b(\d+)x(\d+)\b/' ] = '$1&#215;$2';
    97114
    98115                $dynamic_characters = array_keys( $dynamic );
    99116                $dynamic_replacements = array_values( $dynamic );
     
    318335        }
    319336
    320337        $tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags ) ) );
     338        $spaces = wp_spaces_regexp();
    321339
    322340        $pattern =
    323341                  '/'
    324342                . '<p>'                              // Opening paragraph
    325                 . '\\s*+'                            // Optional leading whitespace
     343                . '(?:' . $spaces . ')*+'            // Optional leading whitespace
    326344                . '('                                // 1: The shortcode
    327345                .     '\\['                          // Opening bracket
    328346                .     "($tagregexp)"                 // 2: Shortcode name
     
    347365                .         ')?'
    348366                .     ')'
    349367                . ')'
    350                 . '\\s*+'                            // optional trailing whitespace
     368                . '(?:' . $spaces . ')*+'            // optional trailing whitespace
    351369                . '<\\/p>'                           // closing paragraph
    352370                . '/s';
    353371
     
    18651883         */
    18661884        $src_url = apply_filters( 'smilies_src', includes_url( "images/smilies/$img" ), $img, site_url() );
    18671885
    1868         return sprintf( ' <img src="%s" alt="%s" class="wp-smiley" /> ', esc_url( $src_url ), esc_attr( $smiley ) );
     1886        return sprintf( '<img src="%s" alt="%s" class="wp-smiley" />', esc_url( $src_url ), esc_attr( $smiley ) );
    18691887}
    18701888
    18711889/**
     
    37813799
    37823800        return false;
    37833801}
     3802
     3803/**
     3804 * Returns the regexp for common whitespace characters.
     3805 *
     3806 * By default, spaces include new lines, tabs, nbsp entities, and the UTF-8 nbsp.
     3807 * This is designed to replace the PCRE \s sequence.  In ticket #22692, that
     3808 * sequence was found to be unreliable due to random inclusion of the A0 byte.
     3809 *
     3810 * @since 3.9.0
     3811 *
     3812 * @return string The spaces regexp.
     3813 */
     3814function wp_spaces_regexp() {
     3815        static $spaces;
     3816
     3817        if (empty($spaces)) {
     3818                $spaces = apply_filters( 'wp_spaces_regexp', '[\r\n\t ]|\xC2\xA0|&nbsp;' );
     3819        }
     3820
     3821        return $spaces;
     3822}
  • src/wp-includes/functions.php

     
    25602560         */
    25612561        krsort($wpsmiliestrans);
    25622562
    2563         $wp_smiliessearch = '/((?:\s|^)';
     2563        $spaces = wp_spaces_regexp();
    25642564
     2565        // Begin first "subpattern"
     2566        $wp_smiliessearch = '/(?<=' . $spaces . '|^)';
     2567
    25652568        $subchar = '';
    25662569        foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
    25672570                $firstchar = substr($smiley, 0, 1);
     
    25702573                // new subpattern?
    25712574                if ($firstchar != $subchar) {
    25722575                        if ($subchar != '') {
    2573                                 $wp_smiliessearch .= ')(?=\s|$))|((?:\s|^)'; ;
     2576                                $wp_smiliessearch .= ')(?=' . $spaces . '|$)';  // End previous "subpattern"
     2577                                $wp_smiliessearch .= '|(?<=' . $spaces . '|^)'; // Begin another "subpattern"
    25742578                        }
    25752579                        $subchar = $firstchar;
    25762580                        $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
     
    25802584                $wp_smiliessearch .= preg_quote($rest, '/');
    25812585        }
    25822586
    2583         $wp_smiliessearch .= ')(?=\s|$))/m';
     2587        $wp_smiliessearch .= ')(?=' . $spaces . '|$)/m';
    25842588
    25852589}
    25862590
  • tests/phpunit/tests/formatting/Smilies.php

     
    275275
    276276                $wpsmiliestrans = $orig_trans; // reset original translations array
    277277        }
    278 }
    279  No newline at end of file
     278
     279        /**
     280         * Check that $wp_smiliessearch pattern will match smilies
     281         * between spaces, but never capture those spaces.
     282         *
     283         * Further check that spaces aren't randomly deleted
     284         * or added when replacing the text with an image.
     285         *
     286         * @ticket 22692
     287         */
     288        function test_spaces_around_smilies() {
     289                $nbsp = "\xC2\xA0";
     290
     291                $input  = array();
     292                $output = array();
     293
     294                $input[]  = 'My test :) smile';
     295                $output[] = array('test <img ', 'alt=":)"', ' /> smile');
     296
     297                $input[]  = 'My test ;) smile';
     298                $output[] = array('test <img ', 'alt=";)"', ' /> smile');
     299
     300                $input[]  = 'My test &nbsp;:)&nbsp;smile';
     301                $output[] = array('test &nbsp;<img ', 'alt=":)"', ' />&nbsp;smile');
     302
     303                $input[]  = 'My test &nbsp;;)&nbsp;smile';
     304                $output[] = array('test &nbsp;<img ', 'alt=";)"', ' />&nbsp;smile');
     305
     306                $input[]  = "My test {$nbsp}:){$nbsp}smile";
     307                $output[] = array("test {$nbsp}<img ", 'alt=":)"', " />{$nbsp}smile");
     308
     309                $input[]  = "My test {$nbsp};){$nbsp}smile";
     310                $output[] = array("test {$nbsp}<img ", 'alt=";)"', " />{$nbsp}smile");
     311
     312                foreach($input as $key => $in) {
     313                        $result = convert_smilies( $in );
     314                        foreach($output[$key] as $k => $out) {
     315
     316                                // Each output element must appear in the results.
     317                                $this->assertContains( $out[$k], $result );
     318
     319                        }
     320                }
     321        }
     322}
  • tests/phpunit/tests/formatting/WPTexturize.php

     
    194194                $this->assertEquals( ' &#8212;&nbsp;', wptexturize( ' --&nbsp;' ) );
    195195                $this->assertEquals( '&nbsp;&#8212; ', wptexturize( '&nbsp;-- ') );
    196196        }
     197
     198        /**
     199         * @ticket 22692
     200         */
     201        function test_spaces_around_quotes() {
     202                $nbsp = "\xC2\xA0";
     203                $pi   = "\xCE\xA0";
     204
     205                // This should never happen, even if the desired output changes some day.
     206
     207                $problem_input  = "$nbsp\"A";
     208                $problem_output = "$nbsp&#8221;A";
     209
     210                $this->assertNotEquals( $problem_output, wptexturize( $problem_input ) );
     211
     212                // These are desirable outputs for the current design.
     213
     214                $input  = array();
     215                $output = array();
     216
     217                $input[]  = "stop. $nbsp\"A quote after 2 spaces.\"";
     218                $output[] = "stop. $nbsp&#8220;A quote after 2 spaces.&#8221;";
     219
     220                $input[]  = "stop.$nbsp$nbsp\"A quote after 2 spaces.\"";
     221                $output[] = "stop.$nbsp$nbsp&#8220;A quote after 2 spaces.&#8221;";
     222
     223                $input[]  = "stop. $nbsp'A quote after 2 spaces.'";
     224                $output[] = "stop. $nbsp&#8216;A quote after 2 spaces.&#8217;";
     225
     226                $input[]  = "stop.$nbsp$nbsp'A quote after 2 spaces.'";
     227                $output[] = "stop.$nbsp$nbsp&#8216;A quote after 2 spaces.&#8217;";
     228
     229                $input[]  = "stop. &nbsp;\"A quote after 2 spaces.\"";
     230                $output[] = "stop. &nbsp;&#8220;A quote after 2 spaces.&#8221;";
     231
     232                $input[]  = "stop.&nbsp;&nbsp;\"A quote after 2 spaces.\"";
     233                $output[] = "stop.&nbsp;&nbsp;&#8220;A quote after 2 spaces.&#8221;";
     234
     235                $input[]  = "stop. &nbsp;'A quote after 2 spaces.'";
     236                $output[] = "stop. &nbsp;&#8216;A quote after 2 spaces.&#8217;";
     237
     238                $input[]  = "stop.&nbsp;&nbsp;'A quote after 2 spaces.'";
     239                $output[] = "stop.&nbsp;&nbsp;&#8216;A quote after 2 spaces.&#8217;";
     240
     241                $input[]  = "Contraction: $pi's";
     242                $output[] = "Contraction: $pi&#8217;s";
     243
     244                foreach($input as $key => $in) {
     245                        $this->assertEquals( $output[$key], wptexturize( $in ) );
     246                }
     247        }
    197248}
  • tests/phpunit/tests/shortcode.php

     
    373373                remove_filter( 'shortcode_atts_bartag', array( $this, '_filter_atts2' ), 10, 3 );
    374374        }
    375375
     376        /**
     377         * Check that shortcode_unautop() will always recognize spaces around shortcodes.
     378         *
     379         * @ticket 22692
     380         */
     381        function test_spaces_around_shortcodes() {
     382                $nbsp = "\xC2\xA0";
     383
     384                $input  = array();
     385
     386                $input[] = "<p>[gallery ids=\"37,15,11\"]</p>";
     387                $input[] = "<p> [gallery ids=\"37,15,11\"] </p>";
     388                $input[] = "<p> $nbsp[gallery ids=\"37,15,11\"] $nbsp</p>";
     389                $input[] = "<p> &nbsp;[gallery ids=\"37,15,11\"] &nbsp;</p>";
     390
     391                $output = "[gallery ids=\"37,15,11\"]";
     392
     393                foreach($input as $in) {
     394                        $this->assertEquals( $output, shortcode_unautop( $in ) );
     395                }
     396        }
    376397}