Skip to content

Commit

Permalink
Fix Verbum comments in Query Loop (#40933)
Browse files Browse the repository at this point in the history
  • Loading branch information
alshakero authored Jan 10, 2025
1 parent c6543c4 commit 59e2d93
Show file tree
Hide file tree
Showing 25 changed files with 295 additions and 210 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fixed

To support adding a comment form inside a query loop
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function verbum_render_element() {
$color_scheme = 'transparent';
}

$verbum = '<div id="comment-form__verbum" class="' . $color_scheme . '"></div>' . $this->hidden_fields();
$verbum = '<div class="comment-form__verbum ' . $color_scheme . '"></div>' . $this->hidden_fields();

// If the blog requires login, Verbum need to be wrapped in a <form> to work.
// Verbum is given `mustLogIn` to handle the login flow.
Expand Down Expand Up @@ -535,8 +535,12 @@ public function add_verbum_meta_data( $comment_id ) {
* Get the hidden fields for the comment form.
*/
public function hidden_fields() {
// Ironically, get_queried_post_id doesn't work inside query loop.
// See: https://github.com/Automattic/wp-calypso/issues/98136
$queried_post = get_post();
$queried_post_id = $queried_post ? $queried_post->ID : 0;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$post_id = isset( $_GET['postid'] ) ? intval( $_GET['postid'] ) : get_queried_object_id();
$post_id = isset( $_GET['postid'] ) ? intval( $_GET['postid'] ) : $queried_post_id;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$is_current_user_subscribed = isset( $_GET['is_current_user_subscribed'] ) ? intval( $_GET['is_current_user_subscribed'] ) : 0;
$nonce = wp_create_nonce( 'highlander_comment' );
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { useContext, useCallback } from 'preact/hooks';
import { translate } from '../../i18n';
import { shouldStoreEmailData } from '../../state';
import { VerbumSignals } from '../../state';
import { ToggleControl } from '../ToggleControl';

const handleChange = ( e: boolean ) => {
shouldStoreEmailData.value = e;
};

export const EmailFormCookieConsent = () => {
const { shouldStoreEmailData } = useContext( VerbumSignals );

const handleChange = useCallback(
( e: boolean ) => {
shouldStoreEmailData.value = e;
},
[ shouldStoreEmailData ]
);

const label = (
<div className="verbum-toggle-control__label">
<p className="primary">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { signal, effect, batch, computed } from '@preact/signals';
import { effect, batch, useSignal, useComputed } from '@preact/signals';
import clsx from 'clsx';
import { useState, useEffect } from 'preact/hooks';
import { useState, useEffect, useContext } from 'preact/hooks';
import { translate } from '../../i18n';
import { Name, Website, Email } from '../../images';
import { mailLoginData, isMailFormInvalid, shouldStoreEmailData } from '../../state';
import { VerbumSignals } from '../../state';
import { getUserInfoCookie, isAuthRequired } from '../../utils';
import { NewCommentEmail } from '../new-comment-email';
import { NewPostsEmail } from '../new-posts-email';
Expand All @@ -15,32 +15,34 @@ interface EmailFormProps {
shouldShowEmailForm: boolean;
}

const isValidEmail = signal( true );
const isEmailTouched = signal( false );
const isNameTouched = signal( false );
const isValidAuthor = signal( true );
const userEmail = computed( () => mailLoginData.value.email || '' );
const userName = computed( () => mailLoginData.value.author || '' );
const userUrl = computed( () => mailLoginData.value.url || '' );
export const EmailForm = ( { shouldShowEmailForm }: EmailFormProps ) => {
const { mailLoginData, isMailFormInvalid, shouldStoreEmailData } = useContext( VerbumSignals );

const validateFormData = () => {
const emailRegex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i;
batch( () => {
isValidEmail.value =
Boolean( userEmail.value ) && Boolean( emailRegex.test( userEmail.value ) );
isValidAuthor.value = Boolean( userName.value.length > 0 );
} );
};
const isValidEmail = useSignal( true );
const isEmailTouched = useSignal( false );
const isNameTouched = useSignal( false );
const isValidAuthor = useSignal( true );
const userEmail = useComputed( () => mailLoginData.value.email || '' );
const userName = useComputed( () => mailLoginData.value.author || '' );
const userUrl = useComputed( () => mailLoginData.value.url || '' );

const setFormData = ( event: ChangeEvent< HTMLInputElement > ) => {
mailLoginData.value = {
...mailLoginData.peek(),
[ event.currentTarget.name ]: event.currentTarget.value,
const validateFormData = () => {
const emailRegex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i;
batch( () => {
isValidEmail.value =
Boolean( userEmail.value ) && Boolean( emailRegex.test( userEmail.value ) );
isValidAuthor.value = Boolean( userName.value.length > 0 );
} );
};

const setFormData = ( event: ChangeEvent< HTMLInputElement > ) => {
mailLoginData.value = {
...mailLoginData.peek(),
[ event.currentTarget.name ]: event.currentTarget.value,
};
validateFormData();
};
validateFormData();
};

export const EmailForm = ( { shouldShowEmailForm }: EmailFormProps ) => {
const { subscribeToComment, subscribeToBlog } = VerbumComments;
const [ emailNewComment, setEmailNewComment ] = useState( false );
const [ emailNewPosts, setEmailNewPosts ] = useState( false );
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#comment-form__verbum .verbum-subscriptions .verbum-form
.comment-form__verbum .verbum-subscriptions .verbum-form
{
.verbum-form__content {
// protect the button from style leaks from the site; reset all.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import clsx from 'clsx';
import { useEffect, useState, useRef } from 'preact/hooks';
import { useEffect, useState, useRef, useContext } from 'preact/hooks';
import { translate } from '../../i18n';
import { userInfo, userLoggedIn, commentUrl, subscribeModalStatus } from '../../state';
import { VerbumSignals } from '../../state';
import { SimpleSubscribeModalProps } from '../../types';
import {
getSubscriptionModalViewCount,
Expand All @@ -13,6 +13,7 @@ import { SimpleSubscribeModalLoggedOut } from './logged-out';
import './style.scss';

export const SimpleSubscribeModal = ( { closeModalHandler, email }: SimpleSubscribeModalProps ) => {
const { userInfo, userLoggedIn, commentUrl, subscribeModalStatus } = useContext( VerbumSignals );
const [ subscribeState, setSubscribeState ] = useState<
'SUBSCRIBING' | 'LOADING' | 'SUBSCRIBED'
>();
Expand Down Expand Up @@ -51,6 +52,13 @@ export const SimpleSubscribeModal = ( { closeModalHandler, email }: SimpleSubscr
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [] );

// This is used to track how many times the modal was shown to the user.
useEffect( () => {
const userId = userInfo.value?.uid || 0;
const currentViewCount = getSubscriptionModalViewCount( userId );
setSubscriptionModalViewCount( currentViewCount + 1, userId );
}, [ userInfo ] );

if ( ! commentUrl.value ) {
// When not showing the modal, we check for modal conditions to show it.
// This is done to avoid subscriptionApi calls for logged out users.
Expand All @@ -69,14 +77,6 @@ export const SimpleSubscribeModal = ( { closeModalHandler, email }: SimpleSubscr
return null;
}

// This is used to track how many times the modal was shown to the user.
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect( () => {
const userId = userInfo.value?.uid || 0;
const currentViewCount = getSubscriptionModalViewCount( userId );
setSubscriptionModalViewCount( currentViewCount + 1, userId );
}, [] );

if ( subscribeState === 'LOADING' ) {
return (
<div className="verbum-simple-subscribe-modal loading-your-comments">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { useContext } from 'preact/hooks';
import useSubscriptionApi from '../../hooks/useSubscriptionApi';
import { translate } from '../../i18n';
import { subscriptionSettings, userInfo, commentUrl, subscribeModalStatus } from '../../state';
import { VerbumSignals } from '../../state';
import { SimpleSubscribeModalProps } from '../../types';
import { shouldShowSubscriptionModal } from '../../utils';
import SubscriptionModal from './subscription-modal';

// This determines if the modal should be shown to the user.
// It's called before the modal is rendered.
export const SimpleSubscribeSetModalShowLoggedIn = () => {
const { subscriptionSettings, userInfo, subscribeModalStatus } = useContext( VerbumSignals );
const { email } = subscriptionSettings.value ?? {
email: {
send_posts: false,
Expand All @@ -27,6 +29,7 @@ export const SimpleSubscribeModalLoggedIn = ( {
closeModalHandler,
}: SimpleSubscribeModalProps ) => {
const { setEmailPostsSubscription } = useSubscriptionApi();
const { userInfo, commentUrl } = useContext( VerbumSignals );

/**
* Handle the subscribe button click.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'preact/hooks';
import { useContext, useEffect, useState } from 'preact/hooks';
import { translate } from '../../i18n';
import { commentUrl } from '../../state';
import { VerbumSignals } from '../../state';
import { SimpleSubscribeModalProps } from '../../types';
import SubscriptionModal from './subscription-modal';
import type { ChangeEvent } from 'preact/compat';
Expand All @@ -16,6 +16,7 @@ export const SimpleSubscribeModalLoggedOut = ( {
const [ userEmail, setUserEmail ] = useState( '' );
const [ iframeUrl, setIframeUrl ] = useState( '' );
const [ subscribeDisabled, setSubscribeDisabled ] = useState( false );
const { commentUrl } = useContext( VerbumSignals );

// Only want this to run once, when email is set for the first time
useEffect( () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import clsx from 'clsx';
import { useContext } from 'preact/hooks';
import { translate } from '../i18n';
import {
commentParent,
isReplyDisabled,
isSavingComment,
isTrayOpen,
userLoggedIn,
} from '../state';
import { VerbumSignals } from '../state';
import { SettingsButton } from './settings-button';

interface CommentFooterProps {
toggleTray: ( event: MouseEvent ) => void;
}

export const CommentFooter = ( { toggleTray }: CommentFooterProps ) => {
const { commentParent, isReplyDisabled, isSavingComment, isTrayOpen, userLoggedIn } =
useContext( VerbumSignals );
return (
<div
className={ clsx( 'verbum-footer', {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* global verbumBlockEditor */
import clsx from 'clsx';
import { forwardRef, type TargetedEvent } from 'preact/compat';
import { useEffect, useState } from 'preact/hooks';
import { useContext, useEffect, useState } from 'preact/hooks';
import { translate } from '../i18n';
import { commentParent, commentValue } from '../state';
import { VerbumSignals } from '../state';
import { isFastConnection } from '../utils';
import { EditorPlaceholder } from './editor-placeholder';

Expand Down Expand Up @@ -35,6 +36,7 @@ export const CommentInputField = forwardRef(
{ handleOnKeyUp }: CommentInputFieldProps,
ref: React.MutableRefObject< HTMLTextAreaElement | null >
) => {
const { commentParent, commentValue } = useContext( VerbumSignals );
const [ editorState, setEditorState ] = useState< 'LOADING' | 'LOADED' | 'ERROR' >( null );
const [ isGBEditorEnabled, setIsGBEditorEnabled ] = useState( false );

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import clsx from 'clsx';
import { useContext } from 'preact/hooks';
import { translate } from '../i18n';
import { commentParent } from '../state';
import { VerbumSignals } from '../state';
import { CustomLoadingSpinner } from './custom-loading-spinner';

export const EditorPlaceholder = ( { onClick, loading } ) => {
const { commentParent } = useContext( VerbumSignals );
return (
<div
className="verbum-editor-wrapper"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import clsx from 'clsx';
import { useContext } from 'preact/hooks';
import useSubscriptionApi from '../hooks/useSubscriptionApi';
import { translate } from '../i18n';
import { Close } from '../images';
import { isTrayOpen, subscriptionSettings, userInfo } from '../state';
import { VerbumSignals } from '../state';
import { serviceData, isFastConnection } from '../utils';
import { NewCommentEmail } from './new-comment-email';
import { NewPostsEmail } from './new-posts-email';
Expand All @@ -25,6 +26,7 @@ interface LoggedInProps {
}

export const LoggedIn = ( { toggleTray, logout }: LoggedInProps ) => {
const { isTrayOpen, subscriptionSettings, userInfo } = useContext( VerbumSignals );
const { setEmailPostsSubscription, setCommentSubscription, setNotificationSubscription } =
useSubscriptionApi();
const { subscribeToComment, subscribeToBlog } = VerbumComments;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Signal } from '@preact/signals';
import clsx from 'clsx';
import { useEffect, useState } from 'preact/hooks';
import { useContext, useEffect, useState } from 'preact/hooks';
import { translate } from '../i18n';
import { commentParent } from '../state';
import { VerbumSignals } from '../state';
import { serviceData } from '../utils';
import { EmailForm } from './EmailForm';

Expand All @@ -12,7 +13,7 @@ interface LoggedOutProps {
loginWindow: Window | null;
}

const getLoginCommentText = () => {
const getLoginCommentText = ( commentParent: Signal ) => {
let defaultText = translate( 'Log in to leave a comment.' );
let optionalText = translate( 'Leave a comment. (log in optional)' );
let nameAndEmailRequired = translate(
Expand Down Expand Up @@ -80,13 +81,17 @@ export const LoggedOut = ( { login, canWeAccessCookies, loginWindow }: LoggedOut
setActiveService( service );
};

const { commentParent } = useContext( VerbumSignals );

return (
<div className="verbum-subscriptions logged-out">
<div className="verbum-subscriptions__wrapper">
<div className="verbum-subscriptions__login">
{ canWeAccessCookies && (
<>
<div className="verbum-subscriptions__login-header">{ getLoginCommentText() }</div>
<div className="verbum-subscriptions__login-header">
{ getLoginCommentText( commentParent ) }
</div>
<div
className={ clsx( 'verbum-logins', {
'logging-in': activeService,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import clsx from 'clsx';
import { userInfo } from '../state';
import { useContext } from 'preact/hooks';
import { VerbumSignals } from '../state';
import { hasSubscriptionOptionsVisible } from '../utils';

interface SettingsButtonProps {
Expand All @@ -8,6 +9,7 @@ interface SettingsButtonProps {
}

export const SettingsButton = ( { expanded, toggleSubscriptionTray }: SettingsButtonProps ) => {
const { userInfo } = useContext( VerbumSignals );
const subscriptionOptionsVisible = hasSubscriptionOptionsVisible();

const handleOnClick = ( event: MouseEvent ) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ type ScriptLoader = {

declare global {
const VerbumComments: VerbumCommentsType;
const verbumBlockEditor: {
attachGutenberg: (
textarea: HTMLTextAreaElement,
content: ( embedUrl: string ) => void,
isRtl: boolean,
onEmbedContent: ( embedUrl: string ) => void
) => void;
};
const vbeCacheBuster: string;
const WP_Enqueue_Dynamic_Script: ScriptLoader;
const wp: Record< string, unknown >;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { useEffect } from 'preact/hooks';
import { commentParent } from '../state';
import { useEffect, useContext } from 'preact/hooks';
import { VerbumSignals } from '../state';

/**
* Hook to observe comment form changes and update state according to comment_parent changes.
*
* @param formElement - The form element to observe.
*/
export default function useFormMutations() {
export default function useFormMutations( formElement: HTMLFormElement ) {
const { commentParent } = useContext( VerbumSignals );

useEffect( () => {
const formElement = document.querySelector( '#commentform' ) as HTMLFormElement;
const commentParentInput = formElement.querySelector( '#comment_parent' );

if ( ! formElement || ! commentParentInput ) {
Expand All @@ -28,5 +31,5 @@ export default function useFormMutations() {
return () => {
mutationObserver.disconnect();
};
}, [] );
}, [ formElement, commentParent ] );
}
Loading

0 comments on commit 59e2d93

Please sign in to comment.