Skip to content

Notes: Add emoji reactions - stored as custom comment type#76767

Open
adamsilverstein wants to merge 114 commits into
trunkfrom
add-notes-emoji-reactions-try-addditional-comment-type
Open

Notes: Add emoji reactions - stored as custom comment type#76767
adamsilverstein wants to merge 114 commits into
trunkfrom
add-notes-emoji-reactions-try-addditional-comment-type

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented Mar 23, 2026

Copy link
Copy Markdown
Member

Summary

Closes #75144

Adds the foundation for emoji reactions on block notes. This PR is scoped to a small curated 5-emoji quick row (heart, celebration, smile, eyes, rocket). The full searchable emoji picker behind a + button lives in a follow-up PR stacked on this one — per @t-hamano's request, so library/bundling decisions can be reviewed separately.

Storage: reactions as a custom comment type

Reactions are stored as individual reaction comment records (one per user-emoji-note triple), as suggested by @swissspidy, in preference to JSON blobs in comment meta:

comment_type    = 'reaction'
comment_parent  = <note ID>
comment_content = <emoji slug>             // e.g. 'heart'
user_id         = <reacting user>

This is more flexible, aligns with WordPress data patterns (similar to the React plugin), and could eventually extend to regular comments. The custom type is hidden from wp-admin/edit-comments.php and excluded from comment counts.

Curated emoji set

The default 5 emojis (heart, celebration, smile, eyes, rocket) are stored as ASCII slugs (e.g. heart). Storing slugs sidesteps utf8 vs utf8mb4 portability issues on the comments table and gives stable grouping in the reaction_summary aggregation.

The list is filterable via the gutenberg_note_reaction_emojis PHP filter and exposed to clients through the REST API schema (reaction_emojis property on OPTIONS /wp/v2/comments), implementing the approach suggested by @Mamaduka.

Efficient reaction loading

Each note response includes a reaction_summary field — { [emojiSlug]: { count, reacted, my_reaction_id } }. The schema lives in class-gutenberg-rest-comment-controller-7-1.php, populated in prepare_item_for_response().

  • No N+1: get_items() pre-fetches summaries for the entire result set with one aggregated GROUP BY query plus one query for the current user's own reactions, regardless of how many notes are returned (see prefetch_reaction_summaries()).
  • Lazy-loaded reactor names: who reacted is not embedded in reaction_summary — names are fetched on tooltip hover, so the initial notes load stays cheap.

Popover architecture

The curated picker uses @wordpress/components/Dropdown, whose Popover portals to <body>. This is essential because the collab sidebar has an overflow: hidden chain reaching all the way up to .interface-interface-skeleton__sidebar (framework-level); a non-portaled popover would clip. The note thread's onBlur handler exempts .components-popover so that focus moving into the picker doesn't deselect the note (which would unmount the trigger and close the picker mid-click).

Related

Remaining feedback from #75549

  • Unbounded reaction requests (@ellatrix) — useEntityRecords for reactions has no per_page limit. Consider lazy-loading reactions only when a note thread is opened. Comment
  • Move emoji SVG icons to @wordpress/icons (@ellatrix) — Low priority, fine for now. Comment
  • Reaction embedding (@Mamaduka) — Reactions could be an embeddable resource on each note to reduce the number of requests. Comment
  • Performance at scale (@Mamaduka) — Consider how reactions perform with thousands of comments (e.g. make.wordpress.org). Comment

Already addressed

  • Move PHP code to wordpress-7.1 compat dir (@Mamaduka, @t-hamano) — Done
  • Rename comment type to reaction (@swissspidy) — Done
  • Emoji extensibility / filtering (@Mamaduka, @youknowriad, @aaronjorbin) — gutenberg_note_reaction_emojis filter, surfaced via REST schema
  • Re-add reaction after removing — Fixed both server-side (status='approve' duplicate guard) and client-side (force-delete + parent-note refetch); regression-guarded by E2E test
  • Full picker scope (@t-hamano) — Moved to a follow-up PR stacked on this one

Screenshot

horizontal picker

i switched to a horizontal layout

Screencast

horizontal.picker.mp4

Testing

Test in Playground: https://playground.wordpress.net/?gutenberg-pr=76767

For testing with multiple users, use the User Switching Plugin - https://wordpress.org/plugins/user-switching/

  • Create a note on a block
  • Click 😊 — pick from the curated 5-emoji row
  • Pick the same emoji twice — verify reaction count goes up, not a duplicate
  • Remove a reaction by clicking its pill, then add the same emoji back — verify it works (regression for the trash-counts-as-duplicate bug)
  • Add multiple different emojis to the same note
  • Hover a reaction pill — verify the tooltip shows the reactor names
  • Verify the popover doesn't get clipped by the pinned "All notes" sidebar's overflow
  • Check wp-admin comments page doesn't show reaction comments
  • Check comment counts aren't inflated by reactions
  • Verify keyboard accessibility: Enter on smiley opens picker, ArrowDown/ArrowUp navigates, Enter selects, Escape closes
  • Run E2E tests: npm run test:e2e -- test/e2e/specs/editor/various/block-notes.spec.js
  • Run PHP tests: npm run test:unit:php:base -- --filter=Gutenberg_REST_Comments

adamsilverstein and others added 30 commits February 2, 2026 10:21
Introduce a new component that displays a horizontal row of emoji
buttons for adding reactions to notes. Features include:

- Curated emoji set: 👍 👎 ❤️ 🎉 😄 😕 👀 🚀
- Keyboard navigation with arrow keys, Home, and End
- Accessible with role="listbox" and role="option"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduce a component that displays current reactions with counts
as pill-shaped buttons. Features include:

- Shows reaction counts for each emoji
- Highlights user's own reactions with distinct styling
- Click to toggle (add/remove) reaction
- "+" button opens emoji picker dropdown

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduce a popover component that shows who reacted and when.
Features include:

- Displays reactions grouped by emoji
- Shows user avatars and names
- Uses humanTimeDiff() for relative timestamps (e.g., "3 days ago")
- Fetches user data for all reactors

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extend the useBlockCommentsActions hook with three new functions:

- onAddReaction: Add a reaction to a comment
- onRemoveReaction: Remove user's reaction from a comment
- onToggleReaction: Toggle reaction (add if not present, remove if present)

Reactions are stored in comment meta._wp_reactions with structure:
{ emoji: [{ userId, timestamp }] }

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Connect the reaction components to the Notes sidebar:

- Import and render ReactionDisplay in CommentBoard
- Add ReactionDetailsPopover for viewing reaction details
- Add "See emoji reaction details" menu action
- Pass onToggleReaction through component hierarchy
- Get current user ID for highlighting own reactions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add SCSS styles for:

- Reactions container with flexbox layout
- Pill-shaped reaction buttons with active state
- Add reaction button with dashed border
- Emoji picker dropdown
- Reaction details popover with user avatars

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive E2E tests for the emoji reactions feature:

- can add an emoji reaction to a note
- can remove own emoji reaction by clicking it
- can see emoji reaction details
- reaction buttons are keyboard accessible
- can add multiple different reactions to same note

Also adds addReactionToComment helper to BlockCommentUtils.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolve merge conflicts with trunk's selectedNote editor state changes
(#75177) while preserving emoji reaction features.

Fix all 5 emoji reaction E2E tests that were timing out because the
Dropdown popover was stealing focus from the thread, triggering the
onBlur handler which collapsed the note and unmounted the emoji picker.

- Add focusOnMount: false to the reaction Dropdown popoverProps
- Add popover focus check to the thread onBlur handler
- Update addReactionToComment E2E helper to wait for the emoji picker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…yling

Replace the plus icon with a Google Docs-inspired smiley face SVG, change
focusOnMount to 'firstElement' so the emoji picker captures focus and
prevents the note from collapsing, and restyle the button to be perfectly
round with a clean white background that appears on hover.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the "Add reaction" smiley button from below the note content to the
upper-right header area alongside the resolve and actions buttons. Also
register _wp_reactions as comment meta in PHP so the REST API accepts it,
and fix the 500 error caused by spreading all comment meta (including
potentially invalid _wp_note_status) when saving reactions.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Add variant="tertiary" to the reaction pill Button components so the
WordPress default dark button styling doesn't override the custom
light gray background.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
The Button component automatically adds the is-pressed class when
aria-pressed is true, which sets a dark background (#1E1E1E). Override
with matching specificity to keep the light blue active state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increase height to 32px, use equal padding on all sides, and reduce
gap between emoji and count to bring the aspect ratio closer to 1:1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The reactions meta registration is a new feature targeting
WordPress 7.0, not a 6.9 backport. Move it to its own file
in lib/compat/wordpress-7.0/ per reviewer feedback.
The editor assumes users are logged in by default, so these
guards are redundant. Matches the pattern used by other
collab sidebar actions.
Reactions update comment metadata without adding, removing,
or resizing comments, so reflowing is unnecessary.
Replace individual getUser() calls with a single getUsers()
request using include, context: view, and _fields to reduce
API calls and support low-capability users.
Negative reactions are better expressed as comments in a
collaborative editing context. The thinking emoji provides
a constructive "I need to consider this" signal instead.
The horizontal layout caused emojis to overflow and get
cut off in the sidebar popover.
Start conservatively with ❤️ 🎉 😄 👀 🚀 to avoid
skin-tone concerns and keep the picker compact. More
reactions can be added later.
adamsilverstein added a commit that referenced this pull request May 11, 2026
Adds the "+" More-emojis trigger as a sibling of the curated smiley
trigger. Tapping it opens a lazy-loaded native picker built from
SearchControl + Composite over Emojibase data served same-origin from
the plugin (28 locales, fetched per-session on first open).

Picks fold into the curated slug when they match (e.g. ❤ → `heart`)
and store as a normalized hex-codepoint key otherwise (e.g. `1f44d` for
👍), so visually-equivalent presentations don't fragment the
reaction_summary aggregation. The hex encode/decode pair and the
HEX_KEY_RE fallback in getEmojiBySlug/getLabelBySlug come along for the
ride, since they only ever fire when this picker is enabled.

Stacked on the basic-reactions baseline so picker library and bundling
choices can be reviewed independently, per t-hamano in #76767.
Four near-identical tests (no parent, parent is a regular comment,
content not in the emoji list, anonymous user) all built the same POST
request and asserted a specific WP_Error. Replace them with a single
parameterized test_cannot_create_reaction_with_invalid_input plus a
named-key data provider, so the matrix of error cases is readable at a
glance and each new case is one row instead of a new method.

Net -23 lines; the duplicate-reaction and "can stack different reactions"
tests stay separate because their request shape differs.
Five emojis fit in a single ~176px-wide row that drops below the smiley
trigger without clipping. This matches the dominant pattern for emoji
reactions (Facebook/Slack/GitHub/Linear/Notion) so the affordance reads
as reactions instead of a generic dropdown menu.

Composite gets orientation="horizontal" so ArrowLeft/ArrowRight drive
the keyboard nav. The e2e test that exercises arrow keys is updated to
match.

@t-hamano t-hamano 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.

Sorry for the late review, @adamsilverstein!

I reviewed only the frontend code. For the backend code, I reviewed it in the core PR. WordPress/wordpress-develop#10930 (review)

Comment thread backport-changelog/7.0/10930.md
* @param {Object} props Component props.
* @param {Function} props.onToggleReaction Callback to toggle a reaction.
*/
export function AddReactionButton( { onToggleReaction } ) {

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.

Standardize button height to 24px and remove unnecessary CSS.

Details
diff --git a/packages/editor/src/components/collab-sidebar/reaction-display.js b/packages/editor/src/components/collab-sidebar/reaction-display.js
index 6852a3728b3..5543d5515e5 100644
--- a/packages/editor/src/components/collab-sidebar/reaction-display.js
+++ b/packages/editor/src/components/collab-sidebar/reaction-display.js
@@ -279,9 +279,10 @@ export function AddReactionButton( { onToggleReaction } ) {
                        contentClassName="editor-collab-sidebar-panel__add-reaction-popover"
                        renderToggle={ ( { isOpen, onToggle } ) => (
                                <Button
-                                       size="compact"
+                                       size="small"
                                        className="editor-collab-sidebar-panel__add-reaction-button"
                                        icon={ smileyIcon }
+                                       iconSize={ 20 }
                                        label={ __( 'Add reaction' ) }
                                        aria-expanded={ isOpen }
                                        onClick={ onToggle }
diff --git a/packages/editor/src/components/collab-sidebar/style.scss b/packages/editor/src/components/collab-sidebar/style.scss
index b18515470f8..945a33a0d9d 100644
--- a/packages/editor/src/components/collab-sidebar/style.scss
+++ b/packages/editor/src/components/collab-sidebar/style.scss
@@ -226,17 +226,8 @@
 }
 
 .editor-collab-sidebar-panel__add-reaction-button {
-       display: inline-flex;
-       margin: 0;
-       align-items: center;
-       justify-content: center;
-       width: 28px;
-       height: 28px !important; // Override Button component's size constraints.
-       min-width: 28px !important;
-       padding: 0;
        border-radius: $radius-round;
        border: $border-width solid $gray-300;
-       background-color: $white;
        cursor: var(--wpds-cursor-control);
 
        &:hover {
@@ -251,10 +242,7 @@
        }
 
        svg {
-               fill: none;
                color: $gray-700;
-               width: 20px;
-               height: 20px;
        }
 }
Before After
Image Image

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.

Applied the suggested approach in b6e3cb1 — switched to size="small" + iconSize={20} and dropped the bespoke 28px/!important CSS in favor of the standard Button sizing.

Comment thread packages/editor/src/components/collab-sidebar/reaction-display.js
Comment on lines +46 to +49
fetchPromise = apiFetch( {
path: '/wp/v2/comments',
method: 'OPTIONS',
} )

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 feel this approach is unusual. The OPTIONS method is typically used to retrieve the allowed operations for an endpoint, not to fetch a list of data. My intuition suggests this should be a GET request, and perhaps a new endpoint is needed to retrieve a list of emojis 🤔

@Mamaduka, do you have any ideas?

@adamsilverstein adamsilverstein May 15, 2026

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.

Fair concern — OPTIONS is unusual for data retrieval. The choice here was driven by wanting the curated emoji list to live in the REST schema (as the reaction_emojis schema default on /wp/v2/comments), since the schema is what the server already exposes as the authoritative shape for a comment. That avoided introducing a new endpoint just to fetch a 5-item curated list. The data lands in response.schema.properties.reaction_emojis.default, which is how OPTIONS is already used today to discover allowed values for other fields. Happy to revisit.

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.

@Mamaduka this question is still open, let me know if I should adjust.

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.

After reconsidering, I still believe that the way OPTIONS is being used is incorrect. Could we remove the OPTIONS endpoint and have the client-side always use this hardcoded reaction list instead?

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.

After reconsidering, I still believe that the way OPTIONS is being used is incorrect. Could we remove the OPTIONS endpoint and have the client-side always use this hardcoded reaction list instead?

Sure, let's do that!

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.

Done in 87384c8 - dropped the OPTIONS fetch and the `reaction_emojis` schema property; the picker now uses the hardcoded curated list. The `gutenberg_note_reaction_emojis` filter still drives server-side validation.

Comment thread packages/editor/src/components/collab-sidebar/style.scss Outdated
Comment thread packages/icons/src/library/smiley.svg Outdated

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.

For now, it might be better to inline this SVG data and not expose it to consumers yet.

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.

Agreed — pulled the smiley back inline in 033e765. Removed smiley.svg and the manifest entry from @wordpress/icons, and the SVG now lives directly in reaction-display.js (via SVG/Path from @wordpress/primitives to keep it cross-platform per ESLint react/forbid-elements). Easy to promote back to @wordpress/icons later if there’s a second consumer.

Comment thread packages/editor/package.json
adamsilverstein and others added 6 commits May 15, 2026 10:51
Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com>
Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com>
Apply review feedback: drop the bespoke 28px-with-!important sizing on
the curated add-reaction button in favor of the standard Button "small"
size with iconSize=20. Removes redundant flex/centering CSS the Button
component already handles.
A resolved note thread shouldn't accept new reactions — they're for
in-progress conversations. Disable the curated reaction picker toggle
when the note's status is "approved" and keep it accessible so screen
readers still announce the control's disabled state.
Replace per-render array.find() calls in ReactionDisplay with a Map
keyed by slug, memoized against the emoji list. O(1) lookup keeps
the render cheap if the curated set grows (full picker landing later
via the stacked PR).
Per review feedback, the smiley face shouldn't be promoted to the
public icons API while the reactions feature is still settling. Move
the SVG back inline in reaction-display.js (using SVG/Path from
@wordpress/primitives so it stays cross-platform) and remove the
smiley entry from @wordpress/icons' manifest and library.
…tions-try-addditional-comment-type

# Conflicts:
#	lib/load.php
#	test/e2e/specs/editor/various/block-notes.spec.js
@adamsilverstein

adamsilverstein commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

This is ready for review. @t-hamano @swissspidy @Mamaduka

adamsilverstein and others added 2 commits June 20, 2026 08:38
Resolve conflicts from trunk removing the wordpress-6.9 compat layer (the
plugin now requires WP 6.9, where block-comments/notes ship in core):

- lib/load.php: keep both the new attachments controller require (trunk)
  and the block-comments + reaction controller requires (PR).
- collab-sidebar/note.js: keep both @wordpress/ui imports (Stack from the PR,
  Button as UIButton from trunk) in a single import statement.
- 6.9 comment controller (deleted in trunk, modified in PR): accept the
  deletion. The reaction controller previously extended it; re-parent
  Gutenberg_REST_Comment_Controller_7_1 to core's WP_REST_Comments_Controller
  and reimplement check_post_type_supports_notes() locally, since core
  declares that helper private. Drop the now-meaningless remove_action for
  the deleted 6.9 registration.
- wordpress-7.1/block-comments.php: drop remove_filter calls that targeted
  6.9 gutenberg functions deleted by trunk; the _7_1 callbacks still apply.
@swissspidy

Copy link
Copy Markdown
Member

I'm probably not the best one to review all of this, but I like the use of the custom comment type and the thoughts you put into fetching reactions in a performant way. Starting with a curated list of emoji also sounds reasonable to me.

@jeffpaul

Copy link
Copy Markdown
Member

Seems like the icons selected here are an alternatively ordered subset of what GitHub shows for reactions itself. How were those chosen? Why were the 👍🏼 and 👎🏼 and 😕 ones left off?

Otherwise some light testing with just one user account these works well.

}

$edit_cap = $is_note ? array( 'edit_post', (int) $request['post'] ) : array( 'moderate_comments' );
if ( isset( $request['status'] ) && ! current_user_can( ...$edit_cap ) ) {

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.

What happens if $request['status'] isn't set?

Core has a separate check before:

if ( $is_note && ! empty( $request['post'] ) && ! current_user_can( 'edit_post', (int) $request['post'] ) ) {
	return new WP_Error(
		'rest_cannot_create_note',
		__( 'Sorry, you are not allowed to create notes for this post.' ),
		array( 'status' => rest_authorization_required_code() )
	);
}

in wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php. Do we need to do the same thing here?

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.

Probably, good suggestion, that would make the answer to your question clearer. Will do.

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 catch - added the explicit `edit_post` guard mirroring core in 9488cf1, so creation no longer depends on `status` being present.

@adamsilverstein

Copy link
Copy Markdown
Member Author

Seems like the icons selected here are an alternatively ordered subset of what GitHub shows for reactions itself. How were those chosen? Why were the 👍🏼 and 👎🏼 and 😕 ones left off?

Otherwise some light testing with just one user account these works well.

@jeffpaul the initial icon set was discussed in a previous thread, I think mostly starting here: #75148 (comment)

I've also got this follow up PR - #78176 - that will add the full set behind a (+) symbol, and maybe we can make the ones you use easier to find by surfacing them in the initial set?

@adamsilverstein

Copy link
Copy Markdown
Member Author

ping @jasmussen for any feedback

array( 'status' => 400 )
);
}

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.

Should we also validate that the comment is for the correct post, something like this:

if ( (int) $parent_comment->comment_post_ID !== (int) $request['post'] ) { return new WP_Error( 'rest_comment_invalid_parent', __( 'A reaction must be attached to a note on the same post.', 'gutenberg' ), array( 'status' => 400 ) ); }

@adamsilverstein adamsilverstein Jun 25, 2026

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.

Added in 9488cf1 - a reaction whose parent note belongs to a different post is now rejected with `rest_comment_invalid_parent`.

* @param WP_Comment $comment Comment object.
* @return array Links for the given comment.
*/
protected function prepare_links( $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.

This changes note _links.children from note replies to reactions. Core’s note controller uses type=note&status=all for child embedding, so clients relying on _embed for note replies will stop seeing replies once a note has children. Reactions should use a separate relation or summary field rather than replacing the existing children contract.

@adamsilverstein adamsilverstein Jun 25, 2026

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.

Agreed. Removed the `prepare_links` override in dee5d00 so notes keep core's reply-embedding contract; reactions already reach the client via the `reaction_summary` field and an on-hover fetch.

Require edit_post capability to create a note or reaction, mirroring
core's note guard, so the check no longer depends on a status field
being present in the request. Also validate that a reaction's parent
note belongs to the same post the reaction targets.

Addresses review feedback on PR #76767.
The prepare_links override repointed a note's _links.children from its
replies (type=note) to reactions (type=reaction), breaking core's
reply-embedding contract for clients relying on _embed. Reactions reach
the client through the reaction_summary field and an on-hover fetch, so
the override served nothing. Remove it and inherit core's behavior.

Addresses review feedback on PR #76767.
The reaction picker fetched the curated emoji list via OPTIONS
/wp/v2/comments, reading it from a reaction_emojis schema default.
OPTIONS is for discovering allowed operations, not data retrieval, and
the curated set is a fixed five-emoji row. Use the hardcoded
REACTION_EMOJIS list directly, drop the useReactionEmojis hook and the
client request, and remove the read-only reaction_emojis schema
property. The gutenberg_note_reaction_emojis filter still drives
server-side validation.

Addresses review feedback on PR #76767.
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 [Status] In Progress Tracking issues with work in progress [Type] Enhancement A suggestion for improvement.

Projects

Status: 🔎 Needs Review

Development

Successfully merging this pull request may close these issues.

Add emoji reactions as a first class comment type

6 participants