<!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>[58089] trunk: Editor: add Style Engine support for nested CSS rules.</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/58089">58089</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/58089","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>isabel_brison</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2024-05-03 04:45:20 +0000 (Fri, 03 May 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'>Editor: add Style Engine support for nested CSS rules.

Adds support for passing a `$rules_group` string to wp_style_engine_get_stylesheet_from_css_rules(), so rules can be nested under a media query, layer or other rule.

Props isabel_brison, ramonopoly.
Fixes <a href="https://core.trac.wordpress.org/ticket/61099">#61099</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesstyleengineclasswpstyleenginecssrulephp">trunk/src/wp-includes/style-engine/class-wp-style-engine-css-rule.php</a></li>
<li><a href="#trunksrcwpincludesstyleengineclasswpstyleenginecssrulesstorephp">trunk/src/wp-includes/style-engine/class-wp-style-engine-css-rules-store.php</a></li>
<li><a href="#trunksrcwpincludesstyleengineclasswpstyleengineprocessorphp">trunk/src/wp-includes/style-engine/class-wp-style-engine-processor.php</a></li>
<li><a href="#trunksrcwpincludesstyleengineclasswpstyleenginephp">trunk/src/wp-includes/style-engine/class-wp-style-engine.php</a></li>
<li><a href="#trunksrcwpincludesstyleenginephp">trunk/src/wp-includes/style-engine.php</a></li>
<li><a href="#trunktestsphpunittestsstyleenginestyleEnginephp">trunk/tests/phpunit/tests/style-engine/styleEngine.php</a></li>
<li><a href="#trunktestsphpunittestsstyleenginewpStyleEngineCssRulephp">trunk/tests/phpunit/tests/style-engine/wpStyleEngineCssRule.php</a></li>
<li><a href="#trunktestsphpunittestsstyleenginewpStyleEngineCssRulesStorephp">trunk/tests/phpunit/tests/style-engine/wpStyleEngineCssRulesStore.php</a></li>
<li><a href="#trunktestsphpunittestsstyleenginewpStyleEngineProcessorphp">trunk/tests/phpunit/tests/style-engine/wpStyleEngineProcessor.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesstyleengineclasswpstyleenginecssrulephp"></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/style-engine/class-wp-style-engine-css-rule.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/style-engine/class-wp-style-engine-css-rule.php     2024-05-02 20:51:14 UTC (rev 58088)
+++ trunk/src/wp-includes/style-engine/class-wp-style-engine-css-rule.php       2024-05-03 04:45:20 UTC (rev 58089)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -36,9 +36,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">        protected $declarations;
</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">+         * A parent CSS selector in the case of nested CSS, or a CSS nested @rule,
+        * such as `@media (min-width: 80rem)` or `@layer module`.
+        *
+        * @since 6.6.0
+        * @var string
+        */
+       protected $rules_group;
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Constructor.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.1.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 6.6.0 Added the `$rules_group` parameter.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string                                    $selector     Optional. The CSS selector. Default empty string.
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string[]|WP_Style_Engine_CSS_Declarations $declarations Optional. An associative array of CSS definitions,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -45,10 +55,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">         *                                                                e.g. `array( "$property" => "$value", "$property" => "$value" )`,
</span><span class="cx" style="display: block; padding: 0 10px">         *                                                                or a WP_Style_Engine_CSS_Declarations object.
</span><span class="cx" style="display: block; padding: 0 10px">         *                                                                Default empty array.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @param string                                    $rules_group  A parent CSS selector in the case of nested CSS, or a CSS nested @rule,
+        *                                                                such as `@media (min-width: 80rem)` or `@layer module`.
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        public function __construct( $selector = '', $declarations = array() ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function __construct( $selector = '', $declarations = array(), $rules_group = '' ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->set_selector( $selector );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->add_declarations( $declarations );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->set_rules_group( $rules_group );
</ins><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><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -90,6 +103,31 @@
</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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Sets the rules group.
+        *
+        * @since 6.6.0
+        *
+        * @param string $rules_group A parent CSS selector in the case of nested CSS, or a CSS nested @rule,
+        *                            such as `@media (min-width: 80rem)` or `@layer module`.
+        * @return WP_Style_Engine_CSS_Rule Returns the object to allow chaining of methods.
+        */
+       public function set_rules_group( $rules_group ) {
+               $this->rules_group = $rules_group;
+               return $this;
+       }
+
+       /**
+        * Gets the rules group.
+        *
+        * @since 6.6.0
+        *
+        * @return string
+        */
+       public function get_rules_group() {
+               return $this->rules_group;
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Gets the declarations object.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.1.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -115,6 +153,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Gets the CSS.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.1.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 6.6.0 Added support for nested CSS with rules groups.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param bool $should_prettify Optional. Whether to add spacing, new lines and indents.
</span><span class="cx" style="display: block; padding: 0 10px">         *                              Default false.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -123,17 +162,28 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return string
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function get_css( $should_prettify = false, $indent_count = 0 ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $rule_indent         = $should_prettify ? str_repeat( "\t", $indent_count ) : '';
-               $declarations_indent = $should_prettify ? $indent_count + 1 : 0;
-               $suffix              = $should_prettify ? "\n" : '';
-               $spacer              = $should_prettify ? ' ' : '';
-               $selector            = $should_prettify ? str_replace( ',', ",\n", $this->get_selector() ) : $this->get_selector();
-               $css_declarations    = $this->declarations->get_declarations_string( $should_prettify, $declarations_indent );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $rule_indent                = $should_prettify ? str_repeat( "\t", $indent_count ) : '';
+               $nested_rule_indent         = $should_prettify ? str_repeat( "\t", $indent_count + 1 ) : '';
+               $declarations_indent        = $should_prettify ? $indent_count + 1 : 0;
+               $nested_declarations_indent = $should_prettify ? $indent_count + 2 : 0;
+               $suffix                     = $should_prettify ? "\n" : '';
+               $spacer                     = $should_prettify ? ' ' : '';
+               // Trims any multiple selectors strings.
+               $selector         = $should_prettify ? implode( ',', array_map( 'trim', explode( ',', $this->get_selector() ) ) ) : $this->get_selector();
+               $selector         = $should_prettify ? str_replace( array( ',' ), ",\n", $selector ) : $selector;
+               $rules_group      = $this->get_rules_group();
+               $has_rules_group  = ! empty( $rules_group );
+               $css_declarations = $this->declarations->get_declarations_string( $should_prettify, $has_rules_group ? $nested_declarations_indent : $declarations_indent );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( empty( $css_declarations ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        return '';
</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">+                if ( $has_rules_group ) {
+                       $selector = "{$rule_indent}{$rules_group}{$spacer}{{$suffix}{$nested_rule_indent}{$selector}{$spacer}{{$suffix}{$css_declarations}{$suffix}{$nested_rule_indent}}{$suffix}{$rule_indent}}";
+                       return $selector;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 return "{$rule_indent}{$selector}{$spacer}{{$suffix}{$css_declarations}{$suffix}{$rule_indent}}";
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunksrcwpincludesstyleengineclasswpstyleenginecssrulesstorephp"></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/style-engine/class-wp-style-engine-css-rules-store.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/style-engine/class-wp-style-engine-css-rules-store.php      2024-05-02 20:51:14 UTC (rev 58088)
+++ trunk/src/wp-includes/style-engine/class-wp-style-engine-css-rules-store.php        2024-05-03 04:45:20 UTC (rev 58089)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -121,13 +121,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * If the rule does not exist, it will be created.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.1.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 6.6.0 Added the $rules_group parameter.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string $selector The CSS selector.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @param string $rules_group A parent CSS selector in the case of nested CSS, or a CSS nested @rule,
+        *                            such as `@media (min-width: 80rem)` or `@layer module`.
</ins><span class="cx" style="display: block; padding: 0 10px">          * @return WP_Style_Engine_CSS_Rule|void Returns a WP_Style_Engine_CSS_Rule object,
</span><span class="cx" style="display: block; padding: 0 10px">         *                                       or void if the selector is empty.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        public function add_rule( $selector ) {
-               $selector = trim( $selector );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function add_rule( $selector, $rules_group = '' ) {
+               $selector    = $selector ? trim( $selector ) : '';
+               $rules_group = $rules_group ? trim( $rules_group ) : '';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Bail early if there is no selector.
</span><span class="cx" style="display: block; padding: 0 10px">                if ( empty( $selector ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -134,6 +138,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        return;
</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">+                if ( ! empty( $rules_group ) ) {
+                       if ( empty( $this->rules[ "$rules_group $selector" ] ) ) {
+                               $this->rules[ "$rules_group $selector" ] = new WP_Style_Engine_CSS_Rule( $selector, array(), $rules_group );
+                       }
+                       return $this->rules[ "$rules_group $selector" ];
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 // Create the rule if it doesn't exist.
</span><span class="cx" style="display: block; padding: 0 10px">                if ( empty( $this->rules[ $selector ] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->rules[ $selector ] = new WP_Style_Engine_CSS_Rule( $selector );
</span></span></pre></div>
<a id="trunksrcwpincludesstyleengineclasswpstyleengineprocessorphp"></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/style-engine/class-wp-style-engine-processor.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/style-engine/class-wp-style-engine-processor.php    2024-05-02 20:51:14 UTC (rev 58088)
+++ trunk/src/wp-includes/style-engine/class-wp-style-engine-processor.php      2024-05-03 04:45:20 UTC (rev 58089)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -58,6 +58,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Adds rules to be processed.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.1.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 6.6.0 Added support for rules_group.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param WP_Style_Engine_CSS_Rule|WP_Style_Engine_CSS_Rule[] $css_rules A single, or an array of,
</span><span class="cx" style="display: block; padding: 0 10px">         *                                                                       WP_Style_Engine_CSS_Rule objects
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -70,7 +71,24 @@
</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">                foreach ( $css_rules as $rule ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $selector = $rule->get_selector();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $selector    = $rule->get_selector();
+                       $rules_group = $rule->get_rules_group();
+
+                       /**
+                        * If there is a rules_group and it already exists in the css_rules array,
+                        * add the rule to it.
+                        * Otherwise, create a new entry for the rules_group.
+                        */
+                       if ( ! empty( $rules_group ) ) {
+                               if ( isset( $this->css_rules[ "$rules_group $selector" ] ) ) {
+                                       $this->css_rules[ "$rules_group $selector" ]->add_declarations( $rule->get_declarations() );
+                                       continue;
+                               }
+                               $this->css_rules[ "$rules_group $selector" ] = $rule;
+                               continue;
+                       }
+
+                       // If the selector already exists, add the declarations to it.
</ins><span class="cx" style="display: block; padding: 0 10px">                         if ( isset( $this->css_rules[ $selector ] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->css_rules[ $selector ]->add_declarations( $rule->get_declarations() );
</span><span class="cx" style="display: block; padding: 0 10px">                                continue;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -117,6 +135,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // Build the CSS.
</span><span class="cx" style="display: block; padding: 0 10px">                $css = '';
</span><span class="cx" style="display: block; padding: 0 10px">                foreach ( $this->css_rules as $rule ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        // See class WP_Style_Engine_CSS_Rule for the get_css method.
</ins><span class="cx" style="display: block; padding: 0 10px">                         $css .= $rule->get_css( $options['prettify'] );
</span><span class="cx" style="display: block; padding: 0 10px">                        $css .= $options['prettify'] ? "\n" : '';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span></span></pre></div>
<a id="trunksrcwpincludesstyleengineclasswpstyleenginephp"></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/style-engine/class-wp-style-engine.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/style-engine/class-wp-style-engine.php      2024-05-02 20:51:14 UTC (rev 58088)
+++ trunk/src/wp-includes/style-engine/class-wp-style-engine.php        2024-05-03 04:45:20 UTC (rev 58089)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -364,6 +364,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Stores a CSS rule using the provided CSS selector and CSS declarations.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.1.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 6.6.0 Added the `$rules_group` parameter.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string   $store_name       A valid store key.
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string   $css_selector     When a selector is passed, the function will return
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -371,12 +372,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">         *                                   otherwise a concatenated string of properties and values.
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string[] $css_declarations An associative array of CSS definitions,
</span><span class="cx" style="display: block; padding: 0 10px">         *                                   e.g. `array( "$property" => "$value", "$property" => "$value" )`.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @param string $rules_group        Optional. A parent CSS selector in the case of nested CSS, or a CSS nested @rule,
+        *                                   such as `@media (min-width: 80rem)` or `@layer module`.
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        public static function store_css_rule( $store_name, $css_selector, $css_declarations ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public static function store_css_rule( $store_name, $css_selector, $css_declarations, $rules_group = '' ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( empty( $store_name ) || empty( $css_selector ) || empty( $css_declarations ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        return;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                static::get_store( $store_name )->add_rule( $css_selector )->add_declarations( $css_declarations );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         static::get_store( $store_name )->add_rule( $css_selector, $rules_group )->add_declarations( $css_declarations );
</ins><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></span></pre></div>
<a id="trunksrcwpincludesstyleenginephp"></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/style-engine.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/style-engine.php    2024-05-02 20:51:14 UTC (rev 58088)
+++ trunk/src/wp-includes/style-engine.php      2024-05-03 04:45:20 UTC (rev 58089)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -113,11 +113,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">  *     .elephant-are-cool{color:gray;width:3em}
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 6.1.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.6.0 Added support for `$rules_group` in the `$css_rules` array.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @param array $css_rules {
</span><span class="cx" style="display: block; padding: 0 10px">  *     Required. A collection of CSS rules.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  *     @type array ...$0 {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ *         @type string   $rules_group  A parent CSS selector in the case of nested CSS,
+ *                                      or a CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
</ins><span class="cx" style="display: block; padding: 0 10px">  *         @type string   $selector     A CSS selector.
</span><span class="cx" style="display: block; padding: 0 10px">  *         @type string[] $declarations An associative array of CSS definitions,
</span><span class="cx" style="display: block; padding: 0 10px">  *                                      e.g. `array( "$property" => "$value", "$property" => "$value" )`.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -154,11 +157,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        continue;
</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">+                $rules_group = $css_rule['rules_group'] ?? null;
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( ! empty( $options['context'] ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        WP_Style_Engine::store_css_rule( $options['context'], $css_rule['selector'], $css_rule['declarations'] );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 WP_Style_Engine::store_css_rule( $options['context'], $css_rule['selector'], $css_rule['declarations'], $rules_group );
</ins><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">-                $css_rule_objects[] = new WP_Style_Engine_CSS_Rule( $css_rule['selector'], $css_rule['declarations'] );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $css_rule_objects[] = new WP_Style_Engine_CSS_Rule( $css_rule['selector'], $css_rule['declarations'], $rules_group );
</ins><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">        if ( empty( $css_rule_objects ) ) {
</span></span></pre></div>
<a id="trunktestsphpunittestsstyleenginestyleEnginephp"></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/style-engine/styleEngine.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/style-engine/styleEngine.php    2024-05-02 20:51:14 UTC (rev 58088)
+++ trunk/tests/phpunit/tests/style-engine/styleEngine.php      2024-05-03 04:45:20 UTC (rev 58089)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -749,4 +749,68 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( '.gandalf{color:white;height:190px;border-style:dotted;padding:10px;margin-bottom:100px;}.dumbledore{color:grey;height:90px;border-style:dotted;}.rincewind{color:grey;height:90px;border-style:dotted;}', $compiled_stylesheet );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * Tests returning a generated stylesheet from a set of nested rules and merging their declarations.
+        *
+        * @ticket 61099
+        *
+        * @covers ::wp_style_engine_get_stylesheet_from_css_rules
+        */
+       public function test_should_merge_declarations_for_rules_groups() {
+               $css_rules = array(
+                       array(
+                               'selector'     => '.saruman',
+                               'rules_group'  => '@container (min-width: 700px)',
+                               'declarations' => array(
+                                       'color'        => 'white',
+                                       'height'       => '100px',
+                                       'border-style' => 'solid',
+                                       'align-self'   => 'stretch',
+                               ),
+                       ),
+                       array(
+                               'selector'     => '.saruman',
+                               'rules_group'  => '@container (min-width: 700px)',
+                               'declarations' => array(
+                                       'color'       => 'black',
+                                       'font-family' => 'The-Great-Eye',
+                               ),
+                       ),
+               );
+
+               $compiled_stylesheet = wp_style_engine_get_stylesheet_from_css_rules( $css_rules, array( 'prettify' => false ) );
+
+               $this->assertSame( '@container (min-width: 700px){.saruman{color:black;height:100px;border-style:solid;align-self:stretch;font-family:The-Great-Eye;}}', $compiled_stylesheet );
+       }
+
+       /**
+        * Tests returning a generated stylesheet from a set of nested rules.
+        *
+        * @ticket 61099
+        *
+        * @covers ::wp_style_engine_get_stylesheet_from_css_rules
+        */
+       public function test_should_return_stylesheet_with_nested_rules() {
+               $css_rules = array(
+                       array(
+                               'rules_group'  => '.foo',
+                               'selector'     => '@media (orientation: landscape)',
+                               'declarations' => array(
+                                       'background-color' => 'blue',
+                               ),
+                       ),
+                       array(
+                               'rules_group'  => '.foo',
+                               'selector'     => '@media (min-width > 1024px)',
+                               'declarations' => array(
+                                       'background-color' => 'cotton-blue',
+                               ),
+                       ),
+               );
+
+               $compiled_stylesheet = wp_style_engine_get_stylesheet_from_css_rules( $css_rules, array( 'prettify' => false ) );
+
+               $this->assertSame( '.foo{@media (orientation: landscape){background-color:blue;}}.foo{@media (min-width > 1024px){background-color:cotton-blue;}}', $compiled_stylesheet );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunktestsphpunittestsstyleenginewpStyleEngineCssRulephp"></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/style-engine/wpStyleEngineCssRule.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/style-engine/wpStyleEngineCssRule.php   2024-05-02 20:51:14 UTC (rev 58088)
+++ trunk/tests/phpunit/tests/style-engine/wpStyleEngineCssRule.php     2024-05-03 04:45:20 UTC (rev 58089)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38,6 +38,24 @@
</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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Tests setting and getting a rules group.
+        *
+        * @ticket 61099
+        *
+        * @covers ::set_rules_group
+        * @covers ::get_rules_group
+        */
+       public function test_should_set_rules_group() {
+               $rule = new WP_Style_Engine_CSS_Rule( '.heres-johnny', array(), '@layer state' );
+
+               $this->assertSame( '@layer state', $rule->get_rules_group(), 'Return value of get_rules_group() does not match value passed to constructor.' );
+
+               $rule->set_rules_group( '@layer pony' );
+
+               $this->assertSame( '@layer pony', $rule->get_rules_group(), 'Return value of get_rules_group() does not match value passed to set_rules_group().' );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Tests that declaration properties are deduplicated.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 56467
</span></span></pre></div>
<a id="trunktestsphpunittestsstyleenginewpStyleEngineCssRulesStorephp"></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/style-engine/wpStyleEngineCssRulesStore.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/style-engine/wpStyleEngineCssRulesStore.php     2024-05-02 20:51:14 UTC (rev 58088)
+++ trunk/tests/phpunit/tests/style-engine/wpStyleEngineCssRulesStore.php       2024-05-03 04:45:20 UTC (rev 58089)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -187,4 +187,22 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( $expected, $new_pizza_store->get_all_rules(), 'Return value for get_all_rules() does not match expectations after adding new rules to store.' );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * Tests adding rules group keys to store.
+        *
+        * @ticket 61099
+        *
+        * @covers ::add_rule
+        */
+       public function test_should_store_as_concatenated_rules_groups_and_selector() {
+               $store_one      = WP_Style_Engine_CSS_Rules_Store::get_store( 'one' );
+               $store_one_rule = $store_one->add_rule( '.tony', '.one' );
+
+               $this->assertSame(
+                       '.one .tony',
+                       "{$store_one_rule->get_rules_group()} {$store_one_rule->get_selector()}",
+                       'add_rule() does not concatenate rules group and selector.'
+               );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunktestsphpunittestsstyleenginewpStyleEngineProcessorphp"></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/style-engine/wpStyleEngineProcessor.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/style-engine/wpStyleEngineProcessor.php 2024-05-02 20:51:14 UTC (rev 58088)
+++ trunk/tests/phpunit/tests/style-engine/wpStyleEngineProcessor.php   2024-05-03 04:45:20 UTC (rev 58089)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -49,6 +49,43 @@
</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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Tests adding nested rules with at-rules and returning compiled CSS rules.
+        *
+        * @ticket 61099
+        *
+        * @covers ::add_rules
+        * @covers ::get_css
+        */
+       public function test_should_return_nested_rules_as_compiled_css() {
+               $a_nice_css_rule = new WP_Style_Engine_CSS_Rule( '.a-nice-rule' );
+               $a_nice_css_rule->add_declarations(
+                       array(
+                               'color'            => 'var(--nice-color)',
+                               'background-color' => 'purple',
+                       )
+               );
+               $a_nice_css_rule->set_rules_group( '@media (min-width: 80rem)' );
+
+               $a_nicer_css_rule = new WP_Style_Engine_CSS_Rule( '.a-nicer-rule' );
+               $a_nicer_css_rule->add_declarations(
+                       array(
+                               'font-family'      => 'Nice sans',
+                               'font-size'        => '1em',
+                               'background-color' => 'purple',
+                       )
+               );
+               $a_nicer_css_rule->set_rules_group( '@layer nicety' );
+
+               $a_nice_processor = new WP_Style_Engine_Processor();
+               $a_nice_processor->add_rules( array( $a_nice_css_rule, $a_nicer_css_rule ) );
+
+               $this->assertSame(
+                       '@media (min-width: 80rem){.a-nice-rule{color:var(--nice-color);background-color:purple;}}@layer nicety{.a-nicer-rule{font-family:Nice sans;font-size:1em;background-color:purple;}}',
+                       $a_nice_processor->get_css( array( 'prettify' => false ) )
+               );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Tests compiling CSS rules and formatting them with new lines and indents.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 56467
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -102,6 +139,54 @@
</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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Tests compiling nested CSS rules and formatting them with new lines and indents.
+        *
+        * @ticket 61099
+        *
+        * @covers ::get_css
+        */
+       public function test_should_return_prettified_nested_css_rules() {
+               $a_wonderful_css_rule = new WP_Style_Engine_CSS_Rule( '.a-wonderful-rule' );
+               $a_wonderful_css_rule->add_declarations(
+                       array(
+                               'color'            => 'var(--wonderful-color)',
+                               'background-color' => 'orange',
+                       )
+               );
+               $a_wonderful_css_rule->set_rules_group( '@media (min-width: 80rem)' );
+
+               $a_very_wonderful_css_rule = new WP_Style_Engine_CSS_Rule( '.a-very_wonderful-rule' );
+               $a_very_wonderful_css_rule->add_declarations(
+                       array(
+                               'color'            => 'var(--wonderful-color)',
+                               'background-color' => 'orange',
+                       )
+               );
+               $a_very_wonderful_css_rule->set_rules_group( '@layer wonderfulness' );
+
+               $a_wonderful_processor = new WP_Style_Engine_Processor();
+               $a_wonderful_processor->add_rules( array( $a_wonderful_css_rule, $a_very_wonderful_css_rule ) );
+
+               $expected = '@media (min-width: 80rem) {
+       .a-wonderful-rule {
+               color: var(--wonderful-color);
+               background-color: orange;
+       }
+}
+@layer wonderfulness {
+       .a-very_wonderful-rule {
+               color: var(--wonderful-color);
+               background-color: orange;
+       }
+}
+';
+               $this->assertSame(
+                       $expected,
+                       $a_wonderful_processor->get_css( array( 'prettify' => true ) )
+               );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Tests adding a store and compiling CSS rules from that store.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 56467
</span></span></pre>
</div>
</div>

</body>
</html>