Add filter replacing written Personalization Tags to email editor
[MAILPOET-6376]
This commit is contained in:
committed by
Rostislav Wolný
parent
9b0cce9c0d
commit
041d76830b
@ -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,
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
Reference in New Issue
Block a user