Skip to content

Navigation: Search all entity types from the Link UI - #82985

Closed
jeryj wants to merge 19 commits into
trunkfrom
update/widen-link-ui-search
Closed

jeryj wants to merge 19 commits into
trunkfrom
update/widen-link-ui-search

Conversation

@jeryj

@jeryj jeryj commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

What?

Closes #77072

Makes the Navigation Link UI search every entity type, instead of only pages. Also, adds functionality that was previously impossible: convert a navigation link block from one type to another (category -> page, page -> category, etc).

Why?

Adding anything but a page to a Navigation means leaving the search box: click the appender, ignore the field that just took focus, click "Add block", pick "Category", land back in a search box, and type (or re-type) what you wanted. The UX is clunky for anything other than the main path.

How?

1. getSuggestionsQuery widens the search from one entity type to many

Previously a navigation link set the query to ONLY search its own type. Now, we search all of them, but pass the navigation link's type as the initial search suggestion type. So, you are in a page link, it will default to showing you just pages when you open it.

// trunk, for a Page Link
{ type: 'post', subtype: 'page', perPage: 20 }

// this PR
{ perPage: 20,
  initialSuggestionsSearchOptions: { type: 'post', subtype: 'page', perPage: 20 } }

Searching a string will now return all entity types that match.

2. transform-suggestions.js shapes what comes back

It receives the results and initial type from the link control, then reorders the results to put its matching type first. So, by default, pages return first, and everything else comes after:

Searching 'co' in a new navigation link item and seeing Contact, Coffee, and Sample Page page results first, followed by Coffee category result

It drops attachments (kind: 'media') as those are not navigation link types AFAIK.

3. Wiring

transformSuggestions is passed from the Navigation Link Block into LinkControl and LinkPicker. There are barely any changes to LinkControl and LinkPicker.

The prop is deliberately absent from the README to default it to Private, matching fetchSuggestions and renderSuggestions on LinkControlSearchInput.

Notes for review

  • noURLSuggestion has had no effect since Improve (and relax) search vs direct URL entry detection in Link Control #51011 removed withURLSuggestion from handleEntitySearch while leaving the argument at the call site. Untouched here; worth its own fix.
  • navigation-list-view.spec.js claimed to assert result types but read the result label, which passed only because the fixtures are titled "Test Page 1/2/3". Fixed in its own commit.

Testing Instructions

  1. Add a Navigation block and click the + appender.
  2. Type the name of a category, tag or post. It should appear with its type shown beside it, and selecting it should insert the matching link block.
  3. Type a word matching both a page and other content. Pages should be listed first.
  4. Click the category link you added and search again. Categories should now be listed first.
  5. Repeat step 2 from the Navigation list view in the Site Editor sidebar.

Screenshots or screencast

Before

Screen.Recording.2026-09-16.at.1.16.51.PM.mov

After

Screen.Recording.2026-09-16.at.1.15.13.PM.mov

🤖 Generated with Claude Code

https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv

@github-actions github-actions Bot added [Package] Block library /packages/block-library [Package] Block editor /packages/block-editor labels Sep 15, 2026
@github-actions

github-actions Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

🤖 PR meta 🤖

📦 Bundle size

Size Change: +828 B (+0.01%)

Total Size: 8.21 MB

📦 View Changed
Filename Size Change
build/scripts/block-editor/index.min.js 499 kB +158 B (+0.03%)
build/scripts/block-library/index.min.js 365 kB +670 B (+0.18%)

712e860 Run

⚡ Performance

Show the results

Client side metrics exclude the server response time.

front-end-block-theme

Metric 38a7b3a trunk % Change
timeToFirstByte 55.65 ms +15.09% -2.96% 55.4 ms +4.33% -1.99% 0.45%
largestContentfulPaint 96 ms +6.25% -8.33% 92 ms +6.52% -4.35% 4.35%
lcpMinusTtfb 35.85 ms +17.85% -4.88% 33.9 ms +9% -1.33% 5.75%
wpBeforeTemplate 27.69 ms +18.92% -0.9% 27.82 ms +7.37% -1.87% -0.47%
wpTemplate 23.87 ms +3.31% -3.02% 23.95 ms +3.01% -2.63% -0.33%
wpTotal 52.15 ms +13.54% -2.99% 51.91 ms +4.32% -1.91% 0.46%
wpMemoryUsage 7.53 MB +0% -0% 7.49 MB +0% -0% 0.46%
wpDbQueries 17 +0% -0% 17 +0% -0% 0%

front-end-classic-theme

Metric 38a7b3a trunk % Change
timeToFirstByte 46.25 ms +8.86% -0.97% 42.35 ms +6.14% -1.65% 9.21%
largestContentfulPaint 100 ms +4% -0% 88 ms +4.55% -0% 13.64%
lcpMinusTtfb 54 ms +0.37% -0.93% 46.3 ms +3.24% -1.62% 16.63%
wpBeforeTemplate 25.92 ms +2.43% -1.89% 25.76 ms +3.92% -1.75% 0.62%
wpTemplate 17.7 ms +1.02% -1.64% 13.6 ms +1.1% -0.96% 30.15%
wpTotal 43.37 ms +8.92% -1.06% 39.65 ms +5.22% -2.04% 9.38%
wpMemoryUsage 6.15 MB +0% -0% 5.97 MB +0% -0% 2.89%
wpDbQueries 14 +0% -0% 10 +0% -0% 40%

media-processing

Metric 38a7b3a trunk % Change
mediaProcessingJpeg 399.32 ms +1.86% -1.36% 396.65 ms +1.2% -1.14% 0.67%
mediaProcessingAvif 6043.28 ms +0.35% -0.06% 6059.55 ms +0.08% -0.23% -0.27%
mediaProcessingJpegToAvif 4170.53 ms +0.71% -0.07% 4169.79 ms +0.09% -0.1% 0.02%

media-upload

Metric 38a7b3a trunk % Change
jpegUploadProcessing 1437.06 ms +36.19% -2.23% 1418.52 ms +0.53% -0.91% 1.31%
pngUploadProcessing 212.96 ms +9.73% -14.57% 210.13 ms +15.19% -3.43% 1.35%
largeJpegUploadProcessing 1411.73 ms +0.8% -0.85% 1408.14 ms +0.16% -0.45% 0.25%
multipleImageUploadProcessing 1619.84 ms +7.11% -3.71% 1571.99 ms +0.35% -1.36% 3.04%

post-editor

Metric 38a7b3a trunk % Change
serverResponse 485.91 ms +4.62% -3.29% 473.95 ms +1.95% -5.92% 2.52%
firstPaint 243.24 ms +17.85% -13.39% 255.84 ms +4.52% -13.52% -4.92%
domContentLoaded 1075.52 ms +1.22% -1.67% 1061 ms +0.94% -1.03% 1.37%
loaded 1076.89 ms +1.24% -1.66% 1062.12 ms +0.95% -1.02% 1.39%
firstContentfulPaint 442.17 ms +2.05% -4.98% 420.77 ms +4.17% -0.66% 5.09%
firstBlock 3212.31 ms +0.92% -1.05% 3158.53 ms +0.96% -0.87% 1.7%
type 19.96 ms +4.81% -5.11% 19.16 ms +9.5% -1.15% 4.18%
typeWithoutInspector 19.42 ms +6.08% -2.63% 19.92 ms +2.36% -6.73% -2.51%
typeWithTopToolbar 26.81 ms +3.66% -7.46% 24.39 ms +4.76% -6.89% 9.92%
typeContainer 8.68 ms +7.49% -8.06% 8.92 ms +17.15% -7.62% -2.69%
focus 77.38 ms +4.59% -7.9% 70.87 ms +6.93% -4.33% 9.19%
firstFocus 205.38 ms +0% -0% 204.87 ms +0% -0% 0.25%
selectAll 505.62 ms +4.26% -4.31% 508.66 ms +7.97% -2.18% -0.6%
listViewOpen 74.4 ms +9.14% -3.48% 72.23 ms +6.55% -5.86% 3%
inserterOpen 24.68 ms +4.82% -9.56% 23.46 ms +15.98% -8.35% 5.2%
inserterHover 3.13 ms +10.86% -3.19% 3.22 ms +9.32% -7.76% -2.8%
inserterSearch 7.77 ms +15.57% -8.88% 7.98 ms +9.4% -5.14% -2.63%
loadPatterns 633.61 ms +3.72% -3.98% 651.97 ms +4.29% -5.92% -2.82%
wpTotal 476.14 ms +4.59% -3.77% 463.9 ms +2.02% -6.04% 2.64%
wpMemoryUsage 13.04 MB +0% -0% 13.01 MB +0% -0% 0.28%
wpDbQueries 54 +0% -0% 54 +0% -1.85% 0%

site-editor

Metric 38a7b3a trunk % Change
serverResponse 489.56 ms +4.36% -2.48% 458.58 ms +3.65% -1.21% 6.76%
firstPaint 280.8 ms +61.11% -5.53% 254.27 ms +3.97% -5.59% 10.43%
domContentLoaded 1131.08 ms +0.55% -1.05% 1132.08 ms +1.31% -0.36% -0.09%
loaded 1132.35 ms +0.55% -1.05% 1133.29 ms +1.33% -0.38% -0.08%
firstContentfulPaint 450.77 ms +0.94% -2.7% 445.65 ms +3.31% -1.68% 1.15%
firstBlock 4154.85 ms +2.12% -1.17% 4153.76 ms +0.55% -0.26% 0.03%
type 19.83 ms +7.21% -3.43% 19.1 ms +4.97% -1.94% 3.82%
navigate 106.02 ms +20.55% -6.97% 119 ms +8.65% -3.9% -10.91%
loadPatterns 1438.53 ms +11.1% -9.2% 1380.19 ms +15.17% -5.28% 4.23%
loadPages 1057.83 ms +1.11% -0.86% 1071.77 ms +1.06% -0.51% -1.3%
wpTotal 479.8 ms +4.44% -2.41% 449.02 ms +3.64% -1.48% 6.85%
wpMemoryUsage 12.01 MB +0% -0% 11.97 MB +0% -0% 0.31%
wpDbQueries 43 +2.33% -0% 43 +2.33% -0% 0%

712e860 Run

@jeryj
jeryj requested a balanced review from Copilot September 15, 2026 20:49
@jeryj jeryj added [Feature] Link Editing Link components (LinkControl, URLInput) and integrations (RichText link formatting) and removed [Package] Block library /packages/block-library [Package] Block editor /packages/block-editor labels Sep 15, 2026
@jeryj jeryj added the [Type] Enhancement A suggestion for improvement. label Sep 15, 2026

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.

🟡 Changes recommended

Unscoped results introduce incorrect entity labeling, relevance ordering, and mixed-version compatibility problems.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Enables Navigation link search across all supported entity types while prioritizing the current link type.

Changes:

  • Adds suggestion transformation APIs and documentation.
  • Filters media and prioritizes relevant entity types.
  • Adds unit and end-to-end coverage.
File summaries
File Description
test/e2e/specs/editor/blocks/navigation.spec.js Tests multi-entity Navigation searches.
packages/block-library/src/navigation-link/shared/controls.jsx Applies transformations in inspector controls.
packages/block-library/src/navigation-link/link-ui/transform-suggestions.js Filters and prioritizes suggestions.
packages/block-library/src/navigation-link/link-ui/test/transform-suggestions.test.js Tests suggestion transformation.
packages/block-library/src/navigation-link/link-ui/test/get-suggestions-query.test.js Tests unscoped queries and initial suggestions.
packages/block-library/src/navigation-link/link-ui/index.jsx Integrates transformed suggestions.
packages/block-library/src/navigation-link/link-ui/get-suggestions-query.js Builds unscoped search queries.
packages/block-editor/src/components/link-picker/link-picker.jsx Forwards the transformation callback.
packages/block-editor/src/components/link-control/use-search-handler.js Transforms fetched results.
packages/block-editor/src/components/link-control/test/index.jsdom.test.jsx Tests the new callback contract.
packages/block-editor/src/components/link-control/search-input.jsx Passes transformations to the search handler.
packages/block-editor/src/components/link-control/README.md Documents the new prop.
packages/block-editor/src/components/link-control/index.jsx Exposes the new LinkControl prop.
packages/block-editor/CHANGELOG.md Records the enhancement.
Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

const { isInitialSuggestions } = suggestionsQuery;

const results = await fetchSearchSuggestions( val, suggestionsQuery );
let results = await fetchSearchSuggestions( val, suggestionsQuery );
Comment thread packages/block-library/src/navigation-link/link-ui/get-suggestions-query.js Outdated
normalizeType( suggestion.type ) === priority.type &&
suggestion.kind === priority.kind;

( isPriority ? prioritised : rest ).push( suggestion );
@github-actions github-actions Bot added [Package] Block library /packages/block-library [Package] Block editor /packages/block-editor labels Sep 16, 2026
@jeryj
jeryj marked this pull request as ready for review September 16, 2026 18:44
@github-actions

github-actions Bot commented Sep 16, 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: jeryj <jeryj@git.wordpress.org>
Co-authored-by: scruffian <scruffian@git.wordpress.org>
Co-authored-by: getdave <get_dave@git.wordpress.org>
Co-authored-by: hanneslsm <hanneslsm@git.wordpress.org>

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

@jeryj jeryj self-assigned this Sep 16, 2026
@jeryj
jeryj requested a balanced review from Copilot September 16, 2026 20:10

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.

🟡 Changes recommended

Unresolved critical and moderate findings affect custom entity links, package compatibility, and result completeness.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 11/11 changed files
  • Comments generated: 3
  • Review effort level: Lite (auto)

Note

Copilot is running an experiment and ran this review at Lite.

Comment on lines 48 to +52
if ( kind === 'taxonomy' ) {
return { type: 'term', subtype: type, perPage };
return { type: 'term', subtype: type };
}
if ( kind === 'post-type' ) {
return { type: 'post', subtype: type, perPage };
return { type: 'post', subtype: type };
Comment on lines +245 to +246
suggestionsQuery={ getSuggestionsQuery( type, kind ) }
transformSuggestions={ transformSuggestions }
Comment on lines +57 to +58
if ( UNSUPPORTED_KINDS.includes( suggestion.kind ) ) {
continue;

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.

This is a good point, but I can't see an easy fix. I think we would need to update Core Data to that fetchLinkSuggestions can take an array of types. Probably worth a followup, or maybe we decided to do that first?

jeryj added a commit that referenced this pull request Sep 16, 2026
The front page and blog home checks compared ids alone. Posts, terms and
media are separate tables, so ids collide: on a fresh site "Hello world!"
and "Uncategorized" are both id 1. Unscoped searches put both kinds in one
result list, so a term could be labelled "Front page".

Reported by Copilot on #82985.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
Comment thread packages/block-editor/CHANGELOG.md Outdated

### Internal

- `LinkControl`: Add an undocumented `transformSuggestions` prop, so a consumer can filter and order search suggestions before they are shown ([#82985](https://github.com/WordPress/gutenberg/pull/82985)).

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.

I don't think simply not documenting the prop is sufficient for us to remove it in future as its still possible someone used it (especially now with AI). Either we should make it public or private.

One option is to private component that adds the prop and wraps LinkControl. That way the prop is only available in the private component. We did this for the ListView component. Happy to help if you think it's a good idea.

@jeryj jeryj Sep 17, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm fine making it public as well. I think it's a useful feature to be able to filter results. I didn't want to assume to make it public from the start though.


await expect(
searchResults.getByRole( 'option' ).first()
).toContainText( DEFAULT_CATEGORY_NAME );

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.

This would also match the page fixture called ${ DEFAULT_CATEGORY_NAME } Notes, so I think we need more strict matching, or to use a different name in the fixture.

Comment thread packages/block-library/src/navigation-link/link-ui/index.jsx
Comment thread test/e2e/specs/editor/blocks/navigation-list-view.spec.js Outdated
Comment thread packages/block-library/src/navigation-link/link-ui/transform-suggestions.js Outdated

@getdave getdave 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.

Thanks for tackling this, @jeryj. The round trip through "Add block" to insert other types has been a genuine problem. #77072 lays it out well.

I want to flag a concern before this merges, because I seem to recall we've been here before.

#48740 made the Nav appender default to a Page link, and it got reverted within two weeks in #49126 because categories stopped appearing in search at all. This PR avoids that specific failure by widening the query instead of narrowing it, but I think it inherits the same root cause from the other direction.

fetchLinkSuggestions merges every entity kind into one list and truncates it to perPage before transformSuggestions ever sees it. If a search term happens to match a lot of posts or media, those can fill the shared 20-slot budget and get discarded by the media filter, or just crowd out a relevant page, before the reordering has anything left to work with.

I looks like @scruffian's review comment confirms this and that there is no easy fix here without Core Data supporting an array of types.

None of this is a reason to drop the discoverability fix. But "search everything, then reorder client-side over a shared, truncated pool" feels like the wrong move. What we probably need is a dedicate link search handler and REST API endpoint. In fact I think Classic WP had this for the Classic Editor?

Would it be worth tackling the Core Data change first, so Navigation can ask for results per type instead of reordering whatever's left after truncation? Keen to hear what you both think.

This doesn't need to block the discoverability win indefinitely. I just want to make sure we're not moving sideways/backwards here.

@jeryj

jeryj commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks for the reviews @getdave and @scruffian!

The 20 search results maybe not including the desired type is an issue I hadn't considered. Glad y'all caught this.

there is no easy fix here without Core Data supporting an array of types.

I think this would only help with solving search for media types, and I'm not sure they even can be searched this way (update: attachments are returned. It would be best to have the array of types for search). We would still want to search all types (except media).

One idea to solve this now: Parallel requests. I want to try two searches, one for our specific type and one global, then filter and append the global search. That should give us at least X results from our specific type, then allow other top matches from other types to still be available.

jeryj and others added 11 commits September 18, 2026 10:10
Threading the callback down into useSearchHandler meant it only applied
to the generic handler, so a consumer passing fetchSuggestions had its
transform silently ignored. Wrap the handler in search-input instead: it
applies to whichever handler is in use, and use-search-handler goes back
to matching trunk exactly, which also removes the unused withURLSuggestion
parameter that the old argument order forced.

Hold the "CREATE" option back and re-append it, so it still always comes
last and consumers never see a suggestion that is not a real entity.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
Drop PrivateLinkControl. LinkControlSearchInput already carries
fetchSuggestions and renderSuggestions as real props that are absent from
the README and therefore unsupported, so transformSuggestions follows that
instead of adding a new privateApis export. private-apis.js returns to
matching trunk.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
It was only handed back out again. The helper answers which entity the
block points at; pagination belongs to the caller.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
normalizeEntity applied the page fallback to suggestions as well as to
block attributes, which is a category error: "what should a link with no
entity prioritise" is a question about the block. It also had a concrete
cost. LinkControl's "Create page" row carries no kind, so it took the
fallback, matched the priority of a freshly appended item, and sorted
above every real page.

Return null for anything that is not an entity and keep the fallback at
the one call site that wants it. Non-entities are then never a match, so
the create row stays where it arrived, and the hold-and-re-append in
search-input goes away.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
Per the repository's testing guidance, one behaviour per case and no
adjacent coverage:

- The LinkControl pair asserting the call arguments and asserting the
  rendered output were two halves of one pass-through. Neither stood
  alone, so they are now one case covering both.
- "removes attachment results" and "keeps posts, pages and terms" were
  the same filtering behaviour asserted twice.
- The two page-fallback cases differ only by input, so they are an
  it.each.
- The alias case only covered `tag`. Covering both aliases closes the
  `post_format` gap: verified by deleting that alias, which fails only
  the new case.

Also fixes indentation in search-input that Prettier flagged once the
merged lockfile's dependencies were installed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
WordPress always has "Uncategorized", so the specs no longer create a
category and no longer hand-roll term cleanup. requestUtils has no
deleteAllTerms, and createRecord rejects a duplicate name with
term_exists, so an interrupted run used to break every later run at
setup. Nothing to leave behind now.

The inspector test seeds a page sharing that word, so one search still
returns both a page and a term and their order can be asserted.

Also strengthens the non-entity case. It asserted that the "Create page"
option stayed last in a list where the other suggestion was itself the
priority, so order was preserved either way and the test passed even with
the guard removed. Against a category it fails as intended.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
- Make transformSuggestions a documented public prop. Leaving it out of
  the README does not stop anyone depending on it, so the choice is
  public or genuinely private, and filtering results is useful on its
  own.
- Match custom types whose slug contains a hyphen. updateAttributes
  stores the first hyphen as an underscore, so normalize the same way
  here. That also makes the post_format alias redundant, leaving `tag`
  as the only name the block and the API disagree on.
- The category assertion in the inspector test matched the page fixture
  "Uncategorized Notes" too, so assert on the type instead.
- The list view search assertions could pass against the initial
  suggestions, which are pages. Wait for a result that only the typed
  search can produce first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
An unscoped search merges four requests and keeps the most relevant
twenty of the merged list, so the link's own type can be crowded out
before the results arrive. Searching "e" against a site with thirteen
pages returns twenty suggestions with no page among them.

Run a second request scoped to the link's own type alongside the first
and merge the two, so that type is always represented. Deduplicate on
kind, type and id together, since ids repeat across post types and
taxonomies.

Order the merged list as:

1. One result of another type, but only when it matches what was typed
   better than anything of the link's own type does. Searching
   "uncategorized" from a Page Link leads with that category; searching
   "contact" when a page is called "Contact" does not, because the page
   already answers it. Ignored below four characters, where a search is
   too vague to call any match obvious.
2. Up to three of the link's own type.
3. Everything else, by how well it matches, keeping the relevance order
   the results arrived in within each tier.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
A whole-title match was treated as better than a start-of-title match, so
searching "coffee" from a Page Link led with a category called "Coffee"
even though a page called "Coffee Guide" matched every character typed.
A shorter title is not a better answer.

Another type now leads only when nothing of the link's own type matches
at all. Tiers still order results within a group, so a whole-title match
still sorts above a start-of-title one among pages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
Dropping every attachment took something away that trunk offers. A Page
Link only ever queried pages, so media never reached it, but Custom Link
has no top level type in its query and is already unscoped: searching
"image" from one on a site with a media library returns attachments
today. That is the one link that can point at a file, since it is an
arbitrary URL rather than a bound entity.

So the filter now applies to everything except a Custom Link, where
`media` stays. Widening adds posts, categories, tags and formats to the
typed links without also adding files to them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLn4hqAvfFyNGLLgsSkCcv
@hanneslsm

Copy link
Copy Markdown

Thanks for working on this. I tested it in Playground, and it feels like a much smoother UX.

I’m not sure whether the /scope: on the right comes from this PR or from Playground, but this could be confusing for users.

image

Another thing that might become more relevant now is that we don’t have a “No results found” state, since this is neither a page nor a category, etc.

image

I’m also curious whether it would be relatively easy to add anchor links to the Link UI. It’s currently a big PITA to link to an anchor. Related: #9660

@jeryj

jeryj commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review, @hanneslsm! The /scope should be coming from playground based on how the link picker parses what the URL is. That isn't changed in this PR.

As for an empty state, that would be a good addition. It's the same as trunk though. If there's not already an open issue for that, could you create one?

For Anchor links, are you hoping for the Anchor links to be searchable from the link control?

@hanneslsm

Copy link
Copy Markdown

As for an empty state, that would be a good addition. It's the same as trunk though. If there's not already an open issue for that, could you create one?

Yes, done: #83324

For Anchor links, are you hoping for the Anchor links to be searchable from the link control?

Correct. I often have a button in the navigation ("Contact us now") which links to the #contact anchor on the front page. Currently, the easiest way is to use a custom link, but it would be great if I could select the anchor directly in the Link UI, just like a page or post.

@jeryj

jeryj commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor Author

I often have a button in the navigation ("Contact us now") which links to the #contact anchor on the front page.

Oh, so it would be an anchor link on a separate page? Not an internal page anchor link? I'll be honest, I think that'd be a big lift to implement, and I see a lot of complexity in how to integrate this in a way that doesn't make the base experience more difficult. Feel free to explore it though if you feel strongly about it!

Thanks for creating #83324!

@jeryj

jeryj commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of #83408 and #83407

@jeryj jeryj closed this Sep 22, 2026
@hanneslsm

hanneslsm commented Sep 23, 2026 •

Copy link
Copy Markdown

Not an internal page anchor link?

Even linking to an internal page would be a huge improvement for every one-pager websites.

@jeryj

jeryj commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

@hanneslsm

Even linking to an internal page would be a huge improvement for every one-pager websites.

This might be more easily doable! Feel free to open an issue!

@hanneslsm

hanneslsm commented Sep 23, 2026 •

Copy link
Copy Markdown

This might be more easily doable! Feel free to open an issue!

Great to hear! I think this already is about the problem: #9660

jeryj added a commit that referenced this pull request Oct 1, 2026
Let a consumer filter, order or add to the search suggestions before they
are shown. It runs inside the entity search, after the fetch and before the
front page is labeled and the "create" option is added, so that option
always stays last. URL input skips it.

A suggestion the transform adds can bring its own icon and type label.

Ported from the review work on #82985.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lxqx12sRhNixE8aH4FAfm2
jeryj added a commit that referenced this pull request Oct 1, 2026
Let a consumer filter, order or add to the search suggestions before they
are shown. It runs inside the entity search, after the fetch and before the
front page is labeled and the "create" option is added, so that option
always stays last. URL input skips it.

A suggestion the transform adds can bring its own icon and type label.

Ported from the review work on #82985.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lxqx12sRhNixE8aH4FAfm2
jeryj added a commit that referenced this pull request Oct 1, 2026
Let a consumer filter, order or add to the search suggestions before they
are shown. It runs inside the entity search, after the fetch and before the
front page is labeled and the "create" option is added, so that option
always stays last. URL input skips it.

A suggestion the transform adds can bring its own icon and type label.

Ported from the review work on #82985.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lxqx12sRhNixE8aH4FAfm2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Link Editing Link components (LinkControl, URLInput) and integrations (RichText link formatting) [Package] Block editor /packages/block-editor [Package] Block library /packages/block-library [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support additional link types in navigation item creation

5 participants