PluginProbe
YayMail – WooCommerce Email Customizer / 4.4.6
YayMail – WooCommerce Email Customizer v4.4.6
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 / Models / TemplateModel.php

TemplateModel.php in YayMail – WooCommerce Email Customizer 4.4.6, at src/Models/TemplateModel.php

749 lines 33.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace YayMail\Models;
4
5 use YayMail\Abstracts\BaseElement;
6 use YayMail\Elements\ElementsHelper;
7 use YayMail\Elements\Heading;
8 use YayMail\Elements\Logo;
9 use YayMail\Elements\Text;
10 use YayMail\Elements\Footer;
11 use YayMail\Integrations\TranslationModule;
12 use YayMail\YayMailTemplate;
13 use YayMail\Utils\SingletonTrait;
14 use YayMail\PostTypes\TemplatePostType;
15 use YayMail\Shortcodes\ShortcodesExecutor;
16 use YayMail\SupportedPlugins;
17 use YayMail\Utils\TemplateHelpers;
18 /**
19 * Template Model
20 *
21 * @method static TemplateModel get_instance()
22 */
23 class TemplateModel {
24 use SingletonTrait;
25
26 private const POST_TABLE = 'posts';
27 private const POST_META_TABLE = 'postmeta';
28 private static $meta_keys = YayMailTemplate::META_KEYS;
29
30 /** @var string[]|null Per-request memo for get_active_default_template_names(). */
31 private static $active_default_template_names = null;
32
33 /**
34 * Query post with given arguments.
35 * Build query string base on given arguments
36 * then use $wpdb to query it.
37 *
38 * Returns post id or null if not found
39 *
40 * @param array $args Given args.
41 */
42 private static function query_template( $args = [] ) {
43
44 if ( ! is_array( $args ) ) {
45 return null;
46 }
47
48 global $wpdb;
49 $posts = $wpdb->prefix . self::POST_TABLE;
50 $post_meta = $wpdb->prefix . self::POST_META_TABLE;
51 $post_type = TemplatePostType::POST_TYPE;
52
53 $clauses = [
54 'select' => "SELECT posts.ID FROM $posts AS posts",
55 'join' => "JOIN $post_meta AS postmeta ON ( posts.ID = postmeta.post_id )",
56 'where' => "WHERE posts.post_type = '$post_type' AND posts.post_status IN ('publish', 'pending', 'future')",
57 ];
58
59 if ( isset( $args['name'] ) ) {
60 $template_name = $args['name'];
61 $template_meta_key = self::$meta_keys['name'];
62 $clauses['where'] .= $wpdb->prepare(
63 ' AND ( postmeta.meta_key=%s AND postmeta.meta_value = %s )',
64 $template_meta_key,
65 $template_name
66 );
67 }
68
69 // Variant clause is always present so default lookups never return a variant post.
70 $variant_meta_key = self::$meta_keys['variant'];
71 if ( isset( $args['variant'] ) && '' !== $args['variant'] ) {
72 $clauses['join'] .= " JOIN $post_meta AS postmeta3 ON ( posts.ID = postmeta3.post_id )";
73 $clauses['where'] .= $wpdb->prepare(
74 ' AND ( postmeta3.meta_key=%s AND postmeta3.meta_value = %s )',
75 $variant_meta_key,
76 $args['variant']
77 );
78 } else {
79 $clauses['join'] .= $wpdb->prepare(
80 " LEFT JOIN $post_meta AS postmeta3 ON ( posts.ID = postmeta3.post_id AND postmeta3.meta_key = %s )", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
81 $variant_meta_key
82 );
83 $clauses['where'] .= " AND ( postmeta3.meta_value IS NULL OR postmeta3.meta_value = '' )";
84 }
85
86 // Oldest post wins when duplicates exist so customizer and send target the same row.
87 $query_string = implode( ' ', $clauses ) . ' ORDER BY posts.ID ASC LIMIT 1';
88 $post_id = $wpdb->get_var( $query_string ); //phpcs:ignore
89
90 return $post_id;
91 }
92
93 /**
94 * Finds all YayMail templates and retrieves relevant information about each template.
95 *
96 * @return array An array of YayMail templates with their corresponding data.
97 * Each template is represented as an associative array containing the following keys:
98 * - 'key': The unique identifier for the template (same as 'id').
99 * - 'template_title': The title of the template.
100 * - 'status': The status of the template.
101 * - 'recipient': The recipient associated with the template.
102 * - 'source': The plugin name that the template originates from.
103 * - 'last_updated': The date and time of the last modification to the template
104 * (formatted according to the WordPress date and time settings) or 'N/A' if not available.
105 * - 'id': The unique identifier for the template (same as 'key').
106 * - '...': Other template-specific data retrieved from YayMail.
107 */
108 public static function find_all() {
109 $templates = [];
110
111 $excluded_templates = apply_filters( 'yaymail_excluded_templates', [ 'yaymail_global_header_footer' ] );
112
113 if ( yaymail_is_wc_installed() ) {
114 /* Wc Emails, may or may not be supported by us */
115 $wc_emails = \WC_Emails::instance()->get_emails();
116
117 foreach ( $wc_emails as $wc_email ) {
118 $template_id = $wc_email->id ?? null;
119
120 if ( ! isset( $template_id ) ) {
121 continue;
122 }
123
124 if ( in_array( $template_id, $excluded_templates, true ) ) {
125 continue;
126 }
127
128 if ( SupportedPlugins::get_instance()->get_support_info( $template_id )['status'] !== 'already_supported' ) {
129 // Templates is currently not editable, but could be supported by pro/addon
130 $template_data = self::get_uneditable_template( $wc_email, $templates );
131 $templates[] = $template_data;
132 continue;
133 }
134
135 $email_data = SupportedPlugins::get_instance()->get_yaymail_template_data( $template_id );
136 $template_data = self::get_yaymail_template( $email_data );
137 if ( isset( $template_data ) ) {
138 unset( $template_data['elements'] );
139 $templates[] = $template_data;
140 }
141 }//end foreach
142 } else {
143 $templates = [];
144 }//end if
145
146 // Make sure it will show templates for Automatewoo ...
147 // Because those templates don't appear in wc_emails
148 $template_ids = array_map( fn( $template ) => $template['name'], $templates );
149 foreach ( yaymail_get_emails() as $yaymail_email ) {
150 $template_id = $yaymail_email->get_id();
151 if ( in_array( $template_id, $excluded_templates, true ) ) {
152 continue;
153 }
154 if ( in_array( $template_id, $template_ids, true ) ) {
155 continue;
156 }
157
158 $email_data = SupportedPlugins::get_instance()->get_yaymail_template_data( $template_id );
159 $template_data = self::get_yaymail_template( $email_data );
160 if ( isset( $template_data ) ) {
161 unset( $template_data['elements'] );
162 $templates[] = $template_data;
163 }
164 }
165
166 return $templates;
167 }
168
169 private static function get_yaymail_template( $email_data ) {
170 /* Template is supported and ready to be edited */
171 $template = new YayMailTemplate( $email_data->get_id() );
172 if ( ! $template->is_exists() || empty( $email_data ) ) {
173 return null;
174 }
175
176 $template_data = $template->get_data();
177 $template_data['elements'] = $template->get_elements();
178 $template_data['key'] = $template_data['id'];
179 $template_data['template_title'] = $email_data->get_title();
180 $template_data['status'] = $template_data['status'];
181 $template_data['recipient'] = $email_data->get_recipient();
182 $template_data['source'] = $email_data->get_source()['plugin_name'] ?? '';
183 $template_data['last_updated'] = isset( get_post( $template_data['id'] )->post_modified ) ? date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( get_post( $template_data['id'] )->post_modified ) ) : esc_html__( 'N/A', 'yaymail' );
184 return $template_data;
185 }
186
187 /**
188 * Get template data for template that is currently not editable by YayMail and YayMail addons
189 * (It might or might not be supported by YayMail)
190 *
191 * @param object $wc_email The WooCommerce email object.
192 * @param array $templates The list of templates.
193 * @return array The template data.
194 */
195 private static function get_uneditable_template( $wc_email, $templates ): array {
196
197 $existed_post_ids = array_map( fn( $template ) => $template['id'], $templates );
198 do {
199 // Create a mockup post id
200 $mock_post_id = wp_rand( 1000, 10000 );
201 } while ( in_array(
202 $mock_post_id,
203 $existed_post_ids,
204 true
205 ) );
206
207 $template_id = $wc_email->id;
208 $support_info = SupportedPlugins::get_instance()->get_support_info( $template_id );
209 $support_status = $support_info['status'];
210 $source = $wc_email->source ?? $support_info['addon']['plugin_name'] ?? '';
211
212 // Get title
213
214 $support_status_labels = [
215 'pro_needed' => __( 'Pro', 'yaymail' ),
216 'addon_needed' => __( 'Addon', 'yaymail' ),
217 'not_supported' => __( 'N/A', 'yaymail' ),
218 ];
219
220 $template_title = $wc_email->title;
221 if ( isset( $support_status_labels[ $support_status ] ) ) {
222 $template_title .= ' (' . $support_status_labels[ $support_status ] . ')';
223 }
224
225 // Get last_updated
226 $post = get_post( $template_id );
227 $last_updated = $post && isset( $post->post_modified )
228 ? date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $post->post_modified ) )
229 : esc_html__( 'N/A', 'yaymail' );
230
231 return [
232 'id' => $mock_post_id,
233 'key' => $mock_post_id,
234 'name' => $template_id,
235 'support_status' => $support_status,
236 'addon_info' => $support_info['addon'],
237 'template_title' => $template_title,
238 'status' => 'inactive',
239 'recipient' => yaymail_get_email_recipient_zone( $wc_email ),
240 'source' => $source,
241 'last_updated' => $last_updated,
242 ];
243 }
244
245 /**
246 * Find template by given name
247 * Returns null if not found
248 *
249 * @param string $name
250 */
251 /**
252 * @param string $name
253 * @param string $language Unused in Lite; kept so callers match the Pro signature.
254 * @param string $variant Variant slug, '' for the default design.
255 */
256 public static function find_by_name( $name, $language = '', $variant = '' ) {
257 $template_id = self::query_template(
258 [
259 'name' => $name,
260 'variant' => $variant,
261 ]
262 );
263 if ( empty( $template_id ) ) {
264 $support_info = SupportedPlugins::get_instance()->get_support_info( $name );
265 return [
266 'support_status' => $support_info['status'] ?? '',
267 'addon_info' => $support_info['addon'] ?? '',
268 ];
269 }
270 return self::get_meta_data( $template_id, $name );
271 }
272
273 /**
274 * Find template by post id
275 * Returns null if not found
276 *
277 * @param number $id
278 */
279 public static function find_by_id( $id ) {
280 if ( ! empty( $id ) && ! is_null( get_post( $id ) ) ) {
281 return self::get_meta_data( $id );
282 }
283 return null;
284 // Returns null on failure
285 }
286
287 public static function insert( $args = false ) {
288 // Insert template data to posts table
289 $template_args = [
290 'post_content' => '',
291 'post_type' => TemplatePostType::POST_TYPE,
292 'post_title' => '',
293 'post_status' => 'publish',
294 ];
295 $new_template_id = wp_insert_post( $template_args );
296
297 // Insert data to post meta table
298 update_post_meta( $new_template_id, self::$meta_keys['name'], $args['name'] );
299 update_post_meta( $new_template_id, self::$meta_keys['elements'], $args['elements'] );
300 update_post_meta( $new_template_id, self::$meta_keys['status'], 'inactive' );
301 update_post_meta( $new_template_id, self::$meta_keys['background_color'], YAYMAIL_COLOR_BACKGROUND_DEFAULT );
302 update_post_meta( $new_template_id, self::$meta_keys['is_v4_supported'], true );
303 if ( ! empty( $args['text_link_color'] ) ) {
304 update_post_meta( $new_template_id, self::$meta_keys['text_link_color'], YAYMAIL_COLOR_WC_DEFAULT );
305 }
306 if ( ! empty( $args['content_background_color'] ) ) {
307 update_post_meta( $new_template_id, self::$meta_keys['content_background_color'], '#ffffff' );
308 }
309 if ( ! empty( $args['content_text_color'] ) ) {
310 update_post_meta( $new_template_id, self::$meta_keys['content_text_color'], '#000000' );
311 }
312 if ( ! empty( $args['title_color'] ) ) {
313 update_post_meta( $new_template_id, self::$meta_keys['title_color'], '#000000' );
314 }
315 if ( ! empty( $args['global_header_settings'] ) ) {
316 update_post_meta( $new_template_id, self::$meta_keys['global_header_settings'], $args['global_header_settings'] );
317 }
318 if ( ! empty( $args['global_footer_settings'] ) ) {
319 update_post_meta( $new_template_id, self::$meta_keys['global_footer_settings'], $args['global_footer_settings'] );
320 }
321 if ( isset( $args['variant'] ) && '' !== $args['variant'] ) {
322 update_post_meta( $new_template_id, self::$meta_keys['variant'], $args['variant'] );
323 }
324
325 // Hook insert data of integrations
326
327 return self::get_meta_data( $new_template_id );
328 }
329
330 public static function update( $template_id, $data, $is_save_revision = false ) {
331 if ( isset( $data['elements'] ) && is_array( $data['elements'] ) && isset( self::$meta_keys['elements'] ) ) {
332 $elements_data = TemplateHelpers::sanitize_elements_recursive( $data['elements'] );
333 update_post_meta( $template_id, self::$meta_keys['elements'], $elements_data );
334 }
335
336 if ( ! empty( $data['background_color'] ) && isset( self::$meta_keys['background_color'] ) ) {
337 update_post_meta( $template_id, self::$meta_keys['background_color'], $data['background_color'] );
338 }
339
340 if ( ! empty( $data['text_link_color'] ) && isset( self::$meta_keys['text_link_color'] ) ) {
341 update_post_meta( $template_id, self::$meta_keys['text_link_color'], $data['text_link_color'] );
342 }
343
344 if ( ! empty( $data['content_background_color'] ) && isset( self::$meta_keys['content_background_color'] ) ) {
345 update_post_meta( $template_id, self::$meta_keys['content_background_color'], $data['content_background_color'] );
346 }
347
348 if ( ! empty( $data['content_text_color'] ) && isset( self::$meta_keys['content_text_color'] ) ) {
349 update_post_meta( $template_id, self::$meta_keys['content_text_color'], $data['content_text_color'] );
350 }
351
352 if ( ! empty( $data['title_color'] ) && isset( self::$meta_keys['title_color'] ) ) {
353 update_post_meta( $template_id, self::$meta_keys['title_color'], $data['title_color'] );
354 }
355
356 if ( isset( $data['status'] ) && isset( self::$meta_keys['status'] ) ) {
357 update_post_meta( $template_id, self::$meta_keys['status'], $data['status'] );
358 }
359
360 if ( ! empty( $data['global_header_settings'] ) && isset( self::$meta_keys['global_header_settings'] ) ) {
361 update_post_meta( $template_id, self::$meta_keys['global_header_settings'], $data['global_header_settings'] );
362 }
363
364 if ( ! empty( $data['global_footer_settings'] ) && isset( self::$meta_keys['global_footer_settings'] ) ) {
365 update_post_meta( $template_id, self::$meta_keys['global_footer_settings'], $data['global_footer_settings'] );
366 }
367
368 if ( isset( $data['preheader'] ) && isset( self::$meta_keys['preheader'] ) ) {
369 update_post_meta( $template_id, self::$meta_keys['preheader'], sanitize_text_field( $data['preheader'] ) );
370 }
371
372 // Update post_modified
373 $post_data = [
374 'ID' => $template_id,
375 'post_modified' => current_time( 'mysql' ),
376 'post_modified_gmt' => current_time( 'mysql', 1 ),
377 ];
378 wp_update_post( $post_data, true );
379
380 if ( $is_save_revision ) {
381 try {
382 $revision_model = RevisionModel::get_instance();
383 $new_revision = $revision_model->save( $template_id, $data );
384 } catch ( \Throwable $th ) {
385 $new_revision = null;
386 }
387
388 return [
389 'updated_data' => self::get_meta_data( $template_id ),
390 'new_revision' => $new_revision,
391 ];
392 }
393
394 return self::get_meta_data( $template_id );
395 }
396
397 public static function delete( $template_id ) {
398 wp_delete_post( $template_id, true );
399 // TODO: remove relatives.
400 }
401
402 /**
403 * Retrieve the global header and footer elements.
404 *
405 * @return array An array containing the global header and footer elements:
406 * - 'global_header_elements': array.
407 * - 'global_footer_elements': array.
408 */
409 public static function get_global_header_and_footer( $language = '', $template_name = 'yaymail_global_header_footer' ) {
410 $query_args = [
411 'name' => $template_name,
412 'language' => in_array( $language, [ 'en', 'en_US' ], true ) ? '' : $language,
413 ];
414 $template_id = self::query_template( $query_args );
415 if ( empty( $template_id ) ) {
416 self::insert(
417 [
418 'name' => $template_name,
419 'elements' => yaymail_get_default_elements( $template_name ),
420 'language' => $language,
421 ]
422 );
423 $template_id = self::query_template( $query_args );
424 }
425 $retrieved_meta_data = self::get_meta_data( $template_id );
426 $elements = isset( $retrieved_meta_data['elements'] ) ? $retrieved_meta_data['elements'] : [];
427
428 if ( empty( $elements ) ) {
429 /**
430 * Get default elements
431 */
432 $global_header_footer_instance = \YayMail\Emails\GlobalHeaderFooter::get_instance();
433 $elements = $global_header_footer_instance->get_default_elements();
434 }
435
436 $divider_index = array_search( 'skeleton_divider', array_column( $elements, 'type' ), true );
437
438 $global_header_elements = [];
439 $global_footer_elements = [];
440
441 if ( false !== $divider_index ) {
442 $global_header_elements = array_slice( $elements, 0, $divider_index );
443 $global_footer_elements = array_slice( $elements, $divider_index + 1 );
444 }
445
446 return [
447 'global_header_elements' => $global_header_elements,
448 'global_footer_elements' => $global_footer_elements,
449 ];
450 }
451
452 public static function get_global_headers_and_footers_for_all_available_languages( $template_name = 'yaymail_global_header_footer' ) {
453 $multi_languages_instances = TranslationModule::get_instance()->current_integration;
454
455 if ( ! empty( $multi_languages_instances ) ) {
456 $languages = $multi_languages_instances->get_available_languages();
457 } else {
458 $languages = [ [ 'code' => 'en' ] ];
459 }
460
461 /**
462 * Each language should have 3 fields: code, name, flag
463 *
464 * @Example [
465 * code: 'en',
466 * name: 'English',
467 * flag: 'http://localhost:8080/wp-content/plugins/sitepress-multilingual-cms/res/flags/en.svg'
468 * ]
469 */
470 $result = array_map(
471 function ( $language ) use ( $template_name ) {
472 $code = isset( $language['code'] ) ? $language['code'] : '';
473 $global_header_and_footer = self::get_global_header_and_footer( 'en' !== $code ? $code : '', $template_name );
474
475 return [
476 'language' => $code,
477 'global_header_elements' => $global_header_and_footer['global_header_elements'] ? $global_header_and_footer['global_header_elements'] : [],
478 'global_footer_elements' => $global_header_and_footer['global_footer_elements'] ? $global_header_and_footer['global_footer_elements'] : [],
479 ];
480 },
481 $languages
482 );
483
484 return array_values( $result );
485 }
486
487 /**
488 * Get template meta data from Database
489 *
490 * @param number $template_post_id
491 * @param string $template_name
492 */
493 private static function get_meta_data( $template_post_id, $template_name = null ) {
494
495 if ( empty( $template_name ) ) {
496 $template_name = self::query_meta_data( $template_post_id, self::$meta_keys['name'], '' );
497 }
498 $status = self::query_meta_data( $template_post_id, self::$meta_keys['status'], 'inactive' );
499
500 $post = isset( $template_post_id ) ? get_post( $template_post_id ) : null;
501 $post_modified = isset( $post ) ? $post->post_modified : '';
502
503 // /** For editable templates */
504 $template_elements = self::query_meta_data( $template_post_id, self::$meta_keys['elements'], [] );
505
506 $support_info = SupportedPlugins::get_instance()->get_support_info( $template_name );
507 if ( $support_info['status'] !== 'already_supported' && 'wp-core-edd-password_reset' !== $template_name ) {
508 // Template is not editable
509 $template_elements = self::get_uneditable_template_placeholder_elements( $support_info );
510 } elseif ( isset( $post ) ) {
511 // TODO: how to store global default value
512 $background_color = self::query_meta_data( $template_post_id, self::$meta_keys['background_color'], YayMailTemplate::DEFAULT_DATA['background_color'] );
513 $text_link_color = self::query_meta_data( $template_post_id, self::$meta_keys['text_link_color'], YayMailTemplate::DEFAULT_DATA['text_link_color'] );
514 $title_color = self::query_meta_data( $template_post_id, self::$meta_keys['title_color'], YayMailTemplate::DEFAULT_DATA['title_color'] );
515 $content_background_color = self::query_meta_data( $template_post_id, self::$meta_keys['content_background_color'], YayMailTemplate::DEFAULT_DATA['content_background_color'] );
516 $content_text_color = self::query_meta_data( $template_post_id, self::$meta_keys['content_text_color'], YayMailTemplate::DEFAULT_DATA['content_text_color'] );
517 $global_header_settings = self::query_meta_data( $template_post_id, self::$meta_keys['global_header_settings'], self::get_default_global_header_settings() );
518 $global_footer_settings = self::query_meta_data( $template_post_id, self::$meta_keys['global_footer_settings'], self::get_default_global_footer_settings() );
519 $preheader = self::query_meta_data( $template_post_id, self::$meta_keys['preheader'], YayMailTemplate::DEFAULT_DATA['preheader'] );
520 }
521
522 return [
523 'id' => $template_post_id,
524 'key' => $template_post_id,
525 'name' => $template_name,
526 'elements' => ElementsHelper::filter_available_elements( $template_elements, $template_name ),
527 'status' => $status,
528 'variant' => self::query_meta_data( $template_post_id, self::$meta_keys['variant'], '' ),
529 'title_color' => $title_color ?? '#000000',
530 'background_color' => $background_color ?? YAYMAIL_COLOR_BACKGROUND_DEFAULT,
531 'text_link_color' => $text_link_color ?? YAYMAIL_COLOR_WC_DEFAULT,
532 'content_background_color' => $content_background_color ?? '#ffffff',
533 'content_text_color' => $content_text_color ?? '#000000',
534 'support_status' => $support_info['status'] ?? 'already_supported',
535 'addon_info' => $support_info['addon'] ?? '',
536 'post_modified' => $post_modified,
537 'global_header_settings' => isset( $global_header_settings ) ? $global_header_settings : [],
538 'global_footer_settings' => isset( $global_footer_settings ) ? $global_footer_settings : [],
539 'preheader' => isset( $preheader ) ? $preheader : YayMailTemplate::DEFAULT_DATA['preheader'],
540 'email_subject' => self::get_email_subject( $template_name ),
541 ];
542 }
543
544 /**
545 * Get email subject from WooCommerce email settings.
546 *
547 * @param string $template_name Email / template id.
548 * @return string|null
549 */
550 private static function get_email_subject( $template_name ) {
551 $settings = self::get_wc_email_settings( $template_name );
552 return is_array( $settings ) && isset( $settings['subject'] ) ? (string) $settings['subject'] : null;
553 }
554
555 /**
556 * Save email subject to WooCommerce email settings (same option as Woo admin).
557 *
558 * @param string $template_name Email / template id.
559 * @param string $subject Subject line.
560 */
561 public static function save_email_subject( $template_name, $subject ) {
562 if ( ! is_string( $template_name ) || '' === $template_name ) {
563 return;
564 }
565
566 $settings = self::get_wc_email_settings( $template_name );
567 $settings['subject'] = sanitize_text_field( $subject );
568 update_option( self::get_wc_email_settings_option_name( $template_name ), $settings );
569 }
570
571 /**
572 * @param string $template_name Email / template id.
573 * @return string
574 */
575 private static function get_wc_email_settings_option_name( $template_name ) {
576 return "woocommerce_{$template_name}_settings";
577 }
578
579 /**
580 * @param string $template_name Email / template id.
581 * @return array
582 */
583 private static function get_wc_email_settings( $template_name ) {
584 $settings = get_option( self::get_wc_email_settings_option_name( $template_name ), [] );
585 return is_array( $settings ) ? $settings : [];
586 }
587
588 private static function get_uneditable_template_placeholder_elements( array $support_info ): array {
589 $elements = [];
590
591 $elements[] = BaseElement::reduce_new_element( Logo::get_data() );
592 $elements[] = BaseElement::reduce_new_element( Heading::get_data() );
593 $elements[] = BaseElement::reduce_new_element( Text::get_data() );
594 $elements[] = BaseElement::reduce_new_element( Footer::get_data( [ 'rich_text' => '<p style="font-size: 14px;margin: 0px 0px 16px; text-align: center;">' . esc_html( get_bloginfo( 'name' ) ) . '&nbsp;- Built with <a style="color: ' . esc_attr( YAYMAIL_COLOR_WC_DEFAULT ) . '; font-weight: normal; text-decoration: underline;" href="https://woocommerce.com" target="_blank" rel="noopener">WooCommerce</a></p>' ] ) );
595
596 return $elements;
597 }
598
599
600 private static function get_default_global_footer_settings(): array {
601 $default = YayMailTemplate::DEFAULT_DATA['global_footer_settings'];
602 if ( ! function_exists( 'WC' ) ) {
603 $default['footer_content'] = '<p style="font-size: 14px;margin: 0px 0px 16px; text-align: center;">[yaymail_site_name]</p>';
604 }
605 return apply_filters( 'yaymail_default_global_footer_settings', $default );
606 }
607
608 private static function get_default_global_header_settings(): array {
609 $default = YayMailTemplate::DEFAULT_DATA['global_header_settings'];
610 if ( ! function_exists( 'WC' ) ) {
611 $default['heading_content'] = '<h1 style="font-size: 30px; font-weight: 300; line-height: normal; margin: 0px; color: inherit;">[yaymail_site_name]</h1>';
612 }
613 return apply_filters( 'yaymail_default_global_header_settings', $default );
614 }
615
616 protected static function query_meta_data( $post_id, $meta_name, $default ) {
617 if ( ! isset( $post_id ) ) {
618 return $default;
619 }
620
621 $meta_value = get_post_meta( $post_id, $meta_name, true );
622
623 if ( empty( $meta_value ) ) {
624 return $default;
625 }
626 return $meta_value;
627 }
628
629 public static function get_shortcodes_by_template_name_and_order_id( $template_name, $order_id ) {
630 do_action( 'yaymail_before_order_id_changed', $order_id );
631
632 $shortcodes = yaymail_get_email_shortcodes( $template_name );
633
634 // TODO: check shortcodes
635 // $shortcodes = apply_filters( 'yaymail_extra_shortcodes', $shortcodes, $template_name, $order_id );
636
637 $executor_data = self::get_shortcode_executor_data( $template_name, $order_id );
638 $executor = new ShortcodesExecutor( $shortcodes, $executor_data );
639 return $executor->get_shortcodes_content();
640 }
641
642 /**
643 * Gets data needed for executing a YayMail shortcode.
644 *
645 * @param string $template_name The template name.
646 * @param string $order_id The order ID. Uses sample data if empty or 'sample_order'.
647 * @return array [template, render_data, settings, is_placeholder]
648 */
649 public static function get_shortcode_executor_data( $template_name, $order_id ) {
650
651 return [
652 'template' => new YayMailTemplate( $template_name ),
653 'render_data' => empty( $order_id ) || ( ! empty( $order_id ) && 'sample_order' === $order_id ) ? [ 'is_sample' => true ] : [ 'order' => wc_get_order( $order_id ) ],
654 'settings' => yaymail_settings(),
655 'is_placeholder' => true,
656 ];
657 }
658
659 public static function get_elements_for_template( $template_id ): array {
660 $support_info = SupportedPlugins::get_instance()->get_support_info( $template_id );
661 if ( $support_info['status'] !== 'already_supported' ) {
662 // 'new_order' only exists on WooCommerce sites; fall back to the WP-core
663 // email so unsupported templates still resolve an elements catalog.
664 $fallback_email_id = yaymail_get_email( 'new_order' ) ? 'new_order' : 'wp-core-mail';
665 $elements = array_map(
666 function( $element ) {
667 $element['available'] = false;
668 return $element;
669 },
670 yaymail_get_email_elements_data( $fallback_email_id )
671 );
672 return $elements;
673 }
674 return yaymail_get_email_elements_data( $template_id );
675 }
676
677 /**
678 * Names of every template whose default post is active, from one query.
679 *
680 * "Default post" mirrors query_template( [ 'name' => $name ] ) followed by the
681 * status meta read: no variant, default language ('' / unset / en_US), oldest
682 * post wins, missing status counts as inactive. Memoised for the request so the
683 * core emails can all consult it at init without one lookup each.
684 *
685 * @return string[]
686 */
687 public static function get_active_default_template_names() {
688 if ( null !== self::$active_default_template_names ) {
689 return self::$active_default_template_names;
690 }
691
692 global $wpdb;
693 $posts = $wpdb->prefix . self::POST_TABLE;
694 $post_meta = $wpdb->prefix . self::POST_META_TABLE;
695
696 $rows = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
697 $wpdb->prepare(
698 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
699 "SELECT posts.ID, name.meta_value AS name, status.meta_value AS status, lang.meta_value AS language, variant.meta_value AS variant
700 FROM $posts AS posts
701 JOIN $post_meta AS name ON ( posts.ID = name.post_id AND name.meta_key = %s )
702 LEFT JOIN $post_meta AS status ON ( posts.ID = status.post_id AND status.meta_key = %s )
703 LEFT JOIN $post_meta AS lang ON ( posts.ID = lang.post_id AND lang.meta_key = %s )
704 LEFT JOIN $post_meta AS variant ON ( posts.ID = variant.post_id AND variant.meta_key = %s )
705 WHERE posts.post_type = %s AND posts.post_status IN ('publish', 'pending', 'future')
706 ORDER BY posts.ID ASC",
707 self::$meta_keys['name'],
708 self::$meta_keys['status'],
709 self::$meta_keys['language'],
710 self::$meta_keys['variant'],
711 TemplatePostType::POST_TYPE
712 ),
713 ARRAY_A
714 );
715
716 $seen = [];
717 $active = [];
718 foreach ( (array) $rows as $row ) {
719 if ( '' !== (string) $row['variant'] ) {
720 continue;
721 }
722 if ( ! in_array( (string) $row['language'], [ '', 'en_US' ], true ) ) {
723 continue;
724 }
725 if ( isset( $seen[ $row['name'] ] ) ) {
726 continue;
727 }
728 $seen[ $row['name'] ] = true;
729 if ( 'active' === $row['status'] ) {
730 $active[] = $row['name'];
731 }
732 }
733
734 self::$active_default_template_names = $active;
735 return $active;
736 }
737
738 public static function get_short_data_by_name( $name ) {
739 $template_id = self::query_template( [ 'name' => $name ] );
740 if ( empty( $template_id ) ) {
741 return null;
742 }
743 return [
744 'id' => $template_id,
745 'status' => self::query_meta_data( $template_id, self::$meta_keys['status'], 'inactive' ),
746 ];
747 }
748 }
749