@@ -333,27 +333,68 @@ private function replace_html( string $block_content, string $attribute_name, $s
333333 switch ( $ block_type ->attributes [ $ attribute_name ]['source ' ] ) {
334334 case 'html ' :
335335 case 'rich-text ' :
336- // Hardcode the selectors and processing until the HTML API is able to read CSS selectors and replace inner HTML.
337- // TODO: Use the HTML API instead.
338- if ( 'core/paragraph ' === $ this ->name && 'content ' === $ attribute_name ) {
339- $ selector = 'p ' ;
340- }
341- if ( 'core/heading ' === $ this ->name && 'content ' === $ attribute_name ) {
342- $ selector = 'h[1-6] ' ;
336+ $ block_reader = new WP_HTML_Tag_Processor ( $ block_content );
337+
338+ // TODO: Support for CSS selectors whenever they are ready in the HTML API.
339+ // In the meantime, support comma-separated selectors by exploding them into an array.
340+ $ selectors = explode ( ', ' , $ block_type ->attributes [ $ attribute_name ]['selector ' ] );
341+ // Add a bookmark to the first tag to be able to iterate over the selectors.
342+ $ block_reader ->next_tag ();
343+ $ block_reader ->set_bookmark ( 'iterate-selectors ' );
344+
345+ // TODO: This shouldn't be needed when the `set_inner_html` function is ready.
346+ // Store the parent tag and its attributes to be able to restore them later in the button.
347+ // The button block has a wrapper while the paragraph and heading blocks don't.
348+ if ( 'core/button ' === $ this ->name ) {
349+ $ button_wrapper = $ block_reader ->get_tag ();
350+ $ button_wrapper_attribute_names = $ block_reader ->get_attribute_names_with_prefix ( '' );
351+ $ button_wrapper_attrs = array ();
352+ foreach ( $ button_wrapper_attribute_names as $ name ) {
353+ $ button_wrapper_attrs [ $ name ] = $ block_reader ->get_attribute ( $ name );
354+ }
343355 }
344- if ( 'core/button ' === $ this ->name && 'text ' === $ attribute_name ) {
345- // Check if it is a <button> or <a> tag.
346- if ( preg_match ( '/<button[^>]*>.*?<\/button>/ ' , $ block_content ) ) {
347- $ selector = 'button ' ;
356+
357+ foreach ( $ selectors as $ selector ) {
358+ // If the parent tag, or any of its children, matches the selector, replace the HTML.
359+ if ( strcasecmp ( $ block_reader ->get_tag ( $ selector ), $ selector ) === 0 || $ block_reader ->next_tag (
360+ array (
361+ 'tag_name ' => $ selector ,
362+ )
363+ ) ) {
364+ $ block_reader ->release_bookmark ( 'iterate-selectors ' );
365+
366+ // TODO: Use `set_inner_html` method whenever it's ready in the HTML API.
367+ // Until then, it is hardcoded for the paragraph, heading, and button blocks.
368+ // Store the tag and its attributes to be able to restore them later.
369+ $ selector_attribute_names = $ block_reader ->get_attribute_names_with_prefix ( '' );
370+ $ selector_attrs = array ();
371+ foreach ( $ selector_attribute_names as $ name ) {
372+ $ selector_attrs [ $ name ] = $ block_reader ->get_attribute ( $ name );
373+ }
374+ $ selector_markup = "< $ selector> " . wp_kses_post ( $ source_value ) . "</ $ selector> " ;
375+ $ amended_content = new WP_HTML_Tag_Processor ( $ selector_markup );
376+ $ amended_content ->next_tag ();
377+ foreach ( $ selector_attrs as $ attribute_key => $ attribute_value ) {
378+ $ amended_content ->set_attribute ( $ attribute_key , $ attribute_value );
379+ }
380+ if ( 'core/paragraph ' === $ this ->name || 'core/heading ' === $ this ->name ) {
381+ return $ amended_content ->get_updated_html ();
382+ }
383+ if ( 'core/button ' === $ this ->name ) {
384+ $ button_markup = "< $ button_wrapper> {$ amended_content ->get_updated_html ()}</ $ button_wrapper> " ;
385+ $ amended_button = new WP_HTML_Tag_Processor ( $ button_markup );
386+ $ amended_button ->next_tag ();
387+ foreach ( $ button_wrapper_attrs as $ attribute_key => $ attribute_value ) {
388+ $ amended_button ->set_attribute ( $ attribute_key , $ attribute_value );
389+ }
390+ return $ amended_button ->get_updated_html ();
391+ }
348392 } else {
349- $ selector = ' a ' ;
393+ $ block_reader -> seek ( ' iterate-selectors ' ) ;
350394 }
351395 }
352- if ( empty ( $ selector ) ) {
353- return $ block_content ;
354- }
355- $ pattern = '/(< ' . $ selector . '[^>]*>).*?(<\/ ' . $ selector . '>)/i ' ;
356- return preg_replace ( $ pattern , '$1 ' . wp_kses_post ( $ source_value ) . '$2 ' , $ block_content );
396+ $ block_reader ->release_bookmark ( 'iterate-selectors ' );
397+ return $ block_content ;
357398
358399 case 'attribute ' :
359400 $ amended_content = new WP_HTML_Tag_Processor ( $ block_content );
0 commit comments