Skip to content

Commit 51dc258

Browse files
lysyjanwoocommercebot
authored andcommitted
Mirror package @woocommerce/email-editor-config from WooCommerce
Upstream-Ref: woocommerce/woocommerce@62f844a
1 parent 818f48f commit 51dc258

File tree

6 files changed

+306
-17
lines changed

6 files changed

+306
-17
lines changed

changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
44

5+
## [1.4.1](https://github.com/woocommerce/email-editor/releases/tag/1.4.1) - 2025-08-08
6+
7+
- Patch - Introduce new class Assets_Manager to simplify integration. [#60165]
8+
59
## [1.4.0](https://github.com/woocommerce/email-editor/releases/tag/1.4.0) - 2025-07-31
610

711
- Minor - Enable Site Logo and Site Title blocks for the Email Editor [#59624]

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"license": "GPL-2.0-or-later",
66
"prefer-stable": true,
77
"minimum-stability": "dev",
8-
"version": "1.4.0",
8+
"version": "1.4.1",
99
"autoload": {
1010
"classmap": [
1111
"src/"

src/Engine/Renderer/class-renderer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ private function render_text_version( $template ) {
172172
// Preserve personalization tags by temporarily replacing them with unique placeholders.
173173
$template = $this->preserve_personalization_tags( $template );
174174

175-
$result = Html2Text::convert( (string) $template );
175+
$result = Html2Text::convert( (string) $template, array( 'ignore_errors' => true ) );
176176
if ( ! $result ) {
177177
return '';
178178
}

src/Engine/class-assets-manager.php

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
<?php
2+
/**
3+
* This file is part of the WooCommerce Email Editor package
4+
*
5+
* @package Automattic\WooCommerce\EmailEditor
6+
*/
7+
8+
declare(strict_types=1);
9+
namespace Automattic\WooCommerce\EmailEditor\Engine;
10+
11+
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger;
12+
13+
/**
14+
* Class responsible for managing email editor assets.
15+
*/
16+
class Assets_Manager {
17+
/**
18+
* Settings controller instance.
19+
*
20+
* @var Settings_Controller
21+
*/
22+
private Settings_Controller $settings_controller;
23+
24+
/**
25+
* Theme controller instance.
26+
*
27+
* @var Theme_Controller
28+
*/
29+
private Theme_Controller $theme_controller;
30+
31+
/**
32+
* User theme instance.
33+
*
34+
* @var User_Theme
35+
*/
36+
private User_Theme $user_theme;
37+
38+
/**
39+
* Email editor assets path.
40+
*
41+
* @var string
42+
*/
43+
private string $assets_path = '';
44+
45+
/**
46+
* Email editor assets URL.
47+
*
48+
* @var string
49+
*/
50+
private string $assets_url = '';
51+
52+
/**
53+
* Logger instance.
54+
*
55+
* @var Email_Editor_Logger
56+
*/
57+
private Email_Editor_Logger $logger;
58+
59+
/**
60+
* Assets Manager constructor with all dependencies.
61+
*
62+
* @param Settings_Controller $settings_controller Settings controller instance.
63+
* @param Theme_Controller $theme_controller Theme controller instance.
64+
* @param User_Theme $user_theme User theme instance.
65+
* @param Email_Editor_Logger $logger Email editor logger instance.
66+
*/
67+
public function __construct(
68+
Settings_Controller $settings_controller,
69+
Theme_Controller $theme_controller,
70+
User_Theme $user_theme,
71+
Email_Editor_Logger $logger
72+
) {
73+
$this->settings_controller = $settings_controller;
74+
$this->theme_controller = $theme_controller;
75+
$this->user_theme = $user_theme;
76+
$this->logger = $logger;
77+
}
78+
79+
/**
80+
* Sets the path for the email editor assets.
81+
*
82+
* @param string $assets_path The path to the email editor assets directory.
83+
* @return void
84+
*/
85+
public function set_assets_path( string $assets_path ): void {
86+
$this->assets_path = $assets_path;
87+
}
88+
89+
/**
90+
* Sets the URL for the email editor assets.
91+
*
92+
* @param string $assets_url The URL to the email editor assets directory.
93+
* @return void
94+
*/
95+
public function set_assets_url( string $assets_url ): void {
96+
$this->assets_url = $assets_url;
97+
}
98+
99+
/**
100+
* Initialize the assets manager.
101+
*/
102+
public function initialize(): void {
103+
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) );
104+
}
105+
106+
/**
107+
* Enqueue admin styles that are needed by the email editor.
108+
*/
109+
public function enqueue_admin_styles(): void {
110+
// Calling action that loads registered blockTypes.
111+
do_action( 'enqueue_block_editor_assets' );
112+
113+
// Load CSS from Post Editor.
114+
wp_enqueue_style( 'wp-edit-post' );
115+
// Load CSS for the format library - used for example in popover.
116+
wp_enqueue_style( 'wp-format-library' );
117+
// Enqueue CSS containing --wp--preset variables.
118+
wp_enqueue_global_styles_css_custom_properties();
119+
120+
// Enqueue media library scripts.
121+
wp_enqueue_media();
122+
}
123+
124+
/**
125+
* Render the email editor's required HTML and admin header.
126+
*
127+
* @param string $element_id Optional. The ID of the main container element. Default is 'woocommerce-email-editor'.
128+
*/
129+
public function render_email_editor_html( string $element_id = 'woocommerce-email-editor' ): void {
130+
// @phpstan-ignore-next-line -- PHPStan tried to check if the file exists.
131+
require_once ABSPATH . 'wp-admin/admin-header.php';
132+
echo '<div id="' . esc_attr( $element_id ) . '" class="block-editor block-editor__container hide-if-no-js"></div>';
133+
}
134+
135+
/**
136+
* Load editor assets.
137+
*
138+
* @param \WP_Post|\WP_Block_Template $edited_item The edited post or template.
139+
* @param string $script_name The name of the registered script.
140+
*/
141+
public function load_editor_assets( $edited_item, string $script_name ): void {
142+
$post_type = $edited_item instanceof \WP_Post ? $edited_item->post_type : 'wp_template';
143+
$post_id = $edited_item instanceof \WP_Post ? $edited_item->ID : $edited_item->id;
144+
145+
$email_editor_assets_path = rtrim( $this->assets_path, '/' ) . '/';
146+
$email_editor_assets_url = rtrim( $this->assets_url, '/' ) . '/';
147+
148+
// Email editor rich text JS - Because the Personalization Tags depend on Gutenberg 19.8.0 and higher
149+
// the following code replaces used Rich Text for the version containing the necessary changes.
150+
$rich_text_assets_file = $email_editor_assets_path . 'assets/rich-text.asset.php';
151+
if ( ! file_exists( $rich_text_assets_file ) ) {
152+
$this->logger->error( 'Rich Text assets file does not exist.', array( 'path' => $rich_text_assets_file ) );
153+
} else {
154+
$rich_text_assets = require $rich_text_assets_file;
155+
wp_deregister_script( 'wp-rich-text' );
156+
wp_enqueue_script(
157+
'wp-rich-text',
158+
$email_editor_assets_url . 'assets/rich-text.js',
159+
$rich_text_assets['dependencies'],
160+
$rich_text_assets['version'],
161+
true
162+
);
163+
}
164+
// End of replacing Rich Text package.
165+
166+
$assets_file = $email_editor_assets_path . 'style.asset.php';
167+
if ( ! file_exists( $assets_file ) ) {
168+
$this->logger->error( 'Email editor assets file does not exist.', array( 'path' => $assets_file ) );
169+
} else {
170+
$assets_file = require $assets_file;
171+
wp_enqueue_style(
172+
'wc-admin-email-editor-integration',
173+
$email_editor_assets_url . 'style.css',
174+
array(),
175+
$assets_file['version']
176+
);
177+
}
178+
179+
// The get_block_categories() function expects a WP_Post or WP_Block_Editor_Context object.
180+
// Therefore, we need to create an instance of WP_Block_Editor_Context when $edited_item is an instance of WP_Block_Template.
181+
if ( $edited_item instanceof \WP_Block_Template ) {
182+
$context = new \WP_Block_Editor_Context(
183+
array(
184+
'post' => $edited_item,
185+
)
186+
);
187+
} else {
188+
$context = $edited_item;
189+
}
190+
// The email editor needs to load block categories to avoid warning and missing category names.
191+
// See: https://github.com/WordPress/WordPress/blob/753817d462955eb4e40a89034b7b7c375a1e43f3/wp-admin/edit-form-blocks.php#L116-L120.
192+
wp_add_inline_script(
193+
'wp-blocks',
194+
sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( get_block_categories( $context ) ) ),
195+
'after'
196+
);
197+
198+
// Preload server-registered block schemas to avoid warning about missing block titles.
199+
// See: https://github.com/WordPress/WordPress/blob/753817d462955eb4e40a89034b7b7c375a1e43f3/wp-admin/edit-form-blocks.php#L144C1-L148C3.
200+
wp_add_inline_script(
201+
'wp-blocks',
202+
sprintf( 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions( %s );', wp_json_encode( get_block_editor_server_block_settings() ) )
203+
);
204+
205+
$localization_data = array(
206+
'current_post_type' => $post_type,
207+
'current_post_id' => $post_id,
208+
'current_wp_user_email' => wp_get_current_user()->user_email,
209+
'editor_settings' => $this->settings_controller->get_settings(),
210+
'editor_theme' => $this->theme_controller->get_base_theme()->get_raw_data(),
211+
'user_theme_post_id' => $this->user_theme->get_user_theme_post()->ID,
212+
'urls' => array(
213+
'listings' => admin_url( 'admin.php?page=wc-settings&tab=email' ),
214+
'send' => admin_url( 'admin.php?page=wc-settings&tab=email' ),
215+
'back' => admin_url( 'admin.php?page=wc-settings&tab=email' ),
216+
),
217+
'block_preview_url' => esc_url( wp_nonce_url( admin_url( '?preview_woocommerce_mail_editor_content=true' ), 'preview-mail' ) ),
218+
);
219+
220+
wp_localize_script(
221+
$script_name,
222+
'WooCommerceEmailEditor',
223+
apply_filters( 'woocommerce_email_editor_script_localization_data', $localization_data )
224+
);
225+
226+
$this->preload_rest_api_data( $post_id, $post_type );
227+
}
228+
229+
/**
230+
* Preload REST API data for the email editor.
231+
*
232+
* @param int|string $post_id The post ID.
233+
* @param string $post_type The post type.
234+
*/
235+
private function preload_rest_api_data( $post_id, string $post_type ): void {
236+
$email_post_type = $post_type;
237+
$user_theme_post_id = $this->user_theme->get_user_theme_post()->ID;
238+
$template_slug = get_post_meta( (int) $post_id, '_wp_page_template', true );
239+
$routes = array(
240+
"/wp/v2/{$email_post_type}/" . intval( $post_id ) . '?context=edit',
241+
"/wp/v2/types/{$email_post_type}?context=edit",
242+
'/wp/v2/global-styles/' . intval( $user_theme_post_id ) . '?context=view', // Global email styles.
243+
'/wp/v2/block-patterns/patterns',
244+
'/wp/v2/templates?context=view',
245+
'/wp/v2/block-patterns/categories',
246+
'/wp/v2/settings',
247+
'/wp/v2/types?context=view',
248+
'/wp/v2/taxonomies?context=view',
249+
);
250+
251+
if ( is_string( $template_slug ) ) {
252+
$routes[] = '/wp/v2/templates/lookup?slug=' . $template_slug;
253+
} else {
254+
$routes[] = "/wp/v2/{$email_post_type}?context=edit&per_page=30&status=publish,sent";
255+
}
256+
257+
// Preload the data for the specified routes.
258+
$preload_data = array_reduce(
259+
$routes,
260+
'rest_preload_api_request',
261+
array()
262+
);
263+
264+
// Add inline script to set up preloading middleware.
265+
wp_add_inline_script(
266+
'wp-blocks',
267+
sprintf(
268+
'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );',
269+
wp_json_encode( $preload_data )
270+
)
271+
);
272+
}
273+
}

src/Engine/class-email-editor.php

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,24 @@ class Email_Editor {
4848
* @var Send_Preview_Email Send Preview controller.
4949
*/
5050
private Send_Preview_Email $send_preview_email;
51-
5251
/**
5352
* Property for Personalization_Tags_Controller that allows initializing personalization tags.
5453
*
5554
* @var Personalization_Tags_Registry Personalization tags registry.
5655
*/
5756
private Personalization_Tags_Registry $personalization_tags_registry;
58-
5957
/**
6058
* Property for the logger.
6159
*
6260
* @var Email_Editor_Logger Logger instance.
6361
*/
6462
private Email_Editor_Logger $logger;
63+
/**
64+
* Property for Assets Manager that should be initialized.
65+
*
66+
* @var Assets_Manager Assets manager instance.
67+
*/
68+
private Assets_Manager $assets_manager;
6569

6670
/**
6771
* Constructor.
@@ -72,21 +76,24 @@ class Email_Editor {
7276
* @param Send_Preview_Email $send_preview_email Preview email controller.
7377
* @param Personalization_Tags_Registry $personalization_tags_controller Personalization tags registry that allows initializing personalization tags.
7478
* @param Email_Editor_Logger $logger Logger instance.
79+
* @param Assets_Manager $assets_manager Assets manager instance.
7580
*/
7681
public function __construct(
7782
Email_Api_Controller $email_api_controller,
7883
Templates $templates,
7984
Patterns $patterns,
8085
Send_Preview_Email $send_preview_email,
8186
Personalization_Tags_Registry $personalization_tags_controller,
82-
Email_Editor_Logger $logger
87+
Email_Editor_Logger $logger,
88+
Assets_Manager $assets_manager
8389
) {
8490
$this->email_api_controller = $email_api_controller;
8591
$this->templates = $templates;
8692
$this->patterns = $patterns;
8793
$this->send_preview_email = $send_preview_email;
8894
$this->personalization_tags_registry = $personalization_tags_controller;
8995
$this->logger = $logger;
96+
$this->assets_manager = $assets_manager;
9097
}
9198

9299
/**
@@ -98,7 +105,9 @@ public function initialize(): void {
98105
$this->logger->info( 'Initializing email editor' );
99106
do_action( 'woocommerce_email_editor_initialized' );
100107
add_filter( 'woocommerce_email_editor_rendering_theme_styles', array( $this, 'extend_email_theme_styles' ), 10, 2 );
101-
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) );
108+
// Initialize the assets manager.
109+
$this->assets_manager->initialize();
110+
102111
$this->register_block_patterns();
103112
$this->register_email_post_types();
104113
$this->register_block_templates();
@@ -287,16 +296,6 @@ public function extend_email_theme_styles( WP_Theme_JSON $theme, WP_Post $post )
287296
return $theme;
288297
}
289298

290-
/**
291-
* Enqueue admin styles that are needed by the email editor.
292-
*
293-
* @return void
294-
*/
295-
public function enqueue_admin_styles(): void {
296-
// Calling action that loads registered blockTypes.
297-
do_action( 'enqueue_block_editor_assets' );
298-
}
299-
300299
/**
301300
* Get the current post object
302301
*

0 commit comments

Comments
 (0)