PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.3
MailPoet – Newsletters, Email Marketing, and Automation v5.34.3
5.36.1 5.36.0 5.35.1 5.35.0 5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / vendor / woocommerce / email-editor / src / Engine / Renderer / class-renderer.php
mailpoet / vendor / woocommerce / email-editor / src / Engine / Renderer Last commit date
ContentRenderer 3 months ago class-html2text-exception.php 1 year ago class-html2text.php 1 year ago class-renderer.php 3 months ago index.php 1 year ago interface-css-inliner.php 1 year ago template-canvas.css 3 months ago template-canvas.php 3 months ago
class-renderer.php
174 lines
1 <?php
2 declare(strict_types = 1);
3 namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer;
4 if (!defined('ABSPATH')) exit;
5 use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Content_Renderer;
6 use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Process_Manager;
7 use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
8 use Automattic\WooCommerce\EmailEditor\Engine\Templates\Templates;
9 use Automattic\WooCommerce\EmailEditor\Engine\Theme_Controller;
10 use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
11 use WP_Style_Engine;
12 class Renderer {
13 private Theme_Controller $theme_controller;
14 private Content_Renderer $content_renderer;
15 private Templates $templates;
16 private Css_Inliner $css_inliner;
17 private Process_Manager $process_manager;
18 private Personalization_Tags_Registry $personalization_tags_registry;
19 private array $personalization_tag_placeholders = array();
20 const TEMPLATE_FILE = 'template-canvas.php';
21 const TEMPLATE_STYLES_FILE = 'template-canvas.css';
22 public function __construct(
23 Content_Renderer $content_renderer,
24 Templates $templates,
25 Css_Inliner $css_inliner,
26 Theme_Controller $theme_controller,
27 Personalization_Tags_Registry $personalization_tags_registry,
28 Process_Manager $process_manager
29 ) {
30 $this->content_renderer = $content_renderer;
31 $this->templates = $templates;
32 $this->theme_controller = $theme_controller;
33 $this->css_inliner = $css_inliner;
34 $this->personalization_tags_registry = $personalization_tags_registry;
35 $this->process_manager = $process_manager;
36 }
37 public function render( \WP_Post $post, string $subject, string $pre_header, string $language, string $meta_robots = '', string $template_slug = '' ): array {
38 if ( ! $template_slug ) {
39 $template_slug = get_page_template_slug( $post ) ? get_page_template_slug( $post ) : 'email-general';
40 }
41 // phpcs:ignore Generic.Commenting.DocComment.MissingShort -- used for phpstan
42 $template = $this->templates->get_block_template( $template_slug );
43 $previous_rendering_context = $this->content_renderer->get_current_rendering_context();
44 try {
45 $rendering_context = $this->content_renderer->create_rendering_context( $language, $post, $template );
46 $this->content_renderer->set_rendering_context( $rendering_context );
47 $email_styles = $this->theme_controller->get_styles();
48 $content_result = $this->content_renderer->render_without_css_inline( $post, $template );
49 $template_html = $content_result['html'];
50 $content_styles = $content_result['styles'];
51 $layout = $this->theme_controller->get_layout_settings();
52 ob_start();
53 include self::TEMPLATE_FILE;
54 $rendered_template = (string) ob_get_clean();
55 $template_styles =
56 WP_Style_Engine::compile_css(
57 array(
58 'background-color' => $email_styles['color']['background'] ?? 'inherit',
59 'color' => $email_styles['color']['text'] ?? 'inherit',
60 'padding-top' => $email_styles['spacing']['padding']['top'] ?? '0px',
61 'padding-bottom' => $email_styles['spacing']['padding']['bottom'] ?? '0px',
62 'font-family' => $email_styles['typography']['fontFamily'] ?? 'inherit',
63 'line-height' => $email_styles['typography']['lineHeight'] ?? '1.5',
64 'font-size' => $email_styles['typography']['fontSize'] ?? 'inherit',
65 'direction' => $rendering_context->get_text_direction(),
66 'text-align' => $rendering_context->get_default_text_align(),
67 ),
68 'body, .email_layout_wrapper'
69 );
70 $template_styles .= WP_Style_Engine::compile_css(
71 array(
72 'direction' => $rendering_context->get_text_direction(),
73 'text-align' => $rendering_context->get_default_text_align(),
74 ),
75 '.email_content_wrapper, .email_preheader'
76 );
77 $template_styles .= '.email_layout_wrapper { box-sizing: border-box;}';
78 $template_styles .= file_get_contents( __DIR__ . '/' . self::TEMPLATE_STYLES_FILE );
79 $template_styles = wp_strip_all_tags( (string) apply_filters( 'woocommerce_email_renderer_styles', $template_styles, $post ) );
80 // Single CSS inlining pass: combine content and template styles, then inline all at once.
81 $all_styles = '<style>' . $template_styles . $content_styles . '</style>';
82 $rendered_template = $this->inline_css_styles( $all_styles . $rendered_template );
83 // Postprocess after CSS inlining (border normalization, CSS variable replacement, etc.).
84 $rendered_template = $this->process_manager->postprocess( $rendered_template );
85 $rendered_template = $this->apply_html_attributes( $rendered_template, $rendering_context );
86 // This is a workaround to support link :hover in some clients. Ideally we would remove the ability to set :hover
87 // however this is not possible using the color panel from Gutenberg.
88 if ( isset( $email_styles['elements']['link'][':hover']['color']['text'] ) ) {
89 $rendered_template = str_replace( '<!-- Forced Styles -->', '<style>a:hover { color: ' . esc_attr( $email_styles['elements']['link'][':hover']['color']['text'] ) . ' !important; }</style>', $rendered_template );
90 }
91 return array(
92 'html' => $rendered_template,
93 'text' => $this->render_text_version( $rendered_template ),
94 );
95 } finally {
96 $this->content_renderer->restore_rendering_context( $previous_rendering_context );
97 }
98 }
99 private function inline_css_styles( $template ) {
100 return $this->css_inliner->from_html( $template )->inline_css()->render();
101 }
102 private function apply_html_attributes( string $template, Rendering_Context $rendering_context ): string {
103 $processor = new \WP_HTML_Tag_Processor( $template );
104 if ( ! $processor->next_tag( array( 'tag_name' => 'html' ) ) ) {
105 return $template;
106 }
107 $language = $rendering_context->get_language();
108 if ( $language ) {
109 $processor->set_attribute( 'lang', str_replace( '_', '-', $language ) );
110 }
111 $processor->set_attribute( 'dir', $rendering_context->get_text_direction() );
112 return $processor->get_updated_html();
113 }
114 private function render_text_version( $template ) {
115 $template = ( mb_detect_encoding( $template, 'UTF-8', true ) ) ? $template : mb_convert_encoding( $template, 'UTF-8', mb_list_encodings() );
116 // Ensure template is a string before processing.
117 if ( ! is_string( $template ) ) {
118 return '';
119 }
120 // Preserve personalization tags by temporarily replacing them with unique placeholders.
121 $template = $this->preserve_personalization_tags( $template );
122 $result = Html2Text::convert( (string) $template, array( 'ignore_errors' => true ) );
123 if ( ! $result ) {
124 return '';
125 }
126 // Restore personalization tags from placeholders.
127 $result = $this->restore_personalization_tags( $result );
128 return $result;
129 }
130 private function preserve_personalization_tags( string $template ): string {
131 $all_registered_tags = $this->personalization_tags_registry->get_all();
132 $this->personalization_tag_placeholders = array();
133 $counter = 0;
134 $base_tokens = array(); // All the tokens used in the email, e.g. [woocommerce/customer-username].
135 $token_prefixes = array(); // All the used prefixes, e.g. woocommerce, mailpoet, etc.
136 foreach ( $all_registered_tags as $tag ) {
137 $token = $tag->get_token(); // E.g. [woocommerce/customer-username].
138 $base_tokens[ $token ] = true;
139 // Remove brackets for regex matching, escape for regex.
140 $token_prefixes[] = preg_quote( substr( $token, 1, -1 ), '/' );
141 }
142 if ( empty( $token_prefixes ) ) {
143 return $template;
144 }
145 // Match all of the code comments that look like a personalization tags.
146 $pattern = '/<!--\[(' . implode( '|', $token_prefixes ) . ')(?:\s+[^\]]*)?\]-->/';
147 $template = preg_replace_callback(
148 $pattern,
149 function ( $matches ) use ( &$counter, $base_tokens ) {
150 // $matches[1] is the token without brackets, add brackets for lookup.
151 $base_token = '[' . $matches[1] . ']';
152 if ( isset( $base_tokens[ $base_token ] ) ) {
153 $placeholder = 'PERSONALIZATION_TAG_PLACEHOLDER_' . $counter;
154 $this->personalization_tag_placeholders[ $placeholder ] = $matches[0];
155 ++$counter;
156 return $placeholder;
157 }
158 return $matches[0];
159 },
160 $template
161 );
162 return $template ?? '';
163 }
164 private function restore_personalization_tags( string $text ): string {
165 if ( empty( $this->personalization_tag_placeholders ) ) {
166 return $text;
167 }
168 foreach ( $this->personalization_tag_placeholders as $placeholder => $html_comment ) {
169 $text = str_replace( $placeholder, $html_comment, $text );
170 }
171 return $text;
172 }
173 }
174