| @@ -26,8 +26,11 @@ | ||
| 26 | 26 | private const POST_TABLE = 'posts'; |
| 27 | 27 | private const POST_META_TABLE = 'postmeta'; |
| 28 | 28 | private static $meta_keys = YayMailTemplate::META_KEYS; |
| 29 | 29 | |
| 30 | + /** @var string[]|null Per-request memo for get_active_default_template_names(). */ | |
| 31 | + private static $active_default_template_names = null; | |
| 32 | + | |
| 30 | 33 | /** |
| 31 | 34 | * Query post with given arguments. |
| 32 | 35 | * Build query string base on given arguments |
| 33 | 36 | * then use $wpdb to query it. |
| @@ -62,11 +65,29 @@ | ||
| 62 | 65 | $template_name |
| 63 | 66 | ); |
| 64 | 67 | } |
| 65 | 68 | |
| 66 | - $query_string = implode( ' ', $clauses ); | |
| 67 | - $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 | + } | |
| 68 | 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 | + | |
| 69 | 90 | return $post_id; |
| 70 | 91 | } |
| 71 | 92 | |
| 72 | 93 | /** |
| @@ -226,12 +247,18 @@ | ||
| 226 | 247 | * Returns null if not found |
| 227 | 248 | * |
| 228 | 249 | * @param string $name |
| 229 | 250 | */ |
| 230 | - 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 = '' ) { | |
| 231 | 257 | $template_id = self::query_template( |
| 232 | 258 | [ |
| 233 | - 'name' => $name, | |
| 259 | + 'name' => $name, | |
| 260 | + 'variant' => $variant, | |
| 234 | 261 | ] |
| 235 | 262 | ); |
| 236 | 263 | if ( empty( $template_id ) ) { |
| 237 | 264 | $support_info = SupportedPlugins::get_instance()->get_support_info( $name ); |
| @@ -290,8 +317,11 @@ | ||
| 290 | 317 | } |
| 291 | 318 | if ( ! empty( $args['global_footer_settings'] ) ) { |
| 292 | 319 | update_post_meta( $new_template_id, self::$meta_keys['global_footer_settings'], $args['global_footer_settings'] ); |
| 293 | 320 | } |
| 321 | + if ( isset( $args['variant'] ) && '' !== $args['variant'] ) { | |
| 322 | + update_post_meta( $new_template_id, self::$meta_keys['variant'], $args['variant'] ); | |
| 323 | + } | |
| 294 | 324 | |
| 295 | 325 | // Hook insert data of integrations |
| 296 | 326 | |
| 297 | 327 | return self::get_meta_data( $new_template_id ); |
| @@ -494,8 +524,9 @@ | ||
| 494 | 524 | 'key' => $template_post_id, |
| 495 | 525 | 'name' => $template_name, |
| 496 | 526 | 'elements' => ElementsHelper::filter_available_elements( $template_elements, $template_name ), |
| 497 | 527 | 'status' => $status, |
| 528 | + 'variant' => self::query_meta_data( $template_post_id, self::$meta_keys['variant'], '' ), | |
| 498 | 529 | 'title_color' => $title_color ?? '#000000', |
| 499 | 530 | 'background_color' => $background_color ?? YAYMAIL_COLOR_BACKGROUND_DEFAULT, |
| 500 | 531 | 'text_link_color' => $text_link_color ?? YAYMAIL_COLOR_WC_DEFAULT, |
| 501 | 532 | 'content_background_color' => $content_background_color ?? '#ffffff', |
| @@ -640,8 +671,69 @@ | ||
| 640 | 671 | ); |
| 641 | 672 | return $elements; |
| 642 | 673 | } |
| 643 | 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; | |
| 644 | 736 | } |
| 645 | 737 | |
| 646 | 738 | public static function get_short_data_by_name( $name ) { |
| 647 | 739 | $template_id = self::query_template( [ 'name' => $name ] ); |