Skip to content

Commit 7ee7ec4

Browse files
committed
Implement text placeholder extraction in compile()
Parse funky comments (</%name>) to extract text placeholders. Store each placeholder's offsets (start position and length) and context. Repeated placeholders are captured as multiple offset entries.
1 parent 1ff56c5 commit 7ee7ec4

2 files changed

Lines changed: 93 additions & 0 deletions

File tree

src/wp-includes/html-api/class-wp-html-template.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,69 @@ public function get_placeholders(): array {
4848
/**
4949
* Compiles the template to extract placeholder metadata.
5050
*
51+
* Parses the template once and caches placeholder positions, lengths,
52+
* and contexts. If a placeholder appears in both text and attribute
53+
* contexts, the attribute context takes precedence (more restrictive).
54+
*
5155
* @since 7.0.0
5256
*/
5357
private function compile(): void {
5458
if ( null !== $this->compiled ) {
5559
return;
5660
}
61+
5762
$this->compiled = array();
63+
64+
$processor = new class( $this->template_string ) extends WP_HTML_Tag_Processor {
65+
public function get_html(): string {
66+
return $this->html;
67+
}
68+
69+
public function get_bookmark( string $name ) {
70+
return $this->bookmarks[ $name ] ?? null;
71+
}
72+
73+
public function get_tag_attributes(): array {
74+
return $this->attributes;
75+
}
76+
};
77+
78+
while ( $processor->next_token() ) {
79+
switch ( $processor->get_token_type() ) {
80+
case '#funky-comment':
81+
$processor->set_bookmark( 'placeholder' );
82+
$mark = $processor->get_bookmark( 'placeholder' );
83+
if ( null === $mark ) {
84+
break;
85+
}
86+
87+
$start = $mark->start;
88+
$length = $mark->length;
89+
$html = $processor->get_html();
90+
91+
// Must be at least `</%x>` (5 chars) and start with `</%`
92+
if ( $length < 5 || '%' !== $html[ $start + 2 ] ) {
93+
break;
94+
}
95+
96+
$placeholder = trim( substr( $html, $start + 3, $length - 4 ), " \t\n\r\f" );
97+
98+
// Valid placeholders match `/[a-z0-9_-]+/i`
99+
if ( strlen( $placeholder ) !== strspn( $placeholder, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-' ) ) {
100+
break;
101+
}
102+
103+
if ( ! isset( $this->compiled[ $placeholder ] ) ) {
104+
$this->compiled[ $placeholder ] = array(
105+
'offsets' => array(),
106+
'context' => 'text',
107+
);
108+
}
109+
110+
$this->compiled[ $placeholder ]['offsets'][] = array( $start, $length );
111+
break;
112+
}
113+
}
58114
}
59115

60116
private function __construct( string $template_string, array $replacements ) {

tests/phpunit/tests/html-api/wpHtmlTemplate.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,4 +772,41 @@ public function test_get_placeholders_returns_metadata() {
772772
$this->assertSame( 'attribute', $placeholders['class']['context'] );
773773
$this->assertSame( 'text', $placeholders['content']['context'] );
774774
}
775+
776+
/**
777+
* Verifies text placeholders are extracted with correct offsets.
778+
*
779+
* @ticket 60229
780+
*
781+
* @covers ::get_placeholders
782+
*/
783+
public function test_extracts_text_placeholders_with_offsets() {
784+
$template = T::from( '<p></%name></p>' );
785+
786+
$placeholders = $template->get_placeholders();
787+
788+
$this->assertArrayHasKey( 'name', $placeholders );
789+
$this->assertSame( 'text', $placeholders['name']['context'] );
790+
$this->assertCount( 1, $placeholders['name']['offsets'] );
791+
// <p> is 3 chars, so </%name> starts at offset 3
792+
$this->assertSame( 3, $placeholders['name']['offsets'][0][0] );
793+
// </%name> is 8 chars
794+
$this->assertSame( 8, $placeholders['name']['offsets'][0][1] );
795+
}
796+
797+
/**
798+
* Verifies repeated text placeholders are captured.
799+
*
800+
* @ticket 60229
801+
*
802+
* @covers ::get_placeholders
803+
*/
804+
public function test_extracts_repeated_text_placeholders() {
805+
$template = T::from( '<p></%name> and </%name></p>' );
806+
807+
$placeholders = $template->get_placeholders();
808+
809+
$this->assertArrayHasKey( 'name', $placeholders );
810+
$this->assertCount( 2, $placeholders['name']['offsets'] );
811+
}
775812
}

0 commit comments

Comments
 (0)