PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.35.0
MailPoet – Newsletters, Email Marketing, and Automation v5.35.0
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 weeks ago class-html2text-exception.php 1 year ago class-html2text.php 1 year ago class-renderer.php 3 weeks 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
177 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 private function inline_css_styles( $template ) {
103 return $this->css_inliner->from_html( $template )->inline_css()->render();
104 }
105 private function apply_html_attributes( string $template, Rendering_Context $rendering_context ): string {
106 $processor = new \WP_HTML_Tag_Processor( $template );
107 if ( ! $processor->next_tag( array( 'tag_name' => 'html' ) ) ) {
108 return $template;
109 }
110 $language = $rendering_context->get_language();
111 if ( $language ) {
112 $processor->set_attribute( 'lang', str_replace( '_', '-', $language ) );
113 }
114 $processor->set_attribute( 'dir', $rendering_context->get_text_direction() );
115 return $processor->get_updated_html();
116 }
117 private function render_text_version( $template ) {
118 $template = ( mb_detect_encoding( $template, 'UTF-8', true ) ) ? $template : mb_convert_encoding( $template, 'UTF-8', mb_list_encodings() );
119 // Ensure template is a string before processing.
120 if ( ! is_string( $template ) ) {
121 return '';
122 }
123 // Preserve personalization tags by temporarily replacing them with unique placeholders.
124 $template = $this->preserve_personalization_tags( $template );
125 $result = Html2Text::convert( (string) $template, array( 'ignore_errors' => true ) );
126 if ( ! $result ) {
127 return '';
128 }
129 // Restore personalization tags from placeholders.
130 $result = $this->restore_personalization_tags( $result );
131 return $result;
132 }
133 private function preserve_personalization_tags( string $template ): string {
134 $all_registered_tags = $this->personalization_tags_registry->get_all();
135 $this->personalization_tag_placeholders = array();
136 $counter = 0;
137 $base_tokens = array(); // All the tokens used in the email, e.g. [woocommerce/customer-username].
138 $token_prefixes = array(); // All the used prefixes, e.g. woocommerce, mailpoet, etc.
139 foreach ( $all_registered_tags as $tag ) {
140 $token = $tag->get_token(); // E.g. [woocommerce/customer-username].
141 $base_tokens[ $token ] = true;
142 // Remove brackets for regex matching, escape for regex.
143 $token_prefixes[] = preg_quote( substr( $token, 1, -1 ), '/' );
144 }
145 if ( empty( $token_prefixes ) ) {
146 return $template;
147 }
148 // Match all of the code comments that look like a personalization tags.
149 $pattern = '/<!--\[(' . implode( '|', $token_prefixes ) . ')(?:\s+[^\]]*)?\]-->/';
150 $template = preg_replace_callback(
151 $pattern,
152 function ( $matches ) use ( &$counter, $base_tokens ) {
153 // $matches[1] is the token without brackets, add brackets for lookup.
154 $base_token = '[' . $matches[1] . ']';
155 if ( isset( $base_tokens[ $base_token ] ) ) {
156 $placeholder = 'PERSONALIZATION_TAG_PLACEHOLDER_' . $counter;
157 $this->personalization_tag_placeholders[ $placeholder ] = $matches[0];
158 ++$counter;
159 return $placeholder;
160 }
161 return $matches[0];
162 },
163 $template
164 );
165 return $template ?? '';
166 }
167 private function restore_personalization_tags( string $text ): string {
168 if ( empty( $this->personalization_tag_placeholders ) ) {
169 return $text;
170 }
171 foreach ( $this->personalization_tag_placeholders as $placeholder => $html_comment ) {
172 $text = str_replace( $placeholder, $html_comment, $text );
173 }
174 return $text;
175 }
176 }
177