init
This commit is contained in:
+119
@@ -0,0 +1,119 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\Blocks\BlockTypes;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Config\Env;
|
||||
use WP_Style_Engine;
|
||||
|
||||
abstract class AbstractBlock {
|
||||
protected $namespace = 'mailpoet';
|
||||
protected $blockName = '';
|
||||
|
||||
public function initialize() {
|
||||
$this->registerAssets();
|
||||
$this->registerBlockType();
|
||||
}
|
||||
|
||||
protected function getBlockType(): string {
|
||||
return $this->namespace . '/' . $this->blockName;
|
||||
}
|
||||
|
||||
protected function parseRenderCallbackAttributes($attributes): array {
|
||||
return is_a($attributes, 'WP_Block') ? $attributes->attributes : $attributes;
|
||||
}
|
||||
|
||||
protected function registerAssets() {
|
||||
if (null !== $this->getEditorScript()) {
|
||||
wp_register_script(
|
||||
$this->getEditorScript('handle'),
|
||||
$this->getEditorScript('path'),
|
||||
$this->getEditorScript('dependencies'),
|
||||
$this->getEditorScript('version'),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
if (null !== $this->getEditorStyle()) {
|
||||
wp_register_style(
|
||||
$this->getEditorStyle('handle'),
|
||||
$this->getEditorStyle('path'),
|
||||
[],
|
||||
$this->getEditorScript('version'),
|
||||
'all'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function registerBlockType() {
|
||||
if (\WP_Block_Type_Registry::get_instance()->is_registered($this->getBlockType())) {
|
||||
return;
|
||||
}
|
||||
$metadata_path = Env::$assetsPath . '/dist/js/email-editor-blocks/' . $this->blockName . '/block.json';
|
||||
$block_settings = [
|
||||
'render_callback' => [$this, 'render'],
|
||||
'editor_script' => $this->getEditorScript('handle'),
|
||||
'editor_style' => $this->getEditorStyle('handle'),
|
||||
];
|
||||
register_block_type_from_metadata(
|
||||
$metadata_path,
|
||||
$block_settings
|
||||
);
|
||||
}
|
||||
|
||||
protected function getEditorScript($key = null) {
|
||||
$asset_file_path = Env::$assetsPath . '/dist/js/email-editor-blocks/' . $this->blockName . '-block.asset.php';
|
||||
|
||||
if (!file_exists($asset_file_path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$asset_file = require $asset_file_path;
|
||||
$script = [
|
||||
'handle' => 'mailpoet-' . $this->blockName . '-block',
|
||||
'path' => Env::$assetsUrl . '/dist/js/email-editor-blocks/' . $this->blockName . '-block.js',
|
||||
'dependencies' => $asset_file['dependencies'],
|
||||
'version' => $asset_file['version'],
|
||||
];
|
||||
return $key ? $script[$key] : $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loading styles expect that the file with styles has the name `style`. If we use the name `index` or something else the prefixing of the name is different.
|
||||
*/
|
||||
protected function getEditorStyle($key = null) {
|
||||
$path = Env::$assetsPath . '/dist/js/email-editor-blocks/style-' . $this->blockName . '-block.css';
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$style = [
|
||||
'handle' => 'mailpoet-' . $this->blockName . '-block',
|
||||
'path' => Env::$assetsUrl . '/dist/js/email-editor-blocks/style-' . $this->blockName . '-block.css',
|
||||
];
|
||||
return $key ? $style[$key] : $style;
|
||||
}
|
||||
|
||||
protected function addSpacer($content, $emailAttrs): string {
|
||||
$gapStyle = WP_Style_Engine::compile_css(array_intersect_key($emailAttrs, array_flip(['margin-top'])), '');
|
||||
$paddingStyle = WP_Style_Engine::compile_css(array_intersect_key($emailAttrs, array_flip(['padding-left', 'padding-right'])), '');
|
||||
|
||||
if (!$gapStyle && !$paddingStyle) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<!--[if mso | IE]><table align="left" role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%%" style="%2$s"><tr><td style="%3$s"><![endif]-->
|
||||
<div class="email-block-layout" style="%2$s %3$s">%1$s</div>
|
||||
<!--[if mso | IE]></td></tr></table><![endif]-->',
|
||||
$content,
|
||||
esc_attr($gapStyle),
|
||||
esc_attr($paddingStyle)
|
||||
);
|
||||
}
|
||||
|
||||
abstract public function render($attributes, $content, $block);
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\Blocks\BlockTypes;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Config\ServicesChecker;
|
||||
use MailPoet\Util\CdnAssetUrl;
|
||||
|
||||
class PoweredByMailpoet extends AbstractBlock {
|
||||
private ServicesChecker $servicesChecker;
|
||||
private CdnAssetUrl $cdnAssetUrl;
|
||||
protected $blockName = 'powered-by-mailpoet';
|
||||
|
||||
public function __construct(
|
||||
ServicesChecker $servicesChecker,
|
||||
CdnAssetUrl $cdnAssetUrl
|
||||
) {
|
||||
$this->cdnAssetUrl = $cdnAssetUrl;
|
||||
$this->servicesChecker = $servicesChecker;
|
||||
}
|
||||
|
||||
public function render($attributes, $content, $block) {
|
||||
if ($this->servicesChecker->isPremiumPluginActive()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$logo = $attributes['logo'] ?? 'default';
|
||||
$logoUrl = $this->cdnAssetUrl->generateCdnUrl('email-editor/logo-' . $logo . '.png');
|
||||
|
||||
return $this->addSpacer(sprintf(
|
||||
'<div class="%1$s" style="text-align:center">%2$s</div>',
|
||||
esc_attr('wp-block-' . $this->blockName),
|
||||
'<img src="' . esc_attr($logoUrl) . '" alt="Powered by MailPoet" width="100px" />'
|
||||
), $block->parsed_block['email_attrs'] ?? []); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\Blocks;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\Blocks\BlockTypes\PoweredByMailpoet;
|
||||
|
||||
class BlockTypesController {
|
||||
private $poweredByMailPoet;
|
||||
|
||||
public function __construct(
|
||||
PoweredByMailpoet $poweredByMailPoet
|
||||
) {
|
||||
$this->poweredByMailPoet = $poweredByMailPoet;
|
||||
}
|
||||
|
||||
public function initialize(): void {
|
||||
$this->poweredByMailPoet->initialize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Entities\NewsletterEntity;
|
||||
use MailPoet\Newsletter\NewsletterSaveController;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use WP_CLI;
|
||||
|
||||
class Cli {
|
||||
private const TEMPLATES = [
|
||||
[
|
||||
'name' => 'testing-email-with-core-blocks',
|
||||
'subject' => 'Hey [subscriber:firstname | default:subscriber], we test new email editor!',
|
||||
'preheader' => 'This is a testing email containing core blocks with different configurations.',
|
||||
],
|
||||
];
|
||||
|
||||
private NewsletterSaveController $newsletterSaveController;
|
||||
|
||||
private WPFunctions $wp;
|
||||
|
||||
public function __construct(
|
||||
NewsletterSaveController $newsletterSaveController,
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->newsletterSaveController = $newsletterSaveController;
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function initialize(): void {
|
||||
if (!class_exists(WP_CLI::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WP_CLI::add_command('mailpoet:email-editor:create-templates', [$this, 'createTemplates'], [
|
||||
'shortdesc' => 'Create MailPoet email editor templates',
|
||||
]);
|
||||
}
|
||||
|
||||
public function createTemplates(): void {
|
||||
WP_CLI::log("Starting creating MailPoet email editor templates.");
|
||||
foreach (self::TEMPLATES as $template) {
|
||||
$content = file_get_contents(__DIR__ . "/templates/{$template['name']}.html");
|
||||
$newsletter = $this->newsletterSaveController->save([
|
||||
'subject' => $template['subject'],
|
||||
'preheader' => $template['preheader'],
|
||||
'type' => NewsletterEntity::TYPE_STANDARD,
|
||||
'new_editor' => true,
|
||||
]);
|
||||
|
||||
$wpPost = $newsletter->getWpPost();
|
||||
if (!$wpPost) {
|
||||
WP_CLI::error("Failed to create a post for the email template {$template['name']}.");
|
||||
}
|
||||
|
||||
$this->wp->wpUpdatePost([
|
||||
'ID' => $wpPost->getId(),
|
||||
'post_title' => $this->getTemplateName($template['name']),
|
||||
'post_content' => $content,
|
||||
]);
|
||||
WP_CLI::log("Created a new email template {$template['name']}.");
|
||||
}
|
||||
WP_CLI::log('Finished creating MailPoet email editor templates.');
|
||||
}
|
||||
|
||||
private function getTemplateName(string $templateName): string {
|
||||
$name = str_replace('-', ' ', $templateName);
|
||||
return ucwords($name);
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Config\AccessControl;
|
||||
use MailPoet\EmailEditor\Engine\Dependency_Check;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class DependencyNotice {
|
||||
private const EMAIL_EDITOR_DEPENDENCY_NOTICE = 'email_editor_dependencies_not_met';
|
||||
private WPFunctions $wp;
|
||||
private Dependency_Check $dependencyCheck;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp,
|
||||
Dependency_Check $dependencyCheck
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
$this->dependencyCheck = $dependencyCheck;
|
||||
}
|
||||
|
||||
public function checkDependenciesAndEventuallyShowNotice(): bool {
|
||||
if ($this->dependencyCheck->are_dependencies_met()) {
|
||||
$this->wp->deleteTransient(self::EMAIL_EDITOR_DEPENDENCY_NOTICE);
|
||||
return false;
|
||||
}
|
||||
// For admins, we redirect to newsletters page and show notice there, for other users we display a notice immediately
|
||||
if ($this->wp->currentUserCan(AccessControl::PERMISSION_MANAGE_EMAILS)) {
|
||||
$this->wp->setTransient(self::EMAIL_EDITOR_DEPENDENCY_NOTICE, true);
|
||||
$this->wp->wpSafeRedirect($this->wp->adminUrl('admin.php?page=mailpoet-newsletters'));
|
||||
return true;
|
||||
} else {
|
||||
$this->displayMessage();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function displayMessageIfNeeded(): void {
|
||||
if ($this->wp->getTransient(self::EMAIL_EDITOR_DEPENDENCY_NOTICE)) {
|
||||
$this->displayMessage();
|
||||
}
|
||||
$this->wp->deleteTransient(self::EMAIL_EDITOR_DEPENDENCY_NOTICE);
|
||||
}
|
||||
|
||||
private function displayMessage(): void {
|
||||
$dependencyErrorMessage = sprintf(
|
||||
// translators: %1$s: WordPress version e.g. 6.7
|
||||
__('This email was created using the new editor, which requires WordPress version %1$s or higher. Please update your setup to continue editing or previewing this email.', 'mailpoet'),
|
||||
Dependency_Check::MIN_WP_VERSION,
|
||||
);
|
||||
echo '<div class="notice notice-warning is-dismissible"><p>' . esc_html($dependencyErrorMessage) . '</p></div>';
|
||||
}
|
||||
}
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Analytics\Analytics;
|
||||
use MailPoet\Config\Env;
|
||||
use MailPoet\Config\Installer;
|
||||
use MailPoet\Config\ServicesChecker;
|
||||
use MailPoet\EmailEditor\Engine\Settings_Controller;
|
||||
use MailPoet\EmailEditor\Engine\Theme_Controller;
|
||||
use MailPoet\EmailEditor\Engine\User_Theme;
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\EmailEditor as EditorInitController;
|
||||
use MailPoet\Entities\NewsletterEntity;
|
||||
use MailPoet\Newsletter\NewslettersRepository;
|
||||
use MailPoet\Settings\SettingsController as MailPoetSettings;
|
||||
use MailPoet\Settings\UserFlagsController;
|
||||
use MailPoet\Util\CdnAssetUrl;
|
||||
use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class EditorPageRenderer {
|
||||
private WPFunctions $wp;
|
||||
|
||||
private Settings_Controller $settingsController;
|
||||
|
||||
private Theme_Controller $themeController;
|
||||
|
||||
private User_Theme $userTheme;
|
||||
|
||||
private DependencyNotice $dependencyNotice;
|
||||
|
||||
private CdnAssetUrl $cdnAssetUrl;
|
||||
|
||||
private ServicesChecker $servicesChecker;
|
||||
|
||||
private SubscribersFeature $subscribersFeature;
|
||||
|
||||
private MailPoetSettings $mailpoetSettings;
|
||||
|
||||
private NewslettersRepository $newslettersRepository;
|
||||
|
||||
private UserFlagsController $userFlagsController;
|
||||
|
||||
private Analytics $analytics;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp,
|
||||
Settings_Controller $settingsController,
|
||||
CdnAssetUrl $cdnAssetUrl,
|
||||
ServicesChecker $servicesChecker,
|
||||
SubscribersFeature $subscribersFeature,
|
||||
Theme_Controller $themeController,
|
||||
User_Theme $userTheme,
|
||||
DependencyNotice $dependencyNotice,
|
||||
MailPoetSettings $mailpoetSettings,
|
||||
NewslettersRepository $newslettersRepository,
|
||||
UserFlagsController $userFlagsController,
|
||||
Analytics $analytics
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
$this->settingsController = $settingsController;
|
||||
$this->cdnAssetUrl = $cdnAssetUrl;
|
||||
$this->servicesChecker = $servicesChecker;
|
||||
$this->subscribersFeature = $subscribersFeature;
|
||||
$this->themeController = $themeController;
|
||||
$this->userTheme = $userTheme;
|
||||
$this->dependencyNotice = $dependencyNotice;
|
||||
$this->mailpoetSettings = $mailpoetSettings;
|
||||
$this->newslettersRepository = $newslettersRepository;
|
||||
$this->userFlagsController = $userFlagsController;
|
||||
$this->analytics = $analytics;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$postId = isset($_GET['post']) ? intval($_GET['post']) : 0;
|
||||
$post = $this->wp->getPost($postId);
|
||||
$currentPostType = $post->post_type; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
|
||||
if (!$post instanceof \WP_Post || $currentPostType !== EditorInitController::MAILPOET_EMAIL_POST_TYPE) {
|
||||
return;
|
||||
}
|
||||
$newsletter = $this->newslettersRepository->findOneBy(['wpPost' => $postId]);
|
||||
if (!$newsletter instanceof NewsletterEntity) {
|
||||
return;
|
||||
}
|
||||
$this->dependencyNotice->checkDependenciesAndEventuallyShowNotice();
|
||||
|
||||
// load analytics (mixpanel) library
|
||||
if ($this->analytics->isEnabled()) {
|
||||
add_filter('admin_footer', [$this, 'loadAnalyticsModule'], 24);
|
||||
}
|
||||
|
||||
// load mailpoet email editor JS integrations
|
||||
$editorIntegrationAssetsParams = require Env::$assetsPath . '/dist/js/email_editor_integration/email_editor_integration.asset.php';
|
||||
$this->wp->wpEnqueueScript(
|
||||
'email_editor_integration',
|
||||
Env::$assetsUrl . '/dist/js/email_editor_integration/email_editor_integration.js',
|
||||
$editorIntegrationAssetsParams['dependencies'],
|
||||
$editorIntegrationAssetsParams['version'],
|
||||
true
|
||||
);
|
||||
$this->wp->wpEnqueueStyle(
|
||||
'email_editor_integration',
|
||||
Env::$assetsUrl . '/dist/js/email_editor_integration/email_editor_integration.css',
|
||||
[],
|
||||
$editorIntegrationAssetsParams['version']
|
||||
);
|
||||
|
||||
// Email editor rich text JS - Because we Personalization Tags depend on Gutenberg 19.8.0 and higher
|
||||
// the following code replaces used Rich Text for the version containing the necessary changes.
|
||||
$assetsParams = require Env::$assetsPath . '/dist/js/email-editor/rich-text.asset.php';
|
||||
$this->wp->wpDeregisterScript('wp-rich-text');
|
||||
$this->wp->wpEnqueueScript(
|
||||
'wp-rich-text',
|
||||
Env::$assetsUrl . '/dist/js/email-editor/rich-text.js',
|
||||
$assetsParams['dependencies'],
|
||||
$assetsParams['version'],
|
||||
true
|
||||
);
|
||||
// End of replacing Rich Text package.
|
||||
|
||||
$assetsParams = require Env::$assetsPath . '/dist/js/email-editor/email_editor.asset.php';
|
||||
|
||||
$this->wp->wpEnqueueScript(
|
||||
'mailpoet_email_editor',
|
||||
Env::$assetsUrl . '/dist/js/email-editor/email_editor.js',
|
||||
$assetsParams['dependencies'],
|
||||
$assetsParams['version'],
|
||||
true
|
||||
);
|
||||
$this->wp->wpEnqueueStyle(
|
||||
'mailpoet_email_editor',
|
||||
Env::$assetsUrl . '/dist/js/email-editor/email_editor.css',
|
||||
[],
|
||||
$assetsParams['version']
|
||||
);
|
||||
|
||||
$currentUserEmail = $this->wp->wpGetCurrentUser()->user_email;
|
||||
$this->wp->wpLocalizeScript(
|
||||
'mailpoet_email_editor',
|
||||
'MailPoetEmailEditor',
|
||||
[
|
||||
'current_post_type' => esc_js($currentPostType),
|
||||
'current_post_id' => $post->ID,
|
||||
'current_wp_user_email' => esc_js($currentUserEmail),
|
||||
'editor_settings' => $this->settingsController->get_settings(),
|
||||
'editor_theme' => $this->themeController->get_base_theme()->get_raw_data(),
|
||||
'user_theme_post_id' => $this->userTheme->get_user_theme_post()->ID,
|
||||
'urls' => [
|
||||
'listings' => admin_url('admin.php?page=mailpoet-newsletters'),
|
||||
'send' => admin_url('admin.php?page=mailpoet-newsletters#/send/' . $newsletter->getId()),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$installedAtDiff = (new \DateTime($this->mailpoetSettings->get('installed_at')))->diff(new \DateTime());
|
||||
// Survey should be displayed only if there are 2 and more emails and the user hasn't seen it yet
|
||||
$displaySurvey = ($this->newslettersRepository->getCountOfEmailsWithWPPost() > 1) && !$this->userFlagsController->get(UserFlagsController::EMAIL_EDITOR_SURVEY);
|
||||
|
||||
// Renders additional script data that some components require e.g. PremiumModal. This is done here instead of using
|
||||
// PageRenderer since that introduces other dependencies we want to avoid. Used by getUpgradeInfo.
|
||||
// some of these values are used by the powered by mailpoet block: mailpoet/assets/js/src/mailpoet-custom-email-editor-blocks/powered-by-mailpoet/
|
||||
$installer = new Installer(Installer::PREMIUM_PLUGIN_SLUG);
|
||||
$inline_script_data = [
|
||||
'mailpoet_premium_plugin_installed' => Installer::isPluginInstalled(Installer::PREMIUM_PLUGIN_SLUG),
|
||||
'mailpoet_premium_active' => $this->servicesChecker->isPremiumPluginActive(),
|
||||
'mailpoet_premium_plugin_download_url' => $this->subscribersFeature->hasValidPremiumKey() ? $installer->generatePluginDownloadUrl() : null,
|
||||
'mailpoet_premium_plugin_activation_url' => $installer->generatePluginActivationUrl(Installer::PREMIUM_PLUGIN_PATH),
|
||||
'mailpoet_has_valid_api_key' => $this->subscribersFeature->hasValidApiKey(),
|
||||
'mailpoet_has_valid_premium_key' => $this->subscribersFeature->hasValidPremiumKey(),
|
||||
'mailpoet_has_premium_support' => $this->subscribersFeature->hasPremiumSupport(),
|
||||
'mailpoet_plugin_partial_key' => $this->servicesChecker->generatePartialApiKey(),
|
||||
'mailpoet_subscribers_count' => $this->subscribersFeature->getSubscribersCount(),
|
||||
'mailpoet_subscribers_limit' => $this->subscribersFeature->getSubscribersLimit(),
|
||||
'mailpoet_subscribers_limit_reached' => $this->subscribersFeature->check(),
|
||||
// settings needed for Satismeter tracking
|
||||
'mailpoet_3rd_party_libs_enabled' => $this->mailpoetSettings->get('3rd_party_libs.enabled') === '1',
|
||||
'mailpoet_display_nps_email_editor' => $displaySurvey,
|
||||
'mailpoet_display_nps_poll' => true,
|
||||
'mailpoet_current_wp_user' => $this->wp->wpGetCurrentUser()->to_array(),
|
||||
'mailpoet_current_wp_user_firstname' => $this->wp->wpGetCurrentUser()->user_firstname,
|
||||
'mailpoet_cdn_url' => $this->cdnAssetUrl->generateCdnUrl(""),
|
||||
'mailpoet_site_url' => $this->wp->siteUrl(),
|
||||
'mailpoet_review_request_illustration_url' => $this->cdnAssetUrl->generateCdnUrl('review-request/review-request-illustration.20190815-1427.svg'),
|
||||
'mailpoet_installed_days_ago' => (int)$installedAtDiff->format('%a'),
|
||||
];
|
||||
$this->wp->wpAddInlineScript('mailpoet_email_editor', implode('', array_map(function ($key) use ($inline_script_data) {
|
||||
return sprintf("var %s=%s;", $key, wp_json_encode($inline_script_data[$key]));
|
||||
}, array_keys($inline_script_data))), 'before');
|
||||
|
||||
// Load CSS from Post Editor
|
||||
$this->wp->wpEnqueueStyle('wp-edit-post');
|
||||
// Load CSS for the format library - used for example in popover
|
||||
$this->wp->wpEnqueueStyle('wp-format-library');
|
||||
|
||||
// Enqueue media library scripts
|
||||
$this->wp->wpEnqueueMedia();
|
||||
|
||||
$this->preloadRestApiData($post);
|
||||
|
||||
require_once ABSPATH . 'wp-admin/admin-header.php';
|
||||
echo '<div id="mailpoet-email-editor" class="block-editor block-editor__container hide-if-no-js"></div>';
|
||||
}
|
||||
|
||||
private function preloadRestApiData(\WP_Post $post): void {
|
||||
$userThemePostId = $this->userTheme->get_user_theme_post()->ID;
|
||||
$templateSlug = get_post_meta($post->ID, '_wp_page_template', true);
|
||||
$routes = [
|
||||
'/wp/v2/mailpoet_email/' . intval($post->ID) . '?context=edit',
|
||||
'/wp/v2/types/mailpoet_email?context=edit',
|
||||
'/wp/v2/global-styles/' . intval($userThemePostId) . '?context=edit', // Global email styles
|
||||
'/wp/v2/block-patterns/patterns',
|
||||
'/wp/v2/templates?context=edit',
|
||||
'/wp/v2/block-patterns/categories',
|
||||
'/wp/v2/settings',
|
||||
'/wp/v2/types?context=view',
|
||||
'/wp/v2/taxonomies?context=view',
|
||||
];
|
||||
|
||||
if ($templateSlug) {
|
||||
$routes[] = '/wp/v2/templates/lookup?slug=' . $templateSlug;
|
||||
} else {
|
||||
$routes[] = '/wp/v2/mailpoet_email?context=edit&per_page=30&status=publish,sent';
|
||||
}
|
||||
|
||||
// Preload the data for the specified routes
|
||||
$preloadData = array_reduce(
|
||||
$routes,
|
||||
'rest_preload_api_request',
|
||||
[]
|
||||
);
|
||||
|
||||
// Add inline script to set up preloading middleware
|
||||
wp_add_inline_script(
|
||||
'wp-blocks',
|
||||
sprintf(
|
||||
'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );',
|
||||
wp_json_encode($preloadData)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function loadAnalyticsModule() { // phpcs:ignore -- MissingReturnStatement not required
|
||||
$publicId = $this->analytics->getPublicId();
|
||||
$isPublicIdNew = $this->analytics->isPublicIdNew();
|
||||
// this is required here because of `analytics-event.js` and order of script load and use in `mailpoet-email-editor-integration/index.ts`
|
||||
$libs3rdPartyEnabled = $this->mailpoetSettings->get('3rd_party_libs.enabled') === '1';
|
||||
|
||||
// we need to set this values because they are used in the analytics.html file
|
||||
?>
|
||||
<script type="text/javascript"> <?php // phpcs:ignore ?>
|
||||
window.mailpoet_analytics_enabled = true;
|
||||
window.mailpoet_analytics_public_id = '<?php echo esc_js($publicId); ?>';
|
||||
window.mailpoet_analytics_new_public_id = <?php echo wp_json_encode($isPublicIdNew); ?>;
|
||||
window.mailpoet_3rd_party_libs_enabled = <?php echo wp_json_encode($libs3rdPartyEnabled); ?>;
|
||||
window.mailpoet_version = '<?php echo esc_js(MAILPOET_VERSION); ?>';
|
||||
window.mailpoet_premium_version = '<?php echo esc_js((defined('MAILPOET_PREMIUM_VERSION')) ? MAILPOET_PREMIUM_VERSION : ''); ?>';
|
||||
</script>
|
||||
<?php
|
||||
|
||||
include_once Env::$viewsPath . '/analytics.html';
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Newsletter\NewslettersRepository;
|
||||
use MailPoet\Newsletter\Url as NewsletterUrl;
|
||||
use MailPoet\NotFoundException;
|
||||
use MailPoet\UnexpectedValueException;
|
||||
use MailPoet\Validator\Builder;
|
||||
|
||||
class EmailApiController {
|
||||
/** @var NewslettersRepository */
|
||||
private $newsletterRepository;
|
||||
|
||||
/** @var NewsletterUrl */
|
||||
private $newsletterUrl;
|
||||
|
||||
public function __construct(
|
||||
NewslettersRepository $newsletterRepository,
|
||||
NewsletterUrl $newsletterUrl
|
||||
) {
|
||||
$this->newsletterRepository = $newsletterRepository;
|
||||
$this->newsletterUrl = $newsletterUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $postEmailData - WP_Post data
|
||||
* @return array - MailPoet specific email data that will be attached to the post API response
|
||||
*/
|
||||
public function getEmailData($postEmailData): array {
|
||||
$newsletter = $this->newsletterRepository->findOneBy(['wpPost' => $postEmailData['id']]);
|
||||
return [
|
||||
'id' => $newsletter ? $newsletter->getId() : null,
|
||||
'subject' => $newsletter ? $newsletter->getSubject() : '',
|
||||
'preheader' => $newsletter ? $newsletter->getPreheader() : '',
|
||||
'preview_url' => $this->newsletterUrl->getViewInBrowserUrl($newsletter),
|
||||
'deleted_at' => $newsletter && $newsletter->getDeletedAt() !== null ? $newsletter->getDeletedAt()->format('c') : null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update MailPoet specific data we store with Emails.
|
||||
*/
|
||||
public function saveEmailData(array $data, \WP_Post $emailPost): void {
|
||||
$newsletter = $this->newsletterRepository->findOneById($data['id']);
|
||||
if (!$newsletter) {
|
||||
throw new NotFoundException('Newsletter was not found');
|
||||
}
|
||||
if ($newsletter->getWpPostId() !== $emailPost->ID) {
|
||||
throw new UnexpectedValueException('Newsletter ID does not match the post ID');
|
||||
}
|
||||
|
||||
$newsletter->setSubject($data['subject']);
|
||||
$newsletter->setPreheader($data['preheader']);
|
||||
|
||||
if (isset($data['deleted_at'])) {
|
||||
if (empty($data['deleted_at'])) {
|
||||
$data['deleted_at'] = null;
|
||||
} else {
|
||||
$data['deleted_at'] = new \DateTime($data['deleted_at']);
|
||||
}
|
||||
$newsletter->setDeletedAt($data['deleted_at']);
|
||||
}
|
||||
|
||||
$this->newsletterRepository->flush();
|
||||
}
|
||||
|
||||
public function trashEmail(\WP_Post $wpPost) {
|
||||
$newsletter = $this->newsletterRepository->findOneBy(['wpPost' => $wpPost->ID]);
|
||||
if (!$newsletter) {
|
||||
throw new NotFoundException('Newsletter was not found');
|
||||
}
|
||||
if ($newsletter->getWpPostId() !== $wpPost->ID) {
|
||||
throw new UnexpectedValueException('Newsletter ID does not match the post ID');
|
||||
}
|
||||
$this->newsletterRepository->bulkTrash([$newsletter->getId()]);
|
||||
}
|
||||
|
||||
public function getEmailDataSchema(): array {
|
||||
return Builder::object([
|
||||
'id' => Builder::integer()->nullable(),
|
||||
'subject' => Builder::string(),
|
||||
'preheader' => Builder::string(),
|
||||
'preview_url' => Builder::string(),
|
||||
'deleted_at' => Builder::string()->nullable(),
|
||||
])->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\Patterns\PatternsController;
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\Templates\TemplatesController;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class EmailEditor {
|
||||
const MAILPOET_EMAIL_POST_TYPE = 'mailpoet_email';
|
||||
|
||||
private WPFunctions $wp;
|
||||
|
||||
private EmailApiController $emailApiController;
|
||||
|
||||
private EditorPageRenderer $editorPageRenderer;
|
||||
|
||||
private PatternsController $patternsController;
|
||||
|
||||
private Cli $cli;
|
||||
|
||||
private EmailEditorPreviewEmail $emailEditorPreviewEmail;
|
||||
|
||||
private PersonalizationTagManager $personalizationTagManager;
|
||||
|
||||
private TemplatesController $templatesController;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp,
|
||||
EmailApiController $emailApiController,
|
||||
EditorPageRenderer $editorPageRenderer,
|
||||
EmailEditorPreviewEmail $emailEditorPreviewEmail,
|
||||
PatternsController $patternsController,
|
||||
TemplatesController $templatesController,
|
||||
Cli $cli,
|
||||
PersonalizationTagManager $personalizationTagManager
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
$this->emailApiController = $emailApiController;
|
||||
$this->editorPageRenderer = $editorPageRenderer;
|
||||
$this->patternsController = $patternsController;
|
||||
$this->templatesController = $templatesController;
|
||||
$this->cli = $cli;
|
||||
$this->emailEditorPreviewEmail = $emailEditorPreviewEmail;
|
||||
$this->personalizationTagManager = $personalizationTagManager;
|
||||
}
|
||||
|
||||
public function initialize(): void {
|
||||
$this->cli->initialize();
|
||||
$this->wp->addFilter('mailpoet_email_editor_post_types', [$this, 'addEmailPostType']);
|
||||
$this->wp->addAction('rest_delete_mailpoet_email', [$this->emailApiController, 'trashEmail'], 10, 1);
|
||||
$this->wp->addFilter('mailpoet_is_email_editor_page', [$this, 'isEditorPage'], 10, 1);
|
||||
$this->wp->addFilter('replace_editor', [$this, 'replaceEditor'], 10, 2);
|
||||
$this->wp->addFilter('mailpoet_email_editor_send_preview_email', [$this->emailEditorPreviewEmail, 'sendPreviewEmail'], 10, 1);
|
||||
$this->patternsController->registerPatterns();
|
||||
$this->templatesController->initialize();
|
||||
$this->extendEmailPostApi();
|
||||
$this->personalizationTagManager->initialize();
|
||||
}
|
||||
|
||||
public function addEmailPostType(array $postTypes): array {
|
||||
$postTypes[] = [
|
||||
'name' => self::MAILPOET_EMAIL_POST_TYPE,
|
||||
'args' => [
|
||||
'labels' => [
|
||||
'name' => __('Emails', 'mailpoet'),
|
||||
'singular_name' => __('Email', 'mailpoet'),
|
||||
],
|
||||
'rewrite' => ['slug' => self::MAILPOET_EMAIL_POST_TYPE],
|
||||
],
|
||||
];
|
||||
return $postTypes;
|
||||
}
|
||||
|
||||
public function isEditorPage(bool $isEditorPage): bool {
|
||||
if ($isEditorPage) {
|
||||
return $isEditorPage;
|
||||
}
|
||||
// We need to check early if we are on the email editor page. The check runs early so we can't use current_screen() here.
|
||||
if ($this->wp->isAdmin() && isset($_GET['post']) && isset($_GET['action']) && $_GET['action'] === 'edit') {
|
||||
$post = $this->wp->getPost((int)$_GET['post']);
|
||||
return $post && $post->post_type === self::MAILPOET_EMAIL_POST_TYPE; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function extendEmailPostApi() {
|
||||
$this->wp->registerRestField(self::MAILPOET_EMAIL_POST_TYPE, 'mailpoet_data', [
|
||||
'get_callback' => [$this->emailApiController, 'getEmailData'],
|
||||
'update_callback' => [$this->emailApiController, 'saveEmailData'],
|
||||
'schema' => $this->emailApiController->getEmailDataSchema(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function replaceEditor($replace, $post) {
|
||||
$currentScreen = get_current_screen();
|
||||
if ($post->post_type === self::MAILPOET_EMAIL_POST_TYPE && $currentScreen) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
$this->editorPageRenderer->render();
|
||||
return true;
|
||||
}
|
||||
return $replace;
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Entities\NewsletterEntity;
|
||||
use MailPoet\Newsletter\NewslettersRepository;
|
||||
use MailPoet\Newsletter\Preview\SendPreviewController;
|
||||
|
||||
class EmailEditorPreviewEmail {
|
||||
private NewslettersRepository $newslettersRepository;
|
||||
|
||||
private SendPreviewController $sendPreviewController;
|
||||
|
||||
public function __construct(
|
||||
NewslettersRepository $newslettersRepository,
|
||||
SendPreviewController $sendPreviewController
|
||||
) {
|
||||
$this->newslettersRepository = $newslettersRepository;
|
||||
$this->sendPreviewController = $sendPreviewController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends preview email
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function sendPreviewEmail($postData): bool {
|
||||
$this->validateData($postData);
|
||||
|
||||
$newsletter = $this->fetchNewsletter($postData);
|
||||
$subscriber = $postData['email'];
|
||||
|
||||
$this->sendPreviewController->sendPreview($newsletter, $subscriber);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function validateData($data) {
|
||||
if (empty($data['email']) || empty($data['postId']) || empty($data['newsletterId'])) {
|
||||
throw new \InvalidArgumentException(esc_html__('Missing required data', 'mailpoet'));
|
||||
}
|
||||
|
||||
if (!is_email($data['email'])) {
|
||||
throw new \InvalidArgumentException(esc_html__('Invalid email address', 'mailpoet'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $postData
|
||||
* @return NewsletterEntity
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function fetchNewsletter($postData): NewsletterEntity {
|
||||
$newsletter = $this->newslettersRepository->findOneById((int)$postData['newsletterId']);
|
||||
|
||||
if (!$newsletter) {
|
||||
throw new \Exception(esc_html__('This email does not exist.', 'mailpoet'));
|
||||
}
|
||||
|
||||
return $newsletter;
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Engine\Renderer\Css_Inliner;
|
||||
use MailPoetVendor\Pelago\Emogrifier\CssInliner;
|
||||
|
||||
class MailPoetCssInliner implements Css_Inliner {
|
||||
private CssInliner $inliner;
|
||||
|
||||
public function from_html(string $unprocessed_html): self {// phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- we need to match the interface
|
||||
$that = new self();
|
||||
$that->inliner = CssInliner::fromHtml($unprocessed_html);
|
||||
return $that;
|
||||
}
|
||||
|
||||
public function inline_css(string $css = ''): self {// phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- we need to match the interface
|
||||
if (!isset($this->inliner)) {
|
||||
throw new \LogicException('You must call from_html before calling inline_css');
|
||||
}
|
||||
$this->inliner->inlineCss($css);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render(): string {
|
||||
if (!isset($this->inliner)) {
|
||||
throw new \LogicException('You must call from_html before calling inline_css');
|
||||
}
|
||||
return $this->inliner->render();
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
class MailpoetCssInlinerFactory {
|
||||
public static function create(): MailPoetCssInliner {
|
||||
return new MailPoetCssInliner();
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\Patterns\Library;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\Patterns\Pattern;
|
||||
|
||||
class OneColumn extends Pattern {
|
||||
protected $name = '1-column-content';
|
||||
protected $block_types = ['core/post-content']; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
protected $template_types = ['email-template']; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
protected $categories = ['email-contents'];
|
||||
|
||||
protected function get_content(): string { // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
|
||||
return '
|
||||
<!-- wp:group {"style":{"spacing":{"padding":{"right":"var:preset|spacing|20","left":"var:preset|spacing|20"}}},"layout":{"type":"constrained"}} -->
|
||||
<div class="wp-block-group" style="padding-right:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)"><!-- wp:heading -->
|
||||
<h2 class="wp-block-heading">' . __('1 column layout', 'mailpoet') . '</h2>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:paragraph -->
|
||||
<p>' . __('A one-column layout is great for simplified and concise content, like announcements or newsletters with brief updates. Drag blocks to add content and customize your styles from the styles panel on the top right.', 'mailpoet') . '</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
||||
<!-- wp:image -->
|
||||
<figure class="wp-block-image"><img alt=""/></figure>
|
||||
<!-- /wp:image -->
|
||||
|
||||
<!-- wp:buttons -->
|
||||
<div class="wp-block-buttons"><!-- wp:button -->
|
||||
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">' . __('Add button text', 'mailpoet') . '</a></div>
|
||||
<!-- /wp:button --></div>
|
||||
<!-- /wp:buttons --></div>
|
||||
<!-- /wp:group -->
|
||||
';
|
||||
}
|
||||
|
||||
protected function get_title(): string { // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
|
||||
/* translators: Name of a content pattern used as starting content of an email */
|
||||
return __('1 Column', 'mailpoet');
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\Patterns\Library;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\Patterns\Pattern;
|
||||
|
||||
class ThreeColumn extends Pattern {
|
||||
protected $name = '3-column-content';
|
||||
protected $block_types = ['core/post-content']; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
protected $template_types = ['email-template']; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
protected $categories = ['email-contents'];
|
||||
|
||||
protected function get_content(): string { // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
|
||||
return '<!-- wp:group {"style":{"spacing":{"padding":{"top":"var:preset|spacing|10","bottom":"var:preset|spacing|10","left":"var:preset|spacing|20","right":"var:preset|spacing|20"}}},"layout":{"type":"constrained"}} -->
|
||||
<div class="wp-block-group" style="padding-top:var(--wp--preset--spacing--10);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--10);padding-left:var(--wp--preset--spacing--20)"><!-- wp:heading -->
|
||||
<h2 class="wp-block-heading">' . __('3 column layout', 'mailpoet') . '</h2>
|
||||
<!-- /wp:heading --></div>
|
||||
<!-- /wp:group -->
|
||||
|
||||
<!-- wp:columns {"style":{"spacing":{"padding":{"right":"var:preset|spacing|10","left":"var:preset|spacing|10"}}},"metadata":{"categories":["email-contents"],"patternName":"mailpoet/1-column-content"}} -->
|
||||
<div class="wp-block-columns" style="padding-right:var(--wp--preset--spacing--10);padding-left:var(--wp--preset--spacing--10)"><!-- wp:column {"style":{"spacing":{"padding":{"top":"0","bottom":"0","left":"var:preset|spacing|10","right":"var:preset|spacing|10"}}}} -->
|
||||
<div class="wp-block-column" style="padding-top:0;padding-right:var(--wp--preset--spacing--10);padding-bottom:0;padding-left:var(--wp--preset--spacing--10)"><!-- wp:image {"scale":"cover"} -->
|
||||
<figure class="wp-block-image"><img alt="" style="object-fit:cover"/></figure>
|
||||
<!-- /wp:image --></div>
|
||||
<!-- /wp:column -->
|
||||
|
||||
<!-- wp:column {"style":{"spacing":{"padding":{"right":"var:preset|spacing|10","left":"var:preset|spacing|10"}}}} -->
|
||||
<div class="wp-block-column" style="padding-right:var(--wp--preset--spacing--10);padding-left:var(--wp--preset--spacing--10)"><!-- wp:image -->
|
||||
<figure class="wp-block-image"><img alt=""/></figure>
|
||||
<!-- /wp:image --></div>
|
||||
<!-- /wp:column -->
|
||||
|
||||
<!-- wp:column {"style":{"spacing":{"padding":{"right":"var:preset|spacing|10","left":"var:preset|spacing|10"}}}} -->
|
||||
<div class="wp-block-column" style="padding-right:var(--wp--preset--spacing--10);padding-left:var(--wp--preset--spacing--10)"><!-- wp:image -->
|
||||
<figure class="wp-block-image"><img alt=""/></figure>
|
||||
<!-- /wp:image --></div>
|
||||
<!-- /wp:column --></div>
|
||||
<!-- /wp:columns -->
|
||||
|
||||
<!-- wp:group {"style":{"spacing":{"padding":{"right":"var:preset|spacing|20","left":"var:preset|spacing|20"}}},"layout":{"type":"constrained"}} -->
|
||||
<div class="wp-block-group" style="padding-right:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)"><!-- wp:paragraph -->
|
||||
<p>' . __('A three-column layout organizes information into sections, making it easier for users to navigate content. Try other layouts by adding or removing columns, drag blocks into them to add content, and customize your email styles from the styles panel.', 'mailpoet') . '</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
||||
<!-- wp:buttons -->
|
||||
<div class="wp-block-buttons"><!-- wp:button -->
|
||||
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">' . __('Add button text', 'mailpoet') . '</a></div>
|
||||
<!-- /wp:button --></div>
|
||||
<!-- /wp:buttons --></div>
|
||||
<!-- /wp:group -->
|
||||
';
|
||||
}
|
||||
|
||||
protected function get_title(): string { // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
|
||||
/* translators: Name of a content pattern used as starting content of an email */
|
||||
return __('3 Columns', 'mailpoet');
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\Patterns\Library;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\Patterns\Pattern;
|
||||
|
||||
class TwoColumn extends Pattern {
|
||||
protected $name = '2-column-content';
|
||||
protected $block_types = ['core/post-content']; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
protected $template_types = ['email-template']; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
protected $categories = ['email-contents'];
|
||||
|
||||
protected function get_content(): string { // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
|
||||
return '<!-- wp:group {"style":{"spacing":{"padding":{"top":"0","bottom":"0","left":"var:preset|spacing|20","right":"var:preset|spacing|20"}}},"layout":{"type":"constrained"}} -->
|
||||
<div class="wp-block-group" style="padding-top:0;padding-right:var(--wp--preset--spacing--20);padding-bottom:0;padding-left:var(--wp--preset--spacing--20)"><!-- wp:heading -->
|
||||
<h2 class="wp-block-heading">' . __('2 column layout', 'mailpoet') . '</h2>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:paragraph -->
|
||||
<p>' . __('A two-column layout organizes information into sections, making it easier for users to navigate content. Try other layouts by adding or removing columns, drag blocks into them to add content and customize your email styles from the styles panel.', 'mailpoet') . '</p>
|
||||
<!-- /wp:paragraph --></div>
|
||||
<!-- /wp:group -->
|
||||
|
||||
<!-- wp:columns {"style":{"spacing":{"padding":{"top":"0","bottom":"0","left":"var:preset|spacing|10","right":"var:preset|spacing|10"}}}} -->
|
||||
<div class="wp-block-columns" style="padding-top:0;padding-right:var(--wp--preset--spacing--10);padding-bottom:0;padding-left:var(--wp--preset--spacing--10)"><!-- wp:column {"width":"","style":{"spacing":{"padding":{"top":"0","bottom":"0","left":"var:preset|spacing|10","right":"var:preset|spacing|10"}}}} -->
|
||||
<div class="wp-block-column" style="padding-top:0;padding-right:var(--wp--preset--spacing--10);padding-bottom:0;padding-left:var(--wp--preset--spacing--10)"><!-- wp:image -->
|
||||
<figure class="wp-block-image"><img alt=""/></figure>
|
||||
<!-- /wp:image -->
|
||||
|
||||
<!-- wp:buttons -->
|
||||
<div class="wp-block-buttons"><!-- wp:button {"width":100} -->
|
||||
<div class="wp-block-button has-custom-width wp-block-button__width-100"><a class="wp-block-button__link wp-element-button">' . __('Add button text', 'mailpoet') . '</a></div>
|
||||
<!-- /wp:button --></div>
|
||||
<!-- /wp:buttons -->
|
||||
|
||||
<!-- wp:heading {"level":3} -->
|
||||
<h3 class="wp-block-heading">' . __('Heading', 'mailpoet') . '</h3>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:paragraph -->
|
||||
<p>' . __('You can also add text blocks into a column next to an image block to create unique layouts.', 'mailpoet') . '</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
||||
<!-- wp:buttons -->
|
||||
<div class="wp-block-buttons"><!-- wp:button {"width":100} -->
|
||||
<div class="wp-block-button has-custom-width wp-block-button__width-100"><a class="wp-block-button__link wp-element-button">' . __('Add button text', 'mailpoet') . '</a></div>
|
||||
<!-- /wp:button --></div>
|
||||
<!-- /wp:buttons --></div>
|
||||
<!-- /wp:column -->
|
||||
|
||||
<!-- wp:column {"style":{"spacing":{"padding":{"right":"var:preset|spacing|10","left":"var:preset|spacing|10"}}}} -->
|
||||
<div class="wp-block-column" style="padding-right:var(--wp--preset--spacing--10);padding-left:var(--wp--preset--spacing--10)"><!-- wp:image -->
|
||||
<figure class="wp-block-image"><img alt=""/></figure>
|
||||
<!-- /wp:image -->
|
||||
|
||||
<!-- wp:buttons -->
|
||||
<div class="wp-block-buttons"><!-- wp:button {"width":100} -->
|
||||
<div class="wp-block-button has-custom-width wp-block-button__width-100"><a class="wp-block-button__link wp-element-button">' . __('Add button text', 'mailpoet') . '</a></div>
|
||||
<!-- /wp:button --></div>
|
||||
<!-- /wp:buttons -->
|
||||
|
||||
<!-- wp:image -->
|
||||
<figure class="wp-block-image"><img alt=""/></figure>
|
||||
<!-- /wp:image --></div>
|
||||
<!-- /wp:column --></div>
|
||||
<!-- /wp:columns -->
|
||||
';
|
||||
}
|
||||
|
||||
protected function get_title(): string { // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
|
||||
/* translators: Name of a content pattern used as starting content of an email */
|
||||
return __('2 Columns', 'mailpoet');
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\Patterns;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Engine\Patterns\Abstract_Pattern;
|
||||
use MailPoet\Util\CdnAssetUrl;
|
||||
|
||||
abstract class Pattern extends Abstract_Pattern {
|
||||
protected CdnAssetUrl $cdnAssetUrl;
|
||||
protected $namespace = 'mailpoet';
|
||||
|
||||
public function __construct(
|
||||
CdnAssetUrl $cdnAssetUrl
|
||||
) {
|
||||
$this->cdnAssetUrl = $cdnAssetUrl;
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\Patterns;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\Patterns\Library\OneColumn;
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\Patterns\Library\ThreeColumn;
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\Patterns\Library\TwoColumn;
|
||||
use MailPoet\Util\CdnAssetUrl;
|
||||
|
||||
class PatternsController {
|
||||
private CdnAssetUrl $cdnAssetUrl;
|
||||
|
||||
public function __construct(
|
||||
CdnAssetUrl $cdnAssetUrl
|
||||
) {
|
||||
$this->cdnAssetUrl = $cdnAssetUrl;
|
||||
}
|
||||
|
||||
public function registerPatterns(): void {
|
||||
$patterns = [];
|
||||
$patterns[] = new OneColumn($this->cdnAssetUrl);
|
||||
$patterns[] = new TwoColumn($this->cdnAssetUrl);
|
||||
$patterns[] = new ThreeColumn($this->cdnAssetUrl);
|
||||
foreach ($patterns as $pattern) {
|
||||
register_block_pattern($pattern->get_namespace() . '/' . $pattern->get_name(), $pattern->get_properties());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Engine\PersonalizationTags\Personalization_Tag;
|
||||
use MailPoet\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\PersonalizationTags\Link;
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\PersonalizationTags\LinksToShortcodesConvertor;
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\PersonalizationTags\Site;
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\PersonalizationTags\Subscriber;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class PersonalizationTagManager {
|
||||
private Subscriber $subscriber;
|
||||
private Site $site;
|
||||
private Link $link;
|
||||
private WPFunctions $wp;
|
||||
private LinksToShortcodesConvertor $linksToShortcodesConvertor;
|
||||
|
||||
public function __construct(
|
||||
Subscriber $subscriber,
|
||||
Site $site,
|
||||
Link $link,
|
||||
WPFunctions $wp,
|
||||
LinksToShortcodesConvertor $linksToShortcodesConvertor
|
||||
) {
|
||||
$this->subscriber = $subscriber;
|
||||
$this->site = $site;
|
||||
$this->link = $link;
|
||||
$this->wp = $wp;
|
||||
$this->linksToShortcodesConvertor = $linksToShortcodesConvertor;
|
||||
}
|
||||
|
||||
public function initialize() {
|
||||
$this->wp->addFilter('mailpoet_email_editor_register_personalization_tags', function( Personalization_Tags_Registry $registry ): Personalization_Tags_Registry {
|
||||
// Subscriber Personalization Tags
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('First Name', 'mailpoet'),
|
||||
'mailpoet/subscriber-firstname',
|
||||
__('Subscriber', 'mailpoet'),
|
||||
[$this->subscriber, 'getFirstName'],
|
||||
['default' => __('subscriber', 'mailpoet')],
|
||||
));
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('Last Name', 'mailpoet'),
|
||||
'mailpoet/subscriber-lastname',
|
||||
__('Subscriber', 'mailpoet'),
|
||||
[$this->subscriber, 'getLastName'],
|
||||
['default' => __('subscriber', 'mailpoet')],
|
||||
));
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('Email', 'mailpoet'),
|
||||
'mailpoet/subscriber-email',
|
||||
__('Subscriber', 'mailpoet'),
|
||||
[$this->subscriber, 'getEmail'],
|
||||
));
|
||||
|
||||
// Site Personalization Tags
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('Site Title', 'mailpoet'),
|
||||
'mailpoet/site-title',
|
||||
__('Site', 'mailpoet'),
|
||||
[$this->site, 'getTitle'],
|
||||
));
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('Homepage URL', 'mailpoet'),
|
||||
'mailpoet/site-homepage-url',
|
||||
__('Site', 'mailpoet'),
|
||||
[$this->site, 'getHomepageURL'],
|
||||
));
|
||||
|
||||
// Links registration
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('Unsubscribe URL', 'mailpoet'),
|
||||
'mailpoet/subscription-unsubscribe-url',
|
||||
__('Link', 'mailpoet'),
|
||||
[$this->link, 'getSubscriptionUnsubscribeUrl'],
|
||||
));
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('Manage subscription URL', 'mailpoet'),
|
||||
'mailpoet/subscription-manage-url',
|
||||
__('Link', 'mailpoet'),
|
||||
[$this->link, 'getSubscriptionManageUrl'],
|
||||
));
|
||||
$registry->register(new Personalization_Tag(
|
||||
__('View in browser URL', 'mailpoet'),
|
||||
'mailpoet/newsletter-view-in-browser-url',
|
||||
__('Link', 'mailpoet'),
|
||||
[$this->link, 'getNewsletterViewInBrowserUrl'],
|
||||
));
|
||||
return $registry;
|
||||
});
|
||||
|
||||
// Convert links to shortcodes before sending the email
|
||||
// This is a temporary solution so that we are able to integrate the new personalization tags
|
||||
// It is needed until we have a proper solution for the personalization tags in the MailPoet Link tracking system
|
||||
$this->wp->addFilter(
|
||||
'mailpoet_sending_newsletter_render_after_pre_process',
|
||||
[$this, 'convertLinksToShortcodes']
|
||||
);
|
||||
}
|
||||
|
||||
public function convertLinksToShortcodes(array $emailContent): array {
|
||||
if (!isset($emailContent['html'])) {
|
||||
return $emailContent;
|
||||
}
|
||||
$emailContent['html'] = $this->linksToShortcodesConvertor->convertLinkTagsToShortcodes($emailContent['html']);
|
||||
return $emailContent;
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\PersonalizationTags;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Entities\NewsletterEntity;
|
||||
use MailPoet\Entities\SendingQueueEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\Newsletter\NewslettersRepository;
|
||||
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
|
||||
use MailPoet\Newsletter\Url as NewsletterUrl;
|
||||
use MailPoet\Subscribers\SubscribersRepository;
|
||||
use MailPoet\Subscription\SubscriptionUrlFactory;
|
||||
|
||||
class Link {
|
||||
|
||||
private SubscriptionUrlFactory $subscriptionUrlFactory;
|
||||
private SubscribersRepository $subscribersRepository;
|
||||
private SendingQueuesRepository $sendingQueuesRepository;
|
||||
private NewsletterUrl $newsletterUrl;
|
||||
private NewslettersRepository $newslettersRepository;
|
||||
|
||||
public function __construct(
|
||||
SubscriptionUrlFactory $subscriptionUrlFactory,
|
||||
SubscribersRepository $subscribersRepository,
|
||||
SendingQueuesRepository $sendingQueuesRepository,
|
||||
NewslettersRepository $newslettersRepository,
|
||||
NewsletterUrl $newsletterUrl
|
||||
) {
|
||||
$this->subscriptionUrlFactory = $subscriptionUrlFactory;
|
||||
$this->subscribersRepository = $subscribersRepository;
|
||||
$this->sendingQueuesRepository = $sendingQueuesRepository;
|
||||
$this->newslettersRepository = $newslettersRepository;
|
||||
$this->newsletterUrl = $newsletterUrl;
|
||||
}
|
||||
|
||||
public function getSubscriptionUnsubscribeUrl(array $context, array $args = []): string {
|
||||
$isPreview = $context['is_preview'] ?? false;
|
||||
$subscriber = !$isPreview ? $this->getSubscriber($context) : null;
|
||||
$queue = $this->getSendingQueue($context);
|
||||
|
||||
return $this->subscriptionUrlFactory->getConfirmUnsubscribeUrl(
|
||||
$subscriber,
|
||||
$queue ? $queue->getId() : null
|
||||
);
|
||||
}
|
||||
|
||||
public function getSubscriptionManageUrl(array $context, array $args = []): string {
|
||||
$isPreview = $context['is_preview'] ?? false;
|
||||
$subscriber = !$isPreview ? $this->getSubscriber($context) : null;
|
||||
|
||||
return $this->subscriptionUrlFactory->getManageUrl(
|
||||
$subscriber
|
||||
);
|
||||
}
|
||||
|
||||
public function getNewsletterViewInBrowserUrl(array $context, array $args = []): string {
|
||||
$isPreview = $context['is_preview'] ?? false;
|
||||
$subscriber = !$isPreview ? $this->getSubscriber($context) : null;
|
||||
$queue = $this->getSendingQueue($context);
|
||||
$newsletter = $this->getNewsletter($context);
|
||||
|
||||
return $this->newsletterUrl->getViewInBrowserUrl(
|
||||
$newsletter,
|
||||
$subscriber,
|
||||
$queue,
|
||||
$isPreview
|
||||
);
|
||||
}
|
||||
|
||||
private function getNewsletter(array $context): ?NewsletterEntity {
|
||||
$newsletterId = $context['newsletter_id'] ?? null;
|
||||
return $newsletterId ? $this->newslettersRepository->findOneById($newsletterId) : null;
|
||||
}
|
||||
|
||||
private function getSendingQueue(array $context): ?SendingQueueEntity {
|
||||
$queueId = $context['queue_id'] ?? null;
|
||||
return $queueId ? $this->sendingQueuesRepository->findOneById($queueId) : null;
|
||||
}
|
||||
|
||||
private function getSubscriber(array $context): ?SubscriberEntity {
|
||||
$subscriberEmail = $context['recipient_email'] ?? null;
|
||||
return $subscriberEmail ? $this->subscribersRepository->findOneBy(['email' => $subscriberEmail]) : null;
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\PersonalizationTags;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Engine\PersonalizationTags\HTML_Tag_Processor;
|
||||
|
||||
/**
|
||||
* Converts link tags to shortcodes.
|
||||
*
|
||||
* This is a temporary solution so that we are able to integrate the new personalization tags
|
||||
* with the MailPoet Link tracking system which is based on shortcodes.
|
||||
*
|
||||
*/
|
||||
class LinksToShortcodesConvertor {
|
||||
private const TOKEN_MAP = [
|
||||
'[mailpoet/subscription-unsubscribe-url]' => '[link:subscription_unsubscribe_url]',
|
||||
'[mailpoet/subscription-manage-url]' => '[link:subscription_manage_url]',
|
||||
'[mailpoet/newsletter-view-in-browser-url]' => '[link:newsletter_view_in_browser_url]',
|
||||
];
|
||||
|
||||
public function convertLinkTagsToShortcodes(string $content): string {
|
||||
$contentProcessor = new HTML_Tag_Processor($content);
|
||||
while ($contentProcessor->next_token()) {
|
||||
if ($contentProcessor->get_token_type() === '#tag' && $contentProcessor->get_tag() === 'A' && $contentProcessor->get_attribute('data-link-href')) {
|
||||
$href = $contentProcessor->get_attribute('data-link-href');
|
||||
if (!isset(self::TOKEN_MAP[$href])) {
|
||||
continue;
|
||||
}
|
||||
$contentProcessor->set_attribute('href', 'http://' . self::TOKEN_MAP[$href]);
|
||||
$contentProcessor->remove_attribute('data-link-href');
|
||||
$contentProcessor->remove_attribute('contenteditable');
|
||||
}
|
||||
}
|
||||
$contentProcessor->flush_updates();
|
||||
$updated = $contentProcessor->get_updated_html();
|
||||
// Remove temporary prefix. It was needed so hat the HTML_Tag_Processor could add value to href.
|
||||
$updated = str_replace('http://[', '[', $updated);
|
||||
return $updated;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\PersonalizationTags;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class Site {
|
||||
|
||||
private WPFunctions $wp;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function getTitle(array $context, array $args = []): string {
|
||||
return htmlspecialchars_decode($this->wp->getBloginfo('name'));
|
||||
}
|
||||
|
||||
public function getHomepageURL(array $context, array $args = []): string {
|
||||
return $this->wp->getBloginfo('url');
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\PersonalizationTags;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Subscribers\SubscribersRepository;
|
||||
|
||||
class Subscriber {
|
||||
|
||||
private SubscribersRepository $subscribersRepository;
|
||||
|
||||
public function __construct(
|
||||
SubscribersRepository $subscribersRepository
|
||||
) {
|
||||
$this->subscribersRepository = $subscribersRepository;
|
||||
}
|
||||
|
||||
public function getFirstName(array $context, array $args = []): string {
|
||||
$subscriberEmail = $context['recipient_email'] ?? null;
|
||||
$subscriber = $subscriberEmail ? $this->subscribersRepository->findOneBy(['email' => $subscriberEmail]) : null;
|
||||
|
||||
return ($subscriber && $subscriber->getFirstName()) ? $subscriber->getFirstName() : $args['default'] ?? '';
|
||||
}
|
||||
|
||||
public function getLastName(array $context, array $args = []): string {
|
||||
$subscriberEmail = $context['recipient_email'] ?? null;
|
||||
$subscriber = $subscriberEmail ? $this->subscribersRepository->findOneBy(['email' => $subscriberEmail]) : null;
|
||||
|
||||
return ($subscriber && $subscriber->getLastName()) ? $subscriber->getLastName() : $args['default'] ?? '';
|
||||
}
|
||||
|
||||
public function getEmail(array $context, array $args = []): string {
|
||||
return $context['recipient_email'] ?? '';
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\Templates\Library;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Util\CdnAssetUrl;
|
||||
|
||||
class Newsletter {
|
||||
private CdnAssetUrl $cdnAssetUrl;
|
||||
|
||||
public function __construct(
|
||||
CdnAssetUrl $cdnAssetUrl
|
||||
) {
|
||||
$this->cdnAssetUrl = $cdnAssetUrl;
|
||||
}
|
||||
|
||||
public function getSlug(): string {
|
||||
return 'newsletter';
|
||||
}
|
||||
|
||||
public function getTitle(): string {
|
||||
return __('Newsletter', 'mailpoet');
|
||||
}
|
||||
|
||||
public function getDescription(): string {
|
||||
return __('Newsletter', 'mailpoet');
|
||||
}
|
||||
|
||||
public function getContent(): string {
|
||||
// translators: This is a text used in a footer on an email <!--[mailpoet/site-title]--> will be replaced with the site title.
|
||||
$footerText = __('You received this email because you are subscribed to the <!--[mailpoet/site-title]-->', 'mailpoet');
|
||||
return '<!-- wp:group {"backgroundColor":"white","layout":{"type":"constrained"},"lock":{"move":false,"remove":false}} -->
|
||||
<div class="wp-block-group has-white-background-color has-background">
|
||||
<!-- wp:group {"style":{"spacing":{"padding":{"top":"var:preset|spacing|30","bottom":"var:preset|spacing|10","left":"var:preset|spacing|20","right":"var:preset|spacing|20"}}}} -->
|
||||
<div
|
||||
class="wp-block-group"
|
||||
style="
|
||||
padding-top: var(--wp--preset--spacing--30);
|
||||
padding-right: var(--wp--preset--spacing--20);
|
||||
padding-bottom: var(--wp--preset--spacing--10);
|
||||
padding-left: var(--wp--preset--spacing--20);
|
||||
"
|
||||
>
|
||||
<!-- wp:image {"width":"130px","sizeSlug":"large"} -->
|
||||
<figure class="wp-block-image size-large is-resized">
|
||||
<img
|
||||
src="' . esc_url($this->cdnAssetUrl->generateCdnUrl('email-editor/your-logo-placeholder.png')) . '"
|
||||
alt="' . __('Your Logo', 'mailpoet') . '"
|
||||
style="width: 130px"
|
||||
/>
|
||||
</figure>
|
||||
<!-- /wp:image -->
|
||||
</div>
|
||||
<!-- /wp:group -->
|
||||
<!-- wp:post-content {"lock":{"move":false,"remove":false},"layout":{"type":"default"}} /-->
|
||||
<!-- wp:group {"style":{"spacing":{"padding":{"right":"var:preset|spacing|20","left":"var:preset|spacing|20","top":"var:preset|spacing|10","bottom":"var:preset|spacing|10"}}}} -->
|
||||
<div
|
||||
class="wp-block-group"
|
||||
style="
|
||||
padding-top: var(--wp--preset--spacing--10);
|
||||
padding-right: var(--wp--preset--spacing--20);
|
||||
padding-bottom: var(--wp--preset--spacing--10);
|
||||
padding-left: var(--wp--preset--spacing--20);
|
||||
"
|
||||
>
|
||||
<!-- wp:paragraph {"align":"center","fontSize":"small","style":{"border":{"top":{"color":"var:preset|color|cyan-bluish-gray","width":"1px","style":"solid"},"right":{},"bottom":{},"left":{}},"spacing":{"padding":{"top":"var:preset|spacing|20","bottom":"var:preset|spacing|20"}},"color":{"text":"#787c82"},"elements":{"link":{"color":{"text":"#787c82"}}}}} -->
|
||||
<p
|
||||
class="has-text-align-center has-text-color has-link-color has-small-font-size"
|
||||
style="
|
||||
border-top-color: var(--wp--preset--color--cyan-bluish-gray);
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
color: #787c82;
|
||||
padding-top: var(--wp--preset--spacing--20);
|
||||
padding-bottom: var(--wp--preset--spacing--20);
|
||||
"
|
||||
>' . $footerText . '<br /><a data-link-href="[mailpoet/subscription-unsubscribe-url]" contenteditable="false" style="text-decoration: underline;" class="mailpoet-email-editor__personalization-tags-link">' . __('Unsubscribe', 'mailpoet') . '</a> | <a data-link-href="[mailpoet/subscription-manage-url]" contenteditable="false" style="text-decoration: underline;" class="mailpoet-email-editor__personalization-tags-link">' . __('Manage subscription', 'mailpoet') . '</a>
|
||||
</p>
|
||||
<!-- /wp:paragraph -->
|
||||
</div>
|
||||
<!-- /wp:group -->
|
||||
<!-- wp:mailpoet/powered-by-mailpoet {"lock":{"move":true,"remove":true}} /-->
|
||||
</div>
|
||||
<!-- /wp:group -->';
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\EmailEditor\Integrations\MailPoet\Templates;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\EmailEditor;
|
||||
use MailPoet\EmailEditor\Integrations\MailPoet\Templates\Library\Newsletter;
|
||||
use MailPoet\Util\CdnAssetUrl;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class TemplatesController {
|
||||
private string $templatePrefix = 'mailpoet';
|
||||
private WPFunctions $wp;
|
||||
private CdnAssetUrl $cdnAssetUrl;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp,
|
||||
CdnAssetUrl $cdnAssetUrl
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
$this->cdnAssetUrl = $cdnAssetUrl;
|
||||
}
|
||||
|
||||
public function initialize() {
|
||||
$this->wp->addAction('mailpoet_email_editor_register_templates', [$this, 'registerTemplates'], 10, 0);
|
||||
}
|
||||
|
||||
public function registerTemplates() {
|
||||
$newsletter = new Newsletter($this->cdnAssetUrl);
|
||||
$templateName = $this->templatePrefix . '//' . $newsletter->getSlug();
|
||||
|
||||
if (\WP_Block_Templates_Registry::get_instance()->is_registered($templateName)) {
|
||||
// skip registration if the template was already registered.
|
||||
return;
|
||||
}
|
||||
|
||||
register_block_template(
|
||||
$templateName,
|
||||
[
|
||||
'title' => $newsletter->getTitle(),
|
||||
'description' => $newsletter->getDescription(),
|
||||
'content' => $newsletter->getContent(),
|
||||
'post_types' => [EmailEditor::MAILPOET_EMAIL_POST_TYPE],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+355
@@ -0,0 +1,355 @@
|
||||
<!-- wp:heading {"textAlign":"center","level":1,"align":"full","textColor":"luminous-vivid-orange","style":{"elements":{"link":{"color":{"text":"var:preset|color|luminous-vivid-orange"}}},"color":{"background":"#f0f0f0"}}} -->
|
||||
<h1
|
||||
class="wp-block-heading alignfull has-text-align-center has-luminous-vivid-orange-color has-text-color has-background has-link-color"
|
||||
style="background-color: #f0f0f0"
|
||||
>
|
||||
Sample Newsletter
|
||||
</h1>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:columns -->
|
||||
<div class="wp-block-columns">
|
||||
<!-- wp:column {"style":{"spacing":{"padding":{"right":"10px","left":"10px"}}}} -->
|
||||
<div class="wp-block-column" style="padding-right: 10px; padding-left: 10px">
|
||||
<!-- wp:heading {"backgroundColor":"pale-cyan-blue","style":{"spacing":{"padding":{"right":"var:preset|spacing|20","left":"var:preset|spacing|20"}}}} -->
|
||||
<h2
|
||||
class="wp-block-heading has-pale-cyan-blue-background-color has-background"
|
||||
style="
|
||||
padding-right: var(--wp--preset--spacing--20);
|
||||
padding-left: var(--wp--preset--spacing--20);
|
||||
"
|
||||
>
|
||||
1 Column Part
|
||||
</h2>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:paragraph -->
|
||||
<p>
|
||||
A one-column layout is great for simplified and concise content, like
|
||||
announcements or newsletters with brief updates. Drag blocks to add
|
||||
content and customize your styles from the styles panel on the top right.
|
||||
</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
||||
<!-- wp:image {"sizeSlug":"large"} -->
|
||||
<figure class="wp-block-image size-large">
|
||||
<img src="https://picsum.photos/id/133/600/300" alt="" />
|
||||
</figure>
|
||||
<!-- /wp:image -->
|
||||
|
||||
<!-- wp:buttons {"layout":{"justifyContent":"center"}} -->
|
||||
<div class="wp-block-buttons">
|
||||
<!-- wp:button {"backgroundColor":"pale-cyan-blue","textColor":"black","width":100,"style":{"elements":{"link":{"color":{"text":"var:preset|color|black"}}}}} -->
|
||||
<div class="wp-block-button has-custom-width wp-block-button__width-100">
|
||||
<a
|
||||
class="wp-block-button__link has-black-color has-pale-cyan-blue-background-color has-text-color has-background has-link-color wp-element-button"
|
||||
>Button</a
|
||||
>
|
||||
</div>
|
||||
<!-- /wp:button -->
|
||||
</div>
|
||||
<!-- /wp:buttons -->
|
||||
</div>
|
||||
<!-- /wp:column -->
|
||||
</div>
|
||||
<!-- /wp:columns -->
|
||||
|
||||
<!-- wp:heading {"textAlign":"center","align":"full","style":{"color":{"background":"#f0f0f0"},"spacing":{"padding":{"top":"var:preset|spacing|20","bottom":"var:preset|spacing|20","left":"0","right":"0"}}}} -->
|
||||
<h2
|
||||
class="wp-block-heading alignfull has-text-align-center has-background"
|
||||
style="
|
||||
background-color: #f0f0f0;
|
||||
padding-top: var(--wp--preset--spacing--20);
|
||||
padding-right: 0;
|
||||
padding-bottom: var(--wp--preset--spacing--20);
|
||||
padding-left: 0;
|
||||
"
|
||||
>
|
||||
2 Columns Part
|
||||
</h2>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:paragraph {"fontFamily":"comic-sans-ms"} -->
|
||||
<p class="has-comic-sans-ms-font-family">
|
||||
A two-column layout organizes information into sections, making it easier for
|
||||
users to navigate content. Try other layouts by adding or removing columns,
|
||||
drag blocks into them to add content and customize your email styles from the
|
||||
styles panel.
|
||||
</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
||||
<!-- wp:columns -->
|
||||
<div class="wp-block-columns">
|
||||
<!-- wp:column -->
|
||||
<div class="wp-block-column">
|
||||
<!-- wp:image {"width":"280px","sizeSlug":"large","align":"left"} -->
|
||||
<figure class="wp-block-image alignleft size-large is-resized">
|
||||
<img
|
||||
src="https://picsum.photos/id/133/300/200"
|
||||
alt=""
|
||||
style="width: 280px"
|
||||
/>
|
||||
</figure>
|
||||
<!-- /wp:image -->
|
||||
</div>
|
||||
<!-- /wp:column -->
|
||||
|
||||
<!-- wp:column {"width":"300px","style":{"spacing":{"padding":{"right":"0","left":"0"}}}} -->
|
||||
<div
|
||||
class="wp-block-column"
|
||||
style="padding-right: 0; padding-left: 0; flex-basis: 300px"
|
||||
>
|
||||
<!-- wp:image {"width":"280px","sizeSlug":"large","align":"right"} -->
|
||||
<figure class="wp-block-image alignright size-large is-resized">
|
||||
<img
|
||||
src="https://picsum.photos/id/133/300/200"
|
||||
alt=""
|
||||
style="width: 280px"
|
||||
/>
|
||||
</figure>
|
||||
<!-- /wp:image -->
|
||||
</div>
|
||||
<!-- /wp:column -->
|
||||
</div>
|
||||
<!-- /wp:columns -->
|
||||
|
||||
<!-- wp:columns -->
|
||||
<div class="wp-block-columns">
|
||||
<!-- wp:column -->
|
||||
<div class="wp-block-column">
|
||||
<!-- wp:heading {"level":3,"textColor":"vivid-red","style":{"elements":{"link":{"color":{"text":"var:preset|color|vivid-red"}}}}} -->
|
||||
<h3
|
||||
class="wp-block-heading has-vivid-red-color has-text-color has-link-color"
|
||||
>
|
||||
Heading 2
|
||||
</h3>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:paragraph {"style":{"typography":{"fontStyle":"italic","fontWeight":"700"}}} -->
|
||||
<p style="font-style: italic; font-weight: 700">
|
||||
You can also add text blocks into a column next to
|
||||
<mark
|
||||
style="background-color: #dc2d2d"
|
||||
class="has-inline-color has-white-color"
|
||||
>an image block</mark
|
||||
>
|
||||
to create unique layouts.
|
||||
</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
||||
<!-- wp:buttons {"layout":{"justifyContent":"right"}} -->
|
||||
<div class="wp-block-buttons">
|
||||
<!-- wp:button {"backgroundColor":"pale-cyan-blue","textColor":"contrast","width":50,"style":{"elements":{"link":{"color":{"text":"var:preset|color|contrast"}}}}} -->
|
||||
<div class="wp-block-button has-custom-width wp-block-button__width-50">
|
||||
<a
|
||||
class="wp-block-button__link has-contrast-color has-pale-cyan-blue-background-color has-text-color has-background has-link-color wp-element-button"
|
||||
>Button</a
|
||||
>
|
||||
</div>
|
||||
<!-- /wp:button -->
|
||||
</div>
|
||||
<!-- /wp:buttons -->
|
||||
</div>
|
||||
<!-- /wp:column -->
|
||||
|
||||
<!-- wp:column {"width":"300px","style":{"spacing":{"padding":{"right":"0","left":"0"}}}} -->
|
||||
<div
|
||||
class="wp-block-column"
|
||||
style="padding-right: 0; padding-left: 0; flex-basis: 300px"
|
||||
>
|
||||
<!-- wp:image {"width":"280px","height":"auto","sizeSlug":"large","align":"right"} -->
|
||||
<figure class="wp-block-image alignright size-large is-resized">
|
||||
<img
|
||||
src="https://picsum.photos/id/133/300/200"
|
||||
alt=""
|
||||
style="width: 280px; height: auto"
|
||||
/>
|
||||
</figure>
|
||||
<!-- /wp:image -->
|
||||
</div>
|
||||
<!-- /wp:column -->
|
||||
</div>
|
||||
<!-- /wp:columns -->
|
||||
|
||||
<!-- wp:columns {"style":{"spacing":{"padding":{"right":"var:preset|spacing|10","left":"var:preset|spacing|10"}}}} -->
|
||||
<div
|
||||
class="wp-block-columns"
|
||||
style="
|
||||
padding-right: var(--wp--preset--spacing--10);
|
||||
padding-left: var(--wp--preset--spacing--10);
|
||||
"
|
||||
>
|
||||
<!-- wp:column -->
|
||||
<div class="wp-block-column">
|
||||
<!-- wp:heading {"textAlign":"center","level":4} -->
|
||||
<h4 class="wp-block-heading has-text-align-center">Product 1</h4>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:image {"width":"150px","sizeSlug":"large","align":"center"} -->
|
||||
<figure class="wp-block-image aligncenter size-large is-resized">
|
||||
<img
|
||||
src="https://picsum.photos/id/36/180/200"
|
||||
alt=""
|
||||
style="width: 150px"
|
||||
/>
|
||||
</figure>
|
||||
<!-- /wp:image -->
|
||||
|
||||
<!-- wp:list -->
|
||||
<ul>
|
||||
<!-- wp:list-item -->
|
||||
<li>Item 1</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
<!-- wp:list-item -->
|
||||
<li>
|
||||
Item 2
|
||||
<!-- wp:list {"textColor":"vivid-red","style":{"elements":{"link":{"color":{"text":"var:preset|color|vivid-red"}}},"typography":{"fontStyle":"italic","fontWeight":"400"}}} -->
|
||||
<ul
|
||||
style="font-style: italic; font-weight: 400"
|
||||
class="has-vivid-red-color has-text-color has-link-color"
|
||||
>
|
||||
<!-- wp:list-item -->
|
||||
<li>Item A</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
<!-- wp:list-item -->
|
||||
<li>Item B</li>
|
||||
<!-- /wp:list-item -->
|
||||
</ul>
|
||||
<!-- /wp:list -->
|
||||
</li>
|
||||
<!-- /wp:list-item -->
|
||||
</ul>
|
||||
<!-- /wp:list -->
|
||||
</div>
|
||||
<!-- /wp:column -->
|
||||
|
||||
<!-- wp:column -->
|
||||
<div class="wp-block-column">
|
||||
<!-- wp:heading {"textAlign":"center","level":4} -->
|
||||
<h4 class="wp-block-heading has-text-align-center">Product 2</h4>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:image {"width":"150px","sizeSlug":"large","align":"center"} -->
|
||||
<figure class="wp-block-image aligncenter size-large is-resized">
|
||||
<img
|
||||
src="https://picsum.photos/id/36/180/200"
|
||||
alt=""
|
||||
style="width: 150px"
|
||||
/>
|
||||
</figure>
|
||||
<!-- /wp:image -->
|
||||
|
||||
<!-- wp:list {"style":{"typography":{"textDecoration":"none"}}} -->
|
||||
<ul style="text-decoration: none">
|
||||
<!-- wp:list-item -->
|
||||
<li>Item 1</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
<!-- wp:list-item -->
|
||||
<li>
|
||||
Item 2
|
||||
<!-- wp:list {"textColor":"vivid-cyan-blue","style":{"elements":{"link":{"color":{"text":"var:preset|color|vivid-cyan-blue"}}},"typography":{"textDecoration":"underline"}}} -->
|
||||
<ul
|
||||
style="text-decoration: underline"
|
||||
class="has-vivid-cyan-blue-color has-text-color has-link-color"
|
||||
>
|
||||
<!-- wp:list-item -->
|
||||
<li>Item A</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
<!-- wp:list-item -->
|
||||
<li>Item B</li>
|
||||
<!-- /wp:list-item -->
|
||||
</ul>
|
||||
<!-- /wp:list -->
|
||||
</li>
|
||||
<!-- /wp:list-item -->
|
||||
</ul>
|
||||
<!-- /wp:list -->
|
||||
</div>
|
||||
<!-- /wp:column -->
|
||||
|
||||
<!-- wp:column -->
|
||||
<div class="wp-block-column">
|
||||
<!-- wp:heading {"textAlign":"center","level":4} -->
|
||||
<h4 class="wp-block-heading has-text-align-center">Product 3</h4>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:image {"width":"150px","sizeSlug":"large","align":"center"} -->
|
||||
<figure class="wp-block-image aligncenter size-large is-resized">
|
||||
<img
|
||||
src="https://picsum.photos/id/36/180/200"
|
||||
alt=""
|
||||
style="width: 150px"
|
||||
/>
|
||||
</figure>
|
||||
<!-- /wp:image -->
|
||||
|
||||
<!-- wp:list {"ordered":true} -->
|
||||
<ol>
|
||||
<!-- wp:list-item -->
|
||||
<li>Item 1</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
<!-- wp:list-item -->
|
||||
<li>
|
||||
Item 2
|
||||
<!-- wp:list {"textColor":"vivid-green-cyan","style":{"elements":{"link":{"color":{"text":"var:preset|color|vivid-green-cyan"}}},"typography":{"fontStyle":"normal","fontWeight":"700"}}} -->
|
||||
<ul
|
||||
style="font-style: normal; font-weight: 700"
|
||||
class="has-vivid-green-cyan-color has-text-color has-link-color"
|
||||
>
|
||||
<!-- wp:list-item -->
|
||||
<li>Item A</li>
|
||||
<!-- /wp:list-item -->
|
||||
|
||||
<!-- wp:list-item -->
|
||||
<li>Item B</li>
|
||||
<!-- /wp:list-item -->
|
||||
</ul>
|
||||
<!-- /wp:list -->
|
||||
</li>
|
||||
<!-- /wp:list-item -->
|
||||
</ol>
|
||||
<!-- /wp:list -->
|
||||
</div>
|
||||
<!-- /wp:column -->
|
||||
</div>
|
||||
<!-- /wp:columns -->
|
||||
|
||||
<!-- wp:buttons {"align":"full","style":{"spacing":{"blockGap":"var:preset|spacing|30"}},"layout":{"justifyContent":"center"}} -->
|
||||
<div class="wp-block-buttons alignfull">
|
||||
<!-- wp:button {"width":25} -->
|
||||
<div class="wp-block-button has-custom-width wp-block-button__width-25">
|
||||
<a class="wp-block-button__link wp-element-button">Button 1</a>
|
||||
</div>
|
||||
<!-- /wp:button -->
|
||||
|
||||
<!-- wp:button {"width":25} -->
|
||||
<div class="wp-block-button has-custom-width wp-block-button__width-25">
|
||||
<a class="wp-block-button__link wp-element-button">Button 2</a>
|
||||
</div>
|
||||
<!-- /wp:button -->
|
||||
|
||||
<!-- wp:button {"width":25} -->
|
||||
<div class="wp-block-button has-custom-width wp-block-button__width-25">
|
||||
<a class="wp-block-button__link wp-element-button">Button 3</a>
|
||||
</div>
|
||||
<!-- /wp:button -->
|
||||
</div>
|
||||
<!-- /wp:buttons -->
|
||||
|
||||
<!-- wp:paragraph {"align":"center","fontSize":"small"} -->
|
||||
<p class="has-text-align-center has-small-font-size">
|
||||
You received this email because you are subscribed to the [site:title]
|
||||
</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
||||
<!-- wp:paragraph {"align":"center","fontSize":"small"} -->
|
||||
<p class="has-text-align-center has-small-font-size">
|
||||
<a href="[link:subscription_unsubscribe_url]">Unsubscribe</a> |
|
||||
<a href="[link:subscription_manage_url]">Manage subscription</a>
|
||||
</p>
|
||||
<!-- /wp:paragraph -->
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
Reference in New Issue
Block a user