PluginProbe
YayMail – WooCommerce Email Customizer / 4.3.2
YayMail – WooCommerce Email Customizer v4.3.2
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.3.2, at src/Models/TemplateModel.php

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