From 05c88ebd2ab0ac6b06b582cd45cd7c94a43faaa0 Mon Sep 17 00:00:00 2001 From: Tony Arcangelini Date: Fri, 10 Jul 2026 13:02:11 +0200 Subject: [PATCH 1/9] Verbum: fix blocked-cookie detection and prevent dead-end comment submissions - Detect unpartitioned cookie access via hasStorageAccess() instead of a write-and-read-back probe, which passes in a partitioned jar - Explain to the visitor why WordPress.com login is unavailable - Block submission when login is required but cannot be completed --- .../cm-841-surface-login-requirement | 4 + .../verbum-comments/class-verbum-comments.php | 2 + .../src/components/logged-out.tsx | 153 +++++++++++------- .../features/verbum-comments/src/index.tsx | 23 ++- .../features/verbum-comments/src/state.tsx | 9 +- .../features/verbum-comments/src/style.scss | 6 + .../src/features/verbum-comments/src/utils.ts | 64 ++++++-- 7 files changed, 182 insertions(+), 79 deletions(-) create mode 100644 projects/packages/jetpack-mu-wpcom/changelog/cm-841-surface-login-requirement diff --git a/projects/packages/jetpack-mu-wpcom/changelog/cm-841-surface-login-requirement b/projects/packages/jetpack-mu-wpcom/changelog/cm-841-surface-login-requirement new file mode 100644 index 000000000000..13d32ec88af5 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/cm-841-surface-login-requirement @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Verbum Comments: detect blocked cookies accurately, explain to the visitor why login options are unavailable, and block submission when login is required but cannot be completed. diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php index 59a7025e7b0a..c0d16cb21191 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php @@ -237,6 +237,8 @@ public function enqueue_assets() { /* translators: %s is the name of the provider (WordPress, Facebook, Twitter) */ 'Logged in via %s' => __( 'Logged in via %s', 'jetpack-mu-wpcom' ), 'Log out' => __( 'Log out', 'jetpack-mu-wpcom' ), + 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.' => __( 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.', 'jetpack-mu-wpcom' ), + 'Your browser is blocking cookies, so WordPress.com login is unavailable here.' => __( 'Your browser is blocking cookies, so WordPress.com login is unavailable here.', 'jetpack-mu-wpcom' ), 'Email' => __( 'Email', 'jetpack-mu-wpcom' ), '(Address never made public)' => __( '(Address never made public)', 'jetpack-mu-wpcom'), // phpcs:ignore PEAR.Functions.FunctionCallSignature.SpaceBeforeCloseBracket 'Instantly' => __( 'Instantly', 'jetpack-mu-wpcom' ), diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx index 1b96b5824aad..e6a83bf87144 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx @@ -6,6 +6,7 @@ import { VerbumSignals } from '../state'; import { serviceData } from '../utils'; import { EmailForm } from './EmailForm'; import type { SocialServiceName } from '../hooks/useSocialLogin'; +import type { ComponentChildren } from 'preact'; const { mustLogIn, requireNameEmail, commentRegistration } = VerbumComments; interface LoggedOutProps { @@ -40,6 +41,14 @@ const getLoginCommentText = ( commentParent: Signal ) => { return { defaultText }; }; +const LoggedOutWrapper = ( { children }: { children: ComponentChildren } ) => ( +
+
+
{ children }
+
+
+); + export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOutProps ) => { const [ activeService, setActiveService ] = useState( '' ); const closeLoginPopupService = requireNameEmail && ! mustLogIn ? 'mail' : ''; @@ -84,72 +93,92 @@ export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOut const { commentParent } = useContext( VerbumSignals ); + if ( ! canWeAccessCookies ) { + if ( mustLogIn ) { + return ( + +
+ { getLoginCommentText( commentParent ) } +
+

+ { translate( + 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.' + ) } +

+
+ ); + } + + return ( + +

+ { translate( + 'Your browser is blocking cookies, so WordPress.com login is unavailable here.' + ) } +

+ +
+ ); + } + return ( -
-
-
- { canWeAccessCookies && ( - <> -
- { getLoginCommentText( commentParent ) } -
-
+
+ { getLoginCommentText( commentParent ) } +
+
+
+ { Object.entries( serviceData ).map( ( [ service, value ] ) => { + // Don't show mail login if "Users must be registered and logged in to comment" enabled. + if ( mustLogIn && service === 'mail' ) { + // eslint-disable-next-line array-callback-return + return; + } + + return ( + - ); - } ) } -
- { [ 'wordpress', 'facebook' ].includes( activeService ) && ( -
-

- -
- ) } -
- - ) } - + + + ); + } ) }
+ { [ 'wordpress', 'facebook' ].includes( activeService ) && ( +
+

+ +
+ ) }
-
+ + ); }; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx index 02a37d8e6175..2c473f1fd623 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx @@ -17,6 +17,8 @@ import { setUserInfoCookie, addWordPressDomain, hasSubscriptionOptionsVisible, + isCommentBlockedByCookies, + resolveCookieAccess, } from './utils'; import type { VerbumAppProps } from './types'; @@ -160,6 +162,11 @@ const Verbum = ( { siteId, parentForm }: VerbumAppProps ) => { }; const handleCommentSubmit = async ( event: Event ) => { + if ( isCommentBlockedByCookies() ) { + event.preventDefault(); + return; + } + window.removeEventListener( 'beforeunload', handleBeforeUnload ); if ( userInfo.value?.service === 'guest' ) { if ( shouldStoreEmailData.value ) { @@ -246,11 +253,13 @@ const { siteId } = { ...VerbumComments, }; -document.querySelectorAll( '.comment-form__verbum' ).forEach( element => { - render( - - - , - element - ); +resolveCookieAccess().then( () => { + document.querySelectorAll( '.comment-form__verbum' ).forEach( element => { + render( + + + , + element + ); + } ); } ); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx index 88fa7047f019..88ef661b513d 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx @@ -1,6 +1,12 @@ import { signal, computed } from '@preact/signals'; import { createContext } from 'preact'; -import { canWeAccessCookies, getUserInfoCookie, isAuthRequired, isEmptyEditor } from './utils'; +import { + canWeAccessCookies, + getUserInfoCookie, + isAuthRequired, + isCommentBlockedByCookies, + isEmptyEditor, +} from './utils'; import type { UserInfo, SubscriptionDetails } from './types'; import type { Signal } from '@preact/signals'; @@ -83,6 +89,7 @@ export function createSignals() { */ const isReplyDisabled = computed( () => { return ( + isCommentBlockedByCookies() || ( isAuthRequired() && ! userLoggedIn.value && ( isMailFormMissingInput.value || isMailFormInvalid.value ) ) || diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss index 7f88cd7861db..6c1a72e78349 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss @@ -332,6 +332,12 @@ padding-bottom: 16px; } + .verbum-subscriptions__cookie-notice { + font-size: 13px; + margin: 0 0 16px; + opacity: 0.8; + } + .verbum-logins { display: flex; align-items: center; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts index 5c9b131f8e3b..f86938da989d 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts @@ -24,19 +24,62 @@ export const serviceData = { }, }; -export const canWeAccessCookies = () => { - // Is a WordPress cookie already set and can we read it? - if ( document.cookie.includes( 'wpc_' ) ) { - return true; +const readCookieNames = () => + document.cookie.split( ';' ).map( cookie => cookie.trim().split( '=' )[ 0 ] ); + +const isCookieJarWritable = () => { + document.cookie = 'verbum_test=1; path=/; SameSite=None; Secure'; + + if ( ! readCookieNames().includes( 'verbum_test' ) ) { + return false; + } + + document.cookie = + 'verbum_test=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=None; Secure'; + + return true; +}; + +interface CookieAccess { + writable: boolean; + unpartitioned: boolean; +} + +let cookieAccess: CookieAccess | undefined; + +export const resolveCookieAccess = async () => { + const { hasStorageAccess } = document as Document & { + hasStorageAccess?: () => Promise< boolean >; + }; + + let unpartitioned = true; + + if ( typeof hasStorageAccess === 'function' ) { + try { + unpartitioned = await Promise.race( [ + hasStorageAccess.call( document ), + new Promise< boolean >( resolve => setTimeout( () => resolve( true ), 1000 ) ), + ] ); + } catch { + unpartitioned = true; + } } - // Can we set a cookie and read our own cookie? - document.cookie = 'verbum_test=1; SameSite=None; Secure'; - if ( document.cookie.includes( 'verbum_test' ) ) { - return true; + cookieAccess = { writable: isCookieJarWritable(), unpartitioned }; +}; + +const getCookieAccess = (): CookieAccess => { + if ( ! cookieAccess ) { + cookieAccess = { writable: isCookieJarWritable(), unpartitioned: true }; } - return false; + return cookieAccess; +}; + +export const canWeAccessCookies = () => { + const { writable, unpartitioned } = getCookieAccess(); + + return writable && unpartitioned; }; /** @@ -238,3 +281,6 @@ export const hasSubscriptionOptionsVisible = () => export const isAuthRequired = () => VerbumComments.requireNameEmail || VerbumComments.commentRegistration; + +export const isCommentBlockedByCookies = () => + Boolean( VerbumComments.mustLogIn ) && ! canWeAccessCookies(); From 36db107bb223da5b60ddbb5720e277b0b3724701 Mon Sep 17 00:00:00 2001 From: Tony Arcangelini Date: Mon, 3 Aug 2026 14:32:00 +0200 Subject: [PATCH 2/9] Verbum: don't block Jetpack-identity commenters, describe disabled submit --- .../verbum-comments/src/components/comment-footer.tsx | 2 ++ .../verbum-comments/src/components/logged-out.tsx | 4 ++-- .../src/features/verbum-comments/src/utils.ts | 8 +++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx index 07377a48c1d0..10955be36792 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx @@ -2,6 +2,7 @@ import clsx from 'clsx'; import { useContext } from 'preact/hooks'; import { translate } from '../i18n'; import { VerbumSignals } from '../state'; +import { COOKIE_NOTICE_ID, isCommentBlockedByCookies } from '../utils'; import { SettingsButton } from './settings-button'; interface CommentFooterProps { @@ -32,6 +33,7 @@ export const CommentFooter = ( { toggleTray }: CommentFooterProps ) => { } ) } disabled={ isReplyDisabled.value } aria-disabled={ isReplyDisabled.value } + aria-describedby={ isCommentBlockedByCookies() ? COOKIE_NOTICE_ID : undefined } > { commentParent.value ? translate( 'Reply' ) : translate( 'Comment' ) } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx index e6a83bf87144..92cfdb7df371 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx @@ -3,7 +3,7 @@ import clsx from 'clsx'; import { useContext, useEffect, useState } from 'preact/hooks'; import { translate } from '../i18n'; import { VerbumSignals } from '../state'; -import { serviceData } from '../utils'; +import { COOKIE_NOTICE_ID, serviceData } from '../utils'; import { EmailForm } from './EmailForm'; import type { SocialServiceName } from '../hooks/useSocialLogin'; import type { ComponentChildren } from 'preact'; @@ -100,7 +100,7 @@ export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOut
{ getLoginCommentText( commentParent ) }
-

+

{ translate( 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.' ) } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts index f86938da989d..0328a96af611 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts @@ -282,5 +282,11 @@ export const hasSubscriptionOptionsVisible = () => export const isAuthRequired = () => VerbumComments.requireNameEmail || VerbumComments.commentRegistration; +export const COOKIE_NOTICE_ID = 'verbum-cookie-notice'; + +// `mustLogIn` reflects the WordPress.com session, which is never present in the third-party +// Jetpack iframe. The Jetpack identity travels in the POST, not a cookie, so it still posts. export const isCommentBlockedByCookies = () => - Boolean( VerbumComments.mustLogIn ) && ! canWeAccessCookies(); + Boolean( VerbumComments.mustLogIn ) && + ! VerbumComments.isJetpackCommentsLoggedIn && + ! canWeAccessCookies(); From 78f2aafeadf8b650ffca9daf4b9d7095fa60e2aa Mon Sep 17 00:00:00 2001 From: Tony Arcangelini Date: Mon, 3 Aug 2026 14:58:20 +0200 Subject: [PATCH 3/9] Verbum: keep Facebook commenters unblocked when cookies are partitioned --- .../verbum-comments/src/components/comment-footer.tsx | 6 ++++-- .../src/features/verbum-comments/src/index.tsx | 2 +- .../src/features/verbum-comments/src/state.tsx | 6 ++++-- .../src/features/verbum-comments/src/utils.ts | 7 +++++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx index 10955be36792..6b3b13320adb 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx @@ -10,7 +10,7 @@ interface CommentFooterProps { } export const CommentFooter = ( { toggleTray }: CommentFooterProps ) => { - const { commentParent, isReplyDisabled, isSavingComment, isTrayOpen, userLoggedIn } = + const { commentParent, isReplyDisabled, isSavingComment, isTrayOpen, userInfo, userLoggedIn } = useContext( VerbumSignals ); return (

{ } ) } disabled={ isReplyDisabled.value } aria-disabled={ isReplyDisabled.value } - aria-describedby={ isCommentBlockedByCookies() ? COOKIE_NOTICE_ID : undefined } + aria-describedby={ + isCommentBlockedByCookies( userInfo.value?.service ) ? COOKIE_NOTICE_ID : undefined + } > { commentParent.value ? translate( 'Reply' ) : translate( 'Comment' ) } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx index 2c473f1fd623..800700dc2556 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx @@ -162,7 +162,7 @@ const Verbum = ( { siteId, parentForm }: VerbumAppProps ) => { }; const handleCommentSubmit = async ( event: Event ) => { - if ( isCommentBlockedByCookies() ) { + if ( isCommentBlockedByCookies( userInfo.value?.service ) ) { event.preventDefault(); return; } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx index 88ef661b513d..9a121597a62d 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx @@ -24,11 +24,13 @@ export function createSignals() { /* * Calculate if user is logged in. For self-hosted sites this check is based only on VerbumComments.isJetpackCommentsLoggedIn. * Here we also check if cookies are accessible, userInfo is set and the service is different from 'guest' or 'jetpack'. + * Facebook skips the cookie check: its identity is proven by the `wpc_fbc` cookie we just read, + * so it holds up where cookies are partitioned but readable. */ const userLoggedIn = computed( () => { return ( VerbumComments.isJetpackCommentsLoggedIn || - ( canWeAccessCookies() && + ( ( canWeAccessCookies() || userInfo.value?.service === 'facebook' ) && userInfo.value && userInfo.value?.service !== 'guest' && userInfo.value?.service !== 'jetpack' ) @@ -89,7 +91,7 @@ export function createSignals() { */ const isReplyDisabled = computed( () => { return ( - isCommentBlockedByCookies() || + isCommentBlockedByCookies( userInfo.value?.service ) || ( isAuthRequired() && ! userLoggedIn.value && ( isMailFormMissingInput.value || isMailFormInvalid.value ) ) || diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts index 0328a96af611..3d4f57eab4f9 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts @@ -285,8 +285,11 @@ export const isAuthRequired = () => export const COOKIE_NOTICE_ID = 'verbum-cookie-notice'; // `mustLogIn` reflects the WordPress.com session, which is never present in the third-party -// Jetpack iframe. The Jetpack identity travels in the POST, not a cookie, so it still posts. -export const isCommentBlockedByCookies = () => +// Jetpack iframe. Two identities post fine without it: `jetpack` travels in the POST itself, +// and `facebook` is verified server-side from `wpc_fbc`, which the frame can still read and +// send when cookies are partitioned rather than blocked. +export const isCommentBlockedByCookies = ( service: string | undefined ) => Boolean( VerbumComments.mustLogIn ) && ! VerbumComments.isJetpackCommentsLoggedIn && + service !== 'facebook' && ! canWeAccessCookies(); From ecd6971ace17402164e964ac08817d55e21e978a Mon Sep 17 00:00:00 2001 From: Tony Arcangelini Date: Mon, 3 Aug 2026 15:10:05 +0200 Subject: [PATCH 4/9] Verbum: simplify comment block to a single signal --- .../src/components/comment-footer.tsx | 6 +--- .../src/components/logged-out.tsx | 4 +-- .../features/verbum-comments/src/index.tsx | 4 +-- .../features/verbum-comments/src/state.tsx | 29 ++++++++++++------- .../src/features/verbum-comments/src/utils.ts | 12 -------- 5 files changed, 23 insertions(+), 32 deletions(-) diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx index 6b3b13320adb..07377a48c1d0 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/comment-footer.tsx @@ -2,7 +2,6 @@ import clsx from 'clsx'; import { useContext } from 'preact/hooks'; import { translate } from '../i18n'; import { VerbumSignals } from '../state'; -import { COOKIE_NOTICE_ID, isCommentBlockedByCookies } from '../utils'; import { SettingsButton } from './settings-button'; interface CommentFooterProps { @@ -10,7 +9,7 @@ interface CommentFooterProps { } export const CommentFooter = ( { toggleTray }: CommentFooterProps ) => { - const { commentParent, isReplyDisabled, isSavingComment, isTrayOpen, userInfo, userLoggedIn } = + const { commentParent, isReplyDisabled, isSavingComment, isTrayOpen, userLoggedIn } = useContext( VerbumSignals ); return (
{ } ) } disabled={ isReplyDisabled.value } aria-disabled={ isReplyDisabled.value } - aria-describedby={ - isCommentBlockedByCookies( userInfo.value?.service ) ? COOKIE_NOTICE_ID : undefined - } > { commentParent.value ? translate( 'Reply' ) : translate( 'Comment' ) } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx index 92cfdb7df371..e6a83bf87144 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx @@ -3,7 +3,7 @@ import clsx from 'clsx'; import { useContext, useEffect, useState } from 'preact/hooks'; import { translate } from '../i18n'; import { VerbumSignals } from '../state'; -import { COOKIE_NOTICE_ID, serviceData } from '../utils'; +import { serviceData } from '../utils'; import { EmailForm } from './EmailForm'; import type { SocialServiceName } from '../hooks/useSocialLogin'; import type { ComponentChildren } from 'preact'; @@ -100,7 +100,7 @@ export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOut
{ getLoginCommentText( commentParent ) }
-

+

{ translate( 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.' ) } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx index 800700dc2556..22cd0f488860 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx @@ -17,7 +17,6 @@ import { setUserInfoCookie, addWordPressDomain, hasSubscriptionOptionsVisible, - isCommentBlockedByCookies, resolveCookieAccess, } from './utils'; import type { VerbumAppProps } from './types'; @@ -27,6 +26,7 @@ import './style.scss'; const Verbum = ( { siteId, parentForm }: VerbumAppProps ) => { const { hasOpenedTrayOnce, + isCommentBlocked, isEmptyComment, isSavingComment, isTrayOpen, @@ -162,7 +162,7 @@ const Verbum = ( { siteId, parentForm }: VerbumAppProps ) => { }; const handleCommentSubmit = async ( event: Event ) => { - if ( isCommentBlockedByCookies( userInfo.value?.service ) ) { + if ( isCommentBlocked.value ) { event.preventDefault(); return; } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx index 9a121597a62d..adf3fe4e9184 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx @@ -1,12 +1,6 @@ import { signal, computed } from '@preact/signals'; import { createContext } from 'preact'; -import { - canWeAccessCookies, - getUserInfoCookie, - isAuthRequired, - isCommentBlockedByCookies, - isEmptyEditor, -} from './utils'; +import { canWeAccessCookies, getUserInfoCookie, isAuthRequired, isEmptyEditor } from './utils'; import type { UserInfo, SubscriptionDetails } from './types'; import type { Signal } from '@preact/signals'; @@ -24,13 +18,11 @@ export function createSignals() { /* * Calculate if user is logged in. For self-hosted sites this check is based only on VerbumComments.isJetpackCommentsLoggedIn. * Here we also check if cookies are accessible, userInfo is set and the service is different from 'guest' or 'jetpack'. - * Facebook skips the cookie check: its identity is proven by the `wpc_fbc` cookie we just read, - * so it holds up where cookies are partitioned but readable. */ const userLoggedIn = computed( () => { return ( VerbumComments.isJetpackCommentsLoggedIn || - ( ( canWeAccessCookies() || userInfo.value?.service === 'facebook' ) && + ( canWeAccessCookies() && userInfo.value && userInfo.value?.service !== 'guest' && userInfo.value?.service !== 'jetpack' ) @@ -85,13 +77,27 @@ export function createSignals() { return ! mailLoginData.value.email || ! mailLoginData.value.author; } ); + /* + * Login is required, the visitor has no identity, and cookies aren't available to get one, + * so there is no way for this comment to be accepted. Facebook is exempt: it is verified from + * the `wpc_fbc` cookie, which still reaches the server when cookies are partitioned. + */ + const isCommentBlocked = computed( () => { + return ( + Boolean( VerbumComments.mustLogIn ) && + ! userLoggedIn.value && + userInfo.value?.service !== 'facebook' && + ! canWeAccessCookies() + ); + } ); + /* * Calculate if the reply button should be disabled. When we have no user data we check the shouldDisableReply value, * otherwise we check if the comment is empty or saving. */ const isReplyDisabled = computed( () => { return ( - isCommentBlockedByCookies( userInfo.value?.service ) || + isCommentBlocked.value || ( isAuthRequired() && ! userLoggedIn.value && ( isMailFormMissingInput.value || isMailFormInvalid.value ) ) || @@ -132,6 +138,7 @@ export function createSignals() { isTrayOpen, hasOpenedTrayOnce, commentValue, + isCommentBlocked, isEmptyComment, isSavingComment, isMailFormInvalid, diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts index 3d4f57eab4f9..ea2cba338125 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts @@ -281,15 +281,3 @@ export const hasSubscriptionOptionsVisible = () => export const isAuthRequired = () => VerbumComments.requireNameEmail || VerbumComments.commentRegistration; - -export const COOKIE_NOTICE_ID = 'verbum-cookie-notice'; - -// `mustLogIn` reflects the WordPress.com session, which is never present in the third-party -// Jetpack iframe. Two identities post fine without it: `jetpack` travels in the POST itself, -// and `facebook` is verified server-side from `wpc_fbc`, which the frame can still read and -// send when cookies are partitioned rather than blocked. -export const isCommentBlockedByCookies = ( service: string | undefined ) => - Boolean( VerbumComments.mustLogIn ) && - ! VerbumComments.isJetpackCommentsLoggedIn && - service !== 'facebook' && - ! canWeAccessCookies(); From d80fc97dde5060986b31a86571a011f24de11139 Mon Sep 17 00:00:00 2001 From: Tony Arcangelini Date: Mon, 3 Aug 2026 15:23:22 +0200 Subject: [PATCH 5/9] Verbum: reduce to a notice and a disabled button --- .../cm-841-surface-login-requirement | 2 +- .../verbum-comments/class-verbum-comments.php | 1 - .../src/components/logged-out.tsx | 165 ++++++++---------- .../features/verbum-comments/src/index.tsx | 17 +- .../features/verbum-comments/src/state.tsx | 13 +- .../features/verbum-comments/src/style.scss | 2 +- .../src/features/verbum-comments/src/utils.ts | 61 +------ 7 files changed, 97 insertions(+), 164 deletions(-) diff --git a/projects/packages/jetpack-mu-wpcom/changelog/cm-841-surface-login-requirement b/projects/packages/jetpack-mu-wpcom/changelog/cm-841-surface-login-requirement index 13d32ec88af5..ab726c9841ed 100644 --- a/projects/packages/jetpack-mu-wpcom/changelog/cm-841-surface-login-requirement +++ b/projects/packages/jetpack-mu-wpcom/changelog/cm-841-surface-login-requirement @@ -1,4 +1,4 @@ Significance: patch Type: fixed -Verbum Comments: detect blocked cookies accurately, explain to the visitor why login options are unavailable, and block submission when login is required but cannot be completed. +Verbum Comments: explain why commenting is unavailable when login is required but the login options cannot be shown, instead of offering a form that will be rejected. diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php index c0d16cb21191..119ed5cf36cd 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php @@ -238,7 +238,6 @@ public function enqueue_assets() { 'Logged in via %s' => __( 'Logged in via %s', 'jetpack-mu-wpcom' ), 'Log out' => __( 'Log out', 'jetpack-mu-wpcom' ), 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.' => __( 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.', 'jetpack-mu-wpcom' ), - 'Your browser is blocking cookies, so WordPress.com login is unavailable here.' => __( 'Your browser is blocking cookies, so WordPress.com login is unavailable here.', 'jetpack-mu-wpcom' ), 'Email' => __( 'Email', 'jetpack-mu-wpcom' ), '(Address never made public)' => __( '(Address never made public)', 'jetpack-mu-wpcom'), // phpcs:ignore PEAR.Functions.FunctionCallSignature.SpaceBeforeCloseBracket 'Instantly' => __( 'Instantly', 'jetpack-mu-wpcom' ), diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx index e6a83bf87144..9c294759c9b8 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx @@ -6,7 +6,6 @@ import { VerbumSignals } from '../state'; import { serviceData } from '../utils'; import { EmailForm } from './EmailForm'; import type { SocialServiceName } from '../hooks/useSocialLogin'; -import type { ComponentChildren } from 'preact'; const { mustLogIn, requireNameEmail, commentRegistration } = VerbumComments; interface LoggedOutProps { @@ -41,14 +40,6 @@ const getLoginCommentText = ( commentParent: Signal ) => { return { defaultText }; }; -const LoggedOutWrapper = ( { children }: { children: ComponentChildren } ) => ( -

-
-
{ children }
-
-
-); - export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOutProps ) => { const [ activeService, setActiveService ] = useState( '' ); const closeLoginPopupService = requireNameEmail && ! mustLogIn ? 'mail' : ''; @@ -93,92 +84,86 @@ export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOut const { commentParent } = useContext( VerbumSignals ); - if ( ! canWeAccessCookies ) { - if ( mustLogIn ) { - return ( - -
- { getLoginCommentText( commentParent ) } -
-

- { translate( - 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.' - ) } -

-
- ); - } - - return ( - -

- { translate( - 'Your browser is blocking cookies, so WordPress.com login is unavailable here.' - ) } -

- -
- ); - } + // Login is required but the login options can't render, so there is no way to comment here. + const isLoginBlocked = ! canWeAccessCookies && mustLogIn; return ( - -
- { getLoginCommentText( commentParent ) } -
-
-
- { Object.entries( serviceData ).map( ( [ service, value ] ) => { - // Don't show mail login if "Users must be registered and logged in to comment" enabled. - if ( mustLogIn && service === 'mail' ) { - // eslint-disable-next-line array-callback-return - return; - } - - return ( - - ); - } ) } + { Object.entries( serviceData ).map( ( [ service, value ] ) => { + // Don't show mail login if "Users must be registered and logged in to comment" enabled. + if ( mustLogIn && service === 'mail' ) { + // eslint-disable-next-line array-callback-return + return; + } + + return ( + + ); + } ) } +
+ { [ 'wordpress', 'facebook' ].includes( activeService ) && ( +
+

+ +
+ ) } +
+ ) } +
- { [ 'wordpress', 'facebook' ].includes( activeService ) && ( -
-

- -
- ) }
- - +
); }; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx index 22cd0f488860..099098872df3 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx @@ -17,7 +17,6 @@ import { setUserInfoCookie, addWordPressDomain, hasSubscriptionOptionsVisible, - resolveCookieAccess, } from './utils'; import type { VerbumAppProps } from './types'; @@ -253,13 +252,11 @@ const { siteId } = { ...VerbumComments, }; -resolveCookieAccess().then( () => { - document.querySelectorAll( '.comment-form__verbum' ).forEach( element => { - render( - - - , - element - ); - } ); +document.querySelectorAll( '.comment-form__verbum' ).forEach( element => { + render( + + + , + element + ); } ); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx index adf3fe4e9184..42958d4f7129 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx @@ -78,17 +78,12 @@ export function createSignals() { } ); /* - * Login is required, the visitor has no identity, and cookies aren't available to get one, - * so there is no way for this comment to be accepted. Facebook is exempt: it is verified from - * the `wpc_fbc` cookie, which still reaches the server when cookies are partitioned. + * Login is required but the login options can't render, so there is no way for this comment to + * be accepted. `mustLogIn` tracks the WordPress.com session, which is absent in the Jetpack + * iframe even for visitors logged in to the site itself, hence the userLoggedIn check. */ const isCommentBlocked = computed( () => { - return ( - Boolean( VerbumComments.mustLogIn ) && - ! userLoggedIn.value && - userInfo.value?.service !== 'facebook' && - ! canWeAccessCookies() - ); + return Boolean( VerbumComments.mustLogIn ) && ! userLoggedIn.value && ! canWeAccessCookies(); } ); /* diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss index 6c1a72e78349..75694b830505 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss @@ -334,7 +334,7 @@ .verbum-subscriptions__cookie-notice { font-size: 13px; - margin: 0 0 16px; + margin-block-end: 16px; opacity: 0.8; } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts index ea2cba338125..5c9b131f8e3b 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts @@ -24,62 +24,19 @@ export const serviceData = { }, }; -const readCookieNames = () => - document.cookie.split( ';' ).map( cookie => cookie.trim().split( '=' )[ 0 ] ); - -const isCookieJarWritable = () => { - document.cookie = 'verbum_test=1; path=/; SameSite=None; Secure'; - - if ( ! readCookieNames().includes( 'verbum_test' ) ) { - return false; - } - - document.cookie = - 'verbum_test=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=None; Secure'; - - return true; -}; - -interface CookieAccess { - writable: boolean; - unpartitioned: boolean; -} - -let cookieAccess: CookieAccess | undefined; - -export const resolveCookieAccess = async () => { - const { hasStorageAccess } = document as Document & { - hasStorageAccess?: () => Promise< boolean >; - }; - - let unpartitioned = true; - - if ( typeof hasStorageAccess === 'function' ) { - try { - unpartitioned = await Promise.race( [ - hasStorageAccess.call( document ), - new Promise< boolean >( resolve => setTimeout( () => resolve( true ), 1000 ) ), - ] ); - } catch { - unpartitioned = true; - } +export const canWeAccessCookies = () => { + // Is a WordPress cookie already set and can we read it? + if ( document.cookie.includes( 'wpc_' ) ) { + return true; } - cookieAccess = { writable: isCookieJarWritable(), unpartitioned }; -}; - -const getCookieAccess = (): CookieAccess => { - if ( ! cookieAccess ) { - cookieAccess = { writable: isCookieJarWritable(), unpartitioned: true }; + // Can we set a cookie and read our own cookie? + document.cookie = 'verbum_test=1; SameSite=None; Secure'; + if ( document.cookie.includes( 'verbum_test' ) ) { + return true; } - return cookieAccess; -}; - -export const canWeAccessCookies = () => { - const { writable, unpartitioned } = getCookieAccess(); - - return writable && unpartitioned; + return false; }; /** From 29d2b1d6ae9daf146a7b75f5d3993d0227eae1b4 Mon Sep 17 00:00:00 2001 From: Tony Arcangelini Date: Mon, 3 Aug 2026 15:29:29 +0200 Subject: [PATCH 6/9] Verbum: treat partitioned cookies as inaccessible --- .../src/features/verbum-comments/src/utils.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts index 5c9b131f8e3b..c9b27e013f18 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts @@ -1,3 +1,4 @@ +import { signal } from '@preact/signals'; import { translate } from './i18n'; import { Facebook, Mail, WordPress } from './images'; import type { UserInfo } from './types'; @@ -24,7 +25,28 @@ export const serviceData = { }, }; +/* + * Firefox and Safari can partition this frame's cookies instead of blocking them, so the checks + * below write and read back fine while the WordPress.com session stays out of reach. Resolves + * after first render, so start optimistic and let the signal re-render what depends on it. + */ +const hasUnpartitionedCookies = signal( true ); + +document + .hasStorageAccess?.() + .then( granted => { + hasUnpartitionedCookies.value = granted; + } ) + .catch( () => { + // Assume cookies are usable if the browser won't say. + } ); + export const canWeAccessCookies = () => { + // Our cookies are readable here, but they aren't the ones login needs. + if ( ! hasUnpartitionedCookies.value ) { + return false; + } + // Is a WordPress cookie already set and can we read it? if ( document.cookie.includes( 'wpc_' ) ) { return true; From 63baeca3c91289d5c0ab0390ea50b221b529dbea Mon Sep 17 00:00:00 2001 From: Tony Arcangelini Date: Tue, 4 Aug 2026 15:45:11 +0200 Subject: [PATCH 7/9] Verbum: revert partitioned-cookie detection, reuse isCommentBlocked --- .../src/components/logged-out.tsx | 7 ++---- .../features/verbum-comments/src/style.scss | 1 - .../src/features/verbum-comments/src/utils.ts | 22 ------------------- 3 files changed, 2 insertions(+), 28 deletions(-) diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx index 9c294759c9b8..d97209644d33 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx @@ -82,10 +82,7 @@ export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOut setActiveService( service ); }; - const { commentParent } = useContext( VerbumSignals ); - - // Login is required but the login options can't render, so there is no way to comment here. - const isLoginBlocked = ! canWeAccessCookies && mustLogIn; + const { commentParent, isCommentBlocked } = useContext( VerbumSignals ); return (
@@ -96,7 +93,7 @@ export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOut { getLoginCommentText( commentParent ) }
) } - { isLoginBlocked && ( + { isCommentBlocked.value && (

{ translate( 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.' diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss index 75694b830505..2c3549ac1e71 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss @@ -335,7 +335,6 @@ .verbum-subscriptions__cookie-notice { font-size: 13px; margin-block-end: 16px; - opacity: 0.8; } .verbum-logins { diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts index c9b27e013f18..5c9b131f8e3b 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts @@ -1,4 +1,3 @@ -import { signal } from '@preact/signals'; import { translate } from './i18n'; import { Facebook, Mail, WordPress } from './images'; import type { UserInfo } from './types'; @@ -25,28 +24,7 @@ export const serviceData = { }, }; -/* - * Firefox and Safari can partition this frame's cookies instead of blocking them, so the checks - * below write and read back fine while the WordPress.com session stays out of reach. Resolves - * after first render, so start optimistic and let the signal re-render what depends on it. - */ -const hasUnpartitionedCookies = signal( true ); - -document - .hasStorageAccess?.() - .then( granted => { - hasUnpartitionedCookies.value = granted; - } ) - .catch( () => { - // Assume cookies are usable if the browser won't say. - } ); - export const canWeAccessCookies = () => { - // Our cookies are readable here, but they aren't the ones login needs. - if ( ! hasUnpartitionedCookies.value ) { - return false; - } - // Is a WordPress cookie already set and can we read it? if ( document.cookie.includes( 'wpc_' ) ) { return true; From f64c2d10c14bd846b688931369b6d2d60cfb17de Mon Sep 17 00:00:00 2001 From: Tony Arcangelini Date: Tue, 4 Aug 2026 16:14:28 +0200 Subject: [PATCH 8/9] Verbum: single source for cookie access, status role, clearer notice copy --- .../verbum-comments/class-verbum-comments.php | 2 +- .../verbum-comments/src/components/logged-out.tsx | 15 +++++++-------- .../src/features/verbum-comments/src/index.tsx | 13 ++----------- .../src/features/verbum-comments/src/state.tsx | 10 ++++++++-- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php index 119ed5cf36cd..99e2ead82116 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/class-verbum-comments.php @@ -237,7 +237,7 @@ public function enqueue_assets() { /* translators: %s is the name of the provider (WordPress, Facebook, Twitter) */ 'Logged in via %s' => __( 'Logged in via %s', 'jetpack-mu-wpcom' ), 'Log out' => __( 'Log out', 'jetpack-mu-wpcom' ), - 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.' => __( 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.', 'jetpack-mu-wpcom' ), + 'Your browser is blocking the cookies needed to log in and comment here. Allow cookies in your privacy settings, then reload the page.' => __( 'Your browser is blocking the cookies needed to log in and comment here. Allow cookies in your privacy settings, then reload the page.', 'jetpack-mu-wpcom' ), 'Email' => __( 'Email', 'jetpack-mu-wpcom' ), '(Address never made public)' => __( '(Address never made public)', 'jetpack-mu-wpcom'), // phpcs:ignore PEAR.Functions.FunctionCallSignature.SpaceBeforeCloseBracket 'Instantly' => __( 'Instantly', 'jetpack-mu-wpcom' ), diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx index d97209644d33..46e08490fa2a 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-out.tsx @@ -10,7 +10,6 @@ import type { SocialServiceName } from '../hooks/useSocialLogin'; const { mustLogIn, requireNameEmail, commentRegistration } = VerbumComments; interface LoggedOutProps { login: ( service: SocialServiceName ) => void; - canWeAccessCookies: boolean; loginWindow: Window | null; } @@ -40,7 +39,7 @@ const getLoginCommentText = ( commentParent: Signal ) => { return { defaultText }; }; -export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOutProps ) => { +export const LoggedOut = ( { login, loginWindow }: LoggedOutProps ) => { const [ activeService, setActiveService ] = useState( '' ); const closeLoginPopupService = requireNameEmail && ! mustLogIn ? 'mail' : ''; @@ -82,25 +81,25 @@ export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOut setActiveService( service ); }; - const { commentParent, isCommentBlocked } = useContext( VerbumSignals ); + const { canAccessCookies, commentParent, isCommentBlocked } = useContext( VerbumSignals ); return (

- { ( canWeAccessCookies || mustLogIn ) && ( + { ( canAccessCookies || mustLogIn ) && (
{ getLoginCommentText( commentParent ) }
) } { isCommentBlocked.value && ( -

+

{ translate( - 'Commenting here requires cookie access. Allow cookies for this site, then reload the page.' + 'Your browser is blocking the cookies needed to log in and comment here. Allow cookies in your privacy settings, then reload the page.' ) }

) } - { canWeAccessCookies && ( + { canAccessCookies && (
diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx index 099098872df3..5c1fd42a33c8 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/index.tsx @@ -12,12 +12,7 @@ import useFormMutations from './hooks/useFormMutations'; import useSocialLogin from './hooks/useSocialLogin'; import { translate } from './i18n'; import { createSignals, VerbumSignals } from './state'; -import { - canWeAccessCookies, - setUserInfoCookie, - addWordPressDomain, - hasSubscriptionOptionsVisible, -} from './utils'; +import { setUserInfoCookie, addWordPressDomain, hasSubscriptionOptionsVisible } from './utils'; import type { VerbumAppProps } from './types'; import './style.scss'; @@ -232,11 +227,7 @@ const Verbum = ( { siteId, parentForm }: VerbumAppProps ) => { { userLoggedIn.value ? ( ) : ( - + ) }
diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx index 42958d4f7129..c3db6b7a8c8e 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/state.tsx @@ -10,6 +10,11 @@ import type { Signal } from '@preact/signals'; * @return An object containing all the signals used in the app. */ export function createSignals() { + /* + * Cookie access can't change without a page reload, so probe once and share the answer. + */ + const canAccessCookies = canWeAccessCookies(); + /* * In userInfo we store the user data for logged-in users. */ @@ -22,7 +27,7 @@ export function createSignals() { const userLoggedIn = computed( () => { return ( VerbumComments.isJetpackCommentsLoggedIn || - ( canWeAccessCookies() && + ( canAccessCookies && userInfo.value && userInfo.value?.service !== 'guest' && userInfo.value?.service !== 'jetpack' ) @@ -83,7 +88,7 @@ export function createSignals() { * iframe even for visitors logged in to the site itself, hence the userLoggedIn check. */ const isCommentBlocked = computed( () => { - return Boolean( VerbumComments.mustLogIn ) && ! userLoggedIn.value && ! canWeAccessCookies(); + return Boolean( VerbumComments.mustLogIn ) && ! userLoggedIn.value && ! canAccessCookies; } ); /* @@ -127,6 +132,7 @@ export function createSignals() { const subscribeModalStatus: Signal< string | undefined > = signal( undefined ); return { + canAccessCookies, userInfo, userLoggedIn, mailLoginData, From 3361e93283e18800ec3dd1b18accce78cec4df0f Mon Sep 17 00:00:00 2001 From: Tony Arcangelini Date: Tue, 4 Aug 2026 17:52:46 +0200 Subject: [PATCH 9/9] Verbum: give the cookie notice the accent-bar treatment --- .../src/features/verbum-comments/src/style.scss | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss index 2c3549ac1e71..4929d022019e 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/style.scss @@ -332,9 +332,15 @@ padding-bottom: 16px; } + // Matches the accent-bar treatment of .verbum-message below. Colors are + // pinned rather than themed so the notice stays legible in every scheme. .verbum-subscriptions__cookie-notice { - font-size: 13px; - margin-block-end: 16px; + margin-block: 0 16px; + padding: 8px 12px; + border-inline-start: 4px solid #f0b849; + background-color: #fef8ee; + color: #3c434a; + font-size: 14px; } .verbum-logins {