Add new class Personalization_Tag
The new class contains all necessary data to replace token with personalized value. [MAILPOET-6328]
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet;
|
||||
|
||||
use MailPoet\EmailEditor\Engine\PersonalizationTags\Personalization_Tag;
|
||||
use MailPoet\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\PersonalizationTags\Subscriber;
|
||||
|
||||
@@ -16,26 +17,26 @@ class PersonalizationTagManager {
|
||||
|
||||
public function initialize() {
|
||||
add_filter('mailpoet_email_editor_register_personalization_tags', function( Personalization_Tags_Registry $registry ): Personalization_Tags_Registry {
|
||||
$registry->register(
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('First Name', 'mailpoet'),
|
||||
'mailpoet/subscriber-firstname',
|
||||
__('Subscriber', 'mailpoet'),
|
||||
[$this->subscriber, 'getFirstName'],
|
||||
['default' => __('subscriber', 'mailpoet')],
|
||||
);
|
||||
$registry->register(
|
||||
));
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('Last Name', 'mailpoet'),
|
||||
'mailpoet/subscriber-lastname',
|
||||
__('Subscriber', 'mailpoet'),
|
||||
[$this->subscriber, 'getLastName'],
|
||||
['default' => __('subscriber', 'mailpoet')],
|
||||
);
|
||||
$registry->register(
|
||||
));
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('Email', 'mailpoet'),
|
||||
'mailpoet/subscriber-email',
|
||||
__('Subscriber', 'mailpoet'),
|
||||
[$this->subscriber, 'getEmail'],
|
||||
);
|
||||
));
|
||||
return $registry;
|
||||
});
|
||||
}
|
||||
|
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the MailPoet Email Editor package.
|
||||
*
|
||||
* @package MailPoet\EmailEditor
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Engine\PersonalizationTags;
|
||||
|
||||
/**
|
||||
* The class represents a personalization tag that contains all necessary information
|
||||
* for replacing the tag with its value and displaying it in the UI.
|
||||
*/
|
||||
class Personalization_Tag {
|
||||
/**
|
||||
* The name of the tag displayed in the UI.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $name;
|
||||
/**
|
||||
* The token which is used in HTML_Tag_Processor to replace the tag with its value.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $token;
|
||||
/**
|
||||
* The category of the personalization tag for categorization on the UI.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $category;
|
||||
/**
|
||||
* The callback function which returns the value of the personalization tag.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
private $callback;
|
||||
/**
|
||||
* The attributes which are used in the Personalization Tag UI.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $attributes;
|
||||
|
||||
/**
|
||||
* Personalization_Tag constructor.
|
||||
*
|
||||
* Example usage:
|
||||
* $tag = new Personalization_Tag(
|
||||
* 'First Name',
|
||||
* 'user:first_name',
|
||||
* 'User',
|
||||
* function( $context, $args ) {
|
||||
* return $context['user_firstname'] ?? 'user';
|
||||
* },
|
||||
* array( default => 'user' )
|
||||
* );
|
||||
*
|
||||
* @param string $name The name of the tag displayed in the UI.
|
||||
* @param string $token The token used in HTML_Tag_Processor to replace the tag with its value.
|
||||
* @param string $category The category of the personalization tag for categorization on the UI.
|
||||
* @param callable $callback The callback function which returns the value of the personalization tag.
|
||||
* @param array $attributes The attributes which are used in the Personalization Tag UI.
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $token,
|
||||
string $category,
|
||||
callable $callback,
|
||||
array $attributes = array()
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->token = $token;
|
||||
$this->category = $category;
|
||||
$this->callback = $callback;
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the personalization tag.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the token of the personalization tag.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_token(): string {
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the category of the personalization tag.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_category(): string {
|
||||
return $this->category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attributes of the personalization tag.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_attributes(): array {
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the callback function for the personalization tag.
|
||||
*
|
||||
* @param mixed $context The context for the personalization tag.
|
||||
* @param array $args The additional arguments for the callback.
|
||||
* @return string The value of the personalization tag.
|
||||
*/
|
||||
public function execute_callback( $context, $args = array() ): string {
|
||||
return call_user_func( $this->callback, ...array_merge( array( $context ), array( $args ) ) );
|
||||
}
|
||||
}
|
@@ -17,7 +17,7 @@ class Personalization_Tags_Registry {
|
||||
/**
|
||||
* List of registered personalization tags.
|
||||
*
|
||||
* @var array
|
||||
* @var Personalization_Tag[]
|
||||
*/
|
||||
private $tags = array();
|
||||
|
||||
@@ -33,35 +33,25 @@ class Personalization_Tags_Registry {
|
||||
/**
|
||||
* Register a new personalization tag.
|
||||
*
|
||||
* @param string $name Unique identifier for the callback.
|
||||
* @param string $tag The tag to be used in the email content.
|
||||
* @param string $category The category of the personalization tag.
|
||||
* @param callable $callback The callable function/method.
|
||||
* @param array $attributes Additional data or settings for the callback (optional).
|
||||
* @param Personalization_Tag $tag The personalization tag to register.
|
||||
* @return void
|
||||
*/
|
||||
public function register( string $name, string $tag, string $category, callable $callback, array $attributes = array() ): void {
|
||||
if ( isset( $this->tags[ $tag ] ) ) {
|
||||
public function register( Personalization_Tag $tag ): void {
|
||||
if ( isset( $this->tags[ $tag->get_token() ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->tags[ $tag ] = array(
|
||||
'tag' => $tag,
|
||||
'name' => $name,
|
||||
'category' => $category,
|
||||
'callback' => $callback,
|
||||
'attributes' => $attributes,
|
||||
);
|
||||
$this->tags[ $tag->get_token() ] = $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a personalization tag by its tag.
|
||||
*
|
||||
* @param string $tag The tag of the personalization tag.
|
||||
* @return array|null The array data or null if not found.
|
||||
* @param string $token The token of the personalization tag.
|
||||
* @return Personalization_Tag|null The array data or null if not found.
|
||||
*/
|
||||
public function get_by_tag( string $tag ): ?array {
|
||||
return $this->tags[ $tag ] ?? null;
|
||||
public function get_by_token( string $token ): ?Personalization_Tag {
|
||||
return $this->tags[ $token ] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -61,12 +61,12 @@ class Personalizer {
|
||||
while ( $content_processor->next_token() ) {
|
||||
if ( $content_processor->get_token_type() === '#comment' ) {
|
||||
$token = $this->parse_token( $content_processor->get_modifiable_text() );
|
||||
$tag = $this->tags_registry->get_by_tag( $token['tag'] );
|
||||
if ( ! $tag || ! isset( $tag['callback'] ) ) {
|
||||
$tag = $this->tags_registry->get_by_token( $token['tag'] );
|
||||
if ( ! $tag ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = call_user_func( $tag['callback'], ...array_merge( array( $this->context ), array( 'args' => $token ['arguments'] ) ) );
|
||||
$value = $tag->execute_callback( $this->context, $token['arguments'] );
|
||||
$content_processor->replace_token( $value );
|
||||
|
||||
} elseif ( $content_processor->get_token_type() === '#tag' && $content_processor->get_tag() === 'TITLE' ) {
|
||||
|
@@ -8,6 +8,7 @@
|
||||
declare(strict_types = 1);
|
||||
namespace MailPoet\EmailEditor\Engine;
|
||||
|
||||
use MailPoet\EmailEditor\Engine\PersonalizationTags\Personalization_Tag;
|
||||
use MailPoet\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
|
||||
|
||||
/**
|
||||
@@ -43,12 +44,14 @@ class Personalizer_Test extends \MailPoetTest {
|
||||
public function testPersonalizeContentWithSingleTag(): void {
|
||||
// Register a tag in the registry.
|
||||
$this->tags_registry->register(
|
||||
new Personalization_Tag(
|
||||
'first_name',
|
||||
'user-firstname',
|
||||
'User',
|
||||
function ( $context, $args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- The $args parameter is not used in this test.
|
||||
return $context['subscriber_name'] ?? 'Default Name';
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
$this->personalizer->set_context( array( 'subscriber_name' => 'John' ) );
|
||||
@@ -62,21 +65,25 @@ class Personalizer_Test extends \MailPoetTest {
|
||||
public function testPersonalizeContentWithMultipleTags(): void {
|
||||
// Register multiple tags in the registry.
|
||||
$this->tags_registry->register(
|
||||
new Personalization_Tag(
|
||||
'first_name',
|
||||
'user/firstname',
|
||||
'Subscriber Info',
|
||||
function ( $context, $args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- The $args parameter is not used in this test.
|
||||
return $context['subscriber_name'] ?? 'Default Name';
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
$this->tags_registry->register(
|
||||
new Personalization_Tag(
|
||||
'email',
|
||||
'user/email',
|
||||
'Subscriber Info',
|
||||
function ( $context, $args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- The $args parameter is not used in this test.
|
||||
return $context['subscriber_email'] ?? 'unknown@example.com';
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Set the context for personalization.
|
||||
@@ -120,12 +127,14 @@ class Personalizer_Test extends \MailPoetTest {
|
||||
*/
|
||||
public function testTagWithArguments(): void {
|
||||
$this->tags_registry->register(
|
||||
new Personalization_Tag(
|
||||
'default_name',
|
||||
'user/firstname',
|
||||
'Subscriber Info',
|
||||
function ( $context, $args ) {
|
||||
return $args['default'] ?? 'Default Name';
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
$html_content = '<p>Hello, <!--user/firstname default="Guest"-->!</p>';
|
||||
@@ -137,12 +146,14 @@ class Personalizer_Test extends \MailPoetTest {
|
||||
*/
|
||||
public function testPersonalizationInTitle(): void {
|
||||
$this->tags_registry->register(
|
||||
new Personalization_Tag(
|
||||
'default_name',
|
||||
'user/firstname',
|
||||
'Subscriber Info',
|
||||
function ( $context, $args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- The $args parameter is not used in this test.
|
||||
return $context['user_name'] ?? 'Default Name';
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
$html_content = '
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
use MailPoet\EmailEditor\Engine\PersonalizationTags\Personalization_Tag;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use MailPoet\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
|
||||
|
||||
@@ -32,61 +33,63 @@ class PersonalizationTagsRegistryTest extends TestCase {
|
||||
* Register tag and retrieve it.
|
||||
*/
|
||||
public function testRegisterAndGetTag(): void {
|
||||
$callback = function () {
|
||||
$callback = function ( $context, $args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- Callback parameters are required.
|
||||
return 'Personalized Value';
|
||||
};
|
||||
|
||||
// Register a tag.
|
||||
$this->registry->register(
|
||||
new Personalization_Tag(
|
||||
'first_name_tag',
|
||||
'first_name',
|
||||
'Subscriber Info',
|
||||
$callback,
|
||||
array( 'description' => 'First name of the subscriber' )
|
||||
)
|
||||
);
|
||||
|
||||
// Retrieve the tag.
|
||||
$tag_data = $this->registry->get_by_tag( 'first_name' );
|
||||
$tag = $this->registry->get_by_token( 'first_name' );
|
||||
|
||||
// Assert that the tag is registered correctly.
|
||||
$this->assertNotNull( $tag_data );
|
||||
$this->assertSame( 'first_name', $tag_data['tag'] );
|
||||
$this->assertSame( 'first_name_tag', $tag_data['name'] );
|
||||
$this->assertSame( 'Subscriber Info', $tag_data['category'] );
|
||||
$this->assertSame( $callback, $tag_data['callback'] );
|
||||
$this->assertSame( 'First name of the subscriber', $tag_data['attributes']['description'] );
|
||||
$this->assertNotNull( $tag );
|
||||
$this->assertSame( 'first_name_tag', $tag->get_name() );
|
||||
$this->assertSame( 'first_name', $tag->get_token() );
|
||||
$this->assertSame( 'Subscriber Info', $tag->get_category() );
|
||||
$this->assertSame( 'Personalized Value', $tag->execute_callback( array(), array() ) );
|
||||
$this->assertSame( array( 'description' => 'First name of the subscriber' ), $tag->get_attributes() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to retrieve a tag that hasn't been registered.
|
||||
*/
|
||||
public function testRetrieveNonexistentTag(): void {
|
||||
$this->assertNull( $this->registry->get_by_tag( 'nonexistent' ) );
|
||||
$this->assertNull( $this->registry->get_by_token( 'nonexistent' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register multiple tags and retrieve them.
|
||||
*/
|
||||
public function testRegisterDuplicateTag(): void {
|
||||
$callback1 = function () {
|
||||
$callback1 = function ( $context, $args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- Callback parameters are required.
|
||||
return 'Value 1';
|
||||
};
|
||||
|
||||
$callback2 = function () {
|
||||
$callback2 = function ( $context, $args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- Callback parameters are required.
|
||||
return 'Value 2';
|
||||
};
|
||||
|
||||
// Register a tag.
|
||||
$this->registry->register( 'tag1', 'tag-1', 'Category 1', $callback1 );
|
||||
$this->registry->register( new Personalization_Tag( 'tag1', 'tag-1', 'Category 1', $callback1 ) );
|
||||
|
||||
// Attempt to register the same tag again.
|
||||
$this->registry->register( 'tag2', 'tag-2', 'Category 2', $callback2 );
|
||||
$this->registry->register( new Personalization_Tag( 'tag2', 'tag-2', 'Category 2', $callback2 ) );
|
||||
|
||||
// Retrieve the tag and ensure the first registration is preserved.
|
||||
$tag_data = $this->registry->get_by_tag( 'tag-1' );
|
||||
$this->assertSame( 'tag1', $tag_data['name'] );
|
||||
$this->assertSame( 'Category 1', $tag_data['category'] );
|
||||
$this->assertSame( $callback1, $tag_data['callback'] );
|
||||
$tag = $this->registry->get_by_token( 'tag-1' );
|
||||
$this->assertSame( 'tag1', $tag->get_name() );
|
||||
$this->assertSame( 'Category 1', $tag->get_category() );
|
||||
$this->assertSame( 'Value 1', $tag->execute_callback( array(), array() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,8 +101,8 @@ class PersonalizationTagsRegistryTest extends TestCase {
|
||||
};
|
||||
|
||||
// Register multiple tags.
|
||||
$this->registry->register( 'tag1', 'tag-1', 'Category 1', $callback );
|
||||
$this->registry->register( 'tag2', 'tag-2', 'Category 2', $callback );
|
||||
$this->registry->register( new Personalization_Tag( 'tag1', 'tag-1', 'Category 1', $callback ) );
|
||||
$this->registry->register( new Personalization_Tag( 'tag2', 'tag-2', 'Category 2', $callback ) );
|
||||
|
||||
// Retrieve all tags.
|
||||
$all_tags = $this->registry->get_all();
|
||||
|
Reference in New Issue
Block a user