Skip to content

Commit 26885cf

Browse files
committed
Refactor wp_replace_in_html_tags()
1 parent 2f23ab7 commit 26885cf

1 file changed

Lines changed: 59 additions & 22 deletions

File tree

src/wp-includes/formatting.php

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -774,52 +774,89 @@ function _get_wptexturize_shortcode_regex( $tagnames ) {
774774
/**
775775
* Replaces characters or phrases within HTML elements only.
776776
*
777+
* This is a dangerous function which can break HTML syntax,
778+
* consider using methods from the HTML API instead.
779+
*
780+
* Example:
781+
*
782+
* '<p class="test">data-class</p>' === wp_replace_in_html_tags(
783+
* '<p data-class="test">data-class</p>',
784+
* array( 'data-class' => 'class' )
785+
* );
786+
*
777787
* @since 4.2.3
788+
* @since {WP_VERSION} Reliably parses HTML via the HTML API.
778789
*
779-
* @param string $haystack The text which has to be formatted.
790+
* @param string $html Replace matches inside the tags of this HTML.
780791
* @param array $replace_pairs In the form array('from' => 'to', ...).
781-
* @return string The formatted text.
792+
* @return string HTML after replacing the `$replace_pairs` matches, but only those
793+
* matches which appear inside HTML opening and closing tags.
782794
*/
783-
function wp_replace_in_html_tags( $haystack, $replace_pairs ) {
784-
// Find all elements.
785-
$textarr = wp_html_split( $haystack );
786-
$changed = false;
795+
function wp_replace_in_html_tags( $html, $replace_pairs ) {
796+
$token_updater = new class( $html ) extends WP_HTML_Tag_Processor {
797+
public function extract_raw_token() {
798+
$this->set_bookmark( 'here' );
799+
$here = $this->bookmarks['here'];
800+
801+
return substr( $this->html, $here->start, $here->length );
802+
}
803+
804+
public function replace_raw_token( $new_raw_html ) {
805+
$this->set_bookmark( 'here' );
806+
$here = $this->bookmarks['here'];
807+
808+
$this->lexical_updates[] = new WP_HTML_Text_Replacement(
809+
$here->start,
810+
$here->length,
811+
$new_raw_html
812+
);
813+
}
814+
};
787815

788816
// Optimize when searching for one item.
789817
if ( 1 === count( $replace_pairs ) ) {
790818
// Extract $needle and $replace.
791819
$needle = array_key_first( $replace_pairs );
792820
$replace = $replace_pairs[ $needle ];
793821

794-
// Loop through delimiters (elements) only.
795-
for ( $i = 1, $c = count( $textarr ); $i < $c; $i += 2 ) {
796-
if ( str_contains( $textarr[ $i ], $needle ) ) {
797-
$textarr[ $i ] = str_replace( $needle, $replace, $textarr[ $i ] );
798-
$changed = true;
822+
while ( $token_updater->next_token() ) {
823+
if ( '#text' === $token_updater->get_token_name() ) {
824+
continue;
825+
}
826+
827+
$token = $token_updater->extract_raw_token();
828+
$updated = str_replace( $needle, $replace, $token );
829+
830+
if ( $token !== $updated ) {
831+
$token_updater->replace_raw_token( $updated );
799832
}
800833
}
801834
} else {
802835
// Extract all $needles.
803836
$needles = array_keys( $replace_pairs );
804837

805-
// Loop through delimiters (elements) only.
806-
for ( $i = 1, $c = count( $textarr ); $i < $c; $i += 2 ) {
838+
while ( $token_updater->next_token() ) {
839+
if ( '#text' === $token_updater->get_token_name() ) {
840+
continue;
841+
}
842+
843+
$token = $token_updater->extract_raw_token();
844+
$updated = $token;
845+
807846
foreach ( $needles as $needle ) {
808-
if ( str_contains( $textarr[ $i ], $needle ) ) {
809-
$textarr[ $i ] = strtr( $textarr[ $i ], $replace_pairs );
810-
$changed = true;
811-
// After one strtr() break out of the foreach loop and look at next element.
847+
if ( str_contains( $token, $needle ) ) {
848+
$updated = strtr( $updated, $replace_pairs );
812849
break;
813850
}
814851
}
815-
}
816-
}
817852

818-
if ( $changed ) {
819-
$haystack = implode( $textarr );
853+
if ( $token !== $updated ) {
854+
$token_updater->replace_raw_token( $updated );
855+
}
856+
}
820857
}
821858

822-
return $haystack;
859+
return $token_updater->get_updated_html();
823860
}
824861

825862
/**

0 commit comments

Comments
 (0)