Skip to content

Core Data: resolve templates from the saved slug, not the edited one - #82515

Open
ramonjd wants to merge 5 commits into
trunkfrom
fix/template-resolution-keydown
Open

ramonjd wants to merge 5 commits into
trunkfrom
fix/template-resolution-keydown

Conversation

@ramonjd

@ramonjd ramonjd commented Sep 7, 2026 •

Copy link
Copy Markdown
Member

What

Template resolution no longer runs while you type in the slug field.

Noticed by @Mamaduka in #78135

Before

Kapture.2026-09-07.at.10.55.24.mp4

After

Kapture.2026-09-07.at.11.02.30.mp4

Why

getTemplateId built its lookup slug from getEditedEntityRecord, which includes unsaved edits. Every keystroke produced a new lookup slug. Each distinct query is its own resolver cache key, so each one fired a GET /wp/v2/templates/lookup request.

Typing hello sent five requests. Four asked about half-typed slugs the user was still in the middle of writing.

The endpoint is a fallback resolver, so each of those returned the same template the post already had. The requests were wasted, not wrong.

How

Read the slug from getRawEntityRecord instead. A slug only selects a template once saved.

The assigned template still comes from the edited record, so picking a template in the UI updates the canvas immediately.

Testing instructions

Open DevTools, Network tab, filter on templates/lookup.

  1. Open a saved post or page.
  2. Type in the Slug field.
  3. On trunk: one request per keystroke, partial slugs visible in the query string (?slug=page-h, ?slug=page-he). With this branch: none.
  4. Save. The template resolves once, from the saved slug.

Also check:

  • A brand-new draft has no saved slug. It should fall back to the page or single-post template.
  • Changing the template in the sidebar dropdown still updates the canvas straight away.
  • After saving a changed slug, the right template still resolves.

getTemplateId derived its template lookup slug from getEditedEntityRecord,
which includes unsaved edits. Typing in the slug field therefore produced a
new lookup slug on every keystroke, and since each distinct query is its own
resolver cache key, each one fired a GET /wp/v2/templates/lookup request.
Typing "hello" sent five requests, four of them for slugs that never existed.

A slug only selects a template once it is saved, so read it from
getRawEntityRecord instead. The explicitly assigned template still comes from
the edited record, so choosing a template in the UI updates the canvas right
away.
@ramonjd
ramonjd requested a review from Mamaduka as a code owner September 7, 2026 01:10
@coderabbitai

coderabbitai Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. To trigger a review, include @coderabbitai review in the PR description. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 0138de82-a977-4c3d-affc-b8594daf6bcc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>
Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

github-actions Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

🤖 PR meta 🤖

📦 Bundle size

Size Change: +15 B (0%)

Total Size: 8 MB

📦 View Changed
Filename Size Change
build/scripts/core-data/index.min.js 37.3 kB +15 B (+0.04%)

7c2865e Run

⚡ Performance

Show the results

Client side metrics exclude the server response time.

front-end-block-theme

Metric f362902 trunk % Change
timeToFirstByte 65.75 ms +2.59% -11.25% 58.3 ms +13.21% -5.49% 12.78%
largestContentfulPaint 96 ms +6.25% -6.25% 92 ms +8.7% -4.35% 4.35%
lcpMinusTtfb 31.9 ms +16.61% -6.43% 31.15 ms +6.9% -2.73% 2.41%
wpBeforeTemplate 35.33 ms +2.43% -18.74% 30.47 ms +16.84% -9.68% 15.95%
wpTemplate 25.56 ms +4.23% -2.46% 24.79 ms +2.99% -4.52% 3.11%
wpTotal 60.86 ms +3.22% -10.52% 54.55 ms +11.93% -6.12% 11.57%
wpMemoryUsage 7.52 MB +0% -0% 7.49 MB +0% -0% 0.45%
wpDbQueries 17 +0% -0% 17 +0% -0% 0%

front-end-classic-theme

Metric f362902 trunk % Change
timeToFirstByte 44.5 ms +13.82% -2.25% 41.6 ms +5.29% -5.89% 6.97%
largestContentfulPaint 92 ms +4.35% -2.17% 84 ms +4.76% -4.76% 9.52%
lcpMinusTtfb 47.25 ms +1.38% -4.13% 42.05 ms +4.04% -2.85% 12.37%
wpBeforeTemplate 26.68 ms +19.42% -2.51% 27.4 ms +9.09% -4.82% -2.63%
wpTemplate 14.61 ms +6.64% -2.67% 10.49 ms +8.77% -2.48% 39.28%
wpTotal 41.49 ms +13.98% -2% 38.36 ms +5.84% -5.08% 8.16%
wpMemoryUsage 5.51 MB +0% -0% 5.37 MB +0% -0% 2.65%
wpDbQueries 14 +0% -0% 10 +0% -0% 40%

media-processing

Metric f362902 trunk % Change
mediaProcessingJpeg 408.12 ms +0.83% -0.89% 402.38 ms +0.87% -0.54% 1.43%
mediaProcessingAvif 6202.95 ms +0.39% -0.18% 6189.91 ms +0.07% -0.43% 0.21%
mediaProcessingJpegToAvif 4404.03 ms +0.14% -0.23% 4395.6 ms +0.15% -0.28% 0.19%

media-upload

Metric f362902 trunk % Change
jpegUploadProcessing 1467.7 ms +32.74% -3.24% 1421.67 ms +0.48% -0.74% 3.24%
pngUploadProcessing 222.8 ms +7.72% -4.17% 217.13 ms +3.06% -1.52% 2.61%
largeJpegUploadProcessing 1405.56 ms +0.86% -0.43% 1422.36 ms +0.67% -0.56% -1.18%
multipleImageUploadProcessing 1569.77 ms +2.46% -0.71% 1577.83 ms +10.44% -0.53% -0.51%

post-editor

Metric f362902 trunk % Change
serverResponse 493.42 ms +4.37% -1.19% 498.6 ms +3.53% -5.71% -1.04%
firstPaint 211.03 ms +30.39% -6.78% 209.12 ms +12.83% -12.46% 0.91%
domContentLoaded 1297.72 ms +0.93% -0.72% 1271.87 ms +0.8% -0.71% 2.03%
loaded 1298.99 ms +0.93% -0.71% 1273.17 ms +0.8% -0.71% 2.03%
firstContentfulPaint 423.01 ms +1.56% -0.47% 423.39 ms +1.11% -8.58% -0.09%
firstBlock 3555.9 ms +0.68% -0.87% 3548.31 ms +1.51% -1.32% 0.21%
type 15.59 ms +6.35% -7.57% 14.44 ms +11.7% -1.73% 7.96%
typeWithoutInspector 15.36 ms +3.78% -8.92% 14.37 ms +5.64% -4.87% 6.89%
typeWithTopToolbar 18.57 ms +4.74% -10.39% 17.9 ms +12.79% -6.48% 3.74%
typeContainer 9.59 ms +5.74% -7.09% 9.21 ms +11.4% -6.62% 4.13%
focus 79.5 ms +10.83% -10.23% 78.35 ms +18.95% -7.86% 1.47%
firstFocus 174.58 ms +0% -0% 168.13 ms +0% -0% 3.84%
selectAll 597.19 ms +1.81% -0.7% 584.19 ms +1.54% -0.67% 2.23%
listViewOpen 71.33 ms +10.61% -6.97% 68.34 ms +4.08% -8.22% 4.38%
inserterOpen 22.15 ms +11.15% -8.13% 23.57 ms +8.87% -8.4% -6.02%
inserterHover 3.41 ms +10.26% -5.28% 3.7 ms +12.7% -6.76% -7.84%
inserterSearch 8.64 ms +1.27% -13.19% 8.42 ms +9.86% -11.16% 2.61%
loadPatterns 633.22 ms +1.16% -1.85% 635.7 ms +3.48% -1.57% -0.39%
wpTotal 483.31 ms +4.49% -1.17% 488.48 ms +3.72% -5.78% -1.06%
wpMemoryUsage 13.06 MB +0% -0% 13.02 MB +0% -0% 0.28%
wpDbQueries 54 +0% -1.85% 54 +0% -1.85% 0%

site-editor

Metric f362902 trunk % Change
serverResponse 508.6 ms +3% -8.53% 509.11 ms +1.96% -4.51% -0.1%
firstPaint 300.68 ms +9.31% -9.58% 265.81 ms +15.51% -14.91% 13.12%
domContentLoaded 1408.95 ms +0.72% -2.14% 1379.2 ms +0.77% -0.86% 2.16%
loaded 1410.14 ms +0.73% -2.13% 1380.42 ms +0.79% -0.85% 2.15%
firstContentfulPaint 438.73 ms +3.14% -1.31% 423.12 ms +1.6% -0.93% 3.69%
firstBlock 4456.6 ms +0.71% -0.19% 4404.83 ms +1.31% -1.06% 1.18%
type 14 ms +10.86% -1.71% 17.08 ms +5.44% -5.15% -18.03%
navigate 101.66 ms +3.7% -12.1% 111.8 ms +20.16% -4.94% -9.07%
loadPatterns 1386.62 ms +8.08% -13.78% 1374.88 ms +6.6% -2.62% 0.85%
loadPages 1122.02 ms +1.49% -1.49% 1135.64 ms +1.13% -3.86% -1.2%
wpTotal 499.07 ms +3.01% -8.71% 499.43 ms +2.09% -4.63% -0.07%
wpMemoryUsage 12.07 MB +0% -0% 12.04 MB +0% -0% 0.23%
wpDbQueries 43 +2.33% -0% 43 +2.33% -0% 0%

7c2865e Run

@github-actions github-actions Bot added the [Package] Core data /packages/core-data label Sep 7, 2026
@ramonjd ramonjd added the [Type] Bug An existing feature does not function as intended label Sep 7, 2026
@ramonjd ramonjd self-assigned this Sep 7, 2026
getRawEntityRecord returns undefined for a record that has never been
saved, not an object with an empty slug. The mock returned the latter, so
the test passed even without the optional chaining that guards it.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused implementation is covered by relevant tests, with no unresolved issues.

Pull request overview

Updates Core Data template resolution to use the saved slug, preventing redundant lookup requests while editing.

Changes:

  • Resolves templates from persisted entity data.
  • Adds coverage for saved, edited, and unsaved slugs.
  • Documents the fix.
File summaries
File Description
packages/core-data/src/test/private-selectors.jsdom.test.js Tests saved, edited, and unsaved slug behavior.
packages/core-data/src/private-selectors.ts Uses the saved slug for template lookup.
packages/core-data/CHANGELOG.md Records the template lookup fix.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@Mamaduka Mamaduka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick follow-up, @ramonjd!

The fix makes sense ✅. However, I'm not sure how useful these new unit tests are. cc @youknowriad

Dropped the test asserting the lookup slug for a saved post: it passes on
trunk too, so it only checked that string concatenation still concatenates.

The two that remain each fail when their defect is reintroduced. One catches
reading the slug from the edited record, the other the crash when a record
has never been saved.
@ramonjd

ramonjd commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

However, I'm not sure how useful these new unit tests are.

Might have gone overboard. I think I can get rid of the first one at least and a bit of the scaffolding. Maybe I can just keep the regression guard.

The mock scaffolding stubbed every dependency of the selector, leaving only
string concatenation under test, and reached into private-apis and the
registry selector's internals to do it. Neither test could assert the thing
that matters, which is that typing sends no lookup requests.
@ramonjd

ramonjd commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

Maybe I can just keep the regression guard.

Let's just rid of them actually. Happy to reinstate, but I don't think they add value. Thanks for the nudge.

@ramonjd
ramonjd enabled auto-merge (squash) September 7, 2026 05:26
@ramonjd
ramonjd disabled auto-merge September 7, 2026 07:13
@youknowriad

Copy link
Copy Markdown
Contributor

I feel like this is not correct though, if you're editing the slug, you want the template that applies to your post now, which means the edited slug.

@Mamaduka

Mamaduka commented Sep 7, 2026

Copy link
Copy Markdown
Member

I feel like this is not correct though, if you're editing the slug, you want the template that applies to your post now, which means the edited slug.

Querying every keystroke isn't ideal either; maybe we can find a good middle ground?

@ramonjd

ramonjd commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

If live preview while typing (rather than resolving from the saved slug here) is required, then I guess we go debounce or how about resolve onBlur?

I think the post and site editors use different slug UIs, so I think we should wait until they're united. I think it's this experiment? #76244

I can close this PR and create an issue to record the problem. I don't have much bandwidth to go deeper on this right now.

@ramonjd

ramonjd commented Sep 7, 2026 •

Copy link
Copy Markdown
Member Author

I think the post and site editors use different slug UIs, so I think we should wait until they're united. I think it's this experiment? #76244

It was late, I was confused 😄 I double checked this claim this morning.

So I think a fix could be in PostURL, but whether it's worth it now or waiting until DataForm's slugField is in place.

PostURL is a public component, and I assume we don't want to debounce in the selector, so my vote for the MVP middle ground would be to extend PostURL with an updateOnBlur prop that ensures one call fires when you leave the field.

Then when DataForm is swapped in we revisit.

@Mamaduka

Mamaduka commented Sep 8, 2026

Copy link
Copy Markdown
Member

Thanks, @ramonjd!

Let's keep this open for now; maybe we'll have a "bingo" moment and solve it without affecting the wider area.

I think PostURL also uses values from the store to display link previews; updating the store onBlur would also mean that previews are delayed, which could be fine, but it's worth keeping in mind.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Core data /packages/core-data [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants