PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 11.1.0-beta.2
WooCommerce v11.1.0-beta.2
11.1.0 11.1.0-rc.2 11.1.0-rc.1 11.1.0-beta.2 11.1.0-beta.1 11.0.1 11.0.0 11.0.0-rc.3 11.0.0-rc.2 11.0.0-rc.1 11.0.0-beta.2 11.0.0-beta.1 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 2 weeks ago class-wc-settings-accounts.php 7 months ago class-wc-settings-advanced.php 2 months ago class-wc-settings-checkout.php 5 years ago class-wc-settings-emails.php 2 weeks ago class-wc-settings-general.php 3 months ago class-wc-settings-integrations.php 1 year ago class-wc-settings-page.php 2 weeks ago class-wc-settings-payment-gateways.php 2 months ago class-wc-settings-point-of-sale.php 1 month ago class-wc-settings-products.php 1 month ago class-wc-settings-shipping.php 2 weeks ago class-wc-settings-site-visibility.php 2 years ago class-wc-settings-tax.php 1 month ago
class-wc-settings-emails.php
1065 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\WCTransactionalEmails;
16 use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateDivergenceDetector;
17 use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateSyncRegistry;
18 use Automattic\WooCommerce\Internal\Features\FeaturesController;
19 use Automattic\WooCommerce\Utilities\FeaturesUtil;
20
21 defined( 'ABSPATH' ) || exit;
22
23 if ( class_exists( 'WC_Settings_Emails', false ) ) {
24 return new WC_Settings_Emails();
25 }
26
27 /**
28 * WC_Settings_Emails.
29 */
30 class WC_Settings_Emails extends WC_Settings_Page {
31
32 /**
33 * Constructor.
34 */
35 public function __construct() {
36 $this->id = 'email';
37 $this->label = __( 'Emails', 'woocommerce' );
38
39 add_action( 'woocommerce_admin_field_email_notification', array( $this, 'email_notification_setting' ) );
40 add_action( 'woocommerce_admin_field_email_notification_block_emails', array( $this, 'email_notification_setting_block_emails' ) );
41 add_action( 'woocommerce_admin_field_email_preview', array( $this, 'email_preview' ) );
42 add_action( 'woocommerce_admin_field_email_image_url', array( $this, 'email_image_url' ) );
43 add_action( 'woocommerce_admin_field_email_font_family', array( $this, 'email_font_family' ) );
44 add_action( 'woocommerce_admin_field_email_color_palette', array( $this, 'email_color_palette' ) );
45 add_action( 'woocommerce_admin_field_previewing_new_templates', array( $this, 'previewing_new_templates' ) );
46 add_action( 'woocommerce_admin_field_email_improvements_button', array( $this, 'email_improvements_button' ) );
47 add_action( 'woocommerce_email_settings_after', array( $this, 'email_preview_single' ) );
48 add_action( 'woocommerce_settings_saved', array( $this, 'enable_email_improvements_when_trying_new_templates' ), 999 );
49 add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_email_header_image', array( $this, 'sanitize_email_header_image' ), 10, 3 );
50 add_filter( 'woocommerce_tracks_event_properties', array( $this, 'append_feature_email_improvements_to_tracks' ) );
51 add_action( FeaturesController::FEATURE_ENABLED_CHANGED_ACTION, array( $this, 'track_email_improvements_feature_change' ), 10, 2 );
52 parent::__construct();
53 }
54
55 /**
56 * Setting page icon.
57 *
58 * @var string
59 */
60 public $icon = 'atSymbol';
61
62 /**
63 * Get own sections.
64 *
65 * @return array
66 */
67 protected function get_own_sections() {
68 return array(
69 '' => __( 'Email options', 'woocommerce' ),
70 );
71 }
72
73 /**
74 * Get settings array.
75 *
76 * @return array
77 */
78 protected function get_settings_for_default_section() {
79 $desc_help_text = sprintf(
80 /* translators: %1$s: Link to WP Mail Logging plugin, %2$s: Link to Email FAQ support page. */
81 __( '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' ),
82 'https://wordpress.org/plugins/wp-mail-logging/',
83 'https://woocommerce.com/document/email-faq'
84 );
85
86 $block_email_editor_enabled = FeaturesUtil::feature_is_enabled( 'block_email_editor' );
87 $email_improvements_enabled = $this->get_email_improvements_enabled();
88
89 // These defaults should be chosen by the same logic as the other color option properties.
90 $default_colors = EmailColors::get_default_colors( $email_improvements_enabled );
91
92 if ( $block_email_editor_enabled ) {
93 $email_notifications_field = 'email_notification_block_emails';
94 $email_notifications_desc = null;
95 } else {
96 $email_notifications_field = 'email_notification';
97 /* translators: %s: help description with link to WP Mail logging and support page. */
98 $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 );
99 }
100
101 $settings =
102 array(
103 array(
104 'title' => __( 'Email notifications', 'woocommerce' ),
105 'desc' => $email_notifications_desc,
106 'type' => 'title',
107 'id' => 'email_notification_settings',
108 ),
109
110 array( 'type' => $email_notifications_field ),
111
112 array(
113 'type' => 'sectionend',
114 'id' => 'email_notification_settings',
115 ),
116
117 array(
118 'type' => 'sectionend',
119 'id' => 'email_recipient_options',
120 ),
121 array(
122 'title' => __( 'Email sender options', 'woocommerce' ),
123 'type' => 'title',
124 'desc' => __( "Set the name and email address you'd like your outgoing emails to use.", 'woocommerce' ),
125 'id' => 'email_options',
126 ),
127
128 array(
129 'title' => __( '"From" name', 'woocommerce' ),
130 'desc' => '',
131 'id' => 'woocommerce_email_from_name',
132 'type' => 'text',
133 'css' => 'min-width:400px;',
134 'default' => esc_attr( get_bloginfo( 'name', 'display' ) ),
135 'autoload' => false,
136 'desc_tip' => true,
137 'skip_initial_save' => true,
138 ),
139
140 array(
141 'title' => __( '"From" address', 'woocommerce' ),
142 'desc' => '',
143 'id' => 'woocommerce_email_from_address',
144 'type' => 'email',
145 'custom_attributes' => array(
146 'multiple' => 'multiple',
147 ),
148 'css' => 'min-width:400px;',
149 'default' => get_option( 'admin_email' ),
150 'autoload' => false,
151 'desc_tip' => true,
152 ),
153 );
154
155 // Add reply-to fields.
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 $settings = array_merge(
193 $settings,
194 array(
195 array(
196 'type' => 'sectionend',
197 'id' => 'email_options',
198 ),
199 )
200 );
201
202 // If the email editor is enabled the design is handled by the email editor.
203 if ( ! $block_email_editor_enabled ) {
204 $settings = array_merge(
205 $settings,
206 array(
207 array(
208 'title' => __( 'Email template', 'woocommerce' ),
209 'type' => 'title',
210 'desc' => __( 'Customize your WooCommerce email template and preview it below.', 'woocommerce' ),
211 'id' => 'email_template_options',
212 ),
213
214 array(
215 'title' => __( 'Try new templates', 'woocommerce' ),
216 'type' => 'previewing_new_templates',
217 'id' => 'previewing_new_templates',
218 ),
219
220 array(
221 'title' => __( 'Logo', 'woocommerce' ),
222 'desc' => __( 'Add your logo to each of your WooCommerce emails. If no logo is uploaded, your site title will be used instead.', 'woocommerce' ),
223 'id' => 'woocommerce_email_header_image',
224 'type' => 'email_image_url',
225 'css' => 'min-width:400px;',
226 'placeholder' => __( 'N/A', 'woocommerce' ),
227 'default' => '',
228 'autoload' => false,
229 'desc_tip' => true,
230 ),
231
232 array(
233 'title' => __( 'Logo width (px)', 'woocommerce' ),
234 'id' => 'woocommerce_email_header_image_width',
235 'desc_tip' => '',
236 'default' => '120',
237 'type' => 'number',
238 'row_class' => $email_improvements_enabled ? '' : 'disabled',
239 ),
240
241 array(
242 'title' => __( 'Header alignment', 'woocommerce' ),
243 'id' => 'woocommerce_email_header_alignment',
244 'desc_tip' => '',
245 'default' => 'left',
246 'type' => 'select',
247 'class' => 'wc-enhanced-select',
248 'options' => array(
249 'left' => __( 'Left', 'woocommerce' ),
250 'center' => __( 'Center', 'woocommerce' ),
251 'right' => __( 'Right', 'woocommerce' ),
252 ),
253 'row_class' => $email_improvements_enabled ? '' : 'disabled',
254 ),
255
256 array(
257 'title' => __( 'Font family', 'woocommerce' ),
258 'id' => 'woocommerce_email_font_family',
259 'default' => 'Helvetica',
260 'type' => 'email_font_family',
261 'row_class' => $email_improvements_enabled ? '' : 'disabled',
262 ),
263
264 array(
265 'title' => __( 'Footer text', 'woocommerce' ),
266 /* translators: %s: Available placeholders for use */
267 '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}' ),
268 'id' => 'woocommerce_email_footer_text',
269 'css' => 'width:400px; height: 75px;',
270 'placeholder' => __( 'N/A', 'woocommerce' ),
271 'type' => 'textarea',
272 'default' => '{site_title}<br />{store_address}',
273 'autoload' => false,
274 'desc_tip' => true,
275 ),
276
277 array(
278 'type' => 'sectionend',
279 'id' => 'email_template_options',
280 ),
281
282 array(
283 'title' => __( 'Color palette', 'woocommerce' ),
284 'type' => 'email_color_palette',
285 'id' => 'email_color_palette',
286 ),
287
288 array(
289 'title' => __( 'Accent', 'woocommerce' ),
290 /* translators: %s: default color */
291 'desc' => sprintf( __( 'Customize the color of your buttons and links. Default %s.', 'woocommerce' ), '<code>' . $default_colors['base'] . '</code>' ),
292 'id' => 'woocommerce_email_base_color',
293 'type' => 'color',
294 'css' => 'width:6em;',
295 'default' => $default_colors['base'],
296 'autoload' => false,
297 'desc_tip' => true,
298 ),
299
300 array(
301 'title' => __( 'Email background', 'woocommerce' ),
302 /* translators: %s: default color */
303 'desc' => sprintf( __( 'Select a color for the background of your emails. Default %s.', 'woocommerce' ), '<code>' . $default_colors['bg'] . '</code>' ),
304 'id' => 'woocommerce_email_background_color',
305 'type' => 'color',
306 'css' => 'width:6em;',
307 'default' => $default_colors['bg'],
308 'autoload' => false,
309 'desc_tip' => true,
310 ),
311
312 array(
313 'title' => __( 'Content background', 'woocommerce' ),
314 /* translators: %s: default color */
315 'desc' => sprintf( __( 'Choose a background color for the content area of your emails. Default %s.', 'woocommerce' ), '<code>' . $default_colors['body_bg'] . '</code>' ),
316 'id' => 'woocommerce_email_body_background_color',
317 'type' => 'color',
318 'css' => 'width:6em;',
319 'default' => $default_colors['body_bg'],
320 'autoload' => false,
321 'desc_tip' => true,
322 ),
323
324 array(
325 'title' => __( 'Heading & text', 'woocommerce' ),
326 /* translators: %s: default color */
327 'desc' => sprintf( __( 'Set the color of your headings and text. Default %s.', 'woocommerce' ), '<code>' . $default_colors['body_text'] . '</code>' ),
328 'id' => 'woocommerce_email_text_color',
329 'type' => 'color',
330 'css' => 'width:6em;',
331 'default' => $default_colors['body_text'],
332 'autoload' => false,
333 'desc_tip' => true,
334 ),
335
336 array(
337 'title' => __( 'Secondary text', 'woocommerce' ),
338 /* translators: %s: footer default color */
339 'desc' => sprintf( __( 'Choose a color for your secondary text, such as your footer content. Default %s.', 'woocommerce' ), '<code>' . $default_colors['footer_text'] . '</code>' ),
340 'id' => 'woocommerce_email_footer_text_color',
341 'type' => 'color',
342 'css' => 'width:6em;',
343 'default' => $default_colors['footer_text'],
344 'autoload' => false,
345 'desc_tip' => true,
346 ),
347
348 array(
349 'title' => __( 'Auto-sync with theme', 'woocommerce' ),
350 'desc' => __( 'Automatically update email styles when theme styles change', 'woocommerce' ),
351 'id' => 'woocommerce_email_auto_sync_with_theme',
352 'type' => 'hidden',
353 'default' => 'no',
354 'autoload' => false,
355 ),
356
357 array(
358 'type' => 'sectionend',
359 'id' => 'email_color_palette',
360 ),
361
362 array(
363 'title' => __( 'Email improvements button', 'woocommerce' ),
364 'type' => 'email_improvements_button',
365 'id' => 'email_improvements_button',
366 ),
367
368 array( 'type' => 'email_preview' ),
369 )
370 );
371 }
372
373 // Remove empty elements that depend on the email_improvements feature flag.
374 $settings = array_filter( $settings );
375
376 /**
377 * Filters the email settings array.
378 *
379 * @since 2.1.0
380 *
381 * @param array $settings Array of email settings.
382 */
383 return apply_filters( 'woocommerce_email_settings', $settings );
384 }
385
386 /**
387 * Get custom fonts for emails.
388 */
389 public function get_custom_fonts() {
390 $custom_fonts = array();
391 if ( wp_is_block_theme() && class_exists( 'WP_Font_Face_Resolver' ) ) {
392 $theme_fonts = WP_Font_Face_Resolver::get_fonts_from_theme_json();
393 if ( count( $theme_fonts ) > 0 ) {
394 foreach ( $theme_fonts as $font ) {
395 if ( ! empty( $font[0]['font-family'] ) ) {
396 $custom_fonts[ $font[0]['font-family'] ] = $font[0]['font-family'];
397 }
398 }
399 }
400 }
401 ksort( $custom_fonts );
402
403 return $custom_fonts;
404 }
405
406 /**
407 * Output the settings.
408 */
409 public function output() {
410 global $current_section;
411
412 // Define emails that can be customised here.
413 $mailer = WC()->mailer();
414 $email_templates = $mailer->get_emails();
415
416 if ( $current_section ) {
417 foreach ( $email_templates as $email_key => $email ) {
418 if ( strtolower( $email_key ) === $current_section ) {
419 $this->run_email_admin_options( $email );
420 break;
421 }
422 }
423 }
424
425 parent::output();
426 }
427
428 /**
429 * Run the 'admin_options' method on a given email.
430 * This method exists to easy unit testing.
431 *
432 * @param object $email The email object to run the method on.
433 */
434 protected function run_email_admin_options( $email ) {
435 $email->admin_options();
436 }
437
438 /**
439 * Save settings.
440 */
441 public function save() {
442 global $current_section;
443
444 if ( ! $current_section ) {
445 $this->save_settings_for_current_section();
446 $this->do_update_options_action();
447 } else {
448 $wc_emails = WC_Emails::instance();
449
450 if ( in_array( $current_section, array_map( 'sanitize_title', array_keys( $wc_emails->get_emails() ) ), true ) ) {
451 foreach ( $wc_emails->get_emails() as $email_id => $email ) {
452 if ( sanitize_title( $email_id ) === $current_section ) {
453 $this->do_update_options_action( $email->id );
454 }
455 }
456 } else {
457 $this->save_settings_for_current_section();
458 $this->do_update_options_action();
459 }
460 }
461 }
462
463 /**
464 * Output email notification settings.
465 */
466 public function email_notification_setting() {
467 // Define emails that can be customised here.
468 $mailer = WC()->mailer();
469 $email_templates = $mailer->get_emails();
470
471 ?>
472 <tr valign="top">
473 <td class="wc_emails_wrapper" colspan="2">
474 <table class="wc_emails widefat" cellspacing="0">
475 <thead>
476 <tr>
477 <?php
478 /**
479 * Filters the columns displayed in the email settings table.
480 *
481 * @since 2.1.0
482 *
483 * @param array $columns Array of column keys and labels.
484 */
485 $columns = apply_filters(
486 'woocommerce_email_setting_columns',
487 array(
488 'status' => '',
489 'name' => __( 'Email', 'woocommerce' ),
490 'email_type' => __( 'Content type', 'woocommerce' ),
491 'recipient' => __( 'Recipient(s)', 'woocommerce' ),
492 'actions' => '',
493 )
494 );
495 foreach ( $columns as $key => $column ) {
496 echo '<th class="wc-email-settings-table-' . esc_attr( $key ) . '">' . esc_html( $column ) . '</th>';
497 }
498 ?>
499 </tr>
500 </thead>
501 <tbody>
502 <?php
503 foreach ( $email_templates as $email_key => $email ) {
504 echo '<tr>';
505
506 foreach ( $columns as $key => $column ) {
507
508 switch ( $key ) {
509 case 'name':
510 echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">
511 <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=email&section=' . strtolower( $email_key ) ) ) . '">' . esc_html( $email->get_title() ) . '</a>
512 ' . wc_help_tip( $email->get_description() ) . '
513 </td>';
514 break;
515 case 'recipient':
516 $to = $email->is_customer_email() ? __( 'Customer', 'woocommerce' ) : $email->get_recipient();
517 $cc = false;
518 $bcc = false;
519 if ( FeaturesUtil::feature_is_enabled( 'email_improvements' ) ) {
520 $ccs = $email->get_cc_recipient();
521 $bccs = $email->get_bcc_recipient();
522 // Translators: %s: comma-separated email addresses to which the email is cc-ed.
523 $cc = $ccs ? sprintf( __( '<b>Cc</b>: %s', 'woocommerce' ), $ccs ) : false;
524 // Translators: %s: comma-separated email addresses to which the email is bcc-ed.
525 $bcc = $bccs ? sprintf( __( '<b>Bcc</b>: %s', 'woocommerce' ), $bccs ) : false;
526 if ( $cc || $bcc ) {
527 // Translators: %s: comma-separated email addresses to which the email is sent.
528 $to = sprintf( __( '<b>To</b>: %s', 'woocommerce' ), $to );
529 }
530 }
531 $allowed_tags = array( 'b' => array() );
532
533 echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">';
534 echo wp_kses( $to, $allowed_tags );
535 if ( $cc ) {
536 echo '<br>' . wp_kses( $cc, $allowed_tags );
537 }
538 if ( $bcc ) {
539 echo '<br>' . wp_kses( $bcc, $allowed_tags );
540 }
541 echo '</td>';
542 break;
543 case 'status':
544 echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">';
545
546 if ( $email->is_manual() ) {
547 echo '<span class="status-manual tips" data-tip="' . esc_attr__( 'Manually sent', 'woocommerce' ) . '">' . esc_html__( 'Manual', 'woocommerce' ) . '</span>';
548 } elseif ( $email->is_enabled() ) {
549 echo '<span class="status-enabled tips" data-tip="' . esc_attr__( 'Enabled', 'woocommerce' ) . '">' . esc_html__( 'Yes', 'woocommerce' ) . '</span>';
550 } else {
551 echo '<span class="status-disabled tips" data-tip="' . esc_attr__( 'Disabled', 'woocommerce' ) . '">-</span>';
552 }
553
554 echo '</td>';
555 break;
556 case 'email_type':
557 echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">
558 ' . esc_html( $email->get_content_type() ) . '
559 </td>';
560 break;
561 case 'actions':
562 echo '<td class="wc-email-settings-table-' . esc_attr( $key ) . '">
563 <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>
564 </td>';
565 break;
566 default:
567 /**
568 * Fires when rendering a custom column in the email settings table.
569 *
570 * @since 2.1.0
571 *
572 * @param WC_Email $email The email object.
573 */
574 do_action( 'woocommerce_email_setting_column_' . $key, $email );
575 break;
576 }
577 }
578
579 echo '</tr>';
580 }
581 ?>
582 </tbody>
583 </table>
584 </td>
585 </tr>
586 <?php
587 }
588
589 /**
590 * Creates the React mount point for listing of block based emails.
591 */
592 public function email_notification_setting_block_emails() {
593 $desc_help_text = sprintf(
594 /* translators: %1$s: Link to WP Mail Logging plugin, %2$s: Link to Email FAQ support page. */
595 __( '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' ),
596 'https://wordpress.org/plugins/wp-mail-logging/',
597 'https://woocommerce.com/document/email-faq'
598 );
599 $email_post_manager = WCTransactionalEmailPostsManager::get_instance();
600 $emails = WC()->mailer()->get_emails();
601 $email_types = array();
602 $post_id_for_template = null;
603 $block_editor_email_ids = WCTransactionalEmails::get_transactional_emails();
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 $file_template_preview_url = in_array( $email->id, $block_editor_email_ids, true )
625 ? wp_nonce_url( admin_url( '?preview_woo_block_email=true&email_id=' . $email->id ), 'preview-woo-block-email' )
626 : null;
627
628 $email_types[] = array(
629 'title' => $email->get_title(),
630 'description' => $email->get_description(),
631 'id' => $email->id,
632 'email_key' => strtolower( $email_key ),
633 'email_class_name' => get_class( $email ),
634 'post_id' => $post_id,
635 'file_template_preview_url' => $file_template_preview_url,
636 'enabled' => $email->is_enabled(),
637 'manual' => $email->is_manual(),
638 'current_version' => '' !== $current_version ? $current_version : null,
639 'template_status' => '' !== $template_status ? $template_status : null,
640 'template_version' => '' !== $template_version ? $template_version : null,
641 'was_backfilled' => $was_backfilled,
642 'recipients' => array(
643 'to' => $email->is_customer_email() ? __( 'Customers', 'woocommerce' ) : $email->get_recipient(),
644 'cc' => $email->get_cc_recipient(),
645 'bcc' => $email->get_bcc_recipient(),
646 ),
647 );
648
649 // Store the first valid post ID we find.
650 if ( ! $post_id_for_template && $post_id ) {
651 $post_id_for_template = $post_id;
652 }
653 }
654 // The email editor's template mode opens through an email post's
655 // editor session, so the URL requires a post ID. When no post exists,
656 // the URL stays null and the client creates a post on demand, building
657 // the URL itself from the template ID passed below.
658 $email_template_id = get_stylesheet() . '//' . WooEmailTemplate::TEMPLATE_SLUG;
659 $edit_template_url = null;
660 if ( $post_id_for_template ) {
661 $edit_template_url = admin_url( 'post.php?post=' . $post_id_for_template . '&action=edit&template=' . $email_template_id );
662 }
663
664 ?>
665 <div
666 id="wc_settings_email_listing_slotfill" class="wc-settings-prevent-change-event woocommerce-email-listing-listview"
667 data-email-types="<?php echo esc_attr( wp_json_encode( $email_types ) ); ?>"
668 data-edit-template-url="<?php echo esc_attr( $edit_template_url ); ?>"
669 data-email-template-id="<?php echo esc_attr( $email_template_id ); ?>"
670 >
671 <div style="
672 display: flex;
673 align-items: center;
674 justify-content: center;
675 padding: 12px;
676 height: 40px;
677 width: 100%;
678 ">
679 <h3> <?php esc_html_e( 'Loading&hellip;', 'woocommerce' ); ?> </h3>
680 </div>
681 </div>
682 <div>
683 <p><?php echo wp_kses_post( wpautop( wptexturize( $desc_help_text ) ) ); ?></p>
684 </div>
685 <?php
686 }
687
688 /**
689 * Creates the React mount point for the email preview.
690 */
691 public function email_preview() {
692 $this->delete_transient_email_settings();
693 $emails = WC()->mailer()->get_emails();
694 $email_types = array();
695 foreach ( $emails as $email ) {
696 $email_types[] = array(
697 'label' => $email->get_title(),
698 'value' => get_class( $email ),
699 );
700 }
701 ?>
702 <div
703 id="wc_settings_email_preview_slotfill"
704 data-preview-url="<?php echo esc_url( wp_nonce_url( admin_url( '?preview_woocommerce_mail=true' ), 'preview-mail' ) ); ?>"
705 data-email-types="<?php echo esc_attr( wp_json_encode( $email_types ) ); ?>"
706 data-email-setting-ids="<?php echo esc_attr( wp_json_encode( EmailPreview::get_email_style_setting_ids() ) ); ?>"
707 ></div>
708 <?php
709 }
710
711 /**
712 * Creates the React mount point for the single email preview.
713 *
714 * @param object $email The email object to run the method on.
715 */
716 public function email_preview_single( $email ) {
717 $this->delete_transient_email_settings();
718 // Email types array should have a single entry for current email.
719 $email_types = array(
720 array(
721 'label' => $email->get_title(),
722 'value' => get_class( $email ),
723 ),
724 );
725 ?>
726 <h2><?php echo esc_html( __( 'Email preview', 'woocommerce' ) ); ?></h2>
727
728 <p><?php echo esc_html( __( 'Preview your email template. You can also test on different devices and send yourself a test email.', 'woocommerce' ) ); ?></p>
729 <div>
730 <div
731 id="wc_settings_email_preview_slotfill"
732 data-preview-url="<?php echo esc_url( wp_nonce_url( admin_url( '?preview_woocommerce_mail=true' ), 'preview-mail' ) ); ?>"
733 data-email-types="<?php echo esc_attr( wp_json_encode( $email_types ) ); ?>"
734 data-email-setting-ids="<?php echo esc_attr( wp_json_encode( EmailPreview::get_email_content_setting_ids( $email->id ) ) ); ?>"
735 ></div>
736 <input type="hidden" id="woocommerce_email_from_name" value="<?php echo esc_attr( get_option( 'woocommerce_email_from_name' ) ); ?>" />
737 <input type="hidden" id="woocommerce_email_from_address" value="<?php echo esc_attr( get_option( 'woocommerce_email_from_address' ) ); ?>" />
738 </div>
739 <?php
740 }
741
742 /**
743 * Deletes transient with email settings used for live preview. This is to
744 * prevent conflicts where the preview would show values from previous session.
745 */
746 private function delete_transient_email_settings() {
747 $setting_ids = EmailPreview::get_all_email_setting_ids();
748 foreach ( $setting_ids as $id ) {
749 delete_transient( $id );
750 }
751 }
752
753 /**
754 * Creates the React mount point for the email image url.
755 *
756 * @param array $value Field value array.
757 */
758 public function email_image_url( $value ) {
759 $option_value = $value['value'];
760 if ( ! isset( $value['field_name'] ) ) {
761 $value['field_name'] = $value['id'];
762 }
763 ?>
764 <tr class="<?php echo esc_attr( $value['row_class'] ); ?>">
765 <th scope="row" class="titledesc">
766 <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>
767 </th>
768 <td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
769 <input
770 name="<?php echo esc_attr( $value['field_name'] ); ?>"
771 id="<?php echo esc_attr( $value['id'] ); ?>"
772 type="hidden"
773 value="<?php echo esc_attr( $option_value ); ?>"
774 />
775 <div
776 id="wc_settings_email_image_url_slotfill"
777 data-id="<?php echo esc_attr( $value['id'] ); ?>"
778 data-image-url="<?php echo esc_attr( $option_value ); ?>"
779 ></div>
780 </td>
781 </tr>
782 <?php
783 }
784
785 /**
786 * Sanitize email image URL.
787 *
788 * @param string $value Option value.
789 * @param array $option Option name.
790 * @param string $raw_value Raw value.
791 * @return string
792 */
793 public function sanitize_email_header_image( $value, $option, $raw_value ) {
794 return sanitize_url( $raw_value );
795 }
796
797 /**
798 * Creates the email font family field with custom font family applied to each option.
799 *
800 * @param array $value Field value array.
801 */
802 public function email_font_family( $value ) {
803 $option_value = $value['value'];
804 // This is a temporary fix to prevent using custom fonts without fallback.
805 $custom_fonts = null;
806
807 ?>
808 <tr class="<?php echo esc_attr( $value['row_class'] ); ?>">
809 <th scope="row" class="titledesc">
810 <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
811 </th>
812 <td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
813 <script type="text/javascript">
814 function renderWithFont( node ) {
815 if ( ! node.element || ! node.element.value ) return node.text;
816 var $wrapper = jQuery( '<span></span>' );
817 $wrapper.css( {'font-family': node.element.dataset['font-family'] || node.element.value} );
818 $wrapper.text( node.text );
819 return $wrapper;
820 }
821 function fontsSelect( selector ) {
822 jQuery( selector ).selectWoo( {
823 minimumResultsForSearch: Infinity,
824 templateResult: renderWithFont
825 } );
826 }
827 jQuery( document.body )
828 .on( 'wc-enhanced-select-init', function() {
829 fontsSelect( '#<?php echo esc_js( $value['id'] ); ?>' );
830 } );
831 </script>
832 <select
833 name="<?php echo esc_attr( $value['field_name'] ); ?>"
834 id="<?php echo esc_attr( $value['id'] ); ?>"
835 >
836 <optgroup label="<?php echo esc_attr__( 'Standard fonts', 'woocommerce' ); ?>">
837 <?php
838 foreach ( EmailFont::$font as $key => $font_family ) {
839 ?>
840 <option
841 value="<?php echo esc_attr( $key ); ?>"
842 data-font-family="<?php echo esc_attr( $font_family ); ?>"
843 <?php selected( $option_value, (string) $key ); ?>
844 ><?php echo esc_html( $key ); ?></option>
845 <?php
846 }
847 ?>
848 </optgroup>
849 <?php if ( $custom_fonts ) : ?>
850 <optgroup label="<?php echo esc_attr__( 'Custom fonts', 'woocommerce' ); ?>">
851 <?php
852 foreach ( $custom_fonts as $key => $val ) {
853 ?>
854 <option
855 value="<?php echo esc_attr( $key ); ?>"
856 <?php selected( $option_value, (string) $key ); ?>
857 ><?php echo esc_html( $val ); ?></option>
858 <?php
859 }
860 ?>
861 </optgroup>
862 <?php endif; ?>
863 </select>
864 </td>
865 </tr>
866 <?php
867 }
868
869 /**
870 * Creates the React mount point for the email color palette title.
871 *
872 * @param array $value Field value array.
873 */
874 public function email_color_palette( $value ) {
875 $email_improvements_enabled = $this->get_email_improvements_enabled();
876 $default_colors = EmailColors::get_default_colors( $email_improvements_enabled );
877 $auto_sync = get_option( EmailStyleSync::AUTO_SYNC_OPTION, 'no' );
878
879 ?>
880 <hr class="wc-settings-email-color-palette-separator" />
881 <div class="wc-settings-email-color-palette-header">
882 <h2 class="wc-settings-email-color-palette-title"><?php echo esc_html( $value['title'] ); ?></h2>
883 <?php if ( $email_improvements_enabled ) : ?>
884 <div
885 class="wc-settings-email-color-palette-buttons"
886 id="wc_settings_email_color_palette_slotfill"
887 data-default-colors="<?php echo esc_attr( wp_json_encode( $default_colors ) ); ?>"
888 <?php echo wp_theme_has_theme_json() ? 'data-has-theme-json' : ''; ?>
889 ></div>
890 <input
891 type="hidden"
892 name="woocommerce_email_auto_sync_with_theme"
893 id="woocommerce_email_auto_sync_with_theme"
894 value="<?php echo esc_attr( $auto_sync ); ?>"
895 />
896 <?php else : ?>
897 <div class="wc-settings-email-color-palette-buttons">
898 <button disabled type="button" class="components-button is-secondary"><?php esc_html_e( 'Sync with theme', 'woocommerce' ); ?></button>
899 </div>
900 <?php endif; ?>
901 </div>
902 <table class="form-table">
903 <?php
904 }
905
906 /**
907 * Show a notice to the user when they are trying out the new email templates.
908 */
909 public function previewing_new_templates(): void {
910 if ( ! $this->is_trying_new_templates() ) {
911 return;
912 }
913 if ( FeaturesUtil::feature_is_enabled( 'email_improvements' ) ) {
914 return;
915 }
916 update_option( 'woocommerce_admin_dismissed_try_email_improvements_modal', 'yes' );
917 ?>
918 <div class="wc-settings-email-color-palette-header submit">
919 <div class="notice notice-info inline">
920 <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>
921 <p>
922 <button name="save" type="submit" class="components-button is-secondary" value="<?php esc_attr_e( 'Save changes', 'woocommerce' ); ?>">
923 <?php esc_html_e( 'Switch to new template', 'woocommerce' ); ?>
924 </button>
925 <a href="?page=wc-settings&tab=email" class="components-button is-tertiary">
926 <?php esc_html_e( 'Keep legacy template', 'woocommerce' ); ?>
927 </a>
928 </p>
929 </div>
930 </div>
931 <?php
932 }
933
934 /**
935 * Show a button to revert or enable email improvements.
936 */
937 public function email_improvements_button(): void {
938 if ( 'yes' === get_transient( 'wc_settings_email_improvements_reverted' ) ) {
939 ?>
940 <div id="wc_settings_features_email_feedback_slotfill"></div>
941 <?php
942 }
943 $is_feature_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
944 $trying_new_templates = $this->is_trying_new_templates();
945 if ( ! $is_feature_enabled && ! $trying_new_templates ) {
946 ?>
947 <hr class="wc-settings-email-color-palette-separator" />
948 <a href="?page=wc-settings&tab=email&try-new-templates" class="components-button is-link">
949 <?php esc_html_e( 'Try our new email templates!', 'woocommerce' ); ?>
950 </a>
951 <?php
952 return;
953 }
954
955 $has_feature_enabled_since_installation = 'yes' === get_option( 'woocommerce_email_improvements_default_enabled', 'no' );
956 if ( $is_feature_enabled && ! $has_feature_enabled_since_installation ) {
957 $disable_feature_args = array(
958 'email_improvements' => '0',
959 '_feature_nonce' => wp_create_nonce( 'change_feature_enable' ),
960 );
961 ?>
962 <hr class="wc-settings-email-color-palette-separator" />
963 <a href="<?php echo esc_url( add_query_arg( $disable_feature_args ) ); ?>"
964 class="components-button is-link"
965 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' ); ?>');"
966 >
967 <?php esc_html_e( 'Revert to legacy template', 'woocommerce' ); ?>
968 </a>
969 <?php
970 return;
971 }
972 ?>
973 <?php
974 }
975
976 /**
977 * Append email improvements prop to Tracks globally.
978 *
979 * @param array $event_properties Event properties array.
980 *
981 * @return array
982 */
983 public function append_feature_email_improvements_to_tracks( $event_properties ) {
984 if ( is_array( $event_properties ) ) {
985 $is_email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
986 $event_properties['feature_email_improvements'] = $is_email_improvements_enabled ? 'enabled' : 'disabled';
987 }
988 return $event_properties;
989 }
990
991 /**
992 * Track email improvements feature change.
993 *
994 * @param string $feature_id The feature ID.
995 * @param bool $enabled True if the feature is enabled, false if it is disabled.
996 */
997 public function track_email_improvements_feature_change( $feature_id, $enabled ) {
998 if ( 'email_improvements' === $feature_id ) {
999 $current_date = gmdate( 'Y-m-d H:i:s' );
1000 if ( $enabled ) {
1001 $enabled_count = get_option( 'woocommerce_email_improvements_enabled_count', 0 );
1002 update_option( 'woocommerce_email_improvements_enabled_count', $enabled_count + 1 );
1003 add_option( 'woocommerce_email_improvements_first_enabled_at', $current_date );
1004 update_option( 'woocommerce_email_improvements_last_enabled_at', $current_date );
1005 } else {
1006 $disabled_count = get_option( 'woocommerce_email_improvements_disabled_count', 0 );
1007 update_option( 'woocommerce_email_improvements_disabled_count', $disabled_count + 1 );
1008 add_option( 'woocommerce_email_improvements_first_disabled_at', $current_date );
1009 update_option( 'woocommerce_email_improvements_last_disabled_at', $current_date );
1010 }
1011 }
1012 }
1013
1014 /**
1015 * When the email settings are saved, if the user is trying out the new email templates, enable the email improvements feature.
1016 */
1017 public function enable_email_improvements_when_trying_new_templates() {
1018 if ( $this->is_trying_new_templates() ) {
1019 $feature_controller = wc_get_container()->get( FeaturesController::class );
1020 $feature_controller->change_feature_enable( 'email_improvements', true );
1021
1022 // Remove the try-new-templates parameter from the URL.
1023 wp_safe_redirect( remove_query_arg( 'try-new-templates' ) );
1024 exit;
1025 }
1026 }
1027
1028 /**
1029 * Get "email improvements" feature status or force it when enabled via URL parameter.
1030 * Transient is used to force the email improvements feature in email preview, which
1031 * is rendered in iframe.
1032 *
1033 * @return bool
1034 */
1035 private function get_email_improvements_enabled() {
1036 $email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
1037 // Check for try-new-templates URL parameter, which is used to force the email improvements feature in preview mode.
1038 if ( $this->is_trying_new_templates() ) {
1039 $email_improvements_enabled = true;
1040 set_transient( EmailPreview::TRANSIENT_PREVIEW_EMAIL_IMPROVEMENTS, 'yes' );
1041 } else {
1042 delete_transient( EmailPreview::TRANSIENT_PREVIEW_EMAIL_IMPROVEMENTS );
1043 }
1044 return $email_improvements_enabled;
1045 }
1046
1047 /**
1048 * Check if the user is trying out the new email templates.
1049 *
1050 * @return bool
1051 */
1052 private function is_trying_new_templates() {
1053 global $current_tab;
1054 if ( 'email' !== $current_tab ) {
1055 return false;
1056 }
1057 if ( isset( $_GET['section'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1058 return false;
1059 }
1060 return isset( $_GET['try-new-templates'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1061 }
1062 }
1063
1064 return new WC_Settings_Emails();
1065