Comments: Support Notes @mentions: kses allowance and notifications#12503
Comments: Support Notes @mentions: kses allowance and notifications#12503adamsilverstein wants to merge 8 commits into
Conversation
The notes @-mention completer stores a mention as `<a class="wp-note-mention" data-user-id="N" href="...">@name</a>`. The default comment kses allowlist only keeps `href` and `title` on links, so for users without `unfiltered_html` the attributes that make a mention a mention (the chip class and the mentioned user's ID) are stripped on save. Add a 'pre_comment_content' context to wp_kses_allowed_html() that allows `class` and `data-user-id` on links so saved mentions survive sanitization. Both attributes are inert markup. Backports the PHP changes from the Gutenberg mentions PR: WordPress/gutenberg#79604
|
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 Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
Allowing class and data-user-id on links in the pre_comment_content context loosened sanitization for every comment, including anonymous front-end comments. Both attributes are CSS/JS selector hooks, so that would let any commenter publish links styled by theme classes or reachable by delegated script handlers. Attach the extended allowlist in wp_filter_comment() only while a note comment's content is being filtered instead. Notes can only be written by logged-in users who can edit the post and never render on the front end, and the sanitization of regular comments is unchanged.
Design review on the Gutenberg side changed the stored mention from a link to a plain span, since a mention marks a person rather than offering navigation. Allow span.class and span.data-user-id instead of the link attributes; the allowance is still attached only while a note comment is filtered.
… attribute The notes mention completer now stores a mention as `<span class="wp-note-mention user-N">@name</span>`, so the kses allowance for note comments shrinks to the single `class` attribute and no longer needs `data-user-id`. Add a test asserting that any other attribute is still stripped from note spans. Trac ticket: https://core.trac.wordpress.org/ticket/65622
1fc1250 to
f74c68b
Compare
Mentions are now inserted as links to the mentioned user's author page - <a class="wp-note-mention user-N" href="..."> - instead of spans, so the note allowance moves from span.class to a.class. Note content now also picks up wp_rel_ugc()'s rel="nofollow ugc" like any other comment link, which the tests cover with a deterministic external href.
Port the notification layer from the Gutenberg Notes @mention work (WordPress/gutenberg#79606). Parse user-N mention classes out of saved note content, email mentioned users and existing thread followers on rest_insert_comment, and subscribe the note author and mentioned users to the thread via _wp_note_followers comment meta (one row per user so concurrent replies cannot clobber each other). The post author is excluded because wp_new_comment_via_rest_notify_postauthor() already notifies them, and recipients are limited to users who can edit_comment the note, matching the REST API's read permission for notes.
Backports the PHP changes from the Gutenberg Notes @mention work: the mention kses allowance (WordPress/gutenberg#79604, WordPress/gutenberg#80221) and the mention/follower notifications (WordPress/gutenberg#79606).
What
Mention markup survives sanitization (kses)
Allows the note mention markup (a
classattribute on links) in comment content, scoped tonotecomments only:_wp_kses_allow_note_mention_attributes()(new, private) extends thepre_comment_contentallowlist withclassonaelements.wp_filter_comment()attaches it immediately before applying thepre_comment_contentfilter and removes it immediately after, and only when$commentdata['comment_type']isnote.The
pre_comment_contentkses context itself is unchanged:wp_kses_allowed_html( 'pre_comment_content' )still returns the default$allowedtags, and regular (including anonymous front-end) comments are sanitized exactly as before.Because the scoping lives inside
wp_filter_comment()- the single choke point both REST write paths pass through withcomment_typealready resolved - core does not need the separate REST-create arming fix the plugin shim required (WordPress/gutenberg#80221).Mention and follower notifications
On
rest_insert_commentfornotecomments (alongside the existing post-author notification),wp_notify_note_mentions():wp_get_note_mentioned_user_ids(): only anchors carrying both thewp-note-mentionclass and auser-Nclass token are treated as mentions, so ordinary links cannot be used to address notifications.wp_send_note_notification())._wp_note_followersmeta row per user on the thread's top-level note - so concurrent replies cannot clobber each other - and the meta is registered for REST (editable by users who canedit_commentthe note) so follower management UI can build on it.Audience rules:
wp_new_comment_via_rest_notify_postauthor()already notifies them of every note.edit_commentthe note, matchingWP_REST_Comments_Controller::check_read_permission()for notes, so emails cannot leak note content to users who cannot see the note in the editor.wp_notes_notifyoption.New filters:
wp_note_notification_recipients,wp_note_notification_subject,wp_note_notification_text.Why
The Notes @mention completer stores a mention as a link to the mentioned user's author page,
<a class="wp-note-mention user-N" href="…">@Name</a>, theuser-Nclass carrying the mentioned user's ID. The default comment kses allowlist ($allowedtags) permitsawith onlyhrefandtitle, so for users withoutunfiltered_htmlthe mention classes are stripped when the note is saved.An earlier revision of this PR added the attributes to the
pre_comment_contentcontext unconditionally. That loosened sanitization for every comment on every site:classis a CSS/JS selector hook, so any commenter - including anonymous visitors - could publish text styled by theme classes (e.g. disguised as a button) or reachable by delegated script handlers. Scoping the allowance to the moment anotecomment passes throughwp_filter_comment()avoids that: notes can only be written by logged-in users withedit_poston the target post and never render on the front end.Mentioning a collaborator in a note is only useful if they hear about it: the notification half closes that loop, and the follower model keeps everyone who has participated in a thread informed of later replies without requiring them to be re-mentioned.
Testing
Unit tests in
tests/phpunit/tests/kses.php:test_wp_kses_allowed_html_pre_comment_content_disallows_mention_attributesverifies thepre_comment_contentcontext still returns the stock$allowedtags.test_note_mention_allows_only_class_on_note_linksverifies every attribute other thanclassand the default link attributes (e.g.onclick,style,data-*) is still stripped from note links.test_note_mention_markup_stripped_from_regular_comment_contentverifies theclassis stripped from the same markup in a regular comment.test_note_mention_allowance_does_not_leak_after_note_filteringverifies a regular comment filtered after a note gets the default rules and the allowlist is restored.Unit tests in
tests/phpunit/tests/comment/wpNotifyNoteMentions.phpcover mention parsing (plain links ignored, IDs deduped), thread-root resolution, the mentioned-user email + auto-subscribe, author self-exclusion, post-author exclusion, capability gating (a mentioned subscriber is not emailed), follower-of-reply notification, thewp_notes_notifyoff switch, the recipients filter, follower removal, and the REST meta registration.Trac ticket: https://core.trac.wordpress.org/ticket/65622