<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[57597] trunk: Shortcodes: Always return an array in `shortcode_parse_atts()`.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/57597">57597</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/57597","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>swissspidy</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2024-02-12 16:06:47 +0000 (Mon, 12 Feb 2024)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Shortcodes: Always return an array in `shortcode_parse_atts()`.

Previously, `shortcode_parse_atts()` would return the input (an empty string) if a shortcode had no attributes, even though the documentation said otherwise.

Always returning an (empty) array reduces confusion and improves developer experience as the return value does not have to be manually checked in the shortcode itself.

Props: nicolefurlan, swissspidy, johnbillion, bedas.
Fixes <a href="https://core.trac.wordpress.org/ticket/59249">#59249</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesmediaphp">trunk/src/wp-includes/media.php</a></li>
<li><a href="#trunksrcwpincludesshortcodesphp">trunk/src/wp-includes/shortcodes.php</a></li>
<li><a href="#trunktestsphpunittestsshortcodephp">trunk/tests/phpunit/tests/shortcode.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesmediaphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/media.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/media.php   2024-02-12 15:36:31 UTC (rev 57596)
+++ trunk/src/wp-includes/media.php     2024-02-12 16:06:47 UTC (rev 57597)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2354,10 +2354,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @return string HTML content to display the caption.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function img_caption_shortcode( $attr, $content = '' ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if ( ! $attr ) {
-               $attr = array();
-       }
-
</del><span class="cx" style="display: block; padding: 0 10px">         // New-style shortcode with the caption inside the shortcode with the link and image tags.
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! isset( $attr['caption'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                if ( preg_match( '#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches ) ) {
</span></span></pre></div>
<a id="trunksrcwpincludesshortcodesphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/shortcodes.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/shortcodes.php      2024-02-12 15:36:31 UTC (rev 57596)
+++ trunk/src/wp-includes/shortcodes.php        2024-02-12 16:06:47 UTC (rev 57597)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -600,11 +600,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * retrieval of the attributes, since all attributes have to be known.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 2.5.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.5.0 The function now always returns an empty array,
+ *              even if the original arguments string cannot be parsed or is empty.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @param string $text Shortcode arguments list.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @return array|string Array of attribute values keyed by attribute name.
- *                      Returns empty array if there are no attributes.
- *                      Returns the original arguments string if it cannot be parsed.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @return array Array of attribute values keyed by attribute name.
+ *               Returns empty array if there are no attributes
+ *               or if the original arguments string cannot be parsed.
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function shortcode_parse_atts( $text ) {
</span><span class="cx" style="display: block; padding: 0 10px">        $atts    = array();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -635,8 +637,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        } else {
-               $atts = ltrim( $text );
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        return $atts;
</span></span></pre></div>
<a id="trunktestsphpunittestsshortcodephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/shortcode.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/shortcode.php   2024-02-12 15:36:31 UTC (rev 57596)
+++ trunk/tests/phpunit/tests/shortcode.php     2024-02-12 16:06:47 UTC (rev 57597)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -105,9 +105,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                return $out;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * @ticket 59249
+        */
</ins><span class="cx" style="display: block; padding: 0 10px">         public function test_noatts() {
</span><span class="cx" style="display: block; padding: 0 10px">                do_shortcode( '[test-shortcode-tag /]' );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertSame( '', $this->atts );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertIsArray( $this->atts );
+               $this->assertEmpty( $this->atts );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertSame( 'test-shortcode-tag', $this->tagname );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -181,9 +185,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( 'test-shortcode-tag', $this->tagname );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * @ticket 59249
+        */
</ins><span class="cx" style="display: block; padding: 0 10px">         public function test_noatts_enclosing() {
</span><span class="cx" style="display: block; padding: 0 10px">                do_shortcode( '[test-shortcode-tag]content[/test-shortcode-tag]' );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertSame( '', $this->atts );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertIsArray( $this->atts );
+               $this->assertEmpty( $this->atts );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertSame( 'content', $this->content );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( 'test-shortcode-tag', $this->tagname );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -208,10 +216,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( 'test-shortcode-tag', $this->tagname );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * @ticket 59249
+        */
</ins><span class="cx" style="display: block; padding: 0 10px">         public function test_unclosed() {
</span><span class="cx" style="display: block; padding: 0 10px">                $out = do_shortcode( '[test-shortcode-tag]' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( '', $out );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertSame( '', $this->atts );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertIsArray( $this->atts );
+               $this->assertEmpty( $this->atts );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertSame( 'test-shortcode-tag', $this->tagname );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -998,4 +1010,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( 'test-shortcode-tag', $this->tagname );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * @ticket 59249
+        */
+       public function test_shortcode_parse_atts_empty() {
+               $out = shortcode_parse_atts( '' );
+               $this->assertIsArray( $out, 'Return value is not an array' );
+               $this->assertEmpty( $out, 'Returned array is not empty' );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre>
</div>
</div>

</body>
</html>