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
← All changes | src/Models/TemplateModel.php +163 -14 4.4.2 → 4.4.6 View file →
@@ -7,8 +7,9 @@
7 7 use YayMail\Elements\Heading;
8 8 use YayMail\Elements\Logo;
9 9 use YayMail\Elements\Text;
10 10 use YayMail\Elements\Footer;
11 +use YayMail\Integrations\TranslationModule;
11 12 use YayMail\YayMailTemplate;
12 13 use YayMail\Utils\SingletonTrait;
13 14 use YayMail\PostTypes\TemplatePostType;
14 15 use YayMail\Shortcodes\ShortcodesExecutor;
@@ -25,8 +26,11 @@
25 26 private const POST_TABLE = 'posts';
26 27 private const POST_META_TABLE = 'postmeta';
27 28 private static $meta_keys = YayMailTemplate::META_KEYS;
28 29
30 + /** @var string[]|null Per-request memo for get_active_default_template_names(). */
31 + private static $active_default_template_names = null;
32 +
29 33 /**
30 34 * Query post with given arguments.
31 35 * Build query string base on given arguments
32 36 * then use $wpdb to query it.
@@ -61,11 +65,29 @@
61 65 $template_name
62 66 );
63 67 }
64 68
65 - $query_string = implode( ' ', $clauses );
66 - $post_id = $wpdb->get_var( $query_string );
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 + }
67 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 +
68 90 return $post_id;
69 91 }
70 92
71 93 /**
@@ -225,12 +247,18 @@
225 247 * Returns null if not found
226 248 *
227 249 * @param string $name
228 250 */
229 - public static function find_by_name( $name ) {
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 = '' ) {
230 257 $template_id = self::query_template(
231 258 [
232 - 'name' => $name,
259 + 'name' => $name,
260 + 'variant' => $variant,
233 261 ]
234 262 );
235 263 if ( empty( $template_id ) ) {
236 264 $support_info = SupportedPlugins::get_instance()->get_support_info( $name );
@@ -289,8 +317,11 @@
289 317 }
290 318 if ( ! empty( $args['global_footer_settings'] ) ) {
291 319 update_post_meta( $new_template_id, self::$meta_keys['global_footer_settings'], $args['global_footer_settings'] );
292 320 }
321 + if ( isset( $args['variant'] ) && '' !== $args['variant'] ) {
322 + update_post_meta( $new_template_id, self::$meta_keys['variant'], $args['variant'] );
323 + }
293 324
294 325 // Hook insert data of integrations
295 326
296 327 return self::get_meta_data( $new_template_id );
@@ -374,18 +405,20 @@
374 405 * @return array An array containing the global header and footer elements:
375 406 * - 'global_header_elements': array.
376 407 * - 'global_footer_elements': array.
377 408 */
378 - public static function get_global_header_and_footer() {
409 + public static function get_global_header_and_footer( $language = '', $template_name = 'yaymail_global_header_footer' ) {
379 410 $query_args = [
380 - 'name' => 'yaymail_global_header_footer',
411 + 'name' => $template_name,
412 + 'language' => in_array( $language, [ 'en', 'en_US' ], true ) ? '' : $language,
381 413 ];
382 414 $template_id = self::query_template( $query_args );
383 415 if ( empty( $template_id ) ) {
384 416 self::insert(
385 417 [
386 - 'name' => 'yaymail_global_header_footer',
387 - 'elements' => yaymail_get_default_elements( 'yaymail_global_header_footer' ),
418 + 'name' => $template_name,
419 + 'elements' => yaymail_get_default_elements( $template_name ),
420 + 'language' => $language,
388 421 ]
389 422 );
390 423 $template_id = self::query_template( $query_args );
391 424 }
@@ -415,8 +448,43 @@
415 448 'global_footer_elements' => $global_footer_elements,
416 449 ];
417 450 }
418 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 +
419 487 /**
420 488 * Get template meta data from Database
421 489 *
422 490 * @param number $template_post_id
@@ -445,10 +513,10 @@
445 513 $text_link_color = self::query_meta_data( $template_post_id, self::$meta_keys['text_link_color'], YayMailTemplate::DEFAULT_DATA['text_link_color'] );
446 514 $title_color = self::query_meta_data( $template_post_id, self::$meta_keys['title_color'], YayMailTemplate::DEFAULT_DATA['title_color'] );
447 515 $content_background_color = self::query_meta_data( $template_post_id, self::$meta_keys['content_background_color'], YayMailTemplate::DEFAULT_DATA['content_background_color'] );
448 516 $content_text_color = self::query_meta_data( $template_post_id, self::$meta_keys['content_text_color'], YayMailTemplate::DEFAULT_DATA['content_text_color'] );
449 - $global_header_settings = self::query_meta_data( $template_post_id, self::$meta_keys['global_header_settings'], YayMailTemplate::DEFAULT_DATA['global_header_settings'] );
450 - $global_footer_settings = self::query_meta_data( $template_post_id, self::$meta_keys['global_footer_settings'], YayMailTemplate::DEFAULT_DATA['global_footer_settings'] );
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() );
451 519 $preheader = self::query_meta_data( $template_post_id, self::$meta_keys['preheader'], YayMailTemplate::DEFAULT_DATA['preheader'] );
452 520 }
453 521
454 522 return [
@@ -456,8 +524,9 @@
456 524 'key' => $template_post_id,
457 525 'name' => $template_name,
458 526 'elements' => ElementsHelper::filter_available_elements( $template_elements, $template_name ),
459 527 'status' => $status,
528 + 'variant' => self::query_meta_data( $template_post_id, self::$meta_keys['variant'], '' ),
460 529 'title_color' => $title_color ?? '#000000',
461 530 'background_color' => $background_color ?? YAYMAIL_COLOR_BACKGROUND_DEFAULT,
462 531 'text_link_color' => $text_link_color ?? YAYMAIL_COLOR_WC_DEFAULT,
463 532 'content_background_color' => $content_background_color ?? '#ffffff',
@@ -527,9 +596,25 @@
527 596 return $elements;
528 597 }
529 598
530 599
531 - private static function query_meta_data( $post_id, $meta_name, $default ) {
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 ) {
532 617 if ( ! isset( $post_id ) ) {
533 618 return $default;
534 619 }
535 620
@@ -573,14 +658,17 @@
573 658
574 659 public static function get_elements_for_template( $template_id ): array {
575 660 $support_info = SupportedPlugins::get_instance()->get_support_info( $template_id );
576 661 if ( $support_info['status'] !== 'already_supported' ) {
577 - $elements = array_map(
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(
578 666 function( $element ) {
579 667 $element['available'] = false;
580 668 return $element;
581 669 },
582 - yaymail_get_email_elements_data( 'new_order' )
670 + yaymail_get_email_elements_data( $fallback_email_id )
583 671 );
584 672 return $elements;
585 673 }
586 674 return yaymail_get_email_elements_data( $template_id );
@@ -585,8 +673,69 @@
585 673 }
586 674 return yaymail_get_email_elements_data( $template_id );
587 675 }
588 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 +
589 738 public static function get_short_data_by_name( $name ) {
590 739 $template_id = self::query_template( [ 'name' => $name ] );
591 740 if ( empty( $template_id ) ) {
592 741 return null;
@@ -595,5 +744,5 @@
595 744 'id' => $template_id,
596 745 'status' => self::query_meta_data( $template_id, self::$meta_keys['status'], 'inactive' ),
597 746 ];
598 747 }
599 -}
748 +}