PluginProbe
YayMail – WooCommerce Email Customizer / 4.4.5
YayMail – WooCommerce Email Customizer v4.4.5
4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 trunk 1.9.6 2.1.4 2.1.5 3.2.2 3.2.6 3.2.7.1 3.2.8.1 3.2.9 3.3 3.3.1 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4 3.4.1 All 57 releases
yaymail / src / Ajax.php

Ajax.php in YayMail – WooCommerce Email Customizer 4.4.5, at src/Ajax.php

999 lines 44.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace YayMail;
4
5 use YayMail\Utils\SingletonTrait;
6 use YayMail\Models\SettingModel;
7 use YayMail\Models\TemplateModel;
8 use YayMail\Models\RevisionModel;
9 use YayMail\Migrations\MainMigration;
10 use YayMail\Utils\Helpers;
11 use YayMail\Utils\Logger;
12 use YayMail\Models\PatternTemplateModel;
13 use YayMail\Utils\TemplateHelpers;
14
15 /**
16 * I18n Logic
17 *
18 * @method static Ajax get_instance()
19 */
20 class Ajax {
21 use SingletonTrait;
22
23 protected function __construct() {
24 $this->init_hooks();
25 }
26
27 protected function init_hooks() {
28 add_action( 'wp_ajax_yaymail_preview_mail', [ $this, 'preview_mail' ] );
29 add_action( 'wp_ajax_yaymail_preview_mail_for_woo', [ $this, 'preview_mail_for_woo' ] );
30 add_action( 'wp_ajax_yaymail_send_test_mail', [ $this, 'send_test_mail' ] );
31 add_action( 'wp_ajax_yaymail_install_yaysmtp', [ $this, 'install_yaysmtp' ] );
32 add_action( 'wp_ajax_yaymail_get_custom_hook_html', [ $this, 'get_custom_hook_html' ] );
33 add_action( 'wp_ajax_yaymail_get_template_data_onload', [ $this, 'get_template_data_onload' ] );
34 add_action( 'wp_ajax_yaymail_export_templates', [ $this, 'export_templates' ] );
35 add_action( 'wp_ajax_yaymail_import_templates', [ $this, 'import_templates' ] );
36 add_action( 'wp_ajax_yaymail_review', [ $this, 'yaymail_review' ] );
37 add_action( 'wp_ajax_yaymail_change_ghf_tour', [ $this, 'change_ghf_tour' ] );
38 add_action( 'wp_ajax_yaymail_dismiss_multi_select_notice', [ $this, 'dismiss_multi_select_notice' ] );
39 add_action( 'wp_ajax_yaymail_export_state', [ $this, 'export_state' ] );
40 add_action( 'wp_ajax_yaymail_import_state', [ $this, 'import_state' ] );
41 add_action( 'wp_ajax_yaymail_dismiss_new_element_notification', [ $this, 'dismiss_new_element_notification' ] );
42 add_action( 'wp_ajax_yaymail_log_client_error', [ $this, 'log_client_error' ] );
43 }
44
45 /**
46 * Records a runtime error reported by the admin SPA (see apps/customizer/src/utils/client-error-reporter.ts).
47 *
48 * Goes to the WooCommerce log (WooCommerce > Status > Logs, source "yaymail-client") so support can ask the
49 * customer to copy it from wp-admin; falls back to the yaymail-logs file when WooCommerce is absent.
50 */
51 public function log_client_error() {
52 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
53 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) || ! current_user_can( 'manage_woocommerce' ) ) {
54 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ], 403 );
55 }
56
57 // A render loop in one browser must not be able to fill the log.
58 $rate_key = 'yaymail_client_error_rate_' . get_current_user_id();
59 $count = (int) get_transient( $rate_key );
60 if ( $count >= 20 ) {
61 return wp_send_json_success( [ 'logged' => false ] );
62 }
63 set_transient( $rate_key, $count + 1, MINUTE_IN_SECONDS );
64
65 $text = function ( $key, $max = 8000 ) {
66 $value = isset( $_POST[ $key ] ) ? sanitize_textarea_field( wp_unslash( $_POST[ $key ] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
67 return mb_substr( $value, 0, $max );
68 };
69
70 $lines = [
71 'CLIENT ERROR [' . $text( 'source', 20 ) . ']: ' . $text( 'message', 1000 ),
72 'Version: ' . $text( 'version', 20 ) . ' | Platform: ' . $text( 'platform', 40 ) . ' | Template: ' . $text( 'template', 200 ),
73 'URL: ' . $text( 'url', 2000 ),
74 'User agent: ' . $text( 'user_agent', 500 ),
75 ];
76 foreach ( [ 'hint' => 'Hint', 'stack' => 'Stack', 'component_stack' => 'Component stack' ] as $key => $label ) {
77 $value = $text( $key );
78 if ( '' !== $value ) {
79 $lines[] = $label . ':' . PHP_EOL . $value;
80 }
81 }
82 $message = implode( PHP_EOL, $lines );
83
84 if ( function_exists( 'wc_get_logger' ) ) {
85 wc_get_logger()->error( $message, [ 'source' => 'yaymail-client' ] );
86 } else {
87 ( new Logger() )->log( $message );
88 }
89
90 wp_send_json_success( [ 'logged' => true ] );
91 }
92
93 public function import_state() {
94 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
95 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
96 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
97 }
98 try {
99 $import_file = isset( $_FILES['import_file'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_FILES['import_file'] ) ) : null;
100 if ( ! $import_file ) {
101 return wp_send_json_error( [ 'mess' => __( 'Can\'t find import file', 'yaymail' ) ] );
102 }
103
104 if ( $import_file['type'] !== 'application/zip' ) {
105 return wp_send_json_error( [ 'mess' => __( 'Invalid file type. Please upload a ZIP file.', 'yaymail' ) ] );
106 }
107
108 $zip = new \ZipArchive();
109 if ( $zip->open( $import_file['tmp_name'] ) !== true ) {
110 return wp_send_json_error( [ 'mess' => __( 'Cannot open ZIP file.', 'yaymail' ) ] );
111 }
112
113 $state_data = null;
114 for ( $i = 0; $i < $zip->numFiles; $i++ ) {
115 $filename = $zip->getNameIndex( $i );
116 // Matches both "yaymail_backup.json" (YayMail) and "yaymagic_email_builder_backup.json"
117 // (Email Builder) -- the zip always holds exactly this one entry, named per
118 // getBrandName() in backup/index.tsx.
119 if ( 1 === preg_match( '/_backup\.json$/', (string) $filename ) ) {
120 $state_data = $zip->getFromIndex( $i );
121 break;
122 }
123 }
124
125 $zip->close();
126
127 if ( ! $state_data ) {
128 return wp_send_json_error( [ 'mess' => __( 'Cannot find the backup JSON file in the ZIP file.', 'yaymail' ) ] );
129 }
130
131 $imported_data = json_decode( $state_data );
132 if ( json_last_error() !== JSON_ERROR_NONE ) {
133 return wp_send_json_error( [ 'mess' => __( 'Invalid JSON data in the state file.', 'yaymail' ) ] );
134 }
135
136 if ( empty( $imported_data->posts ) || empty( $imported_data->postmeta ) || empty( $imported_data->options ) ) {
137 return wp_send_json_error( [ 'mess' => __( 'Invalid state file structure.', 'yaymail' ) ] );
138 }
139
140 $migration_model = \YayMail\Models\MigrationModel::get_instance();
141
142 $source_version = $imported_data->version;
143
144 $imported_posts = array_values(
145 array_filter(
146 $imported_data->posts,
147 function( $post ) {
148 return isset( $post->post_type ) && 'yaymail_template' === $post->post_type;
149 }
150 )
151 );
152
153 $imported_postmeta = array_values(
154 array_filter(
155 $imported_data->postmeta,
156 function( $postmeta ) use ( $imported_posts ) {
157 if ( empty( $imported_posts ) ) {
158 return false;
159 }
160 if ( ! isset( $postmeta->post_id ) || ! isset( $postmeta->meta_key ) ) {
161 return false;
162 }
163 if ( strpos( (string) $postmeta->meta_key, 'yaymail' ) === false ) {
164 return false;
165 }
166 foreach ( $imported_posts as $post ) {
167 if ( isset( $post->ID ) && (int) $post->ID === (int) $postmeta->post_id ) {
168 return true;
169 }
170 }
171 return false;
172 }
173 )
174 );
175
176 $imported_options = array_values(
177 array_filter(
178 $imported_data->options,
179 function( $option ) {
180 return isset( $option->option_name ) && strpos( (string) $option->option_name, 'yaymail' ) !== false;
181 }
182 )
183 );
184
185 $backup_data = [
186 'posts' => $imported_posts,
187 'postmeta' => $imported_postmeta,
188 'options' => $imported_options,
189 'created_date' => $imported_data->created_date ?? current_datetime()->format( 'Y-m-d H:i:s' ),
190 'name' => '_yaymail_import_backup_' . $source_version,
191 'version' => $source_version,
192 ];
193
194 $migration_model->reset( $backup_data );
195
196 wp_send_json_success(
197 [
198 'message' => __( 'Import state successfully', 'yaymail' ),
199 ]
200 );
201 } catch ( \Error $error ) {
202 yaymail_get_logger( $error );
203 wp_send_json_error( [ 'mess' => __( 'Import failed: ', 'yaymail' ) . $error->getMessage() ] );
204 } catch ( \Exception $exception ) {
205 yaymail_get_logger( $exception );
206 wp_send_json_error( [ 'mess' => __( 'Import failed: ', 'yaymail' ) . $exception->getMessage() ] );
207 }//end try
208 }
209
210 public function export_state() {
211 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
212 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
213 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
214 }
215
216 try {
217 global $wpdb;
218
219 /**
220 * Backup posts and postmeta
221 */
222 $query_posts = "
223 SELECT *
224 FROM {$wpdb->posts}
225 WHERE post_type = 'yaymail_template'
226 ";
227 $yaymail_template_posts = $wpdb->get_results( $query_posts );// phpcs:ignore
228
229 $query_postmeta = "
230 SELECT *
231 FROM {$wpdb->postmeta}
232 WHERE meta_key LIKE '%yaymail%'
233 ";
234 $yaymail_template_postmeta = $wpdb->get_results( $query_postmeta );// phpcs:ignore
235
236 $backup_data = [
237 'posts' => $yaymail_template_posts,
238 'postmeta' => $yaymail_template_postmeta,
239 ];
240 /** ****************************** */
241
242 /**
243 * Backup options
244 */
245 $query_options = "
246 SELECT *
247 FROM {$wpdb->options}
248 WHERE option_name LIKE '%yaymail%'
249 ";
250 $yaymail_options = $wpdb->get_results( $query_options ); // phpcs:ignore
251 $backup_data['options'] = $yaymail_options;
252
253 $backup_data['created_date'] = current_datetime()->format( 'Y-m-d H:i:s' );
254
255 // Fall back through running version / YAYWP_VERSION / '1.0' when the
256 // backup option hasn't been set yet (e.g. init_modules() hasn't
257 // recorded it), otherwise a falsy 'version' gets baked into the
258 // exported ZIP and MigrationModel::reset() rejects it on import with
259 // "Back up does not exist".
260 $version_backup = get_option( 'yaymail_version_backup' );
261 if ( ! empty( $version_backup ) ) {
262 $backup_data['version'] = $version_backup;
263 } elseif ( ! empty( yaymail_version() ) ) {
264 $backup_data['version'] = yaymail_version();
265 } else {
266 $backup_data['version'] = defined( 'YAYWP_VERSION' ) ? YAYWP_VERSION : '1.0';
267 }
268
269 $backup_data = apply_filters( 'yaymail_backup_state_data', $backup_data );
270
271 wp_send_json_success(
272 [
273 'message' => 'success',
274 'data' => $backup_data,
275 'file_name' => $this->export_file_name_prefix() . '_export_backup_' . gmdate( 'm-d-Y' ),
276 ]
277 );
278
279 } catch ( \Error $error ) {
280 yaymail_get_logger( $error );
281 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
282 } catch ( \Exception $exception ) {
283 yaymail_get_logger( $exception );
284 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
285 }//end try
286 }
287
288 public function sanitize( $array ) {
289
290 return wp_kses_post_deep( $array );
291 }
292
293 /**
294 * File name prefix for exported/backup downloads, matching the frontend's
295 * brand name per platform (constants/theme.ts WP_COLORS vs the free "yaymail"
296 * default). Reads the "platform" the frontend sends alongside these AJAX
297 * requests (see common/ajax's getPlatform() calls) since these admin-ajax.php
298 * requests don't reliably expose the calling screen via get_current_screen().
299 */
300 private function export_file_name_prefix() {
301 $platform = isset( $_POST['platform'] ) ? sanitize_text_field( wp_unslash( $_POST['platform'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing
302 return 'yaymagic-email-builder' === $platform ? 'yaymagic_email_builder' : 'yaymail';
303 }
304
305 public function process_plugin_installer( $slug ) {
306 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
307 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
308 require_once ABSPATH . 'wp-admin/includes/class-wp-ajax-upgrader-skin.php';
309 require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
310
311 $api = plugins_api(
312 'plugin_information',
313 [
314 'slug' => $slug,
315 'fields' => [
316 'short_description' => false,
317 'sections' => false,
318 'requires' => false,
319 'rating' => false,
320 'ratings' => false,
321 'downloaded' => false,
322 'last_updated' => false,
323 'added' => false,
324 'tags' => false,
325 'compatibility' => false,
326 'homepage' => false,
327 'donate_link' => false,
328 ],
329 ]
330 );
331
332 $skin = new \WP_Ajax_Upgrader_Skin();
333
334 $plugin_upgrader = new \Plugin_Upgrader( $skin );
335
336 try {
337 $result = $plugin_upgrader->install( $api->download_link );
338
339 if ( is_wp_error( $result ) ) {
340 yaymail_get_logger( $result );
341 }
342
343 return true;
344 } catch ( \Exception $exception ) {
345 yaymail_get_logger( $exception );
346 }
347
348 return false;
349 }
350
351 public function install_yaysmtp() {
352 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
353 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
354 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
355 }
356
357 if ( ! current_user_can( 'install_plugins' ) && ! current_user_can( 'activate_plugins' ) ) {
358 return wp_send_json_error( [ 'mess' => __( 'You do not have permission to install plugins', 'yaymail' ) ] );
359 }
360
361 try {
362 $is_installed = $this->process_plugin_installer( 'yaysmtp' );
363
364 if ( false === $is_installed ) {
365 wp_send_json_error( [ 'message' => $is_installed ] );
366 }
367
368 $result = activate_plugin( 'yaysmtp/yay-smtp.php' );
369
370 if ( is_wp_error( $result ) ) {
371 return wp_send_json_error( [ 'mess' => esc_html( $result->get_error_message() ) ] );
372 }
373
374 wp_send_json_success(
375 [
376 'installed' => null === $result,
377 ]
378 );
379
380 } catch ( \Error $error ) {
381 yaymail_get_logger( $error );
382 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
383 } catch ( \Exception $exception ) {
384 yaymail_get_logger( $exception );
385 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
386 }//end try
387 }
388
389 public function send_test_mail() {
390 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
391 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
392 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
393 }
394 try {
395 $template_name = isset( $_POST['template_name'] ) ? sanitize_text_field( wp_unslash( $_POST['template_name'] ) ) : '';
396 $order_id = isset( $_POST['order_id'] ) ? sanitize_text_field( wp_unslash( $_POST['order_id'] ) ) : 'sample_order';
397 $email = isset( $_POST['email'] ) ? sanitize_text_field( $_POST['email'] ) : '';
398 $is_wc_email = strpos( $template_name, 'wp-core-' ) !== 0;
399
400 if ( empty( $template_name ) ) {
401 return wp_send_json_error( [ 'mess' => __( 'Can\'t find template', 'yaymail' ) ] );
402 }
403
404 if ( empty( $order_id ) && $is_wc_email ) {
405 return wp_send_json_error( [ 'mess' => __( 'Can\'t find order', 'yaymail' ) ] );
406 }
407
408 if ( empty( $email ) ) {
409 return wp_send_json_error( [ 'mess' => __( 'Can\'t find email', 'yaymail' ) ] );
410 }
411
412 $variant = yaymail_sanitize_template_variant( isset( $_POST['variant'] ) ? sanitize_text_field( wp_unslash( $_POST['variant'] ) ) : '' );
413 $template = new YayMailTemplate( $template_name, '', $variant );
414
415 $render_data = [];
416
417 if ( empty( $order_id ) || ( 'sample_order' === $order_id ) ) {
418 $render_data['is_sample'] = true;
419 } else {
420 $render_data['order'] = wc_get_order( $order_id );
421 }
422
423 $render_data['is_customized_preview'] = true;
424 // check if email template on preview and send test mail
425
426 update_option( 'yaymail_default_email_test', $email );
427
428 $html = $template->get_content( $render_data );
429
430 $headers = "Content-Type: text/html\r\n";
431 $subject = __( 'Email Test', 'yaymail' );
432
433 if ( $is_wc_email ) {
434 $class_wc_email = \WC_Emails::instance();
435 $send_mail = $class_wc_email->send( $email, $subject, $html, $headers, [] );
436 } else {
437 // $html is already the fully-rendered wp-core-mail template output.
438 // Without this marker, WpMail::custom_wp_mail_body() (hooked on the
439 // 'wp_mail' filter, meant to wrap *raw* WP core messages like a
440 // password-reset email) can't tell it apart from unrendered content
441 // and wraps it in the template a second time -- the same marker
442 // AddonWpMailController::woocommerce_mail_content() uses for real
443 // WooCommerce sends.
444 $html = '<!-- yaymail:wp-has-template-email-content -->' . $html;
445 $send_mail = wp_mail( $email, $subject, $html, $headers, [] );
446 }
447 if ( ! $send_mail ) {
448 return wp_send_json_error( [ 'mess' => __( 'Can\'t send email', 'yaymail' ) ] );
449 }
450
451 wp_send_json_success(
452 [
453 'email' => $email,
454 'send_mail_success' => $send_mail,
455 ]
456 );
457 } catch ( \Error $error ) {
458 yaymail_get_logger( $error );
459 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
460 } catch ( \Exception $exception ) {
461 yaymail_get_logger( $exception );
462 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
463 }//end try
464 }
465
466 public function preview_mail() {
467 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
468 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
469 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
470 }
471 try {
472 $order_id = ! empty( $_POST['order_id'] ) ? sanitize_text_field( wp_unslash( $_POST['order_id'] ) ) : 'sample_order';
473 $template_data = isset( $_POST['template_data'] ) ? $this->sanitize( json_decode( wp_unslash( $_POST['template_data'] ), true ) ) : []; //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
474 $unsaved_settings = isset( $_POST['unsaved_settings'] ) ? $this->sanitize( wp_unslash( $_POST['unsaved_settings'] ) ) : []; //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
475
476 if ( empty( $template_data ) ) {
477 return wp_send_json_error( [ 'mess' => __( 'Can\'t find template', 'yaymail' ) ] );
478 }
479
480 if ( empty( $order_id ) ) {
481 return wp_send_json_error( [ 'mess' => __( 'Can\'t find order', 'yaymail' ) ] );
482 }
483
484 $template = new YayMailTemplate( $template_data['name'] );
485
486 if ( ! empty( $unsaved_settings ) ) {
487 global $yaymail_unsaved_settings;
488 $yaymail_unsaved_settings = $unsaved_settings;
489 }
490
491 $template->set_background_color( $template_data['background_color'] );
492 $template->set_text_link_color( $template_data['text_link_color'] );
493 $template->set_global_header_settings( $template_data['global_header_settings'] );
494 $template->set_global_footer_settings( $template_data['global_footer_settings'] );
495 $template->set_elements( $template_data['elements'] );
496
497 $render_data = [];
498
499 if ( empty( $order_id ) || ( 'sample_order' === $order_id ) ) {
500 $render_data['is_sample'] = true;
501 } else {
502 $render_data['order'] = wc_get_order( $order_id );
503 }
504
505 $render_data['is_customized_preview'] = true;
506 // check if email template on preview and send test mail
507
508 $html = $template->get_content( $render_data );
509
510 if ( strpos( $template->get_name(), 'wp-core-' ) !== 0 ) {
511 // TODO: render with passing settings
512 $current_email = null;
513 $subject = 'Sample Subject';
514 $emails = wc()->mailer()->emails;
515 foreach ( $emails as $email ) {
516 if ( $email->id === $template_data['name'] ) {
517 $current_email = $email;
518 if ( method_exists( $current_email, 'set_object' ) ) {
519 if ( ! empty( $render_data['order'] ) && is_a( $render_data['order'], '\WC_Order' ) ) {
520 $current_email->set_object( $render_data['order'] );
521 } else {
522 $current_email->set_object( Helpers::get_dummy_order() );
523 }
524 }
525 break;
526 }
527 }
528 }
529
530 if ( ! empty( $current_email ) ) {
531 $subject = $current_email->get_subject();
532 }
533 $email_address = wp_get_current_user()->user_email ?? '[email protected]';
534
535 wp_send_json_success(
536 [
537 'html' => $html,
538 'subject' => $subject,
539 'email_address' => $email_address,
540 ]
541 );
542 } catch ( \Error $error ) {
543 yaymail_get_logger( $error );
544 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
545 } catch ( \Exception $exception ) {
546 yaymail_get_logger( $exception );
547 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
548 }//end try
549 }
550
551 public function preview_mail_for_woo() {
552 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
553 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
554 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
555 }
556 try {
557 $template_name = isset( $_POST['template_name'] ) ? sanitize_text_field( wp_unslash( $_POST['template_name'] ) ) : '';
558 $search_order_id = isset( $_POST['search_order_id'] ) ? sanitize_text_field( wp_unslash( $_POST['search_order_id'] ) ) : null;
559 $email_address = isset( $_POST['email_address'] ) ? sanitize_text_field( wp_unslash( $_POST['email_address'] ) ) : '';
560 $variant = yaymail_sanitize_template_variant( isset( $_POST['variant'] ) ? sanitize_text_field( wp_unslash( $_POST['variant'] ) ) : '' );
561
562 $email_preview_output = PreviewEmail\PreviewEmailWoo::email_preview_output( $search_order_id, $template_name, $email_address, $variant );
563
564 $email_preview_output = apply_filters( 'yaymail_preview_email', $email_preview_output, $search_order_id, $template_name, $email_address, $variant );
565
566 $send_mail = false;
567
568 if ( ! empty( $email_address ) && ! empty( $email_preview_output['html'] ) ) {
569 $headers = "Content-Type: text/html\r\n";
570 $class_wc_email = \WC_Emails::instance();
571 $subject = __( 'Email Preview', 'yaymail' );
572 $send_mail = $class_wc_email->send( $email_address, $subject, $email_preview_output['html'], $headers, [] );
573 if ( ! $send_mail ) {
574 return wp_send_json_error( [ 'mess' => __( 'Can\'t send email', 'yaymail' ) ] );
575 }
576 }
577
578 wp_send_json_success(
579 [
580 'html' => ! empty( $email_preview_output['html'] ) ? $email_preview_output['html'] : __( 'No email content found', 'yaymail' ),
581 'subject' => ! empty( $email_preview_output['subject'] ) ? $email_preview_output['subject'] : __( 'No subject found', 'yaymail' ),
582 'is_disabled_send_mail' => ! empty( $email_preview_output['is_disabled_send_mail'] ) ? $email_preview_output['is_disabled_send_mail'] : false,
583 'send_mail_success' => $send_mail,
584 ]
585 );
586 } catch ( \Error $error ) {
587 yaymail_get_logger( $error );
588 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
589 } catch ( \Exception $exception ) {
590 yaymail_get_logger( $exception );
591 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
592 }//end try
593 }
594
595 public function export_templates() {
596 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
597 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
598 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
599 }
600 try {
601 $templates = isset( $_POST['templates'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['templates'] ) ) : [];
602 // TODO: sanitize
603 $default = [
604 'post_type' => 'yaymail_template',
605 'post_status' => [ 'publish', 'pending', 'future' ],
606 'posts_per_page' => '-1',
607 'meta_query' => [
608 [
609 'key' => YayMailTemplate::META_KEYS['name'],
610 'value' => $templates,
611 'compare' => 'IN',
612 ],
613 // Export the default design only; import keys on name and would collapse variants onto it.
614 [
615 'key' => YayMailTemplate::META_KEYS['variant'],
616 'compare' => 'NOT EXISTS',
617 ],
618 ],
619 ];
620 $export_data = [];
621 $query = new \WP_Query( $default );
622 if ( $query->have_posts() ) {
623 $posts = $query->get_posts();
624 foreach ( $posts as $post ) {
625 $template_name = get_post_meta( $post->ID, YayMailTemplate::META_KEYS['name'], true );
626 $elements = get_post_meta( $post->ID, YayMailTemplate::META_KEYS['elements'], true );
627 $language = get_post_meta( $post->ID, YayMailTemplate::META_KEYS['language'], true );
628 $text_link_color = get_post_meta( $post->ID, YayMailTemplate::META_KEYS['text_link_color'], true );
629 $background_color = get_post_meta( $post->ID, YayMailTemplate::META_KEYS['background_color'], true );
630 $content_background_color = get_post_meta( $post->ID, YayMailTemplate::META_KEYS['content_background_color'], true );
631 $content_text_color = get_post_meta( $post->ID, YayMailTemplate::META_KEYS['content_text_color'], true );
632 $title_color = get_post_meta( $post->ID, YayMailTemplate::META_KEYS['title_color'], true );
633 $file_name = "{$template_name}.json";
634 // Every WP-core template (e.g. wp-core-mail) is saved with a
635 // non-empty language meta (the site locale), unlike WooCommerce
636 // templates -- gating on "no language" here used to silently
637 // drop every WP-core template from the export with no error.
638 // find_by_name() below only ever looks templates up by name, so
639 // there's no separate per-language row to disambiguate against.
640 $export_data[] = [
641 'file_name' => $file_name,
642 'templates_data' => [
643 'template' => $template_name,
644 'elements' => $elements,
645 'language' => $language,
646 'text_link_color' => $text_link_color,
647 'background_color' => $background_color,
648 'content_background_color' => $content_background_color,
649 'content_text_color' => $content_text_color,
650 'title_color' => $title_color,
651 ],
652 ];
653 }//end foreach
654 }//end if
655 wp_reset_postdata();
656 wp_send_json_success(
657 [
658 'message' => __( 'Export successfully', 'yaymail' ),
659 'data' => $export_data,
660 'file_name' => $this->export_file_name_prefix() . '_customizer_templates_' . gmdate( 'm-d-Y' ),
661 ]
662 );
663 } catch ( \Error $error ) {
664 yaymail_get_logger( $error );
665 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
666 } catch ( \Exception $exception ) {
667 yaymail_get_logger( $exception );
668 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
669 }//end try
670 }
671
672 public function import_templates() {
673 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
674 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
675 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
676 }
677 try {
678 if ( ! empty( $_FILES ) ) {
679 $result = $this->process_import( $_FILES );
680 wp_send_json_success(
681 [
682 'imported_data' => $result,
683 ]
684 );
685 } else {
686 wp_send_json_error( [ 'message' => __( 'Can\'t find import files.', 'yaymail' ) ] );
687 }
688 } catch ( \Error $error ) {
689 yaymail_get_logger( $error );
690 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
691 } catch ( \Exception $exception ) {
692 yaymail_get_logger( $exception );
693 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
694 }
695 }
696
697 public function process_import( $files ) {
698 global $wp_filesystem;
699 if ( empty( $wp_filesystem ) ) {
700 require_once ABSPATH . '/wp-admin/includes/file.php';
701 WP_Filesystem();
702 }
703 $imported_templates = [];
704 $is_legacy = false;
705 foreach ( $files as $file ) {
706 if ( isset( $file['type'] ) ) {
707 if ( 'application/json' === $file['type'] ) {
708 if ( ! empty( $file['tmp_name'] ) ) {
709 $file_tmp_name = sanitize_text_field( $file['tmp_name'] );
710 $file_content = $wp_filesystem->get_contents( $file_tmp_name );
711 $file_content = json_decode( $file_content, true );
712 if ( ! isset( $file_content['template'] ) ) {
713 if ( isset( $file_content['yaymailTemplateExport'] ) ) {
714 $is_legacy = true;
715 $imported_templates = array_merge( $imported_templates, $this->process_import_legacy( $file_content ) );
716 } else {
717 continue;
718 }
719 } else {
720 $update_result = $this->processing_import_update_data( $file_content );
721 if ( ! empty( $update_result ) ) {
722 $imported_templates[] = $update_result;
723 }
724 }
725 }//end if
726 }//end if
727 }//end if
728 }//end foreach
729 if ( $is_legacy ) {
730 MainMigration::get_instance()->migrate( true );
731 }
732 return $imported_templates;
733 }
734
735 public function process_import_legacy( $file_content ) {
736 $updated_templates = [];
737 // Import templates
738 foreach ( $file_content['yaymailTemplateExport'] as $template ) {
739 $updated_result = $this->processing_import_update_data( $template, true );
740 if ( ! empty( $updated_result ) ) {
741 $updated_templates[] = $updated_result;
742 }
743 }//end foreach
744 // Import settings
745 $import_settings = isset( $file_content['yaymail_settings'] ) ? $file_content['yaymail_settings'] : [];
746 if ( ! empty( $import_settings ) ) {
747 update_option( 'yaymail_settings', $import_settings );
748 }
749 return $updated_templates;
750 }
751
752 public function processing_import_update_data( $data, $is_legacy = false ) {
753 $template_name = $data['template'] ?? null;
754 $elements = $data['elements'] ?? null;
755 $text_link_color = $data['text_link_color'] ?? null;
756 $background_color = $data['background_color'] ?? null;
757 $title_color = $data['title_color'] ?? null;
758 $content_background_color = $data['content_background_color'] ?? null;
759 $content_text_color = $data['content_text_color'] ?? null;
760
761 if ( empty( $template_name ) ) {
762 return null;
763 }
764
765 $template = new YayMailTemplate( $template_name );
766 if ( ! $template->is_exists() ) {
767 return null;
768 }
769
770 $template->set_elements( $elements );
771 $template->set_text_link_color( $text_link_color );
772 $template->set_background_color( $background_color );
773 $template->set_title_color( $title_color );
774 $template->set_content_background_color( $content_background_color );
775 $template->set_content_text_color( $content_text_color );
776 if ( $is_legacy ) {
777 $template->set_status( 'inactive' );
778 }
779
780 $template->save();
781
782 wp_reset_postdata();
783
784 return [
785 'template_name' => $template_name,
786 ];
787 }
788
789 /**
790 * Process a custom hook request and generate HTML content.
791 *
792 * This function handles a custom hook request, generates HTML content based on the provided data and attributes.
793 * It is designed to be used as an AJAX callback.
794 *
795 * @example $_POST['data'] =
796 * [
797 * 'template_data' => YayMail\YayMailTemplate,
798 * 'order_id' => 'sample_order',
799 * 'attributes' => [
800 * [
801 * 'name' => 'hook',
802 * 'value' => 'your_hook'
803 * ],
804 * [
805 * 'name' => 'background_color',
806 * 'value' => '#ffffff'
807 * ]
808 * ]
809 * ]
810 *
811 * @return void This function sends a JSON response with HTML content or error messages.
812 */
813 public function get_custom_hook_html() {
814 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
815 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
816 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
817 }
818 try {
819 $attributes = isset( $_POST['data']['attributes'] ) ? $_POST['data']['attributes'] : []; // phpcs:ignore
820 if ( empty( $attributes ) ) {
821 return wp_send_json_error( [ 'mess' => __( 'Attributes empty', 'yaymail' ) ] );
822 }
823
824 /**
825 * Build data for shortcode
826 */
827 $template_model = \YayMail\Models\TemplateModel::get_instance();
828 $data = [];
829 if ( ! empty( $_POST['data']['template_data'] ) ) {
830 $data = \YayMail\Models\TemplateModel::get_shortcode_executor_data( sanitize_text_field( wp_unslash( $_POST['data']['template_data'] ) ), sanitize_text_field( wp_unslash( $_POST['data']['order_id'] ) ) );
831
832 $data['template']->set_props( sanitize_text_field( wp_unslash( $_POST['data']['template_data'] ) ) );
833 }
834
835 $hook_shortcodes = \YayMail\Shortcodes\HookShortcodes::get_instance();
836 $html = $hook_shortcodes->yaymail_handle_custom_hook_shortcode( $data, $attributes );
837 wp_send_json_success(
838 [
839 'html' => $html,
840 ]
841 );
842 } catch ( \Error $error ) {
843 yaymail_get_logger( $error );
844 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
845 } catch ( \Exception $exception ) {
846 yaymail_get_logger( $exception );
847 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
848 }//end try
849 }
850
851 /**
852 * Get all needed data when load YayMail template to customizer.
853 */
854 public function get_template_data_onload() {
855 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
856 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
857 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
858 }
859 try {
860 $setting_model = SettingModel::get_instance();
861 $settings_data = $setting_model->find_all();
862
863 $template_name = isset( $_POST['data']['template_name'] ) ? sanitize_text_field( wp_unslash( $_POST['data']['template_name'] ) ) : 'new_order';
864 $order_id = isset( $_POST['data']['order_id'] ) ? sanitize_text_field( wp_unslash( $_POST['data']['order_id'] ) ) : 'sample_order';
865 $variant = yaymail_sanitize_template_variant( isset( $_POST['data']['variant'] ) ? sanitize_text_field( wp_unslash( $_POST['data']['variant'] ) ) : '' );
866
867 $template_model = TemplateModel::get_instance();
868
869 $shortcodes_data = $template_model->get_shortcodes_by_template_name_and_order_id( $template_name, $order_id );
870
871 $templates_data = apply_filters( 'yaymail_get_all_templates', $template_model->find_all() );
872
873 $selected_template_data = $template_model->find_by_name( $template_name, '', $variant );
874
875 $elements_data = TemplateModel::get_elements_for_template( $template_name );
876
877 $revision_model = RevisionModel::get_instance();
878 $revisions_data = $revision_model->get_by_template( $template_name, $variant );
879
880 wp_send_json_success(
881 [
882 'settings_data' => $settings_data,
883 'templates_data' => $templates_data,
884 'selected_template_data' => $selected_template_data,
885 'elements_data' => $elements_data,
886 'revisions_data' => $revisions_data,
887 'shortcodes_data' => $shortcodes_data,
888 ]
889 );
890 } catch ( \Error $error ) {
891 yaymail_get_logger( $error );
892 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
893 } catch ( \Exception $exception ) {
894 yaymail_get_logger( $exception );
895 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
896 } catch ( \Throwable $throwable ) {
897 yaymail_get_logger( $throwable );
898 wp_send_json_error( [ 'mess' => $throwable->getMessage() ] );
899 }//end try
900 }
901
902 public function yaymail_review() {
903 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
904 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
905 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
906 }
907 try {
908
909 $yaymail_review = update_option( 'yaymail_review', true );
910
911 wp_send_json_success(
912 [
913 'reviewed' => $yaymail_review,
914 ]
915 );
916
917 } catch ( \Error $error ) {
918 yaymail_get_logger( $error );
919 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
920 } catch ( \Exception $exception ) {
921 yaymail_get_logger( $exception );
922 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
923 }
924 }
925
926 public function change_ghf_tour() {
927 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
928 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
929 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
930 }
931
932 try {
933 $next_move = isset( $_POST['next_move'] ) ? sanitize_text_field( wp_unslash( $_POST['next_move'] ) ) : 'initial';
934 $ghf_tour = update_option( 'yaymail_ghf_tour', $next_move );
935
936 wp_send_json_success(
937 [
938 'ghf_tour' => $ghf_tour,
939 ]
940 );
941 } catch ( \Error $error ) {
942 yaymail_get_logger( $error );
943 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
944 } catch ( \Exception $exception ) {
945 yaymail_get_logger( $exception );
946 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
947 }
948 }
949
950 public function dismiss_multi_select_notice() {
951 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
952 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
953 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
954 }
955
956 try {
957 update_option( 'yaymail_show_multi_select_notice', 'no' );
958
959 wp_send_json_success(
960 [
961 'show_multi_select_notice' => 'no',
962 ]
963 );
964 } catch ( \Error $error ) {
965 yaymail_get_logger( $error );
966 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
967 } catch ( \Exception $exception ) {
968 yaymail_get_logger( $exception );
969 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
970 }
971 }
972
973 public function dismiss_new_element_notification() {
974 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
975 if ( ! wp_verify_nonce( $nonce, 'yaymail_frontend_nonce' ) ) {
976 return wp_send_json_error( [ 'mess' => __( 'Verify nonce failed', 'yaymail' ) ] );
977 }
978
979 $elements = isset( $_POST['elements'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['elements'] ) ) : [];
980
981 $viewed_new_elements = get_option( 'yaymail_viewed_new_elements', [] );
982 $viewed_new_elements = array_unique( array_merge( $viewed_new_elements, $elements ) );
983
984 try {
985 update_option( 'yaymail_viewed_new_elements', $viewed_new_elements );
986
987 wp_send_json_success(
988 [
989 'viewed_new_elements' => $viewed_new_elements,
990 ]
991 );
992 } catch ( \Error $error ) {
993 wp_send_json_error( [ 'mess' => $error->getMessage() ] );
994 } catch ( \Exception $exception ) {
995 yaymail_get_logger( $exception );
996 wp_send_json_error( [ 'mess' => $exception->getMessage() ] );
997 }
998 }
999 }