[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
Sat Oct 25 09:37:12 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             |  Resolution:
 Keywords:  has-patch          |     Focuses:  performance
-------------------------------+------------------------------

Comment (by michelleeby):

 == Revised Patch 2: Directive Caching

 Previous attempts to optimize
 `WP_Interactivity_API::data_wp_each_processor` included 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. However, this solution did not consider how
 the WP_HTML_Tag_Processor is designed.

 As far as I can tell, the WP_HTML_Tag_Processor architecture works by:

 - Sequentially scanning HTML to find tags (via strpos, strcspn, etc.)
 - Tracking positions as byte offsets
 - Modifying HTML through WP_HTML_Text_Replacement objects

 It seems there's no way to "jump to position X" without scanning from the
 beginning. Byte offsets shift as HTML is modified, and bookmarks are
 designed for single-pass processing, not cross-rendering reuse.

 Looking more carefully at the bottleneck, the real issue is that for each
 item in the array, the code:

 1. Create a new WP_Interactivity_API_Directives_Processor
 2. Call $p->next_tag() repeatedly (which does expensive string scanning)
 3. Call get_attribute_names_with_prefix('data-wp-') for each tag
 4. Parse directive names and extract values
 5. Evaluate directives

 The optimization opportunity is steps 2-4, not step 5. The code can't
 avoid re-scanning the HTML (that's how the Tag Processor works), but it
 can cache what it learned about where directives are and what they are.


 == Steps to Reproduce the Bottleneck

 1. Download, install and activate "interactive-stress-test.zip" which is
 attached to the ticket.
 2. The plugin creates 3 posts, "Stress Test – Light", "Stress Test –
 Medium", "Stress Test – Heavy". View "Stress Test - Light" on the
 frontend.
 3. Navigate to the Medium and Heavy posts on the frontend. In browser
 console, observe the time that the "Interactivity API processed in".

 == Steps to Run Experiments

 1. Navigate to the "Stress Test – Light" post on the frontend.
 2. Click the "Run Batch Test (10x)" button
 3. Follow the pop up prompts. They will guide you through the medium and
 heavy tests and ask to save the results as a CSV. The results can also be
 seen in the browser console.

 == Results

 **Core WordPress**

 ''Summary Statistics''

 ||= Variation =||= Runs =||= Avg Time (ms) =||= Min Time (ms) =||= Max
 Time (ms) =||
 ||light        ||   10   ||     231.68      ||     196.20      ||
 275.80      ||
 ||medium       ||   10   ||     562.00      ||     511.10      ||
 698.40      ||
 ||heavy        ||   10   ||    1081.62      ||    1051.30      ||
 1148.80      ||

 ''Individual Run Data''

 ||= Variation =||= Run 1  =||= Run 2  =||= Run 3  =||= Run 4  =||= Run 5
 =||= Run 6  =||= Run 7  =||= Run 8  =||= Run 9  =||= Run 10  =||
 ||light        ||  215.00  ||  196.20  ||  226.20  ||  263.10  ||  218.70
 ||  272.20  ||  207.00  ||  211.60  ||  275.80  ||   231.00  ||
 ||medium       ||  514.70  ||  546.30  ||  646.90  ||  514.00  ||  554.70
 ||  591.10  ||  698.40  ||  524.10  ||  511.10  ||   518.70  ||
 ||heavy        || 1051.30  || 1053.60  || 1062.00  || 1053.60  || 1072.20
 || 1069.30  || 1148.80  || 1101.50  || 1098.00  ||  1105.90  ||

 **Patched WordPress**

 ''Summary Statistics''

 ||= Variation =||= Runs =||= Avg Time (ms) =||= Min Time (ms) =||= Max
 Time (ms) =||
 ||light        ||   10   ||     201.12      ||     152.80      ||
 362.50      ||
 ||medium       ||   10   ||     392.73      ||     366.00      ||
 437.40      ||
 ||heavy        ||   10   ||     796.62      ||     756.80      ||
 838.30      ||

 ''Individual Run Data''

 ||= Variation =||= Run 1 =||= Run 2 =||= Run 3 =||= Run 4 =||= Run 5 =||=
 Run 6 =||= Run 7 =||= Run 8 =||= Run 9 =||= Run 10 =||
 ||light        || 165.20  || 168.10  || 362.50  || 193.80  || 158.10  ||
 152.80  || 157.20  || 175.10  || 254.10  ||  224.30  ||
 ||medium       || 384.50  || 369.60  || 411.60  || 366.00  || 405.30  ||
 400.30  || 437.40  || 372.30  || 398.70  ||  381.60  ||
 ||heavy        || 756.80  || 791.20  || 799.30  || 776.90  || 787.20  ||
 772.20  || 818.70  || 838.30  || 803.60  ||  822.00  ||

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/64093#comment:3>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list