Add filter replacing written Personalization Tags to email editor

[MAILPOET-6376]
This commit is contained in:
Jan Lysý
2024-12-16 14:46:23 +01:00
committed by Rostislav Wolný
parent 9b0cce9c0d
commit 041d76830b
3 changed files with 113 additions and 1 deletions

View File

@ -7,9 +7,14 @@ import {
createTextToHtmlMap,
getCursorPosition,
isMatchingComment,
replacePersonalizationTagsWithHTMLComments,
} from '../../components/personalization-tags/rich-text-utils';
import { PersonalizationTagsModal } from '../../components/personalization-tags/personalization-tags-modal';
import { useCallback, useState } from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';
import * as React from 'react';
import { storeName } from '../../store';
import { createHigherOrderComponent } from '@wordpress/compose';
/**
* Disable Rich text formats we currently cannot support
@ -121,4 +126,82 @@ function extendRichTextFormats() {
} );
}
export { disableCertainRichTextFormats, extendRichTextFormats };
const personalizationTagsLiveContentUpdate = createHigherOrderComponent(
( BlockEdit ) => ( props ) => {
const { attributes, setAttributes, name } = props;
const { content } = attributes;
// Fetch the personalization tags list
const list = useSelect(
( select ) => select( storeName ).getPersonalizationTagsList(),
[]
);
// Memoized function to replace content tags
const updatedContent = useCallback( () => {
if ( ! content ) {
return '';
}
return replacePersonalizationTagsWithHTMLComments( content, list );
}, [ content, list ] );
// Handle content updates
const handleSetAttributes = useCallback(
( newAttributes ) => {
if ( newAttributes.content !== undefined ) {
const replacedContent =
replacePersonalizationTagsWithHTMLComments(
newAttributes.content,
list
);
setAttributes( {
...newAttributes,
content: replacedContent,
} );
} else {
setAttributes( newAttributes );
}
},
[ list, setAttributes ]
);
// Only process supported blocks
if (
name === 'core/paragraph' ||
name === 'core/heading' ||
name === 'core/list-item'
) {
return (
<BlockEdit
{ ...props }
attributes={ {
...attributes,
content: updatedContent(),
} }
setAttributes={ handleSetAttributes }
/>
);
}
// Return default for unsupported blocks
return <BlockEdit { ...props } />;
},
'personalizationTagsLiveContentUpdate'
);
/**
* Replace written personalization tags with HTML comments in real-time.
*/
function replaceWrittenPersonalizationTags() {
addFilter(
'editor.BlockEdit',
'mailpoet-email-editor/with-live-content-update',
personalizationTagsLiveContentUpdate
);
}
export {
disableCertainRichTextFormats,
extendRichTextFormats,
replaceWrittenPersonalizationTags,
};

View File

@ -11,6 +11,7 @@ import { disableImageFilter, hideExpandOnClick } from './core/image';
import {
disableCertainRichTextFormats,
extendRichTextFormats,
replaceWrittenPersonalizationTags,
} from './core/rich-text';
import { enhanceButtonBlock } from './core/button';
import { enhanceButtonsBlock } from './core/buttons';
@ -29,6 +30,7 @@ export function initBlocks() {
enhanceColumnsBlock();
enhancePostContentBlock();
extendRichTextFormats();
replaceWrittenPersonalizationTags();
alterSupportConfiguration();
registerCoreBlocks();
}

View File

@ -1,4 +1,5 @@
import * as React from '@wordpress/element';
import { PersonalizationTag } from '../../store';
/**
* Maps indices of characters in HTML representation of the value to corresponding characters of stored value in RichText content. The stored value doesn't contain tags.
@ -184,9 +185,35 @@ const isMatchingComment = (
return htmlCommentRegex.test( substring );
};
/**
* Replace registered personalization tags with HTML comments in content.
* @param content string The content to replace the tags in.
* @param tags PersonalizationTag[] The tags to replace in the content.
*/
const replacePersonalizationTagsWithHTMLComments = (
content: string,
tags: PersonalizationTag[]
) => {
tags.forEach( ( tag ) => {
if ( ! content.includes( tag.token ) ) {
// Skip if the token is not in the content
return;
}
const escapedRegExp = tag.token.replace(
/[.*+?^${}()|[\]\\]/g,
'\\$&'
); // Escape special characters
const regex = new RegExp( `(?<!<!--)${ escapedRegExp }(?!-->)`, 'g' ); // Match token not inside HTML comments
content = content.replace( regex, `<!--${ tag.token }-->` );
} );
return content;
};
export {
isMatchingComment,
getCursorPosition,
createTextToHtmlMap,
mapRichTextToValue,
replacePersonalizationTagsWithHTMLComments,
};