Skip to content

Notes: Carry mention user IDs in a data attribute instead of classes - #80496

Closed
adamsilverstein wants to merge 8 commits into
trunkfrom
update/note-mentions-data-attribute
Closed

Notes: Carry mention user IDs in a data attribute instead of classes#80496
adamsilverstein wants to merge 8 commits into
trunkfrom
update/note-mentions-data-attribute

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented Jul 21, 2026

Copy link
Copy Markdown
Member

Closes #80502.

What

Switch the Notes @ mention markup from a pair of classes to a single purpose-specific data attribute:

-<a class="wp-note-mention user-N" href="…">@Name</a>
+<a data-wp-note-mention-user="N" href="…">@Name</a>

and replace the elaborate per-note kses arm/disarm machinery in lib/compat/wordpress-7.1/block-comments.php with a single always-registered wp_kses_allowed_html filter that allows only that one attribute on a in the pre_comment_content context.

Since the wp-note-mention class has never shipped in a stable WordPress release, it is removed entirely - no legacy selector or fallback is kept (per review).

Why

On the Core backport of the notes mention kses handling (wordpress-develop#12503), @westonruter suggested carrying the mentioned user ID in a data attribute instead of a class. A class allowance lets note authors persist arbitrary classes on links, widening the CSS and JavaScript selector blast radius in the admin. A purpose-specific data-wp-note-mention-user attribute is inert: it is not a styling or scripting hook anywhere outside the notes sidebar.

Because the payload is now a single inert attribute rather than an open class, the per-note-write arming and disarming (the preprocess_comment / rest_preprocess_comment arming hooks plus the self-removing pre_comment_content disarm at PHP_INT_MAX and the rest_request_after_callbacks backstop) is no longer needed. It collapses to one always-on filter.

Correction to the original suggestion

The premise that data attributes "would be allowed by Kses by default" holds only for the post kses context. The comment context (pre_comment_content) uses the minimal $allowedtags in wp-includes/kses.php, where a allows only href/title and data-* is not permitted (the data-* wildcard path in wp_kses_attr_check() requires the allowlist to already contain data-*). So a narrow kses allowance is still required; it just shrinks from "any class" to one inert attribute, and the arm/disarm machinery goes away.

This is proven by a new baseline unit test, test_comment_kses_strips_data_attribute_by_default, which removes the notes filter and asserts wp_kses( $mention_markup, 'pre_comment_content' ) strips data-wp-note-mention-user.

Behavior change

Regular (including anonymous) commenters can now persist this one inert data-wp-note-mention-user attribute on links in any comment content, not just notes. This is acceptable because:

  • the attribute has no styling or JavaScript hook outside the notes sidebar, and
  • mention notification parsing (Gutenberg #79606 and its Core equivalent) only processes note-type comments, so the attribute is meaningless anywhere else.

Every other link attribute (class, event handlers, styles, other data-* attributes) is still stripped exactly as in core's defaults, covered by test_only_the_mention_attribute_and_default_link_attributes_are_allowed.

Coordination follow-ups

  • Gutenberg #79606 (mention notifications) parses the user ID out of the user-N class in PHP (preg_match( '/^user-([1-9][0-9]*)$/' )). It should switch to reading the data-wp-note-mention-user attribute; no legacy-class fallback is needed since the class never shipped in a stable release.
  • wordpress-develop #12503 can then be reduced to the same narrow attribute allowance in core (a pre_comment_content data-wp-note-mention-user allowance), at which point the function_exists( '_wp_kses_allow_note_mention_attributes' ) guard here disables this plugin copy.

Testing instructions

Test with WordPress Playground

  1. As a user without unfiltered_html (e.g. an author), open a post, select some text or a block, and add a note.
  2. Type @ and pick a teammate. The mention renders as a chip.
  3. Save the note. The chip survives the round-trip and its anchor carries data-wp-note-mention-user="<user id>" (inspect the element) and links to the author page. This is the case the kses allowance exists for.

Automated coverage:

  • PHP: phpunit/tests/notes-mention-kses-test.php
  • e2e: the Mentions in the note form describe in test/e2e/specs/editor/various/block-notes.spec.js
  • Storybook: Editor/CollabSidebar/NoteMention renders the mention chip.

The `@` mention completer stored the mentioned user's ID in a
`class="wp-note-mention user-N"` on the anchor. A class allowance lets
note authors persist arbitrary classes on links, widening the CSS and
JavaScript selector blast radius in the admin. Switch the payload to a
single purpose-specific `data-wp-note-mention-user` attribute, which is
inert outside the notes sidebar.

Drop the `wp-note-mention` class from newly inserted mentions: with the
class allowance gone (see the kses change), classes would be stripped
server-side for authors without `unfiltered_html`, making draft and
saved markup inconsistent. The chip styles now target
`[data-wp-note-mention-user]` while keeping the legacy `.wp-note-mention`
selector so notes saved before this change stay styled.
The mention allowance previously extended the comment kses allowlist to
permit any `class` on links, so it had to be armed only while a `note`
comment was filtered and disarmed immediately after, via a chain of
`preprocess_comment` / `rest_preprocess_comment` arming hooks and a
self-removing disarm on `pre_comment_content` at `PHP_INT_MAX` plus a
`rest_request_after_callbacks` backstop.

Now that mentions carry the user ID in a single inert
`data-wp-note-mention-user` attribute rather than a class, that
machinery is unnecessary. Replace it with one always-registered
`wp_kses_allowed_html` filter that allows only that exact attribute on
`a` in the `pre_comment_content` context.

Note: `data-*` attributes are only allowed by default in the `post`
kses context, not `pre_comment_content`, so a narrow allowance is still
required. Because the attribute is inert (no styling or JS hook outside
the notes sidebar, and notification parsing only reads `note` comments),
allowing it globally in comment content is acceptable. The
`function_exists` core-deference guard is kept so this disables once WP
core ships an equivalent.
Update the fixtures to the `data-wp-note-mention-user` markup and the
new always-on model. Add a baseline test proving the comment kses
context strips the mention data attribute without the notes filter,
documenting the load-bearing fact that `pre_comment_content` (unlike the
`post` context) does not allow `data-*` by default.

Assert the attribute survives in note content and, now, in regular
comment content too, documenting the intended behavior change; keep the
check that every other link attribute (`class`, event handlers, styles,
other data attributes) is still stripped. Drop the arm/disarm
leak-prevention and REST-arming tests, whose machinery no longer exists.
Replace the `toHaveClass( /^wp-note-mention user-N$/ )` assertions on the
draft and saved mention chips with `toHaveAttribute(
'data-wp-note-mention-user', String( mentionedUserId ) )`, matching the
switch from a class to a data attribute. The `href` `/author/` assertion
is kept.
Add a presentational story rendering the note-content mention chip in
both the current `data-wp-note-mention-user` form and the legacy
`wp-note-mention` class form inside the collab-sidebar panel structure,
so the built editor styles apply. It confirms both forms render as an
identical chip, which is why the chip styles keep the legacy selector.
@github-actions

github-actions Bot commented Jul 21, 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: adamsilverstein <adamsilverstein@git.wordpress.org>
Co-authored-by: westonruter <westonruter@git.wordpress.org>
Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>

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

@github-actions github-actions Bot added the [Package] Editor /packages/editor label Jul 21, 2026
@adamsilverstein adamsilverstein added [Type] Enhancement A suggestion for improvement. [Feature] Notes Phase 3 of the Gutenberg roadmap around block commenting labels Jul 21, 2026
The kses simplification in this PR changes what wordpress-develop#12503
backports, so the Core backport changelog check requires listing it
against that Core PR.
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

Size Change: +33 B (0%)

Total Size: 7.74 MB

📦 View Changed
Filename Size Change
build/scripts/editor/index.min.js 500 kB +3 B (0%)
build/styles/editor/style-rtl.css 31.3 kB +6 B (+0.02%)
build/styles/editor/style-rtl.min.css 26.6 kB +9 B (+0.03%)
build/styles/editor/style.css 31.3 kB +6 B (+0.02%)
build/styles/editor/style.min.css 26.6 kB +9 B (+0.03%)

compressed-size-action

Comment thread packages/editor/src/components/collab-sidebar/style.scss Outdated
Comment thread packages/editor/src/components/collab-sidebar/style.scss Outdated
The class was never shipped in a stable WordPress release, so no saved
notes carry it. Removing it now avoids keeping a legacy selector
forever. The plain-link carve-out now excludes mentions by the data
attribute alone, per review feedback.
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

Flaky tests detected in 23c8c17.
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.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/29807083373
📝 Reported issues:

@github-project-automation github-project-automation Bot moved this to 🔎 Needs Review in WordPress 7.1 Editor Tasks Jul 21, 2026
@adamsilverstein adamsilverstein added [Type] Bug An existing feature does not function as intended and removed [Type] Enhancement A suggestion for improvement. labels Jul 21, 2026
@adamsilverstein adamsilverstein self-assigned this Jul 21, 2026
@adamsilverstein adamsilverstein added the [Status] In Progress Tracking issues with work in progress label Jul 21, 2026
@Mamaduka

Mamaduka commented Jul 21, 2026

Copy link
Copy Markdown
Member

IIRC, the whole point of using classes was to get Link-format UI for free, without needing to add faux formatting. The discussion can be found in PR.

While I understand the concerns about data manipulation from WordPress/wordpress-develop#12503 (review), it's not clear what the desired UX/UI outcomes should be.

Have we tried using class, data-id and data-type Budug? All these attributes are supported by the link format. But first, we need to decide what UX/UI should look like for formats.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Probably useful for testing, but not much different from actually running e2e tests. Plus, everything is hardcoded, so this won't catch any regressions.

I would drop the story file.

@Mamaduka

Copy link
Copy Markdown
Member

Here are some interesting behavior(s), I've observed while comparing trunk and this branch

  • (on this branch) if you edit a mention via Link format UI, it stops being a mention, format will remove any data-* attribute not registered for it. (on trunk) mention remains at least visually, unless required classes are removed.
  • (on both branches) you can partially delete mention, and it will still refer to the assigned user via class or new data attribute.

I think we might need stricter checks before notifying users.

Screencast

CleanShot.2026-07-21.at.10.55.08.mp4

@adamsilverstein

Copy link
Copy Markdown
Member Author

IIRC, the whole point of using classes was to get Link-format UI for free, without needing to add faux formatting. The discussion can be found in PR.

While I understand the concerns about data manipulation from WordPress/wordpress-develop#12503 (review), it's not clear what the desired UX/UI outcomes should be.

Have we tried using class, data-id and data-type Budug? All these attributes are supported by the link format. But first, we need to decide what UX/UI should look like for formats.

The motivation for considering dropping using classes directly is current approach of allowing any class attributes to be added by less privileged users to note content. Since classes impact display, it would be possible for someone for example to hide or change links by sending the right class. When @westonruter suggested data attributes, he expected they were already allowed by kses and even though that is not the case I thought it would be worth exploring the approach.

Perhaps what we can do instead is:

  • Stick with the current class based approach
  • Simplify the Kses callback so it:
    • runs for all comment types avoiding the complex hooking/unhooking required to target only the 'note' type
    • only allows the specific set of classes we have allowlisted to be included for note @ mentions

@adamsilverstein

Copy link
Copy Markdown
Member Author

I think we might need stricter checks before notifying users.

What would that look like? making sure the full username is present?

Maybe we should switch to span.wp-note-mention.data-wp-note-mention-user. Because it seems we actually want to differentiate mentions from links.

Good point, let's try that.

Notes:

  • Let's keep the wp-note-mention class, so some random format won't pick this up as its own. Formats are differentiated by tagName and class.

ok

  • We could keep data-wp-note-mention-user if it makes later handling easier.

Reviewing this again, I'm not sure it helps if we still need the classes. Instead, I'll drop the data attribute and focus on adjust the kses callback to see if I can only allow the specific classes we need.

  • Based on my tests, there's no need to register a special format for mentions. RichText can handle "rogue" span elements.

👍🏼

@Mamaduka

Copy link
Copy Markdown
Member

Here are summarized thoughts:

  • Note mentions aren't really links, they're just token tiggers for notifications and values to be represented as "chips" in note content.
  • Use the span element and let's keep the wp-note-mention class, so some random format won't pick this up as its own. Formats are differentiated by tagName and class.
  • Based on my tests, there's no need to register a special format for mentions. RichText can handle "rogue" span elements.
  • Notifications might require an extra identity check, something like a user ID that matches the @mention string. Mention strings can be partially edited, while wrapped elements retain the attributes.

Reviewing this again, I'm not sure it helps if we still need the classes. Instead, I'll drop the data attribute and focus on adjust the kses callback to see if I can only allow the specific classes we need.

Don't have a strong opinion here. I'll defer to you and @westonruter.

@adamsilverstein

Copy link
Copy Markdown
Member Author

Thanks for all the feedback. I'll work on an alternate approach in a separate PR.

@adamsilverstein

Copy link
Copy Markdown
Member Author

Superseded by #80528, which lands the approach from the discussion here: mentions become non-interactive <span class="wp-note-mention user-N"> chips (no more Link format UI interference), the data attribute is dropped, and the kses handling collapses to two small always-on filters that reduce span classes to exactly the two mention tokens - closing the open-class allowance without the arm/disarm machinery.

@Mamaduka your notification identity-check point is flagged there as a follow-up for #79606, where the mention parsing lives.

@github-project-automation github-project-automation Bot moved this from 🔎 Needs Review to ✅ Done in WordPress 7.1 Editor Tasks Jul 21, 2026
@Mamaduka
Mamaduka deleted the update/note-mentions-data-attribute branch July 21, 2026 15:23
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] Bug An existing feature does not function as intended

Projects

Development

Successfully merging this pull request may close these issues.

Fix note @ mentions render as links and rely on an open kses class allowance

4 participants

Sponsor
SponsoredKunjungi sekarang
Promo