Search Blocks: fix result and filter lists not rendering after results load#49876
Search Blocks: fix result and filter lists not rendering after results load#49876lancewillett wants to merge 2 commits into
Conversation
…s load After @wordpress/interactivity was externalized, the Search Blocks run against the host Interactivity runtime's data-wp-each. That runtime stops re-rendering a data-wp-each list when the bound array's reference is swapped after the initial (empty) render — which is what the store did on every search (`state.results = mapped`). Results and filter buckets rendered nothing even though the store data, the count, and scalar bindings all updated. Mutate the each-bound arrays/objects in place (results, aggregations, retainedFilterOptions, and loadMore's append) instead of reassigning, so the runtime keeps tracking the same container; declare those slots on the client store state for a stable container; and correct the templates' data-wp-key → data-wp-each-key (data-wp-each requires its own key directive). Verified against the live runtime: results and filter facets render again. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 🔴 Action required: Please include detailed testing steps, explaining how to test your change, like so: 🔴 Action required: We would recommend that you add a section to the PR description to specify whether this PR includes any changes to data or privacy, like so: Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! |
Code Coverage SummaryCoverage changed in 1 file.
|
|
@kangzj Requested review (this PR is AI-generated, so likely needs some more testing and validation). See FG-38 for the original report. |
Drop the unreachable type-guard branches from replaceStateArray / replaceStateObject: the slots they touch (results, aggregations, retainedFilterOptions) are declared on the initial state, so they are always the right type. replaceStateObject now deletes only keys absent from the next value before assigning, which also makes a next === current call a safe no-op. This closes the coverage gap CI flagged on the removed branches. Add three tests asserting the each-bound containers keep their reference (toBe) while their contents update: overwriting a kept aggregation key, dropping a stale key, and loadMore appending in place. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Related to FG-38
What
Fix the Search Blocks result list and filter buckets rendering empty after results load.
Why
Once
@wordpress/interactivityis supplied by the host runtime (externalized from the build), thedata-wp-eachdirective stops re-rendering a list when the bound array's reference is replaced after the initial render. The store replaced the arrays on every search (state.results = ( data.results ?? [] ).map( ... ),state.aggregations = remapAggregationsToFilterKeys( ... )).At hydration
state.resultsis the empty seeded array, so the each subscribes to that array instance and renders zero items. The fetch then assigns a brand-new array, so the each never re-renders — even though the store data, the result count, and scalar (data-wp-text/data-wp-bind) bindings all update correctly. Result: the results list and the filter buckets stay empty.Fix
results,aggregations,retainedFilterOptions, andloadMore's append (replaceStateArray/replaceStateObject). This is the load-bearing change.stateso there is always a stable container.data-wp-key→data-wp-each-key;data-wp-eachreads its key from its owneach-keydirective, sodata-wp-keyon the<template>was a no-op.Testing
search(); all search-blocks JS tests pass (597).🤖 Generated with Claude Code