[wp-trac] [WordPress Trac] #64093: Interactivity API: Performance bottleneck in `data_wp_each_processor` due to repeated template parsing
WordPress Trac
noreply at wordpress.org
Tue Oct 14 09:33:43 UTC 2025
#64093: Interactivity API: Performance bottleneck in `data_wp_each_processor` due
to repeated template parsing
-------------------------------+-----------------------------
Reporter: michelleeby | Owner: (none)
Type: enhancement | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Interactivity API | Version: trunk
Severity: normal | Keywords: has-patch
Focuses: performance |
-------------------------------+-----------------------------
== Summary
A performance bottleneck exists in
WP_Interactivity_API::data_wp_each_processor when it processes a data-wp-
each directive with a large number of items. The current implementation
re-scans the entire inner template HTML for every item in the loop,
leading to exponential performance degradation as the number of items
increases. This ticket proposes an optimized approach using pre-
computation and caching to parse the template only once.
== Problem Description
During a high-traffic load test (500 virtual users) on a production
endpoint for a major enterprise customer, we identified
WP_Interactivity_API::data_wp_each_processor as the primary bottleneck.
New Relic traces consistently showed this single function consuming over
60% of the total request time (e.g., 40.89 seconds).
The root cause of the inefficiency lies in its nested-loop-like behavior:
- The function iterates through the array provided to the data-wp-each
directive (let's call the number of items N).
- Inside every iteration, it instantiates a new WP_HTML_Tag_Processor for
the template and recursively calls $this->process_directives().
- This recursive call forces the WP_HTML_Tag_Processor to scan the
template from the beginning to find all directive tags (let's say there
are M tags to process).
This results in a time complexity of approximately O(N⋅M), where the
expensive work of finding all directive tags within the template is
repeated for every single item in the source array. For a list with
hundreds of items and a template with several directives, this becomes
computationally prohibitive.
== Steps to Reproduce
- Register an interactive block or view script.
- Use the data-wp-each directive on a <template> tag.
- Provide a large array to the directive via wp_interactivity_state(), for
example, an array with 500+ items.
- Inside the <template>, include several elements with other interactivity
directives (e.g., data-wp-text, data-wp-bind:aria-label, data-wp-class).
- Load the page and profile the server response time. You will observe an
extremely high execution time for the data_wp_each_processor method.
== Proposed Solution: Pre-computation and Caching
The proposed solution refactors the processor to adopt a "pre-compute and
cache" strategy. Instead of re-parsing the template on every iteration, we
can build a "blueprint" of the template once, cache it, and then use it to
efficiently process each item.
The new logic is as follows:
- **Blueprint Creation:** On the first encounter of a given template HTML,
create a "blueprint.": Instantiate a WP_HTML_Tag_Processor for the
template. Iterate through it once to find all tags containing data-wp-
directives. For each interactive tag found, create a bookmark using
$p->set_bookmark().
- **Caching:** Store the array of bookmark names in a static class
property (private static $template_blueprints), using an md5 hash of the
template's HTML as the cache key.
- **Optimized Loop:** For each item in the data array: Instantiate a new
WP_HTML_Tag_Processor with the template HTML. Instead of scanning, iterate
through the cached bookmark names. Use $p->seek( $bookmark_name ) to jump
directly to the next interactive tag. Finally, call the original
process_directives() on that specific tag.
I think this change would fundamentally alter the time complexity to
something closer to O(M+N⋅D), where M is the one-time cost of scanning the
template to build the blueprint, and D is the number of interactive
directives that need processing for each of the N items. This would be a
massive performance improvement.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/64093>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list