PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.4
WooCommerce v10.9.4
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / admin / settings / class-wc-settings-emails.php
woocommerce / includes / admin / settings Last commit date
views 1 month ago class-wc-settings-accounts.php 5 months ago class-wc-settings-advanced.php 1 month ago class-wc-settings-checkout.php 5 years ago class-wc-settings-emails.php 1 month ago class-wc-settings-general.php 1 month ago class-wc-settings-integrations.php 1 year ago class-wc-settings-page.php 1 week ago class-wc-settings-payment-gateways.php 1 week ago class-wc-settings-point-of-sale.php 3 months ago class-wc-settings-products.php 1 month ago class-wc-settings-shipping.php 3 months ago class-wc-settings-site-visibility.php 2 years ago class-wc-settings-tax.php 5 months ago
class-wc-settings-emails.php
1055 lines
1 <?php
2 /**
3 * WooCommerce Email Settings
4 *
5 * @package WooCommerce\Admin
6 * @version 2.1.0
7 */
8
9 use Automattic\WooCommerce\Internal\Admin\EmailPreview\EmailPreview;
10 use Automattic\WooCommerce\Internal\Email\EmailColors;
11 use Automattic\WooCommerce\Internal\Email\EmailFont;
12 use Automattic\WooCommerce\Internal\Email\EmailStyleSync;
13 use Automattic\WooCommerce\Internal\EmailEditor\EmailTemplates\WooEmailTemplate;
14 use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsManager;
15 use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateDivergenceDetector;
16 use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateSyncRegistry;
17 use Automattic\WooCommerce\Internal\Features\FeaturesController;
18 use Automattic\WooCommerce\Utilities\FeaturesUtil;
19
20 defined( 'ABSPATH' ) || exit;
21
22 if ( class_exists( 'WC_Settings_Emails', false ) ) {
23 return new WC_Settings_Emails();
24 }
25
26 /**
27 * WC_Settings_Emails.
28 */
29 class WC_Settings_Emails extends WC_Settings_Page {
30
31 /**
32 * Constructor.
33 */
34 public function __construct() {
35 $this->id = 'email';
36 $this->label = __( 'Emails', 'woocommerce' );
37
38 add_action( 'woocommerce_admin_field_email_notification', array( $this, 'email_notification_setting' ) );
39 add_action( 'woocommerce_admin_field_email_notification_block_emails', array( $this, 'email_notification_setting_block_emails' ) );
40 add_action( 'woocommerce_admin_field_email_preview', array( $this, 'email_preview' ) );
41 add_action( 'woocommerce_admin_field_email_image_url', array( $this, 'email_image_url' ) );
42 add_action( 'woocommerce_admin_field_email_font_family', array( $this, 'email_font_family' ) );
43 add_action( 'woocommerce_admin_field_email_color_palette', array( $this, 'email_color_palette' ) );
44 add_action( 'woocommerce_admin_field_previewing_new_templates', array( $this, 'previewing_new_templates' ) );
45 add_action( 'woocommerce_admin_field_email_improvements_button', array( $this, 'email_improvements_button' ) );
46 add_action( 'woocommerce_email_settings_after', array( $this, 'email_preview_single' ) );
47 add_action( 'woocommerce_settings_saved', array( $this, 'enable_email_improvements_when_trying_new_templates' ), 999 );
48 add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_email_header_image', array( $this, 'sanitize_email_header_image' ), 10, 3 );
49 add_filter( 'woocommerce_tracks_event_properties', array( $this, 'append_feature_email_improvements_to_tracks' ) );
50 add_action( FeaturesController::FEATURE_ENABLED_CHANGED_ACTION, array( $this, 'track_email_improvements_feature_change' ), 10, 2 );
51 parent::__construct();
52 }
53
54 /**
55 * Setting page icon.
56 *
57 * @var string
58 */
59 public $icon = 'atSymbol';
60
61 /**
62 * Get own sections.
63 *
64 * @return array
65 */
66 protected function get_own_sections() {
67 return array(
68 '' => __( 'Email options', 'woocommerce' ),
69 );
70 }
71
72 /**
73 * Get settings array.
74 *
75 * @return array
76 */
77 protected function get_settings_for_default_section() {
78 $desc_help_text = sprintf(
79 /* translators: %1$s: Link to WP Mail Logging plugin, %2$s: Link to Email FAQ support page. */
80 __( 'To ensure your store&rsquo;s notifications arrive in your and your customers&rsquo; inboxes, we recommend connecting your email address to your domain and setting up a dedicated SMTP server. If something doesn&rsquo;t seem to be sending correctly, install the <a href="%1$s">WP Mail Logging Plugin</a> or check the <a href="%2$s">Email FAQ page</a>.', 'woocommerce' ),
81 'https://wordpress.org/plugins/wp-mail-logging/',
82 'https://woocommerce.com/document/email-faq'
83 );
84
85 $block_email_editor_enabled = FeaturesUtil::feature_is_enabled( 'block_email_editor' );
86 $email_improvements_enabled = $this->get_email_improvements_enabled();
87
88 // These defaults should be chosen by the same logic as the other color option properties.
89 $default_colors = EmailColors::get_default_colors( $email_improvements_enabled );
90
91 if ( $block_email_editor_enabled ) {
92 $email_notifications_field = 'email_notification_block_emails';
93 $email_notifications_desc = null;
94 } else {
95 $email_notifications_field = 'email_notification';
96 /* translators: %s: help description with link to WP Mail logging and support page. */
97 $email_notifications_desc = sprintf( __( 'Email notifications sent from WooCommerce are listed below. Click on an email to configure it.<br>%s', 'woocommerce' ), $desc_help_text );
98 }
99
100 $settings =
101 array(
102 array(
103 'title' => __( 'Email notifications', 'woocommerce' ),
104 'desc' => $email_notifications_desc,
105 'type' => 'title',
106 'id' => 'email_notification_settings',
107 ),
108
109 array( 'type' => $email_notifications_field ),
110
111 array(
112 'type' => 'sectionend',
113 'id' => 'email_notification_settings',
114 ),
115
116 array(
117 'type' => 'sectionend',
118 'id' => 'email_recipient_options',
119 ),
120 array(
121 'title' => __( 'Email sender options', 'woocommerce' ),
122 'type' => 'title',
123 'desc' => __( "Set the name and email address you'd like your outgoing emails to use.", 'woocommerce' ),
124 'id' => 'email_options',
125 ),
126
127 array(
128 'title' => __( '"From" name', 'woocommerce' ),
129 'desc' => '',
130 'id' => 'woocommerce_email_from_name',
131 'type' => 'text',
132 'css' => 'min-width:400px;',
133 'default' => esc_attr( get_bloginfo( 'name', 'display' ) ),
134 'autoload' => false,
135 'desc_tip' => true,
136 'skip_initial_save' => true,
137 ),
138
139 array(
140 'title' => __( '"From" address', 'woocommerce' ),
141 'desc' => '',
142 'id' => 'woocommerce_email_from_address',
143 'type' => 'email',
144 'custom_attributes' => array(
145 'multiple' => 'multiple',
146 ),
147 'css' => 'min-width:400px;',
148 'default' => get_option( 'admin_email' ),
149 'autoload' => false,
150 'desc_tip' => true,
151 ),
152 );
153
154 // Add reply-to fields when block email editor is enabled.
155 if ( $block_email_editor_enabled ) {
156 $settings = array_merge(
157 $settings,
158 array(
159 array(
160 'title' => __( 'Add "Reply-to" email', 'woocommerce' ),
161 'desc' => __( 'Add a different email address to receive replies.', 'woocommerce' ),
162 'id' => 'woocommerce_email_reply_to_enabled',
163 'type' => 'checkbox',
164 'default' => 'no',
165 'autoload' => false,
166 ),
167
168 array(
169 'title' => __( '"Reply-to" name', 'woocommerce' ),
170 'desc' => '',
171 'id' => 'woocommerce_email_reply_to_name',
172 'type' => 'text',
173 'css' => 'min-width:400px;',
174 'default' => '',
175 'autoload' => false,
176 'desc_tip' => true,
177 ),
178
179 array(
180 'title' => __( '"Reply-to" address', 'woocommerce' ),
181 'desc' => '',
182 'id' => 'woocommerce_email_reply_to_address',
183 'type' => 'email',
184 'css' => 'min-width:400px;',
185 'default' => '',
186 'autoload' => false,
187 'desc_tip' => true,
188 ),
189 )
190 );
191 }
192
193 $settings = array_merge(
194 $settings,
195 array(
196 array(
197 'type' => 'sectionend',
198 'id' => 'email_options',
199 ),
200 )
201 );
202
203 // If the email editor is enabled the design is handled by the email editor.
204 if ( ! $block_email_editor_enabled ) {
205 $settings = array_merge(
206 $settings,
207 array(
208 array(
209 'title' => __( 'Email template', 'woocommerce' ),
210 'type' => 'title',
211 'desc' => __( 'Customize your WooCommerce email template and preview it below.', 'woocommerce' ),
212 'id' => 'email_template_options',
213 ),
214
215 array(
216 'title' => __( 'Try new templates', 'woocommerce' ),
217 'type' => 'previewing_new_templates',
218 'id' => 'previewing_new_templates',
219 ),
220
221 array(
222 'title' => __( 'Logo', 'woocommerce' ),
223 'desc' => __( 'Add your logo to each of your WooCommerce emails. If no logo is uploaded, your site title will be used instead.', 'woocommerce' ),
224 'id' => 'woocommerce_email_header_image',
225 'type' => 'email_image_url',
226 'css' => 'min-width:400px;',
227 'placeholder' => __( 'N/A', 'woocommerce' ),
228 'default' => '',
229 'autoload' => false,
230 'desc_tip' => true,
231 ),
232
233 array(
234 'title' => __( 'Logo width (px)', 'woocommerce' ),
235 'id' => 'woocommerce_email_header_image_width',
236 'desc_tip' => '',
237 'default' => '120',
238 'type' => 'number',
239 'row_class' => $email_improvements_enabled ? '' : 'disabled',
240 ),
241
242 array(
243 'title' => __( 'Header alignment', 'woocommerce' ),
244 'id' => 'woocommerce_email_header_alignment',
245 'desc_tip' => '',
246 'default' => 'left',
247 'type' => 'select',
248 'class' => 'wc-enhanced-select',
249 'options' => array(
250 'left' => __( 'Left', 'woocommerce' ),
251 'center' => __( 'Center', 'woocommerce' ),
252 'right' => __( 'Right', 'woocommerce' ),
253 ),
254 'row_class' => $email_improvements_enabled ? '' : 'disabled',
255 ),
256
257 array(
258 'title' => __( 'Font family', 'woocommerce' ),
259 'id' => 'woocommerce_email_font_family',
260 'default' => 'Helvetica',
261 'type' => 'email_font_family',
262 'row_class' => $email_improvements_enabled ? '' : 'disabled',
263 ),
264
265 array(
266 'title' => __( 'Footer text', 'woocommerce' ),
267 /* translators: %s: Available placeholders for use */
268 'desc' => __( 'This text will appear in the footer of all of your WooCommerce emails.', 'woocommerce' ) . ' ' . sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '{site_title} {site_url} {store_address} {store_email}' ),
269 'id' => 'woocommerce_email_footer_text',
270 'css' => 'width:400px; height: 75px;',
271 'placeholder' => __( 'N/A', 'woocommerce' ),
272 'type' => 'textarea',
273 'default' => '{site_title}<br />{store_address}',
274 'autoload' => false,
275 'desc_tip' => true,
276 ),
277
278 array(
279 'type' => 'sectionend',
280 'id' => 'email_template_options',
281 ),
282
283 array(
284 'title' => __( 'Color palette', 'woocommerce' ),
285 'type' => 'email_color_palette',
286 'id' => 'email_color_palette',
287 ),
288
289 array(
290 'title' => __( 'Accent', 'woocommerce' ),
291 /* translators: %s: default color */
292 'desc' => sprintf( __( 'Customize the color of your buttons and links. Default %s.', 'woocommerce' ), '<code>' . $default_colors['base'] . '</code>' ),
293 'id' => 'woocommerce_email_base_color',
294 'type' => 'color',
295 'css' => 'width:6em;',
296 'default' => $default_colors['base'],
297 'autoload' => false,
298 'desc_tip' => true,
299 ),
300
301 array(
302 'title' => __( 'Email background', 'woocommerce' ),
303 /* translators: %s: default color */
304 'desc' => sprintf( __( 'Select a color for the background of your emails. Default %s.', 'woocommerce' ), '<code>' . $default_colors['bg'] . '</code>' ),
305 'id' => 'woocommerce_email_background_color',
306 'type' => 'color',
307 'css' => 'width:6em;',
308 'default' => $default_colors['bg'],
309 'autoload' => false,
310 'desc_tip' => true,
311 ),
312
313 array(
314 'title' => __( 'Content background', 'woocommerce' ),
315 /* translators: %s: default color */
316 'desc' => sprintf( __( 'Choose a background color for the content area of your emails. Default %s.', 'woocommerce' ), '<code>' . $default_colors['body_bg'] . '</code>' ),
317 'id' => 'woocommerce_email_body_background_color',
318 'type' => 'color',
319 'css' => 'width:6em;',
320 'default' => $default_colors['body_bg'],
321 'autoload' => false,
322 'desc_tip' => true,
323 ),
324
325 array(
326 'title' => __( 'Heading & text', 'woocommerce' ),
327 /* translators: %s: default color */
328 'desc' => sprintf( __( 'Set the color of your headings and text. Default %s.', 'woocommerce' ), '<code>' . $default_colors['body_text'] . '</code>' ),
329 'id' => 'woocommerce_email_text_color',
330 'type' => 'color',
331 'css' => 'width:6em;',
332 'default' => $default_colors['body_text'],
333 'autoload' => false,
334 'desc_tip' => true,
335 ),
336
337 array(
338 'title' => __( 'Secondary text', 'woocommerce' ),
339 /* translators: %s: footer default color */
340 'desc' => sprintf( __( 'Choose a color for your secondary text, such as your footer content. Default %s.', 'woocommerce' ), '<code>' . $default_colors['footer_text'] . '</code>' ),
341 'id' => 'woocommerce_email_footer_text_color',
342 'type' => 'color',
343 'css' => 'width:6em;',
344 'default' => $default_colors['footer_text'],
345 'autoload' => false,
346 'desc_tip' => true,
347 ),
348
349 array(
350 'title' => __( 'Auto-sync with theme', 'woocommerce' ),
351 'desc' => __( 'Automatically update email styles when theme styles change', 'woocommerce' ),
352 'id' => 'woocommerce_email_auto_sync_with_theme',
353 'type' => 'hidden',
354 'default' => 'no',
355 'autoload' => false,
356 ),
357
358 array(
359 'type' => 'sectionend',
360 'id' => 'email_color_palette',
361 ),
362
363 array(
364 'title' => __( 'Email improvements button', 'woocommerce' ),
365 'type' => 'email_improvements_button',
366 'id' => 'email_improvements_button',
367 ),
368
369 array( 'type' => 'email_preview' ),
370 )
371 );
372 }
373
374 // Remove empty elements that depend on the email_improvements feature flag.
375 $settings = array_filter( $settings );
376
377 /**
378 * Filters the email settings array.
379 *
380 * @since 2.1.0
381 *
382 * @param array $settings Array of email settings.
383 */
384 return apply_filters( 'woocommerce_email_settings', $settings );
385 }
386
387 /**
388 * Get custom fonts for emails.
389 */
390 public function get_custom_fonts() {
391 $custom_fonts = array();
392 if ( wp_is_block_theme() && class_exists( 'WP_Font_Face_Resolver' ) ) {
393 $theme_fonts = WP_Font_Face_Resolver::get_fonts_from_theme_json();
394 if ( count( $theme_fonts ) > 0 ) {
395 foreach ( $theme_fonts as $font ) {
396 if ( ! empty( $font[0]['font-family'] ) ) {
397 $custom_fonts[ $font[0]['font-family'] ] = $font[0]['font-family'];
398 }
399 }
400 }
401 }
402 ksort( $custom_fonts );
403
404 return $custom_fonts;
405 }
406
407 /**
408 * Output the settings.
409 */
410 public function output() {
411 global $current_section;
412
413 // Define emails that can be customised here.
414 $mailer = WC()->mailer();
415 $email_templates = $mailer->get_emails();
416
417 if ( $current_section ) {
418 foreach ( $email_templates as $email_key => $email ) {
419 if ( strtolower( $email_key ) === $current_section ) {
420 $this->run_email_admin_options( $email );
421 break;
422 }
423 }
424 }
425
426 parent::output();
427 }
428
429 /**
430 * Run the 'admin_options' method on a given email.
431 * This method exists to easy unit testing.
432 *
433 * @param object $email The email object to run the method on.
434 */
435 protected function run_email_admin_options( $email ) {
436 $email->admin_options();
437 }
438
439 /**
440 * Save settings.
441 */
442 public function save() {
443 global $current_section;
444
445 if ( ! $current_section ) {
446 $this->save_settings_for_current_section();
447 $this->do_update_options_action();
448 } else {
449 $wc_emails = WC_Emails::instance();
450
451 if ( in_array( $current_section, array_map( 'sanitize_title', array_keys( $wc_emails->get_emails() ) ), true ) ) {
452 foreach ( $wc_emails->get_emails() as $email_id => $email ) {
453 if ( sanitize_title( $email_id ) === $current_section ) {
454 $this->do_update_options_action( $email->id );
455 }
456 }
457 } else {
458 $this->save_settings_for_current_section();
459 $this->do_update_options_action();
460 }
461 }
462 }
463
464 /**
465 * Output email notification settings.
466 */
467 public function email_notification_setting() {
468 // Define emails that can be customised here.
469 $mailer = WC()->mailer();
470 $email_templates = $mailer->get_emails();
471
472 ?>
473 <tr valign="top">
474 <td class="wc_emails_wrapper" colspan="2">
475 <table class="wc_emails widefat" cellspacing="0">
476 <thead>
477 <tr>
478 <?php
479 /**
480 * Filters the columns displayed in the email settings table.
481 *
482 * @since 2.1.0
483 *
484 * @param array $columns Array of column keys and labels.
485 */
486 $columns = apply_filters(
487 'woocommerce_email_setting_columns',
488 array(
489 'status' => '',
490 'name' => __( 'Email', 'woocommerce' ),
491 'email_type' => __( 'Content type', 'woocommerce' ),
492 'recipient' => __( 'Recipient(s)', 'woocommerce' ),
493 'actions' => '',
494 )
495 );
496 foreach ( $columns as $key => $column ) {
497 echo '<th class="wc-email-settings-table-' . esc_attr( $key ) . '">' . esc_html( $column ) . '</th>';
498 }
499 ?>
500 </tr>
501 </thead>
502 <tbody>
503 <?php
504 foreach ( $email_templates as $email_key => $email ) {
505 echo '<tr>';
506
507 foreach ( $columns as $key => $column ) {
508
509 switch ( $key ) {
510 case 'name':
511 echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">
512 <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=email&section=' . strtolower( $email_key ) ) ) . '">' . esc_html( $email->get_title() ) . '</a>
513 ' . wc_help_tip( $email->get_description() ) . '
514 </td>';
515 break;
516 case 'recipient':
517 $to = $email->is_customer_email() ? __( 'Customer', 'woocommerce' ) : $email->get_recipient();
518 $cc = false;
519 $bcc = false;
520 if ( FeaturesUtil::feature_is_enabled( 'email_improvements' ) ) {
521 $ccs = $email->get_cc_recipient();
522 $bccs = $email->get_bcc_recipient();
523 // Translators: %s: comma-separated email addresses to which the email is cc-ed.
524 $cc = $ccs ? sprintf( __( '<b>Cc</b>: %s', 'woocommerce' ), $ccs ) : false;
525 // Translators: %s: comma-separated email addresses to which the email is bcc-ed.
526 $bcc = $bccs ? sprintf( __( '<b>Bcc</b>: %s', 'woocommerce' ), $bccs ) : false;
527 if ( $cc || $bcc ) {
528 // Translators: %s: comma-separated email addresses to which the email is sent.
529 $to = sprintf( __( '<b>To</b>: %s', 'woocommerce' ), $to );
530 }
531 }
532 $allowed_tags = array( 'b' => array() );
533
534 echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">';
535 echo wp_kses( $to, $allowed_tags );
536 if ( $cc ) {
537 echo '<br>' . wp_kses( $cc, $allowed_tags );
538 }
539 if ( $bcc ) {
540 echo '<br>' . wp_kses( $bcc, $allowed_tags );
541 }
542 echo '</td>';
543 break;
544 case 'status':
545 echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">';
546
547 if ( $email->is_manual() ) {
548 echo '<span class="status-manual tips" data-tip="' . esc_attr__( 'Manually sent', 'woocommerce' ) . '">' . esc_html__( 'Manual', 'woocommerce' ) . '</span>';
549 } elseif ( $email->is_enabled() ) {
550 echo '<span class="status-enabled tips" data-tip="' . esc_attr__( 'Enabled', 'woocommerce' ) . '">' . esc_html__( 'Yes', 'woocommerce' ) . '</span>';
551 } else {
552 echo '<span class="status-disabled tips" data-tip="' . esc_attr__( 'Disabled', 'woocommerce' ) . '">-</span>';
553 }
554
555 echo '</td>';
556 break;
557 case 'email_type':
558 echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">
559 ' . esc_html( $email->get_content_type() ) . '
560 </td>';
561 break;
562 case 'actions':
563 echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">
564 <a class="button alignright" href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=email&section=' . strtolower( $email_key ) ) ) . '">' . esc_html__( 'Manage', 'woocommerce' ) . '</a>
565 </td>';
566 break;
567 default:
568 /**
569 * Fires when rendering a custom column in the email settings table.
570 *
571 * @since 2.1.0
572 *
573 * @param WC_Email $email The email object.
574 */
575 do_action( 'woocommerce_email_setting_column_' . $key, $email );
576 break;
577 }
578 }
579
580 echo '</tr>';
581 }
582 ?>
583 </tbody>
584 </table>
585 </td>
586 </tr>
587 <?php
588 }
589
590 /**
591 * Creates the React mount point for listing of block based emails.
592 */
593 public function email_notification_setting_block_emails() {
594 $desc_help_text = sprintf(
595 /* translators: %1$s: Link to WP Mail Logging plugin, %2$s: Link to Email FAQ support page. */
596 __( 'To ensure your store&rsquo;s notifications arrive in your and your customers&rsquo; inboxes, we recommend connecting your email address to your domain and setting up a dedicated SMTP server. If something doesn&rsquo;t seem to be sending correctly, install the <a href="%1$s">WP Mail Logging Plugin</a> or check the <a href="%2$s">Email FAQ page</a>.', 'woocommerce' ),
597 'https://wordpress.org/plugins/wp-mail-logging/',
598 'https://woocommerce.com/document/email-faq'
599 );
600 $email_post_manager = WCTransactionalEmailPostsManager::get_instance();
601 $emails = WC()->mailer()->get_emails();
602 $email_types = array();
603 $post_id_for_template = null;
604 foreach ( $emails as $email_key => $email ) {
605 $post_id = $email_post_manager->get_email_template_post_id( $email->id );
606 $sync_config = WCEmailTemplateSyncRegistry::get_email_sync_config( $email->id );
607 // `current_version` is the canonical version core ships right now;
608 // the list view's "Review update" cell and RSM-141's editor banner
609 // gate on `merchant_reviewed_version < current_version` so a row
610 // stays customized but stops showing the indicator once the
611 // merchant has reviewed this release.
612 $current_version = is_array( $sync_config ) ? (string) ( $sync_config['version'] ?? '' ) : '';
613
614 // Project the template-sync meta directly onto the slotfill payload
615 // so the RSM-145 `_list_viewed` aggregate event can compute
616 // `eligible_count` immediately on mount without waiting for the
617 // REST enrichment in `useTransactionalEmails` to resolve. REST
618 // enrichment still runs and overrides these values once it lands —
619 // both sources read from the same post meta, so they always agree.
620 $template_status = $post_id ? (string) get_post_meta( $post_id, WCEmailTemplateDivergenceDetector::STATUS_META_KEY, true ) : '';
621 $template_version = $post_id ? (string) get_post_meta( $post_id, WCEmailTemplateDivergenceDetector::VERSION_META_KEY, true ) : '';
622 $was_backfilled = $post_id ? (bool) get_post_meta( $post_id, WCEmailTemplateDivergenceDetector::BACKFILLED_META_KEY, true ) : false;
623
624 $email_types[] = array(
625 'title' => $email->get_title(),
626 'description' => $email->get_description(),
627 'id' => $email->id,
628 'email_key' => strtolower( $email_key ),
629 'post_id' => $post_id,
630 'enabled' => $email->is_enabled(),
631 'manual' => $email->is_manual(),
632 'current_version' => '' !== $current_version ? $current_version : null,
633 'template_status' => '' !== $template_status ? $template_status : null,
634 'template_version' => '' !== $template_version ? $template_version : null,
635 'was_backfilled' => $was_backfilled,
636 'recipients' => array(
637 'to' => $email->is_customer_email() ? __( 'Customers', 'woocommerce' ) : $email->get_recipient(),
638 'cc' => $email->get_cc_recipient(),
639 'bcc' => $email->get_bcc_recipient(),
640 ),
641 );
642
643 // Store the first valid post ID we find.
644 if ( ! $post_id_for_template && $post_id ) {
645 $post_id_for_template = $post_id;
646 }
647 }
648 // Create URL for email editor template mode.
649 $edit_template_url = null;
650 if ( $post_id_for_template ) {
651 $email_template_id = get_stylesheet() . '//' . WooEmailTemplate::TEMPLATE_SLUG;
652 $edit_template_url = admin_url( 'post.php?post=' . $post_id_for_template . '&action=edit&template=' . $email_template_id );
653 }
654
655 ?>
656 <div
657 id="wc_settings_email_listing_slotfill" class="wc-settings-prevent-change-event woocommerce-email-listing-listview"
658 data-email-types="<?php echo esc_attr( wp_json_encode( $email_types ) ); ?>"
659 data-edit-template-url="<?php echo esc_attr( $edit_template_url ); ?>"
660 >
661 <div style="
662 display: flex;
663 align-items: center;
664 justify-content: center;
665 padding: 12px;
666 height: 40px;
667 width: 100%;
668 ">
669 <h3> <?php esc_html_e( 'Loading&hellip;', 'woocommerce' ); ?> </h3>
670 </div>
671 </div>
672 <div>
673 <p><?php echo wp_kses_post( wpautop( wptexturize( $desc_help_text ) ) ); ?></p>
674 </div>
675 <?php
676 }
677
678 /**
679 * Creates the React mount point for the email preview.
680 */
681 public function email_preview() {
682 $this->delete_transient_email_settings();
683 $emails = WC()->mailer()->get_emails();
684 $email_types = array();
685 foreach ( $emails as $email ) {
686 $email_types[] = array(
687 'label' => $email->get_title(),
688 'value' => get_class( $email ),
689 );
690 }
691 ?>
692 <div
693 id="wc_settings_email_preview_slotfill"
694 data-preview-url="<?php echo esc_url( wp_nonce_url( admin_url( '?preview_woocommerce_mail=true' ), 'preview-mail' ) ); ?>"
695 data-email-types="<?php echo esc_attr( wp_json_encode( $email_types ) ); ?>"
696 data-email-setting-ids="<?php echo esc_attr( wp_json_encode( EmailPreview::get_email_style_setting_ids() ) ); ?>"
697 ></div>
698 <?php
699 }
700
701 /**
702 * Creates the React mount point for the single email preview.
703 *
704 * @param object $email The email object to run the method on.
705 */
706 public function email_preview_single( $email ) {
707 $this->delete_transient_email_settings();
708 // Email types array should have a single entry for current email.
709 $email_types = array(
710 array(
711 'label' => $email->get_title(),
712 'value' => get_class( $email ),
713 ),
714 );
715 ?>
716 <h2><?php echo esc_html( __( 'Email preview', 'woocommerce' ) ); ?></h2>
717
718 <p><?php echo esc_html( __( 'Preview your email template. You can also test on different devices and send yourself a test email.', 'woocommerce' ) ); ?></p>
719 <div>
720 <div
721 id="wc_settings_email_preview_slotfill"
722 data-preview-url="<?php echo esc_url( wp_nonce_url( admin_url( '?preview_woocommerce_mail=true' ), 'preview-mail' ) ); ?>"
723 data-email-types="<?php echo esc_attr( wp_json_encode( $email_types ) ); ?>"
724 data-email-setting-ids="<?php echo esc_attr( wp_json_encode( EmailPreview::get_email_content_setting_ids( $email->id ) ) ); ?>"
725 ></div>
726 <input type="hidden" id="woocommerce_email_from_name" value="<?php echo esc_attr( get_option( 'woocommerce_email_from_name' ) ); ?>" />
727 <input type="hidden" id="woocommerce_email_from_address" value="<?php echo esc_attr( get_option( 'woocommerce_email_from_address' ) ); ?>" />
728 </div>
729 <?php
730 }
731
732 /**
733 * Deletes transient with email settings used for live preview. This is to
734 * prevent conflicts where the preview would show values from previous session.
735 */
736 private function delete_transient_email_settings() {
737 $setting_ids = EmailPreview::get_all_email_setting_ids();
738 foreach ( $setting_ids as $id ) {
739 delete_transient( $id );
740 }
741 }
742
743 /**
744 * Creates the React mount point for the email image url.
745 *
746 * @param array $value Field value array.
747 */
748 public function email_image_url( $value ) {
749 $option_value = $value['value'];
750 if ( ! isset( $value['field_name'] ) ) {
751 $value['field_name'] = $value['id'];
752 }
753 ?>
754 <tr class="<?php echo esc_attr( $value['row_class'] ); ?>">
755 <th scope="row" class="titledesc">
756 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo wc_help_tip( $value['desc'] ); // WPCS: XSS ok. ?></label>
757 </th>
758 <td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
759 <input
760 name="<?php echo esc_attr( $value['field_name'] ); ?>"
761 id="<?php echo esc_attr( $value['id'] ); ?>"
762 type="hidden"
763 value="<?php echo esc_attr( $option_value ); ?>"
764 />
765 <div
766 id="wc_settings_email_image_url_slotfill"
767 data-id="<?php echo esc_attr( $value['id'] ); ?>"
768 data-image-url="<?php echo esc_attr( $option_value ); ?>"
769 ></div>
770 </td>
771 </tr>
772 <?php
773 }
774
775 /**
776 * Sanitize email image URL.
777 *
778 * @param string $value Option value.
779 * @param array $option Option name.
780 * @param string $raw_value Raw value.
781 * @return string
782 */
783 public function sanitize_email_header_image( $value, $option, $raw_value ) {
784 return sanitize_url( $raw_value );
785 }
786
787 /**
788 * Creates the email font family field with custom font family applied to each option.
789 *
790 * @param array $value Field value array.
791 */
792 public function email_font_family( $value ) {
793 $option_value = $value['value'];
794 // This is a temporary fix to prevent using custom fonts without fallback.
795 $custom_fonts = null;
796
797 ?>
798 <tr class="<?php echo esc_attr( $value['row_class'] ); ?>">
799 <th scope="row" class="titledesc">
800 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
801 </th>
802 <td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
803 <script type="text/javascript">
804 function renderWithFont( node ) {
805 if ( ! node.element || ! node.element.value ) return node.text;
806 var $wrapper = jQuery( '<span></span>' );
807 $wrapper.css( {'font-family': node.element.dataset['font-family'] || node.element.value} );
808 $wrapper.text( node.text );
809 return $wrapper;
810 }
811 function fontsSelect( selector ) {
812 jQuery( selector ).selectWoo( {
813 minimumResultsForSearch: Infinity,
814 templateResult: renderWithFont
815 } );
816 }
817 jQuery( document.body )
818 .on( 'wc-enhanced-select-init', function() {
819 fontsSelect( '#<?php echo esc_js( $value['id'] ); ?>' );
820 } );
821 </script>
822 <select
823 name="<?php echo esc_attr( $value['field_name'] ); ?>"
824 id="<?php echo esc_attr( $value['id'] ); ?>"
825 >
826 <optgroup label="<?php echo esc_attr__( 'Standard fonts', 'woocommerce' ); ?>">
827 <?php
828 foreach ( EmailFont::$font as $key => $font_family ) {
829 ?>
830 <option
831 value="<?php echo esc_attr( $key ); ?>"
832 data-font-family="<?php echo esc_attr( $font_family ); ?>"
833 <?php selected( $option_value, (string) $key ); ?>
834 ><?php echo esc_html( $key ); ?></option>
835 <?php
836 }
837 ?>
838 </optgroup>
839 <?php if ( $custom_fonts ) : ?>
840 <optgroup label="<?php echo esc_attr__( 'Custom fonts', 'woocommerce' ); ?>">
841 <?php
842 foreach ( $custom_fonts as $key => $val ) {
843 ?>
844 <option
845 value="<?php echo esc_attr( $key ); ?>"
846 <?php selected( $option_value, (string) $key ); ?>
847 ><?php echo esc_html( $val ); ?></option>
848 <?php
849 }
850 ?>
851 </optgroup>
852 <?php endif; ?>
853 </select>
854 </td>
855 </tr>
856 <?php
857 }
858
859 /**
860 * Creates the React mount point for the email color palette title.
861 *
862 * @param array $value Field value array.
863 */
864 public function email_color_palette( $value ) {
865 $email_improvements_enabled = $this->get_email_improvements_enabled();
866 $default_colors = EmailColors::get_default_colors( $email_improvements_enabled );
867 $auto_sync = get_option( EmailStyleSync::AUTO_SYNC_OPTION, 'no' );
868
869 ?>
870 <hr class="wc-settings-email-color-palette-separator" />
871 <div class="wc-settings-email-color-palette-header">
872 <h2 class="wc-settings-email-color-palette-title"><?php echo esc_html( $value['title'] ); ?></h2>
873 <?php if ( $email_improvements_enabled ) : ?>
874 <div
875 class="wc-settings-email-color-palette-buttons"
876 id="wc_settings_email_color_palette_slotfill"
877 data-default-colors="<?php echo esc_attr( wp_json_encode( $default_colors ) ); ?>"
878 <?php echo wp_theme_has_theme_json() ? 'data-has-theme-json' : ''; ?>
879 ></div>
880 <input
881 type="hidden"
882 name="woocommerce_email_auto_sync_with_theme"
883 id="woocommerce_email_auto_sync_with_theme"
884 value="<?php echo esc_attr( $auto_sync ); ?>"
885 />
886 <?php else : ?>
887 <div class="wc-settings-email-color-palette-buttons">
888 <button disabled type="button" class="components-button is-secondary"><?php esc_html_e( 'Sync with theme', 'woocommerce' ); ?></button>
889 </div>
890 <?php endif; ?>
891 </div>
892 <table class="form-table">
893 <?php
894 }
895
896 /**
897 * Show a notice to the user when they are trying out the new email templates.
898 */
899 public function previewing_new_templates(): void {
900 if ( ! $this->is_trying_new_templates() ) {
901 return;
902 }
903 if ( FeaturesUtil::feature_is_enabled( 'email_improvements' ) ) {
904 return;
905 }
906 update_option( 'woocommerce_admin_dismissed_try_email_improvements_modal', 'yes' );
907 ?>
908 <div class="wc-settings-email-color-palette-header submit">
909 <div class="notice notice-info inline">
910 <p><?php esc_html_e( 'Previewing new template designs. You can customize and test your emails and switch to the new template whenever you are ready.', 'woocommerce' ); ?></p>
911 <p>
912 <button name="save" type="submit" class="components-button is-secondary" value="<?php esc_attr_e( 'Save changes', 'woocommerce' ); ?>">
913 <?php esc_html_e( 'Switch to new template', 'woocommerce' ); ?>
914 </button>
915 <a href="?page=wc-settings&tab=email" class="components-button is-tertiary">
916 <?php esc_html_e( 'Keep legacy template', 'woocommerce' ); ?>
917 </a>
918 </p>
919 </div>
920 </div>
921 <?php
922 }
923
924 /**
925 * Show a button to revert or enable email improvements.
926 */
927 public function email_improvements_button(): void {
928 if ( 'yes' === get_transient( 'wc_settings_email_improvements_reverted' ) ) {
929 ?>
930 <div id="wc_settings_features_email_feedback_slotfill"></div>
931 <?php
932 }
933 $is_feature_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
934 $trying_new_templates = $this->is_trying_new_templates();
935 if ( ! $is_feature_enabled && ! $trying_new_templates ) {
936 ?>
937 <hr class="wc-settings-email-color-palette-separator" />
938 <a href="?page=wc-settings&tab=email&try-new-templates" class="components-button is-link">
939 <?php esc_html_e( 'Try our new email templates!', 'woocommerce' ); ?>
940 </a>
941 <?php
942 return;
943 }
944
945 $has_feature_enabled_since_installation = 'yes' === get_option( 'woocommerce_email_improvements_default_enabled', 'no' );
946 if ( $is_feature_enabled && ! $has_feature_enabled_since_installation ) {
947 $disable_feature_args = array(
948 'email_improvements' => '0',
949 '_feature_nonce' => wp_create_nonce( 'change_feature_enable' ),
950 );
951 ?>
952 <hr class="wc-settings-email-color-palette-separator" />
953 <a href="<?php echo esc_url( add_query_arg( $disable_feature_args ) ); ?>"
954 class="components-button is-link"
955 onclick="return confirm('<?php esc_attr_e( 'Are you sure want to revert to legacy? Doing so will erase any changes you’ve made to your new email templates, and will restore your previous email designs.', 'woocommerce' ); ?>');"
956 >
957 <?php esc_html_e( 'Revert to legacy template', 'woocommerce' ); ?>
958 </a>
959 <?php
960 return;
961 }
962 ?>
963 <?php
964 }
965
966 /**
967 * Append email improvements prop to Tracks globally.
968 *
969 * @param array $event_properties Event properties array.
970 *
971 * @return array
972 */
973 public function append_feature_email_improvements_to_tracks( $event_properties ) {
974 if ( is_array( $event_properties ) ) {
975 $is_email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
976 $event_properties['feature_email_improvements'] = $is_email_improvements_enabled ? 'enabled' : 'disabled';
977 }
978 return $event_properties;
979 }
980
981 /**
982 * Track email improvements feature change.
983 *
984 * @param string $feature_id The feature ID.
985 * @param bool $enabled True if the feature is enabled, false if it is disabled.
986 */
987 public function track_email_improvements_feature_change( $feature_id, $enabled ) {
988 if ( 'email_improvements' === $feature_id ) {
989 $current_date = gmdate( 'Y-m-d H:i:s' );
990 if ( $enabled ) {
991 $enabled_count = get_option( 'woocommerce_email_improvements_enabled_count', 0 );
992 update_option( 'woocommerce_email_improvements_enabled_count', $enabled_count + 1 );
993 add_option( 'woocommerce_email_improvements_first_enabled_at', $current_date );
994 update_option( 'woocommerce_email_improvements_last_enabled_at', $current_date );
995 } else {
996 $disabled_count = get_option( 'woocommerce_email_improvements_disabled_count', 0 );
997 update_option( 'woocommerce_email_improvements_disabled_count', $disabled_count + 1 );
998 add_option( 'woocommerce_email_improvements_first_disabled_at', $current_date );
999 update_option( 'woocommerce_email_improvements_last_disabled_at', $current_date );
1000 }
1001 }
1002 }
1003
1004 /**
1005 * When the email settings are saved, if the user is trying out the new email templates, enable the email improvements feature.
1006 */
1007 public function enable_email_improvements_when_trying_new_templates() {
1008 if ( $this->is_trying_new_templates() ) {
1009 $feature_controller = wc_get_container()->get( FeaturesController::class );
1010 $feature_controller->change_feature_enable( 'email_improvements', true );
1011
1012 // Remove the try-new-templates parameter from the URL.
1013 wp_safe_redirect( remove_query_arg( 'try-new-templates' ) );
1014 exit;
1015 }
1016 }
1017
1018 /**
1019 * Get "email improvements" feature status or force it when enabled via URL parameter.
1020 * Transient is used to force the email improvements feature in email preview, which
1021 * is rendered in iframe.
1022 *
1023 * @return bool
1024 */
1025 private function get_email_improvements_enabled() {
1026 $email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
1027 // Check for try-new-templates URL parameter, which is used to force the email improvements feature in preview mode.
1028 if ( $this->is_trying_new_templates() ) {
1029 $email_improvements_enabled = true;
1030 set_transient( EmailPreview::TRANSIENT_PREVIEW_EMAIL_IMPROVEMENTS, 'yes' );
1031 } else {
1032 delete_transient( EmailPreview::TRANSIENT_PREVIEW_EMAIL_IMPROVEMENTS );
1033 }
1034 return $email_improvements_enabled;
1035 }
1036
1037 /**
1038 * Check if the user is trying out the new email templates.
1039 *
1040 * @return bool
1041 */
1042 private function is_trying_new_templates() {
1043 global $current_tab;
1044 if ( 'email' !== $current_tab ) {
1045 return false;
1046 }
1047 if ( isset( $_GET['section'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1048 return false;
1049 }
1050 return isset( $_GET['try-new-templates'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1051 }
1052 }
1053
1054 return new WC_Settings_Emails();
1055