diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php index 9551a61c65..55a0884619 100644 --- a/src/wp-includes/formatting.php +++ b/src/wp-includes/formatting.php @@ -100,6 +100,16 @@ function wptexturize($text) { // Pattern-based replacements of characters. $dynamic = array(); + // '99' is an ambiguous case among other patterns; assume it's an abbreviated year at the end of a quotation. + if ( "'" !== $apos && "'" !== $closing_single_quote ) { + $dynamic[ '/\'(\d\d)\'(?=\Z|[.,)}>\-\]]|' . $spaces . ')/' ] = $apos . '$1' . $closing_single_quote; + } + + // '99 '99s '99's (apostrophe) But never '9 or '999 or '99.0. + if ( "'" !== $apos ) { + $dynamic[ '/\'(?=\d\d(?:\Z|(?!\d|[.,]\d)))/' ] = $apos; + } + // Quoted Numbers like "42" or '42.00' if ( '"' !== $opening_quote && '"' !== $closing_quote ) { $dynamic[ '/(?<=\A|' . $spaces . ')"(\d[\d\.\,]*)"/' ] = $opening_quote . '$1' . $closing_quote; @@ -108,11 +118,6 @@ function wptexturize($text) { $dynamic[ '/(?<=\A|' . $spaces . ')\'(\d[\d\.\,]*)\'/' ] = $opening_single_quote . '$1' . $closing_single_quote; } - // '99 '99s '99's (apostrophe) - if ( "'" !== $apos ) { - $dynamic[ '/\'(?=\d)/' ] = $apos; - } - // Single quote at start, or preceded by (, {, <, [, ", -, or spaces. if ( "'" !== $opening_single_quote ) { $dynamic[ '/(?<=\A|[([{<"\-]|' . $spaces . ')\'/' ] = $opening_single_quote; diff --git a/tests/phpunit/tests/formatting/WPTexturize.php b/tests/phpunit/tests/formatting/WPTexturize.php index 63647334c9..f518a3d264 100644 --- a/tests/phpunit/tests/formatting/WPTexturize.php +++ b/tests/phpunit/tests/formatting/WPTexturize.php @@ -1279,4 +1279,87 @@ class Tests_Formatting_WPTexturize extends WP_UnitTestCase { ), ); } -} + + /** + * Year abbreviations consist of exactly two digits. + * + * @ticket 26850 + * @dataProvider data_quotes_and_dashes + */ + function test_year_abbr( $input, $output ) { + return $this->assertEquals( $output, wptexturize( $input ) ); + } + + function data_year_abbr() { + return array( + array( + "word '99 word", + "word ’99 word", + ), + array( + "word '99. word", + "word ’99. word", + ), + array( + "word '99, word", + "word ’99, word", + ), + array( + "word '99; word", + "word ’99; word", + ), + array( + "word '99' word", // For this pattern, prime doesn't make sense. Should get apos and a closing quote. + "word ’99’ word", + ), + array( + "word '99'. word", + "word ’99’. word", + ), + array( + "word '99', word", + "word ’99’, word", + ), + array( + "word '99.' word", + "word ’99.’ word", + ), + array( + "word '99", + "word ’99", + ), + array( + "'99 word", + "’99 word", + ), + array( + "word '999 word", // Does not match the apos pattern, should be opening quote. + "word ‘999 word", + ), + array( + "word '9 word", + "word ‘9 word", + ), + array( + "word '99.9 word", + "word ‘99.9 word", + ), + array( + "word '999", + "word ‘999", + ), + array( + "word '9", + "word ‘9", + ), + array( + "in '4 years, 3 months,' Obama cut the deficit", + "in ‘4 years, 3 months,’ Obama cut the deficit", + ), + array( + "testing's '4' through 'quotes'", + "testing’s ‘4’ through ‘quotes’", + ), + ); + } +} \ No newline at end of file