Skip to content

Add search and filters to the All Notes sidebar - #84060

Open
adamsilverstein wants to merge 10 commits into
trunkfrom
add/notes-sidebar-filter
Open

adamsilverstein wants to merge 10 commits into
trunkfrom
add/notes-sidebar-filter

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Search and filters for the "All notes" sidebar, so a thread can be found in a long list.

Fixes #84058

Claude wrote this one up after building it:

What?

Fixes #84058

Adds a search field and filters at the top of the "All notes" sidebar, under the heading and above the thread list:

  • Search matches the text of a note and its replies (case insensitive, markup ignored).
  • Status: All, Open, or Resolved.
  • Author: matches threads where the person wrote the note or any reply. Only shown when more than one person has left notes.

When nothing matches, the sidebar says "No notes found." instead of showing the new note form. The floating notes are unchanged.

Why?

Once a post has a lot of notes, the sidebar is hard to scan. This gets more pressing as Suggestion mode (#73411) adds more entries to the same list.

How?

  • A new notes-filters.tsx holds the controls (SearchControl and SelectControl from @wordpress/components) and a pure filterNotes() helper.
  • Filter state lives in NotesSidebar as local state, not a preference, following @Mamaduka's feedback on Notes Sidebar: Add filtering options for resolved/open Notes #75982 about not persisting filters yet.
  • The selected thread always stays in the list, so opening a note from the canvas still works while a filter is active.

Not included yet

The issue also asks for a kind filter (comment vs. insert / delete / replace / attribute suggestion) and accepted / rejected statuses. Those only exist once Suggestion mode lands, so they are left out here. Adding them later should only mean extending the options and the filterNotes() check.

Related

Testing Instructions

Test in WordPress Playground

  1. Open a post and add notes to three or four blocks. Resolve one of them.
  2. Open the "All notes" sidebar.
  3. Type in the search field and check that only matching threads show, including matches in replies.
  4. Search for something that doesn't exist and check "No notes found." appears.
  5. Clear the search, then switch Status to Resolved and Open.
  6. As a second user, add a note or reply. Check that the Author filter appears and narrows the list.
  7. With a filter active, click a note indicator on a block whose note is filtered out. The note should still open in the sidebar.

Automated: filterNotes() has unit tests (including the author filter, which would need a second user in e2e), and a new e2e test in block-notes.spec.js covers search, the empty state, and the status filter.

Screenshots

All notes Searching "image"
All notes with filters Search results

Screencast

notes-sidebar-filter-84060.mp4

AI Use

Claude Code drafted both the code and this description while I steered. I will review and test.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VQpfAuMvYyYfwPAmcavDSk

A long list of notes is hard to scan. Add a search field plus status and
author filters above the thread list so a thread can be found quickly.
The selected thread stays visible so opening a note from the canvas
still works while a filter is active.

Claude-Session: https://claude.ai/code/session_01VQpfAuMvYyYfwPAmcavDSk
@adamsilverstein adamsilverstein added [Type] Enhancement A suggestion for improvement. [Feature] Notes Phase 3 of the Gutenberg roadmap around block commenting labels Oct 4, 2026
@github-actions github-actions Bot added the [Package] Editor /packages/editor label Oct 4, 2026
@github-actions

github-actions Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

🤖 PR meta 🤖

🎉 Props

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: adamsilverstein <adamsilverstein@git.wordpress.org>
Co-authored-by: yashjawale <yashjawale@git.wordpress.org>
Co-authored-by: annezazu <annezazu@git.wordpress.org>
Co-authored-by: jasmussen <joen@git.wordpress.org>
Co-authored-by: sethrubenstein <smrubenstein@git.wordpress.org>

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

Updated as activity occurs, without notifying anyone named here. Add the props-bot label to refresh.

📦 Bundle size

Size Change: +1.23 kB (+0.01%)

Total Size: 8.52 MB

📦 View Changed
Filename Size Change
build/scripts/editor/index.min.js 637 kB +736 B (+0.12%)
build/styles/editor/style-rtl.css 32.7 kB +125 B (+0.38%)
build/styles/editor/style-rtl.min.css 27.8 kB +125 B (+0.45%)
build/styles/editor/style.css 32.8 kB +122 B (+0.37%)
build/styles/editor/style.min.css 27.8 kB +120 B (+0.43%)

e353acc Run

⚡ Performance

Show the results

Client side metrics exclude the server response time.

front-end-block-theme

Metric be8d248 trunk % Change
timeToFirstByte 36 ms +14.86% -4.31% 35.45 ms +6.35% -3.53% 1.55%
largestContentfulPaint 68 ms +0% -11.76% 64 ms +0% -6.25% 6.25%
lcpMinusTtfb 26.65 ms +25.52% -3% 26.55 ms +9.04% -3.2% 0.38%
wpBeforeTemplate 18.88 ms +8.42% -3.97% 18.7 ms +7.27% -2.46% 0.96%
wpTemplate 13.45 ms +9.22% -2.01% 13.53 ms +6.21% -5.25% -0.59%
wpTotal 32.46 ms +13% -3.36% 32.45 ms +6.47% -4.31% 0.03%
wpMemoryUsage 7.61 MB +0% -0% 7.58 MB +0% -0% 0.46%
wpDbQueries 17 +0% -0% 17 +0% -0% 0%

front-end-classic-theme

Metric be8d248 trunk % Change
timeToFirstByte 26.75 ms +7.66% -1.87% 26.85 ms +7.64% -2.23% -0.37%
largestContentfulPaint 64 ms +3.13% -6.25% 62 ms +3.23% -3.23% 3.23%
lcpMinusTtfb 36.95 ms +3.25% -5.41% 33.75 ms +7.11% -1.78% 9.48%
wpBeforeTemplate 16.85 ms +8.37% -4.45% 16.35 ms +13.03% -1.53% 3.06%
wpTemplate 7.66 ms +5.35% -3% 7.62 ms +7.35% -3.54% 0.52%
wpTotal 24.36 ms +8.37% -2.13% 24.27 ms +8.41% -2.27% 0.37%
wpMemoryUsage 6.14 MB +0% -0% 6.10 MB +0% -0% 0.59%
wpDbQueries 10 +0% -0% 10 +0% -0% 0%

media-processing

Metric be8d248 trunk % Change
mediaProcessingJpeg 228.5 ms +4% -2.22% 228.4 ms +0.18% -1.02% 0.04%
mediaProcessingAvif 3714.87 ms +0.52% -0.12% 3750.65 ms +1% -0.91% -0.95%
mediaProcessingJpegToAvif 2561.82 ms +0.75% -0.58% 2573.51 ms +0.68% -1.31% -0.45%

media-upload

Metric be8d248 trunk % Change
jpegUploadProcessing 1406.28 ms +1.49% -35.67% 884.64 ms +1.32% -0.69% 58.97%
pngUploadProcessing 176.82 ms +11.13% -3.44% 164.48 ms +8.68% -5.19% 7.5%
largeJpegUploadProcessing 910.79 ms +0.78% -1.87% 901.63 ms +0.88% -1.08% 1.02%
multipleImageUploadProcessing 1058.47 ms +9.65% -2.83% 1040.97 ms +47.86% -5.34% 1.68%

post-editor

Metric be8d248 trunk % Change
serverResponse 514.09 ms +5.18% -4.77% 524.19 ms +1.6% -5.58% -1.93%
firstPaint 233.48 ms +11.77% -14.46% 227.92 ms +26.05% -7.8% 2.44%
domContentLoaded 1181.82 ms +0.84% -0.78% 1196.3 ms +1.04% -1.09% -1.21%
loaded 1183.19 ms +0.84% -0.79% 1197.68 ms +1.07% -1.09% -1.21%
firstContentfulPaint 491.8 ms +1.26% -1.19% 503.12 ms +1.48% -1.29% -2.25%
firstBlock 3449.67 ms +1.25% -0.6% 3514.47 ms +0.99% -1.34% -1.84%
type 17.65 ms +6.06% -3.12% 18.83 ms +6.85% -4.09% -6.27%
typeWithoutInspector 17.78 ms +10.97% -1.86% 19.14 ms +5.17% -6.58% -7.11%
typeWithTopToolbar 24.79 ms +4.72% -7.06% 24.28 ms +1.07% -3.38% 2.1%
typeContainer 8.78 ms +11.16% -2.16% 9 ms +10% -9.56% -2.44%
focus 118.77 ms +6.74% -7.54% 117.67 ms +5.03% -7.39% 0.93%
firstFocus 231 ms +0% -0% 232.49 ms +0% -0% -0.64%
selectAll 574.07 ms +6.34% -1.14% 559.42 ms +17.23% -0.66% 2.62%
listViewOpen 84.25 ms +7.26% -8.78% 76.14 ms +5.27% -2.1% 10.65%
inserterOpen 40.8 ms +17.4% -5.47% 42.67 ms +8.93% -4.38% -4.38%
inserterHover 11.77 ms +9.86% -5.44% 13.28 ms +11.37% -8.73% -11.37%
inserterSearch 8.82 ms +12.02% -8.5% 9.58 ms +0.84% -4.91% -7.93%
loadPatterns 643.12 ms +4.8% -3.39% 741.07 ms +4.36% -4.61% -13.22%
wpTotal 502.97 ms +4.98% -4.93% 512.5 ms +1.67% -5.8% -1.86%
wpMemoryUsage 13.33 MB +0% -0% 13.30 MB +0% -0% 0.25%
wpDbQueries 54 +0% -1.85% 54 +0% -1.85% 0%

site-editor

Metric be8d248 trunk % Change
serverResponse 246.1 ms +6.14% -4.64% 258.39 ms +5.02% -5.5% -4.76%
firstPaint 175.31 ms +83.05% -8% 240.58 ms +13.78% -26.92% -27.13%
domContentLoaded 758.25 ms +2.54% -3.86% 786.22 ms +2.63% -5.32% -3.56%
loaded 759.29 ms +2.53% -3.86% 787.26 ms +2.65% -5.31% -3.55%
firstContentfulPaint 336.45 ms +4.65% -4.34% 349.09 ms +6.75% -4.36% -3.62%
firstBlock 2743.17 ms +4.23% -2.24% 2858.82 ms +1.53% -2.28% -4.05%
type 14.55 ms +7.7% -6.12% 14.21 ms +0.77% -0.84% 2.39%
navigate 90.35 ms +9.56% -9.77% 83.46 ms +8.79% -4.8% 8.26%
loadPatterns 991.44 ms +26.07% -6.38% 1095.05 ms +16.08% -15.71% -9.46%
loadPages 972.7 ms +3.86% -0.89% 941.22 ms +5.18% -0.71% 3.34%
wpTotal 238.89 ms +6.34% -5.5% 251.12 ms +5.13% -5.72% -4.87%
wpMemoryUsage 12.38 MB +0% -0% 12.34 MB +0% -0% 0.3%
wpDbQueries 43 +2.33% -0% 43.5 +1.15% -1.15% -1.15%

e353acc Run

🏁 Flaky tests

Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

As a user I want to set button hover background color and see it applied on the frontend (Site Editor v2) in /test/e2e/specs/site-editor/global-styles-button-states.spec.js, passed after 1 failed attempt.
Error: apiRequestContext.get: socket hang up
Call log:
  - → GET http://localhost:8889/wp-admin/themes.php
    - user-agent: Playwright/1.63.0 (x64; ubuntu 24.04) node/24.20 CI/1
    - accept: */*
    - accept-encoding: gzip,deflate,br
    - cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_23778236db82f19306f247e20a353a99=admin%7C1791974431%7CbDR0HbKSokJRmTX04kVd7AFUa6bsZJ2JVb0AQCG2NKr%7C43abdc6b02404ce9707a4f86807764c654a62914a5068f0069a9b281d9daf0c7; wordpress_logged_in_23778236db82f19306f247e20a353a99=admin%7C1791974431%7CbDR0HbKSokJRmTX04kVd7AFUa6bsZJ2JVb0AQCG2NKr%7Cf47bfc2b885898346fe04d28d0268448c5ea27e4d668b11324d8f5c9c347457b; wp-settings-time-1=1791801698

    at RequestUtils.activateTheme (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/themes.ts:10:36)
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/site-editor/global-styles-button-states.spec.js:5:22
Custom Completer: should allow newlines after multiple option completions in /test/e2e/specs/editor/various/autocomplete-and-mentions.spec.js, passed after 1 failed attempt.
Error: expect(received).toBe(expected) // Object.is equality

- Expected  - 1
+ Received  + 1

@@ -1,11 +1,11 @@
  <!-- wp:paragraph -->
  <p>🫐 test</p>
  <!-- /wp:paragraph -->

  <!-- wp:paragraph -->
- <p>🫐 test</p>
+ <p>🍎 test</p>
  <!-- /wp:paragraph -->

  <!-- wp:paragraph -->
  <p>🫐 test</p>
  <!-- /wp:paragraph -->

Call Log:
- Timeout 5000ms exceeded while waiting on the predicate
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/autocomplete-and-mentions.spec.js:466:6
should cut and paste individual blocks with collapsed selection in /test/e2e/specs/editor/various/copy-cut-paste.spec.js, passed after 1 failed attempt.
Error: expect(string).toMatchSnapshot(expected) failed

  @@ -1,3 +1,3 @@
   <!-- wp:paragraph -->
  -<p>2Cut - collapsed selection</p>
  +<p>2</p>
   <!-- /wp:paragraph -->


    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/copy-cut-paste.spec.js:45:49

e353acc Run

adamsilverstein and others added 2 commits October 5, 2026 09:22
…lter

# Conflicts:
#	packages/editor/src/components/collab-sidebar/index.jsx
#	packages/editor/src/components/collab-sidebar/notes.jsx
Deleting the last thread by the filtered author left the list stuck on
"No notes found", and the Author control was hidden once only one
author remained. Drop an author filter whose author has no notes left,
and keep the control visible while an author filter is active.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQpfAuMvYyYfwPAmcavDSk
@adamsilverstein adamsilverstein changed the title Notes: Add search and filters to the All notes sidebar Add search and filters to the All Notes sidebar Oct 5, 2026
@yashjawale

Copy link
Copy Markdown
Contributor

Thanks for the PR!
Functionally everything appears to work nicely from my testing.

I do have one suggestion, in the future there might be more controls to filter comments in panel (eg. just show orphan comments) and the section can get a bit crowded.

What if the filter options are moved inside a collapsible section with a toggle button besides the search bar?

Screen.Recording.2026-10-07.at.5.00.52.PM.mov

Another nit: When a filter is applied that no nots matching the criteria are found, the fallback message is "No notes found."

image

Will it be better if the fallback is something along the lines of "No notes found matching given criteria." so its more apparent, in case the user loses track of filters being applied as currently there's no strong indicator that they're seeing a filtered view?

@adamsilverstein

Copy link
Copy Markdown
Member Author

Thanks for the PR! Functionally everything appears to work nicely from my testing.

Thanks for testing that @yashjawale

I do have one suggestion, in the future there might be more controls to filter comments in panel (eg. just show orphan comments) and the section can get a bit crowded.
What if the filter options are moved inside a collapsible section with a toggle button besides the search bar?

I like the suggestion of a filter icon to access filters, this is a very common pattern on the web and makes more room for the search bar which is likely the main tool people want to use. I'll give it a try!

cc: @jasmussen @fcoveram for design feedback.

Screen.Recording.2026-10-07.at.5.00.52.PM.mov
Another nit: When a filter is applied that no nots matching the criteria are found, the fallback message is "No notes found."

Will it be better if the fallback is something along the lines of "No notes found matching given criteria." so its more apparent, in case the user loses track of filters being applied as currently there's no strong indicator that they're seeing a filtered view?

I feel like it's fairly obvious what the message means here, but I'll look into it further and see how we handle empty results in other places in core.

adamsilverstein and others added 2 commits October 7, 2026 16:38
…lter

# Conflicts:
#	packages/editor/src/components/collab-sidebar/index.jsx
#	packages/editor/src/components/collab-sidebar/notes.jsx
Gives the search field the full row and leaves room for more filters
later, as suggested in review. The toggle shows how many filters are
applied so a filtered list is obvious while the panel is closed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016fENxDcG7csgCLvJSZUMnL
@adamsilverstein

Copy link
Copy Markdown
Member Author

@yashjawale I gave the filter toggle a try, here is where it landed - let me know what you think!

Claude made the change and described it here:

The Status and Author filters now sit behind a funnel button next to the search field, the same pattern DataViews uses. Search gets the full row, and there is room for more filters later (eg. orphaned notes).

When a filter is applied, the button shows a count badge and its label becomes "Filter (1 applied)", so a filtered list is still obvious with the panel closed. The panel also starts open when filters are already set, for example after closing and reopening the sidebar.

Default Filter open, Status: Open Panel closed, filter applied
Default Filter open Closed with badge

On the empty message: DataViews uses "No results" for its empty list and "No results found" in its search widget, so "No notes found." lines up with what core does elsewhere. With the badge showing that filters are on, it seemed fine to leave the copy as is.

Also merged trunk, resolving conflicts with #84106 and #84110.

@yashjawale

Copy link
Copy Markdown
Contributor

Thanks! That's amazing.

The count badge also helps indicate that filters are active, that takes care of second point too. 🚀

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

A small nit...

border-radius: var(--wpds-border-radius-lg);
font-size: 11px;
outline: var(--wpds-border-width-focus) solid var(--wpds-color-background-surface-neutral-strong);
color: var(--wpds-color-foreground-interactive-neutral-strong);

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.

Using the brand variation of color token instead of neutral will match better with the brand token being used for the background.

Suggested change
color: var(--wpds-color-foreground-interactive-neutral-strong);
color: var(--wpds-color-foreground-interactive-brand-strong);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good call, applied in d7f0561.

Comment on lines +178 to +186
? sprintf(
/* translators: %d: Number of filters applied. */
_n(
'Filter (%d applied)',
'Filter (%d applied)',
panelFilterCount
),
panelFilterCount
)

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.

Noticed that here _n() returns same strings for both singular/plural cases.
Different strings may be used in context of other languages so perhaps _n is right for this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Oh, interesting! I'm guessing in some languages the %d applied part could be different, but I'm not suret about that. I'll ask Claude to research it further. Thanks for raising.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Following up on this one, _n() is the correct choice here.

Claude looked into how other languages handle this, findings below:

_n() exists so each locale can supply its own plural forms. The English strings only seed the source, so identical singular and plural text is fine. Many languages have more than two forms, and the participle agrees with the count:

  • Polish has three forms (1, 2-4, 5+), eg. "zastosowany", "zastosowane", "zastosowanych".
  • Russian and Ukrainian also have three; Arabic has six.
  • With a plain __(), translators get a single string and can't match the number.

Core does the same thing. The plugin list table status links pass identical strings, eg. _n( 'Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', $count ): https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-admin/includes/class-wp-plugins-list-table.php

The translator comment (%d: Number of filters applied.) already gives the needed context, so no change here.

@annezazu

annezazu commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Took this for a spin and it's working really well! The only thing I noticed as a gotcha is that if you have a collapsed notes thread and you filter by an author, it's not immediately clear where that author's comment is. It might make sense to automatically expand when searching as a result.

Screen.Recording.2026-10-08.at.11.39.59.AM.mov

@adamsilverstein

Copy link
Copy Markdown
Member Author

It might make sense to automatically expand when searching as a result.

Ah good suggestion, thanks to testing and the feedback @annezazu - I'll work on that!

adamsilverstein and others added 3 commits October 8, 2026 21:37
…lter

# Conflicts:
#	packages/editor/src/components/collab-sidebar/index.jsx
The badge sits on the brand-strong background, so pair it with the
matching brand-strong foreground token rather than the neutral one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KsbeGRZoTeN4LyueWAEwPr
A search or author filter can match a reply hidden behind the "N more
replies" button, leaving no visible sign of why the thread matched.
Show every reply while either filter is active.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KsbeGRZoTeN4LyueWAEwPr
@adamsilverstein

Copy link
Copy Markdown
Member Author

@annezazu this is in now, thanks for the suggestion!

Claude made the change, summary below:

While a search or author filter is active, each thread shows all of its replies instead of collapsing the middle ones behind "N more replies", so the reply that matched is visible. The reply form stays hidden, and clearing the filter collapses the threads again. The status filter doesn't expand anything, since it matches on the thread rather than its replies.

Added in 3510058 with an e2e test covering it.

Also in this round: merged trunk, and switched the filter count badge text to the brand foreground token per @yashjawale's suggestion (d7f0561).

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

[Feature] Notes Phase 3 of the Gutenberg roadmap around block commenting [Package] Editor /packages/editor [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Notes: add a search/filter field to the All notes sidebar

3 participants