1010/**
1111 * Core class used to inspect and modify CSS declarations in an HTML style attribute.
1212 *
13- * The processor operates on decoded style attribute values. Values read from
14- * {@see WP_HTML_Tag_Processor::get_attribute()} can be passed directly to this
15- * class, and values returned by {@see WP_HTML_Style_Attribute_Processor::get_updated_style()}
16- * can be passed back to {@see WP_HTML_Tag_Processor::set_attribute()}.
13+ * The processor operates on the decoded CSS text value of a style attribute:
14+ * the CSS declaration-list contents of a declaration block, excluding the
15+ * delimiting braces. It does not parse HTML attribute syntax, decode character
16+ * references, or operate on raw HTML markup.
17+ *
18+ * Values read from {@see WP_HTML_Tag_Processor::get_attribute()} can be passed
19+ * directly to this class, and values returned by
20+ * {@see WP_HTML_Style_Attribute_Processor::get_updated_style()} can be passed
21+ * back to {@see WP_HTML_Tag_Processor::set_attribute()}.
1722 *
1823 * Unlike associative-array based style helpers, this processor preserves the
1924 * declaration list model of CSS. Multiple declarations with the same property
@@ -50,6 +55,13 @@ class WP_HTML_Style_Attribute_Processor {
5055 */
5156 private $ declarations = array ();
5257
58+ /**
59+ * Whether the style attribute value has been parsed.
60+ *
61+ * @var bool
62+ */
63+ private $ parsed = false ;
64+
5365 /**
5466 * Index of the current declaration, or -1 before the first declaration.
5567 *
@@ -81,7 +93,7 @@ class WP_HTML_Style_Attribute_Processor {
8193 /**
8294 * Constructor.
8395 *
84- * @param string|bool|null $style Decoded style attribute value.
96+ * @param string|bool|null $style Decoded CSS text value from a style attribute .
8597 */
8698 public function __construct ( $ style = '' ) {
8799 if ( null === $ style || true === $ style ) {
@@ -91,7 +103,6 @@ public function __construct( $style = '' ) {
91103 }
92104
93105 $ this ->style = $ style ;
94- $ this ->parse ();
95106 }
96107
97108 /**
@@ -100,10 +111,12 @@ public function __construct( $style = '' ) {
100111 * When a property name is provided, normal CSS properties are matched
101112 * ASCII-case-insensitively while custom properties are matched exactly.
102113 *
103- * @param string|null $property_name Optional property name to match.
114+ * @param string|null $property_name Optional declaration property name to match.
104115 * @return bool Whether a matching declaration was found.
105116 */
106117 public function next_declaration ( ?string $ property_name = null ): bool {
118+ $ this ->ensure_parsed ();
119+
107120 for ( $ i = $ this ->current_declaration + 1 ; $ i < count ( $ this ->declarations ); $ i ++ ) {
108121 if (
109122 null === $ property_name ||
@@ -234,6 +247,8 @@ public function append_declaration( string $property_name, string $value, bool $
234247 return false ;
235248 }
236249
250+ $ this ->ensure_parsed ();
251+
237252 $ old_declaration_count = count ( $ this ->declarations );
238253 $ trimmed_style = rtrim ( $ this ->style , self ::WHITESPACE );
239254 $ insert_at = strlen ( $ trimmed_style );
@@ -265,9 +280,9 @@ public function append_declaration( string $property_name, string $value, bool $
265280 }
266281
267282 /**
268- * Returns the updated style attribute value.
283+ * Returns the updated decoded CSS text value for the style attribute .
269284 *
270- * @return string Updated style attribute value.
285+ * @return string Updated decoded CSS text value for the style attribute .
271286 */
272287 public function get_updated_style (): string {
273288 if ( empty ( $ this ->lexical_updates ) ) {
@@ -305,8 +320,12 @@ static function ( $a, $b ) {
305320 * Parses CSS tokens and declarations from the style attribute value.
306321 */
307322 private function parse (): void {
323+ $ this ->tokens = array ();
324+ $ this ->declarations = array ();
325+
308326 $ processor = WP_CSS_Token_Processor::create ( $ this ->style );
309327 if ( null === $ processor ) {
328+ $ this ->parsed = true ;
310329 return ;
311330 }
312331
@@ -323,6 +342,18 @@ private function parse(): void {
323342 }
324343
325344 $ this ->parse_declaration_list ();
345+ $ this ->parsed = true ;
346+ }
347+
348+ /**
349+ * Lazily parses the style attribute value when declaration access needs it.
350+ */
351+ private function ensure_parsed (): void {
352+ if ( $ this ->parsed ) {
353+ return ;
354+ }
355+
356+ $ this ->parse ();
326357 }
327358
328359 /**
@@ -733,12 +764,11 @@ private function get_current_declaration(): ?array {
733764 private function apply_lexical_updates ( int $ current_declaration , bool $ current_declaration_removed = false ): void {
734765 $ this ->style = $ this ->get_updated_style ();
735766
736- $ this ->tokens = array ();
737- $ this ->declarations = array ();
738767 $ this ->lexical_updates = array ();
739768 $ this ->lexical_update_order = 0 ;
740769 $ this ->current_declaration = $ current_declaration ;
741770 $ this ->current_declaration_removed = $ current_declaration_removed ;
771+ $ this ->parsed = false ;
742772
743773 $ this ->parse ();
744774
@@ -881,6 +911,7 @@ private function is_parseable_append( int $insert_at, string $separator, string
881911 $ expected_after = $ expected_start + strlen ( $ declaration_text );
882912 $ candidate_style = substr ( $ this ->style , 0 , $ insert_at ) . $ separator . $ declaration_text . substr ( $ this ->style , $ insert_at );
883913 $ candidate = new self ( $ candidate_style );
914+ $ candidate ->ensure_parsed ();
884915
885916 if ( count ( $ candidate ->declarations ) !== $ old_declaration_count + 1 ) {
886917 return false ;
0 commit comments