Skip to content

HTML Templating#23

Draft
sirreal wants to merge 53 commits intotrunkfrom
html-api/add-html-templating
Draft

HTML Templating#23
sirreal wants to merge 53 commits intotrunkfrom
html-api/add-html-templating

Conversation

@sirreal
Copy link
Owner

@sirreal sirreal commented Feb 5, 2026

WIP

@sirreal sirreal force-pushed the html-api/add-html-templating branch from 9d8c415 to 54d85bc Compare February 5, 2026 08:42
Replace `extends WP_HTML_Tag_Processor` with an internal anonymous class
that provides accessor methods for the protected properties needed during
template rendering. This improves encapsulation by not exposing the tag
processor's public API on the template class.
Documents the new two-class API (WP_HTML_Template + WP_HTML_Bound_Template)
that enables efficient repeated rendering through lazy compilation and
lightweight bind operations.
Single-class API with strict error handling:
- from() / bind() / render() essential interface
- Immutable bind() returns new instance
- All error conditions return false
- Templates usable as replacement values for HTML injection
Add $compiled property and get_placeholders() accessor. The compile()
method is stubbed and will be implemented to extract placeholder
positions, lengths, and contexts from the template.
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.
Extract placeholders from attribute values using regex. When a
placeholder appears in both text and attribute contexts, promote
to attribute context (more restrictive escaping applies everywhere).
Trigger _doing_it_wrong() for:
- Missing replacement keys (placeholder without value)
- Unused replacement keys (value without placeholder)
- Template values in attribute context

Share compiled data between original and bound template instances
for efficiency.
Replace inline parsing with a render loop that uses pre-compiled
placeholder metadata. Track text normalizations and attribute text
segments during compilation. Apply all updates from end to start
using substr_replace() to preserve positions.

This completes the lazy compilation refactor: compile once on first
use, then reuse cached metadata for subsequent bind/render calls.
Use WP_HTML_Decoder::decode_attribute to decode static attribute text
before re-encoding, preventing double-escaping of existing character
references (e.g. &amp; staying &amp; instead of becoming &amp;amp;).

Also track trailing text segments after the last placeholder within
attribute values, not just leading/inter-placeholder segments.
@sirreal sirreal force-pushed the html-api/add-html-templating branch from 54d85bc to d90142b Compare February 6, 2026 15:54
Documents a proposed refactor to consolidate three separate arrays
(compiled, text_normalizations, attr_escapes) into a unified $edits
array with a separate $placeholder_names index for validation.
…plate

Preparation for unifying $compiled, $text_normalizations, and $attr_escapes
into a single edits array with a separate placeholder name index.

See docs/plans/2026-02-06-unified-edits-array-design.md
Text normalizations are now appended to the unified edits array as
pre-computed replacements. The legacy $text_normalizations array is
retained temporarily for parallel validation during migration.
Text placeholders are now appended to the unified edits array with
context='text'. Placeholder names are also registered in $placeholder_names
for O(1) validation during bind().
Static text segments in attribute values are now decoded and re-encoded
during compilation. Only segments that actually change are added to $edits.
This moves escape computation from render time to compile time.

Also fixes a typo in test_attribute_replacement_is_not_recursive where the
placeholder syntax used `<%/` instead of the correct `</%`.
Attribute placeholders are now appended to the unified edits array with
context='attribute'. Names are registered in $placeholder_names.
Render now iterates the edits array in reverse order instead of building
an intermediate $updates array from three separate sources. Pre-computed
replacements are applied directly; placeholders are looked up and escaped.

Removes usort() call - edits are naturally in document order from compile.

Also ensures bind() copies $edits and $placeholder_names to the new instance.
Validation now uses the pre-built $placeholder_names index for O(1) lookups
instead of iterating through $compiled to build a lookup on each bind() call.
These are now fully superseded by the unified $edits array.
Text normalizations and attribute escapes are stored as pre-computed
replacements in $edits during compile().
Document that $compiled could be derived from $edits on-demand to eliminate
redundant storage, but keeping it for now to preserve get_placeholders() API.
Apply WordPress Coding Standards formatting:
- Align equals signs in assignment blocks
- Format multi-line function calls (strtr) per PEAR standard
Replace the $compiled property with an $is_compiled boolean flag.
The grouped placeholder metadata is now derived on-demand in
get_placeholders() by iterating through the $edits array, eliminating
redundant storage while maintaining identical public API behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant