PluginProbe
YayMail – WooCommerce Email Customizer / 4.4.0
YayMail – WooCommerce Email Customizer v4.4.0
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 3.4.2 3.4.3 All 55 releases
yaymail / src / Models / TemplateModel.php

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

549 lines 23.7 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\YayMailTemplate;
12 use YayMail\Utils\SingletonTrait;
13 use YayMail\PostTypes\TemplatePostType;
14 use YayMail\Shortcodes\ShortcodesExecutor;
15 use YayMail\SupportedPlugins;
16 use YayMail\Utils\TemplateHelpers;
17 /**
18 * Template Model
19 *
20 * @method static TemplateModel get_instance()
21 */
22 class TemplateModel {
23 use SingletonTrait;
24
25 private const POST_TABLE = 'posts';
26 private const POST_META_TABLE = 'postmeta';
27 private static $meta_keys = YayMailTemplate::META_KEYS;
28
29 /**
30 * Query post with given arguments.
31 * Build query string base on given arguments
32 * then use $wpdb to query it.
33 *
34 * Returns post id or null if not found
35 *
36 * @param array $args Given args.
37 */
38 private static function query_template( $args = [] ) {
39
40 if ( ! is_array( $args ) ) {
41 return null;
42 }
43
44 global $wpdb;
45 $posts = $wpdb->prefix . self::POST_TABLE;
46 $post_meta = $wpdb->prefix . self::POST_META_TABLE;
47 $post_type = TemplatePostType::POST_TYPE;
48
49 $clauses = [
50 'select' => "SELECT posts.ID FROM $posts AS posts",
51 'join' => "JOIN $post_meta AS postmeta ON ( posts.ID = postmeta.post_id )",
52 'where' => "WHERE posts.post_type = '$post_type' AND posts.post_status IN ('publish', 'pending', 'future')",
53 ];
54
55 if ( isset( $args['name'] ) ) {
56 $template_name = $args['name'];
57 $template_meta_key = self::$meta_keys['name'];
58 $clauses['where'] .= $wpdb->prepare(
59 ' AND ( postmeta.meta_key=%s AND postmeta.meta_value = %s )',
60 $template_meta_key,
61 $template_name
62 );
63 }
64
65 $query_string = implode( ' ', $clauses );
66 $post_id = $wpdb->get_var( $query_string );
67
68 return $post_id;
69 }
70
71 /**
72 * Finds all YayMail templates and retrieves relevant information about each template.
73 *
74 * @return array An array of YayMail templates with their corresponding data.
75 * Each template is represented as an associative array containing the following keys:
76 * - 'key': The unique identifier for the template (same as 'id').
77 * - 'template_title': The title of the template.
78 * - 'status': The status of the template.
79 * - 'recipient': The recipient associated with the template.
80 * - 'source': The plugin name that the template originates from.
81 * - 'last_updated': The date and time of the last modification to the template
82 * (formatted according to the WordPress date and time settings) or 'N/A' if not available.
83 * - 'id': The unique identifier for the template (same as 'key').
84 * - '...': Other template-specific data retrieved from YayMail.
85 */
86 public static function find_all() {
87 $templates = [];
88
89 $excluded_templates = apply_filters( 'yaymail_excluded_templates', [ 'yaymail_global_header_footer' ] );
90
91 if ( yaymail_is_wc_installed() ) {
92 /* Wc Emails, may or may not be supported by us */
93 $wc_emails = \WC_Emails::instance()->get_emails();
94
95 foreach ( $wc_emails as $wc_email ) {
96 $template_id = $wc_email->id ?? null;
97
98 if ( ! isset( $template_id ) ) {
99 continue;
100 }
101
102 if ( in_array( $template_id, $excluded_templates, true ) ) {
103 continue;
104 }
105
106 if ( SupportedPlugins::get_instance()->get_support_info( $template_id )['status'] !== 'already_supported' ) {
107 // Templates is currently not editable, but could be supported by pro/addon
108 $template_data = self::get_uneditable_template( $wc_email, $templates );
109 $templates[] = $template_data;
110 continue;
111 }
112
113 $email_data = SupportedPlugins::get_instance()->get_yaymail_template_data( $template_id );
114 $template_data = self::get_yaymail_template( $email_data );
115 if ( isset( $template_data ) ) {
116 unset( $template_data['elements'] );
117 $templates[] = $template_data;
118 }
119 }//end foreach
120 } else {
121 $templates = [];
122 }//end if
123
124 // Make sure it will show templates for Automatewoo ...
125 // Because those templates don't appear in wc_emails
126 $template_ids = array_map( fn( $template ) => $template['name'], $templates );
127 foreach ( yaymail_get_emails() as $yaymail_email ) {
128 $template_id = $yaymail_email->get_id();
129 if ( in_array( $template_id, $excluded_templates, true ) ) {
130 continue;
131 }
132 if ( in_array( $template_id, $template_ids, true ) ) {
133 continue;
134 }
135
136 $email_data = SupportedPlugins::get_instance()->get_yaymail_template_data( $template_id );
137 $template_data = self::get_yaymail_template( $email_data );
138 if ( isset( $template_data ) ) {
139 unset( $template_data['elements'] );
140 $templates[] = $template_data;
141 }
142 }
143
144 return $templates;
145 }
146
147 private static function get_yaymail_template( $email_data ) {
148 /* Template is supported and ready to be edited */
149 $template = new YayMailTemplate( $email_data->get_id() );
150 if ( ! $template->is_exists() || empty( $email_data ) ) {
151 return null;
152 }
153
154 $template_data = $template->get_data();
155 $template_data['elements'] = $template->get_elements();
156 $template_data['key'] = $template_data['id'];
157 $template_data['template_title'] = $email_data->get_title();
158 $template_data['status'] = $template_data['status'];
159 $template_data['recipient'] = $email_data->get_recipient();
160 $template_data['source'] = $email_data->get_source()['plugin_name'] ?? '';
161 $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' );
162 return $template_data;
163 }
164
165 /**
166 * Get template data for template that is currently not editable by YayMail and YayMail addons
167 * (It might or might not be supported by YayMail)
168 *
169 * @param object $wc_email The WooCommerce email object.
170 * @param array $templates The list of templates.
171 * @return array The template data.
172 */
173 private static function get_uneditable_template( $wc_email, $templates ): array {
174
175 $existed_post_ids = array_map( fn( $template ) => $template['id'], $templates );
176 do {
177 // Create a mockup post id
178 $mock_post_id = wp_rand( 1000, 10000 );
179 } while ( in_array(
180 $mock_post_id,
181 $existed_post_ids,
182 true
183 ) );
184
185 $template_id = $wc_email->id;
186 $support_info = SupportedPlugins::get_instance()->get_support_info( $template_id );
187 $support_status = $support_info['status'];
188 $source = $wc_email->source ?? $support_info['addon']['plugin_name'] ?? '';
189
190 // Get title
191
192 $support_status_labels = [
193 'pro_needed' => __( 'Pro', 'yaymail' ),
194 'addon_needed' => __( 'Addon', 'yaymail' ),
195 'not_supported' => __( 'N/A', 'yaymail' ),
196 ];
197
198 $template_title = $wc_email->title;
199 if ( isset( $support_status_labels[ $support_status ] ) ) {
200 $template_title .= ' (' . $support_status_labels[ $support_status ] . ')';
201 }
202
203 // Get last_updated
204 $post = get_post( $template_id );
205 $last_updated = $post && isset( $post->post_modified )
206 ? date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $post->post_modified ) )
207 : esc_html__( 'N/A', 'yaymail' );
208
209 return [
210 'id' => $mock_post_id,
211 'key' => $mock_post_id,
212 'name' => $template_id,
213 'support_status' => $support_status,
214 'addon_info' => $support_info['addon'],
215 'template_title' => $template_title,
216 'status' => 'inactive',
217 'recipient' => yaymail_get_email_recipient_zone( $wc_email ),
218 'source' => $source,
219 'last_updated' => $last_updated,
220 ];
221 }
222
223 /**
224 * Find template by given name
225 * Returns null if not found
226 *
227 * @param string $name
228 */
229 public static function find_by_name( $name ) {
230 $template_id = self::query_template(
231 [
232 'name' => $name,
233 ]
234 );
235 if ( empty( $template_id ) ) {
236 $support_info = SupportedPlugins::get_instance()->get_support_info( $name );
237 return [
238 'support_status' => $support_info['status'] ?? '',
239 'addon_info' => $support_info['addon'] ?? '',
240 ];
241 }
242 return self::get_meta_data( $template_id, $name );
243 }
244
245 /**
246 * Find template by post id
247 * Returns null if not found
248 *
249 * @param number $id
250 */
251 public static function find_by_id( $id ) {
252 if ( ! empty( $id ) && ! is_null( get_post( $id ) ) ) {
253 return self::get_meta_data( $id );
254 }
255 return null;
256 // Returns null on failure
257 }
258
259 public static function insert( $args = false ) {
260 // Insert template data to posts table
261 $template_args = [
262 'post_content' => '',
263 'post_type' => TemplatePostType::POST_TYPE,
264 'post_title' => '',
265 'post_status' => 'publish',
266 ];
267 $new_template_id = wp_insert_post( $template_args );
268
269 // Insert data to post meta table
270 update_post_meta( $new_template_id, self::$meta_keys['name'], $args['name'] );
271 update_post_meta( $new_template_id, self::$meta_keys['elements'], $args['elements'] );
272 update_post_meta( $new_template_id, self::$meta_keys['status'], 'inactive' );
273 update_post_meta( $new_template_id, self::$meta_keys['background_color'], YAYMAIL_COLOR_BACKGROUND_DEFAULT );
274 update_post_meta( $new_template_id, self::$meta_keys['is_v4_supported'], true );
275 if ( ! empty( $args['text_link_color'] ) ) {
276 update_post_meta( $new_template_id, self::$meta_keys['text_link_color'], YAYMAIL_COLOR_WC_DEFAULT );
277 }
278 if ( ! empty( $args['content_background_color'] ) ) {
279 update_post_meta( $new_template_id, self::$meta_keys['content_background_color'], '#ffffff' );
280 }
281 if ( ! empty( $args['content_text_color'] ) ) {
282 update_post_meta( $new_template_id, self::$meta_keys['content_text_color'], '#000000' );
283 }
284 if ( ! empty( $args['title_color'] ) ) {
285 update_post_meta( $new_template_id, self::$meta_keys['title_color'], '#000000' );
286 }
287 if ( ! empty( $args['global_header_settings'] ) ) {
288 update_post_meta( $new_template_id, self::$meta_keys['global_header_settings'], $args['global_header_settings'] );
289 }
290 if ( ! empty( $args['global_footer_settings'] ) ) {
291 update_post_meta( $new_template_id, self::$meta_keys['global_footer_settings'], $args['global_footer_settings'] );
292 }
293
294 // Hook insert data of integrations
295
296 return self::get_meta_data( $new_template_id );
297 }
298
299 public static function update( $template_id, $data, $is_save_revision = false ) {
300 if ( isset( $data['elements'] ) && is_array( $data['elements'] ) && isset( self::$meta_keys['elements'] ) ) {
301 $elements_data = TemplateHelpers::sanitize_elements_recursive( $data['elements'] );
302 update_post_meta( $template_id, self::$meta_keys['elements'], $elements_data );
303 }
304
305 if ( ! empty( $data['background_color'] ) && isset( self::$meta_keys['background_color'] ) ) {
306 update_post_meta( $template_id, self::$meta_keys['background_color'], $data['background_color'] );
307 }
308
309 if ( ! empty( $data['text_link_color'] ) && isset( self::$meta_keys['text_link_color'] ) ) {
310 update_post_meta( $template_id, self::$meta_keys['text_link_color'], $data['text_link_color'] );
311 }
312
313 if ( ! empty( $data['content_background_color'] ) && isset( self::$meta_keys['content_background_color'] ) ) {
314 update_post_meta( $template_id, self::$meta_keys['content_background_color'], $data['content_background_color'] );
315 }
316
317 if ( ! empty( $data['content_text_color'] ) && isset( self::$meta_keys['content_text_color'] ) ) {
318 update_post_meta( $template_id, self::$meta_keys['content_text_color'], $data['content_text_color'] );
319 }
320
321 if ( ! empty( $data['title_color'] ) && isset( self::$meta_keys['title_color'] ) ) {
322 update_post_meta( $template_id, self::$meta_keys['title_color'], $data['title_color'] );
323 }
324
325 if ( isset( $data['status'] ) && isset( self::$meta_keys['status'] ) ) {
326 update_post_meta( $template_id, self::$meta_keys['status'], $data['status'] );
327 }
328
329 if ( ! empty( $data['global_header_settings'] ) && isset( self::$meta_keys['global_header_settings'] ) ) {
330 update_post_meta( $template_id, self::$meta_keys['global_header_settings'], $data['global_header_settings'] );
331 }
332
333 if ( ! empty( $data['global_footer_settings'] ) && isset( self::$meta_keys['global_footer_settings'] ) ) {
334 update_post_meta( $template_id, self::$meta_keys['global_footer_settings'], $data['global_footer_settings'] );
335 }
336
337 // Update post_modified
338 $post_data = [
339 'ID' => $template_id,
340 'post_modified' => current_time( 'mysql' ),
341 'post_modified_gmt' => current_time( 'mysql', 1 ),
342 ];
343 wp_update_post( $post_data, true );
344
345 if ( $is_save_revision ) {
346 try {
347 $revision_model = RevisionModel::get_instance();
348 $new_revision = $revision_model->save( $template_id, $data );
349 } catch ( \Throwable $th ) {
350 $new_revision = null;
351 }
352
353 return [
354 'updated_data' => self::get_meta_data( $template_id ),
355 'new_revision' => $new_revision,
356 ];
357 }
358
359 return self::get_meta_data( $template_id );
360 }
361
362 public static function delete( $template_id ) {
363 wp_delete_post( $template_id, true );
364 // TODO: remove relatives.
365 }
366
367 /**
368 * Retrieve the global header and footer elements.
369 *
370 * @return array An array containing the global header and footer elements:
371 * - 'global_header_elements': array.
372 * - 'global_footer_elements': array.
373 */
374 public static function get_global_header_and_footer() {
375 $query_args = [
376 'name' => 'yaymail_global_header_footer',
377 ];
378 $template_id = self::query_template( $query_args );
379 if ( empty( $template_id ) ) {
380 self::insert(
381 [
382 'name' => 'yaymail_global_header_footer',
383 'elements' => yaymail_get_default_elements( 'yaymail_global_header_footer' ),
384 ]
385 );
386 $template_id = self::query_template( $query_args );
387 }
388 $retrieved_meta_data = self::get_meta_data( $template_id );
389 $elements = isset( $retrieved_meta_data['elements'] ) ? $retrieved_meta_data['elements'] : [];
390
391 if ( empty( $elements ) ) {
392 /**
393 * Get default elements
394 */
395 $global_header_footer_instance = \YayMail\Emails\GlobalHeaderFooter::get_instance();
396 $elements = $global_header_footer_instance->get_default_elements();
397 }
398
399 $divider_index = array_search( 'skeleton_divider', array_column( $elements, 'type' ), true );
400
401 $global_header_elements = [];
402 $global_footer_elements = [];
403
404 if ( false !== $divider_index ) {
405 $global_header_elements = array_slice( $elements, 0, $divider_index );
406 $global_footer_elements = array_slice( $elements, $divider_index + 1 );
407 }
408
409 return [
410 'global_header_elements' => $global_header_elements,
411 'global_footer_elements' => $global_footer_elements,
412 ];
413 }
414
415 /**
416 * Get template meta data from Database
417 *
418 * @param number $template_post_id
419 * @param string $template_name
420 */
421 private static function get_meta_data( $template_post_id, $template_name = null ) {
422
423 if ( empty( $template_name ) ) {
424 $template_name = self::query_meta_data( $template_post_id, self::$meta_keys['name'], '' );
425 }
426 $status = self::query_meta_data( $template_post_id, self::$meta_keys['status'], 'inactive' );
427
428 $post = isset( $template_post_id ) ? get_post( $template_post_id ) : null;
429 $post_modified = isset( $post ) ? $post->post_modified : '';
430
431 // /** For editable templates */
432 $template_elements = self::query_meta_data( $template_post_id, self::$meta_keys['elements'], [] );
433
434 $support_info = SupportedPlugins::get_instance()->get_support_info( $template_name );
435 if ( $support_info['status'] !== 'already_supported' && 'wp-core-edd-password_reset' !== $template_name ) {
436 // Template is not editable
437 $template_elements = self::get_uneditable_template_placeholder_elements( $support_info );
438 } elseif ( isset( $post ) ) {
439 // TODO: how to store global default value
440 $background_color = self::query_meta_data( $template_post_id, self::$meta_keys['background_color'], YayMailTemplate::DEFAULT_DATA['background_color'] );
441 $text_link_color = self::query_meta_data( $template_post_id, self::$meta_keys['text_link_color'], YayMailTemplate::DEFAULT_DATA['text_link_color'] );
442 $title_color = self::query_meta_data( $template_post_id, self::$meta_keys['title_color'], YayMailTemplate::DEFAULT_DATA['title_color'] );
443 $content_background_color = self::query_meta_data( $template_post_id, self::$meta_keys['content_background_color'], YayMailTemplate::DEFAULT_DATA['content_background_color'] );
444 $content_text_color = self::query_meta_data( $template_post_id, self::$meta_keys['content_text_color'], YayMailTemplate::DEFAULT_DATA['content_text_color'] );
445 $global_header_settings = self::query_meta_data( $template_post_id, self::$meta_keys['global_header_settings'], YayMailTemplate::DEFAULT_DATA['global_header_settings'] );
446 $global_footer_settings = self::query_meta_data( $template_post_id, self::$meta_keys['global_footer_settings'], YayMailTemplate::DEFAULT_DATA['global_footer_settings'] );
447 }
448
449 return [
450 'id' => $template_post_id,
451 'key' => $template_post_id,
452 'name' => $template_name,
453 'elements' => ElementsHelper::filter_available_elements( $template_elements, $template_name ),
454 'status' => $status,
455 'title_color' => $title_color ?? '#000000',
456 'background_color' => $background_color ?? YAYMAIL_COLOR_BACKGROUND_DEFAULT,
457 'text_link_color' => $text_link_color ?? YAYMAIL_COLOR_WC_DEFAULT,
458 'content_background_color' => $content_background_color ?? '#ffffff',
459 'content_text_color' => $content_text_color ?? '#000000',
460 'support_status' => $support_info['status'] ?? 'already_supported',
461 'addon_info' => $support_info['addon'] ?? '',
462 'post_modified' => $post_modified,
463 'global_header_settings' => isset( $global_header_settings ) ? $global_header_settings : [],
464 'global_footer_settings' => isset( $global_footer_settings ) ? $global_footer_settings : [],
465 ];
466 }
467
468 private static function get_uneditable_template_placeholder_elements( array $support_info ): array {
469 $elements = [];
470
471 $elements[] = BaseElement::reduce_new_element( Logo::get_data() );
472 $elements[] = BaseElement::reduce_new_element( Heading::get_data() );
473 $elements[] = BaseElement::reduce_new_element( Text::get_data() );
474 $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>' ] ) );
475
476 return $elements;
477 }
478
479
480 private static function query_meta_data( $post_id, $meta_name, $default ) {
481 if ( ! isset( $post_id ) ) {
482 return $default;
483 }
484
485 $meta_value = get_post_meta( $post_id, $meta_name, true );
486
487 if ( empty( $meta_value ) ) {
488 return $default;
489 }
490 return $meta_value;
491 }
492
493 public static function get_shortcodes_by_template_name_and_order_id( $template_name, $order_id ) {
494 do_action( 'yaymail_before_order_id_changed', $order_id );
495
496 $shortcodes = yaymail_get_email_shortcodes( $template_name );
497
498 // TODO: check shortcodes
499 // $shortcodes = apply_filters( 'yaymail_extra_shortcodes', $shortcodes, $template_name, $order_id );
500
501 $executor_data = self::get_shortcode_executor_data( $template_name, $order_id );
502 $executor = new ShortcodesExecutor( $shortcodes, $executor_data );
503 return $executor->get_shortcodes_content();
504 }
505
506 /**
507 * Gets data needed for executing a YayMail shortcode.
508 *
509 * @param string $template_name The template name.
510 * @param string $order_id The order ID. Uses sample data if empty or 'sample_order'.
511 * @return array [template, render_data, settings, is_placeholder]
512 */
513 public static function get_shortcode_executor_data( $template_name, $order_id ) {
514
515 return [
516 'template' => new YayMailTemplate( $template_name ),
517 'render_data' => empty( $order_id ) || ( ! empty( $order_id ) && 'sample_order' === $order_id ) ? [ 'is_sample' => true ] : [ 'order' => wc_get_order( $order_id ) ],
518 'settings' => yaymail_settings(),
519 'is_placeholder' => true,
520 ];
521 }
522
523 public static function get_elements_for_template( $template_id ): array {
524 $support_info = SupportedPlugins::get_instance()->get_support_info( $template_id );
525 if ( $support_info['status'] !== 'already_supported' ) {
526 $elements = array_map(
527 function( $element ) {
528 $element['available'] = false;
529 return $element;
530 },
531 yaymail_get_email_elements_data( 'new_order' )
532 );
533 return $elements;
534 }
535 return yaymail_get_email_elements_data( $template_id );
536 }
537
538 public static function get_short_data_by_name( $name ) {
539 $template_id = self::query_template( [ 'name' => $name ] );
540 if ( empty( $template_id ) ) {
541 return null;
542 }
543 return [
544 'id' => $template_id,
545 'status' => self::query_meta_data( $template_id, self::$meta_keys['status'], 'inactive' ),
546 ];
547 }
548 }
549