Opened 8 months ago
Last modified 29 hours ago
#64638 assigned enhancement
Add emoji reactions as a comment type for Notes
| Reported by: | adamsilverstein | Owned by: | adamsilverstein |
|---|---|---|---|
| Priority: | normal | Milestone: | 7.2 |
| Component: | Editor | Version: | |
| Severity: | normal | Keywords: | has-patch has-unit-tests gutenberg-merge commit |
| Cc: | Focuses: |
Description (last modified by )
Claude rewrote this description to match the approach that shipped in Gutenberg:
Adds a
reactioncomment type so users can react to collaborative Notes with one of five emoji: heart, celebration, smile, eyes and rocket. Each reaction is stored as its own comment under the note, rather than as_wp_note_reactionscomment meta on the note as originally proposed here.
Data model
comment_typeisreaction,comment_parentis the note, andcomment_contentis one of five emoji hex keys:2764,1f389,1f604,1f440,1f680. Raw emoji bytes aren't stored, since the comments table isn't guaranteed to be utf8mb4.- One reaction per emoji per user per note. Reactions are always approved and authored by the current user.
REST API
- Reactions are created and deleted through
/wp/v2/comments, using the note permission checks (edit_poston the note's post) rather thanmoderate_comments. They aren't publicly readable and can't be edited.- On create, the parent must be a note on the same post that isn't trashed, spam, or in a resolved thread. Invalid keys return 400 and duplicates return 409.
- Notes get a read-only
reaction_summaryfield, keyed by hex key, with{ count, current_user_reaction }. Summaries for a page of notes are prefetched in at most two queries.Everywhere else
- Reactions are trashed and deleted along with their note.
- They're excluded from the admin comments list, comment counts, pending counts,
get_lastcommentmodified(), comment feeds, and a note'schildrenlink.reactionis added to the avatar comment types.Restoring a trashed note doesn't restore its reactions yet, see https://github.com/WordPress/gutenberg/issues/84202.
References
- Gutenberg PR (merged): https://github.com/WordPress/gutenberg/pull/76767
- wordpress-develop PR: https://github.com/WordPress/wordpress-develop/pull/10930
- Earlier comment meta approach (superseded): https://github.com/WordPress/gutenberg/pull/75148
Change History (18)
This ticket was mentioned in PR #10930 on WordPress/wordpress-develop by @adamsilverstein.
8 months ago
#1
- Keywords has-unit-tests added
#2
@
8 months ago
Why store reactions like this and not as a separate comment type? Makes it more flexible and potentially useful for regular comments as well. See also https://wordpress.org/plugins/react/
@adamsilverstein commented on PR #10930:
8 months ago
#4
I have updated this backport PR to apply the custom comment type approach for storage used in https://github.com/WordPress/gutenberg/pull/75549 which replaces the meta based approach in https://github.com/WordPress/gutenberg/issues/75144.
#5
@
8 months ago
- Milestone 7.0 → 7.1
WP 7.0 pre-beta1 Triage:
Unfortunately this enhancement didn't make it before beta 1 code freeze. Thus, let's move it to milestone 7.1.
@adamsilverstein commented on PR #10930:
5 months ago
#6
Thanks for the review @t-hamano! I've pushed f3b5af251b addressing the feedback:
@sincebumps: Updated all PR-introduced@since 7.0.0to@since 7.1.0(incomment.php,link-template.php, andclass-wp-rest-comments-controller.php).WP_Comment_Query: Updated the existing exclusion block to iterate overwp_get_internal_comment_types()so bothnoteandreactionare excluded by default unless explicitly requested.get_lastcommentmodified(): Added acomment_type NOT IN (…)clause built fromwp_get_internal_comment_types()to all three timezone branches so internal comment types no longer affect the last modified date.- Reaction icon list: Moved
wp_get_note_reaction_emojis()intoWP_REST_Comments_Controller::get_note_reaction_emojis()as aprotected staticmethod, per your suggestion to avoid a public global while the icon-library plans are still being worked out. wp_internal_comment_typesfilter: Removed — agreed it's not needed for an internal helper.wp_list_plucksimplification at line 360: Applied. The'note' === $comment->comment_typecheck inside the loop was redundant since$request['type']is already gated to'note'above andWP_Comment_Queryconstrains the result set, so it's gone too.
Locally, the relevant test suites (Tests_Comment_*, Tests_REST_Comments, Tests_Avatar) all pass: OK (165 tests, 476 assertions).
#7
@
5 months ago
Removing trunk version as this is not going to be shipped with WP 7.0 but in the next releases.
#8
@
5 months ago
- Description modified (diff)
- Summary Editor: Register emoji reactions comment meta for Notes → Register emoji reactions comment meta for Notes
- Version trunk
Since this is an enhancement, there's no first version of WordPress this can be reproduced in. Removing trunk version.
This ticket was mentioned in Slack in #core by adrianduffell. View the logs.
3 months ago
#10
@
3 months ago
With the 7.1 beta approaching, this has a chance to be included if the PR can be reviewed in the coming days.
#11
@
3 months ago
- Milestone 7.1 → 7.2
Since this feature has been punt to 7.2, let's punt this ticket as well.
@adamsilverstein commented on PR #10930:
3 months ago
#12
Re-synced this branch with the latest changes on the upstream Gutenberg PR (https://github.com/WordPress/gutenberg/pull/76767), which had accumulated some PHP hardening since the last update here. Two new commits:
REST API: Harden reaction validation and canonicalize stored slugs (dd9b750d51)
- A reaction's parent note must now belong to the post the reaction targets.
- Hex-codepoint slugs are validated against assignable Unicode: values above U+10FFFF or in the UTF-16 surrogate range (U+D800-U+DFFF) are rejected.
- The stored
comment_contentis the validated canonical slug, so markup in the request (e.g.<b>heart</b>) can no longer splitreaction_summarygrouping. - Error codes now match the Gutenberg implementation (
rest_comment_invalid_parent,rest_comment_invalid_reaction,rest_comment_duplicate_reaction), so client-observable behavior won't change when the feature ships in core.
REST API: Converge concurrent duplicate reactions to a single row (417c5bf9c1)
- The pre-insert uniqueness check is not atomic, so concurrent requests could both insert. After insert, the earliest matching row (lowest comment ID) is kept, later duplicates are deleted, and the response repoints to the survivor.
New tests cover the same-post parent check, invalid codepoints (5 cases), canonical slug storage, and the concurrency convergence (simulated via rest_pre_insert_comment injection). Full WP_Test_REST_Comments_Controller suite passes: 223 tests, 1089 assertions.
@adamsilverstein commented on PR #10930:
7 weeks ago
#13
Four of the eight findings from the review round on the Gutenberg PR land in this backend rather than the client, so the matching fixes are up here now. Two of them change REST behavior, so worth a look before this goes any further.
_Claude wrote up the four fixes:_
The findings come from an AI-assisted review on https://github.com/WordPress/gutenberg/pull/76767. All four are fixed in 4f1c947, with the
@sincetags retargeted at 7.2.0 in a892699, keeping the plugin and core in step.
Reaction updates are no longer allowed.
create_item()validates the author, parent note, target post and canonical slug as a set, and the inherited generic update route re-validates none of it.check_edit_permission()falls through toedit_comment, which maps toedit_poston the note's post - so anyone who can edit that post could PATCH a reaction onto another user, move it to a note on a post they cannot edit, or store a duplicate or invalid slug.update_item_permissions_check()now returnsrest_comment_update_not_allowed(403) for reactions. Notes stay editable. Removing a reaction was always a delete, so nothing legitimate loses a path.
Reactions no longer outlive their note.
wp_delete_comment()reparents a deleted comment's children one level up instead of deleting them, so permanently deleting a note left its reactions behind as approved top-level rows still carrying the reactor's identity and date.wp_trash_comment()cascades only tonotechildren, so a trashed note kept its reactions approved. Both now cascade, along withwp_untrash_comment(), via a newwp_get_note_reaction_ids(). Replies come along for free since core trashes and deletes each one in turn. A regression test pins that non-note children are still reparented as before.
Hex codepoint keys are no longer accepted. They were valid input but nothing shipping today decodes them back, so a hex slug rendered as its own storage key in place of the emoji and its label. Only slugs from
get_note_reaction_emojis()are accepted now. Widening this later, when a picker exists that can decode them, stays backward compatible - narrowing it later would not.
The duplicate cleanup repoints correctly when it loses the race. The
count( $duplicates ) > 1guard skipped the repoint in exactly the case that needed it: a competing request running the same cleanup deletes this request's row first, leaving one survivor that is not$comment_id.get_comment()then returned null and the request failed on state that had already changed. It now repoints whenever any matching row survives.
Verified locally: 535
--group commentand 227WP_Test_REST_Comments_Controllertests pass. Each new test was checked red first - the update lock, the deletion and trash cascades, and the concurrency repoint all fail without their fix, the last erroring onget_comment()returning null for the deleted row.
#14
@
44 hours ago
I see there’s been a lot of recent activity on the PR, including @t-hamano’s review yesterday, which is great to see.
As 7.2 beta 1 is approaching, @adamsilverstein @wildworks, are we targeting 7.2 for this? If it needs more time, we can punt it to 7.3.
#15
@
29 hours ago
- Keywords commit added
I see there’s been a lot of recent activity on the PR, including @t-hamano’s review yesterday, which is great to see.
The upstream PR is approved, giving it some final review and polish.
Then I'm going to get this merged ahead of beta 1 so we can get some wider testing and feedback.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
## Summary
Register the
_wp_note_reactionscomment meta inwp_create_initial_comment_meta(), alongside the existing_wp_note_statusmeta. This meta stores emoji reaction data for the block editor's collaborative Notes feature.### Data Model
Each emoji key (e.g.,
"👍","❤️") maps to an array of reaction objects:{ "👍": [ { "userId": 1, "date": "2025-01-15T10:30:00" }, { "userId": 2, "date": "2025-01-15T11:00:00" } ], "❤️": [ { "userId": 1, "date": "2025-01-15T10:35:00" } ] }### REST Schema
objecttrue[](empty array)additionalProperties: Each property is an array of objects with:userId(integer) — The reacting user's IDdate(string|null, date-time format) — When the reaction was added### Auth
Uses the same
edit_commentcapability check as_wp_note_status.## References
---