PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.36.0
MailPoet – Newsletters, Email Marketing, and Automation v5.36.0
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 days ago class-html2text-exception.php 11 months ago class-html2text.php 11 months ago class-renderer.php 3 days ago index.php 11 months ago interface-css-inliner.php 11 months ago template-canvas.css 3 months ago template-canvas.php 3 months ago
class-renderer.php
187 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 'font-weight' => $email_styles['typography']['fontWeight'] ?? 'inherit',
64 'font-style' => $email_styles['typography']['fontStyle'] ?? 'inherit',
65 'letter-spacing' => $email_styles['typography']['letterSpacing'] ?? 'normal',
66 'line-height' => $email_styles['typography']['lineHeight'] ?? '1.5',
67 'font-size' => $email_styles['typography']['fontSize'] ?? 'inherit',
68 'direction' => $rendering_context->get_text_direction(),
69 'text-align' => $rendering_context->get_default_text_align(),
70 ),
71 'body, .email_layout_wrapper'
72 );
73 $template_styles .= WP_Style_Engine::compile_css(
74 array(
75 'direction' => $rendering_context->get_text_direction(),
76 'text-align' => $rendering_context->get_default_text_align(),
77 ),
78 '.email_content_wrapper, .email_preheader'
79 );
80 $template_styles .= '.email_layout_wrapper { box-sizing: border-box;}';
81 $template_styles .= file_get_contents( __DIR__ . '/' . self::TEMPLATE_STYLES_FILE );
82 $template_styles = wp_strip_all_tags( (string) apply_filters( 'woocommerce_email_renderer_styles', $template_styles, $post ) );
83 // Single CSS inlining pass: combine content and template styles, then inline all at once.
84 $all_styles = '<style>' . $template_styles . $content_styles . '</style>';
85 $rendered_template = $this->inline_css_styles( $all_styles . $rendered_template );
86 // Postprocess after CSS inlining (border normalization, CSS variable replacement, etc.).
87 $rendered_template = $this->process_manager->postprocess( $rendered_template );
88 $rendered_template = $this->apply_html_attributes( $rendered_template, $rendering_context );
89 // This is a workaround to support link :hover in some clients. Ideally we would remove the ability to set :hover
90 // however this is not possible using the color panel from Gutenberg.
91 if ( isset( $email_styles['elements']['link'][':hover']['color']['text'] ) ) {
92 $rendered_template = str_replace( '<!-- Forced Styles -->', '<style>a:hover { color: ' . esc_attr( $email_styles['elements']['link'][':hover']['color']['text'] ) . ' !important; }</style>', $rendered_template );
93 }
94 return array(
95 'html' => $rendered_template,
96 'text' => $this->render_text_version( $rendered_template ),
97 );
98 } finally {
99 $this->content_renderer->restore_rendering_context( $previous_rendering_context );
100 }
101 }
102 public function render_from_content( string $content, string $template_slug, string $subject, string $pre_header, string $language = 'en', string $meta_robots = '' ): array {
103 $synthetic_post = new \WP_Post(
104 (object) array(
105 'ID' => 0,
106 'post_status' => 'publish',
107 'post_content' => $content,
108 )
109 );
110 return $this->render( $synthetic_post, $subject, $pre_header, $language, $meta_robots, $template_slug );
111 }
112 private function inline_css_styles( $template ) {
113 return $this->css_inliner->from_html( $template )->inline_css()->render();
114 }
115 private function apply_html_attributes( string $template, Rendering_Context $rendering_context ): string {
116 $processor = new \WP_HTML_Tag_Processor( $template );
117 if ( ! $processor->next_tag( array( 'tag_name' => 'html' ) ) ) {
118 return $template;
119 }
120 $language = $rendering_context->get_language();
121 if ( $language ) {
122 $processor->set_attribute( 'lang', str_replace( '_', '-', $language ) );
123 }
124 $processor->set_attribute( 'dir', $rendering_context->get_text_direction() );
125 return $processor->get_updated_html();
126 }
127 private function render_text_version( $template ) {
128 $template = ( mb_detect_encoding( $template, 'UTF-8', true ) ) ? $template : mb_convert_encoding( $template, 'UTF-8', mb_list_encodings() );
129 // Ensure template is a string before processing.
130 if ( ! is_string( $template ) ) {
131 return '';
132 }
133 // Preserve personalization tags by temporarily replacing them with unique placeholders.
134 $template = $this->preserve_personalization_tags( $template );
135 $result = Html2Text::convert( (string) $template, array( 'ignore_errors' => true ) );
136 if ( ! $result ) {
137 return '';
138 }
139 // Restore personalization tags from placeholders.
140 $result = $this->restore_personalization_tags( $result );
141 return $result;
142 }
143 private function preserve_personalization_tags( string $template ): string {
144 $all_registered_tags = $this->personalization_tags_registry->get_all();
145 $this->personalization_tag_placeholders = array();
146 $counter = 0;
147 $base_tokens = array(); // All the tokens used in the email, e.g. [woocommerce/customer-username].
148 $token_prefixes = array(); // All the used prefixes, e.g. woocommerce, mailpoet, etc.
149 foreach ( $all_registered_tags as $tag ) {
150 $token = $tag->get_token(); // E.g. [woocommerce/customer-username].
151 $base_tokens[ $token ] = true;
152 // Remove brackets for regex matching, escape for regex.
153 $token_prefixes[] = preg_quote( substr( $token, 1, -1 ), '/' );
154 }
155 if ( empty( $token_prefixes ) ) {
156 return $template;
157 }
158 // Match all of the code comments that look like a personalization tags.
159 $pattern = '/<!--\[(' . implode( '|', $token_prefixes ) . ')(?:\s+[^\]]*)?\]-->/';
160 $template = preg_replace_callback(
161 $pattern,
162 function ( $matches ) use ( &$counter, $base_tokens ) {
163 // $matches[1] is the token without brackets, add brackets for lookup.
164 $base_token = '[' . $matches[1] . ']';
165 if ( isset( $base_tokens[ $base_token ] ) ) {
166 $placeholder = 'PERSONALIZATION_TAG_PLACEHOLDER_' . $counter;
167 $this->personalization_tag_placeholders[ $placeholder ] = $matches[0];
168 ++$counter;
169 return $placeholder;
170 }
171 return $matches[0];
172 },
173 $template
174 );
175 return $template ?? '';
176 }
177 private function restore_personalization_tags( string $text ): string {
178 if ( empty( $this->personalization_tag_placeholders ) ) {
179 return $text;
180 }
181 foreach ( $this->personalization_tag_placeholders as $placeholder => $html_comment ) {
182 $text = str_replace( $placeholder, $html_comment, $text );
183 }
184 return $text;
185 }
186 }
187