diff --git a/src/wp-includes/js/shortcode.js b/src/wp-includes/js/shortcode.js index 79423eecff..86f8dc64b8 100644 --- a/src/wp-includes/js/shortcode.js +++ b/src/wp-includes/js/shortcode.js @@ -134,8 +134,9 @@ window.wp = window.wp || {}; // 5. An attribute name, that corresponds to... // 6. an unquoted value. // 7. A numeric attribute in double quotes. - // 8. An unquoted numeric attribute. - pattern = /([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*'([^']*)'(?:\s|$)|([\w-]+)\s*=\s*([^\s'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/g; + // 8. A numeric attribute in single quotes. + // 9. An unquoted numeric attribute. + pattern = /([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*'([^']*)'(?:\s|$)|([\w-]+)\s*=\s*([^\s'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|'([^']*)'(?:\s|$)|(\S+)(?:\s|$)/g; // Map zero-width spaces to actual spaces. text = text.replace( /[\u00a0\u200b]/g, ' ' ); @@ -152,6 +153,8 @@ window.wp = window.wp || {}; numeric.push( match[7] ); } else if ( match[8] ) { numeric.push( match[8] ); + } else if ( match[9] ) { + numeric.push( match[9] ); } } diff --git a/src/wp-includes/shortcodes.php b/src/wp-includes/shortcodes.php index 166a7f3c6c..8cd37d0ae4 100644 --- a/src/wp-includes/shortcodes.php +++ b/src/wp-includes/shortcodes.php @@ -487,7 +487,7 @@ function unescape_invalid_shortcodes( $content ) { * @return string The shortcode attribute regular expression */ function get_shortcode_atts_regex() { - return '/([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*\'([^\']*)\'(?:\s|$)|([\w-]+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/'; + return '/([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*\'([^\']*)\'(?:\s|$)|([\w-]+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|\'([^\']*)\'(?:\s|$)|(\S+)(?:\s|$)/'; } /** @@ -519,8 +519,10 @@ function shortcode_parse_atts($text) { $atts[strtolower($m[5])] = stripcslashes($m[6]); elseif (isset($m[7]) && strlen($m[7])) $atts[] = stripcslashes($m[7]); - elseif (isset($m[8])) + elseif (isset($m[8]) && strlen($m[8])) $atts[] = stripcslashes($m[8]); + elseif (isset($m[9])) + $atts[] = stripcslashes($m[9]); } // Reject any unclosed HTML elements diff --git a/tests/phpunit/tests/shortcode.php b/tests/phpunit/tests/shortcode.php index ec25f76fea..273d04d715 100644 --- a/tests/phpunit/tests/shortcode.php +++ b/tests/phpunit/tests/shortcode.php @@ -840,4 +840,34 @@ EOF; ); return wp_json_encode( $arr ); } + + /** + * @ticket 37304 + * + * Test 'value' syntax for empty attributes + */ + function test_empty_single_quote_attribute() { + $out = do_shortcode( '[test-shortcode-tag a="foo" b=\'bar\' c=baz foo \'bar\' "baz" ]test empty atts[/test-shortcode-tag]' ); + $this->assertEquals( array( 'a' => 'foo', 'b' => 'bar', 'c' => 'baz', 0 => 'foo', 1 => 'bar', 2 => 'baz' ), $this->atts ); + } + + /** + * @ticket 37304 + */ + function test_positional_atts_single_quotes() { + $out = do_shortcode( "[test-shortcode-tag 'something in quotes' 'something else']" ); + $this->assertEquals( '', $out ); + $this->assertEquals( array( 0 => 'something in quotes', 1 => 'something else' ), $this->atts ); + $this->assertEquals( 'test-shortcode-tag', $this->tagname ); + } + + /** + * @ticket 37304 + */ + function test_positional_atts_mixed_quotes() { + $out = do_shortcode( "[test-shortcode-tag 'something in quotes' \"something else\" 123 foo bar='baz' example=\"test\" ]" ); + $this->assertEquals( '', $out ); + $this->assertEquals( array( 0 => 'something in quotes', 1 => 'something else', 2 => '123', 3 => 'foo', 'bar' => 'baz', 'example' => 'test'), $this->atts ); + $this->assertEquals( 'test-shortcode-tag', $this->tagname ); + } } diff --git a/tests/qunit/wp-includes/js/shortcode.js b/tests/qunit/wp-includes/js/shortcode.js index 72c8aa9a38..2fd3c54d4c 100644 --- a/tests/qunit/wp-includes/js/shortcode.js +++ b/tests/qunit/wp-includes/js/shortcode.js @@ -196,4 +196,20 @@ jQuery( function() { deepEqual( wp.shortcode.attrs('foo not="a blocker" bar baz'), expected, 'attr parsed numeric attributes'); }); + + test( 'attrs() should return numeric attributes created with single, double, and no quotes', function() { + var expected = { + 'named': {}, 'numeric' : ['foo', 'bar', 'baz'] + }; + + deepEqual( wp.shortcode.attrs('foo "bar" \'baz\''), expected, 'attr parsed numeric attributes'); + }); + + test( 'attrs() should return mixed attributes created with single, double, and no quotes', function() { + var expected = { + 'named': { a: 'foo', b: 'bar', c: 'baz' }, 'numeric' : ['foo', 'bar', 'baz'] + }; + + deepEqual( wp.shortcode.attrs('a="foo" b=\'bar\' c=baz foo "bar" \'baz\''), expected, 'attr parsed numeric attributes'); + }); });