automattic / jetpack-comments
Replaces the default WordPress comment form.
Package info
github.com/Automattic/jetpack-comments
Type:jetpack-library
pkg:composer/automattic/jetpack-comments
Requires
- php: >=7.4
- automattic/jetpack-assets: ^5.0.4
- automattic/jetpack-image-cdn: ^0.8.0
Requires (Dev)
None
Suggests
- automattic/jetpack-autoloader: Allow for better interoperability with other plugins that use this package.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-15 21:04:33 UTC
README
Replaces the default WordPress comment form. This is the successor to Highlander Comments, and the new home for the feature WordPress.com ships as Verbum.
Nothing loads unless the filter says so:
add_filter( 'jetpack_comments_new_hotness', '__return_true' );
While it returns false the site's existing comment experience is untouched. On WordPress.com the comment-new-hotness blog sticker answers it; see "Where it loads from".
Register it early. The two loaders below read it at different points, so the
deadline is the earlier of the two: plugins_loaded on Simple, after_setup_theme
for the Jetpack module. A plugin or mu-plugin makes both. A theme's functions.php
only makes the second, so on Simple the filter would be read before it was added.
What it does
The form renders on the site the comment is posted to, and posts to that site's own wp-comments-post.php. No iframe, and the only call to WordPress.com is the exchange behind a popup sign-in, so it behaves the same on Simple, Atomic and self-hosted.
- A textarea that grows as you type.
- Sign in with WordPress.com, Google or Facebook, through a popup rather than an iframe. See "The checkpoint" below.
- Name, email and website for logged-out readers, honoring
require_name_emailand the comment cookies opt-in. These use core's own field names. - An identity line and a log-out link for readers logged in to the site itself.
- Reply threading, by watching the
comment_parentinput WordPress rewrites.
Sites that require registration take a popup sign-in as registration. Where no sign-in is available (a site with no blog token) they get a log-in prompt in place of the guest fields, and the submit button held disabled.
The checkpoint
The popup opens https://public-api.wordpress.com/connect/?comment_identity=1 with the blog id, provider, a 32-byte challenge, the site's origin, a nine-minute expiry (WordPress.com allows ten, the spare minute absorbs clock skew) and an HMAC-SHA256 signature over those five, keyed with the blog token secret. On Simple there is no blog token, and the code is already inside WordPress.com, so the Consulate signs with its own key. A click after the expiry fetches a fresh URL from wpcom/v2/comments/identity/connect before opening. That route goes through the WPCOM REST API v2 loader, so it is same-origin on self-hosted and Atomic and served by public-api.wordpress.com/wpcom/v2/sites/{id}/… on Simple.
The popup posts back { type: 'jetpack-comment-identity', code, name, avatar, challenge }, or an error, and only a message from https://public-api.wordpress.com carrying the current challenge is read. The form shows the name and avatar and carries the code in a hidden field. When the comment posts, the site redeems the code server-side over wpcom/v2/sites/{blog_id}/comments/identity/exchange, fills the author and email from the answer, and treats the commenter as registered. Codes are single use and good for an hour.
A successful exchange also sets two first-party cookies with the same expiry. jetpack_comment_identity is the passport: httponly, signed with the site's auth salt over the blog id too, so it is refused on any other site of a network, carrying the id, provider, name, email and avatar, and read only by the server when a comment posts. jetpack_comment_identity_display carries provider, name, avatar and the blog id for the page's script to draw the signed-in row from, and the script ignores it on any other blog, because on a network the cookie domain is shared. It has to be a cookie: the HTML is page-cached and served to everyone, so nothing about the visitor can be rendered into it, which is also why the signed popup URLs in the page are shared until they expire.
A returning commenter is admitted on the passport alone for as long as it lasts, up to 30 days, without going back to WordPress.com. The form says so with a hidden jetpack_comment_identity_passport field, and the server reads the passport only when that field is posted, so a log-out that never reached the server still leaves the reader posting as the guest the form showed them as. That is deliberate: consent for this site was given on the connect page, and the exchange already returned everything the comment needs. "Log out" posts the jetpack_comments_identity_logout admin-ajax action, which takes both cookies back, and flags the page so the next popup carries reauth=1: WordPress.com keeps its own 30-day cookie for the person, and without that flag it would sign the same person straight back in. The flag lives in memory, so it covers switching accounts without a reload; after one, WordPress.com's cookie decides, as it already does on every other site. That is admin-ajax rather than REST because only the site's own host can clear its first-party cookie, and on Simple that host serves no REST API. A spent or expired code clears them and asks the reader to sign in again, and so does a passport marker posted after the passport itself is gone, say from a log-out in another tab.
Not here yet
Subscriptions. The "email me new comments" and "email me new posts" options, and the modal after submitting. Jetpack Subscriptions adds its checkboxes through comment_form_submit_field, which this form replaces wholesale, so they are dropped while the filter is on. On Simple the older subscription_comment_form output is removed for the same reason, so that no host shows a subscribe option rather than one showing it and another not.
What it stores
A comment's author, email and URL go in the comment row, written by core. A
comment left through the checkpoint also gets three meta keys, written from the
exchange answer and never from the request: jetpack_comment_identity_id, the
opaque per-site id WordPress.com derives for the person; jetpack_comment_identity_provider;
and jetpack_comment_identity_avatar, served through the image CDN at display time.
Guests and users logged in to the site itself get no meta at all, because both are derivable from what core already keeps.
The experience this replaces wrote hc_post_as, hc_foreign_user_id,
hc_avatar and hc_wpcom_id_sig. Nothing here writes those, but hc_avatar is
still read for comments that already carry one, with the host check it always had.
The rule to apply when adding a key: store a field in the same change that adds something which reads it.
Layout
src/ is organized by feature, not by language. Each feature owns its PHP, its components and its styles. A directory means several files collaborate; one class stays one file.
src/
class-comments.php the filter, and what to boot
class-avatars.php avatars on comments already written
form/ takeover, mount, nonce, layout, the text box, submit
identity/ who is commenting: guest fields, log-in prompt, attribution
checkpoint/ the popup sign-in, the exchange, the passport cookie, its REST routes
ui/ widgets shared across the form
shared/ signals, and the PHP-to-JS settings shape
Sections appear when there is something to put in them. Subscriptions, a block editor and submission handling each earn a directory once they exist, and a REST route belongs to the feature it serves rather than to a folder of endpoints.
The comment meta this writes is on Jetpack Sync's comment meta whitelist, so it
reaches WordPress.com from Jetpack and Atomic sites the way hc_avatar does.
Where it loads from
Two places check the filter, so one switch covers every environment. On Simple and Atomic, packages/jetpack-mu-wpcom answers it from the comment-new-hotness blog sticker, and the popup sign-in on WordPress.com requires the same sticker on every host, self-hosted included. A tester who only sets the filter gets the form, and "Not found." in the popup.
| Environment | Loader | What stands down |
|---|---|---|
| Self-hosted, Atomic | plugins/jetpack, in the Comments module |
Jetpack_Comments, and its iframe to jetpack.wordpress.com |
| Simple | packages/jetpack-mu-wpcom, in load_verbum_comments() |
Verbum_Comments |
The Comments module still has to be active on the Jetpack plugin side. Its settings screen is left in place, and the greeting and color scheme it sets are both applied here.
Security
Need to report a security vulnerability? Go to https://automattic.com/security/ or directly to our security bug bounty site https://hackerone.com/automattic.
License
Jetpack Comments is licensed under GNU General Public License v2 (or later)