| @@ -2,8 +2,9 @@ | ||
| 2 | 2 | |
| 3 | 3 | namespace YayMail\Utils; |
| 4 | 4 | |
| 5 | 5 | use YayMail\Constants\AttributesData; |
| 6 | +use YayMail\Constants\TemplatesData; | |
| 6 | 7 | use YayMail\Shortcodes\ShortcodesExecutor; |
| 7 | 8 | use YayMail\YayMailTemplate; |
| 8 | 9 | |
| 9 | 10 | defined( 'ABSPATH' ) || exit; |
| @@ -421,8 +422,45 @@ | ||
| 421 | 422 | return $value; |
| 422 | 423 | } |
| 423 | 424 | |
| 424 | 425 | /** |
| 426 | + * Ensure each nested element has parentId pointing to its direct parent. | |
| 427 | + * Root-level elements have no parentId (customizer "Select parent" relies on this). | |
| 428 | + * | |
| 429 | + * @param array $elements Template elements tree. | |
| 430 | + * @param string|null $parent_id Parent element id for direct children. | |
| 431 | + * @return array | |
| 432 | + */ | |
| 433 | + public static function normalize_elements_parent_ids( $elements, $parent_id = null ) { | |
| 434 | + if ( ! is_array( $elements ) ) { | |
| 435 | + return []; | |
| 436 | + } | |
| 437 | + | |
| 438 | + $normalized = []; | |
| 439 | + | |
| 440 | + foreach ( $elements as $element ) { | |
| 441 | + if ( ! is_array( $element ) ) { | |
| 442 | + continue; | |
| 443 | + } | |
| 444 | + | |
| 445 | + if ( null !== $parent_id && '' !== $parent_id ) { | |
| 446 | + $element['parentId'] = $parent_id; | |
| 447 | + } else { | |
| 448 | + unset( $element['parentId'] ); | |
| 449 | + } | |
| 450 | + | |
| 451 | + if ( ! empty( $element['children'] ) && is_array( $element['children'] ) ) { | |
| 452 | + $child_parent_id = isset( $element['id'] ) ? $element['id'] : null; | |
| 453 | + $element['children'] = self::normalize_elements_parent_ids( $element['children'], $child_parent_id ); | |
| 454 | + } | |
| 455 | + | |
| 456 | + $normalized[] = $element; | |
| 457 | + } | |
| 458 | + | |
| 459 | + return $normalized; | |
| 460 | + } | |
| 461 | + | |
| 462 | + /** | |
| 425 | 463 | * Append invisible characters so inbox clients do not pull body text into the preview line. |
| 426 | 464 | * |
| 427 | 465 | * @param string $preheader Visible preheader text. |
| 428 | 466 | * @param int $target_length Approximate preview window (Gmail ~90–140, Outlook ~130). |
| @@ -488,8 +526,45 @@ | ||
| 488 | 526 | return $preheader; |
| 489 | 527 | } |
| 490 | 528 | |
| 491 | 529 | /** |
| 530 | + * Render YayMail shortcodes inside an email subject at send time. | |
| 531 | + * | |
| 532 | + * Twin of process_email_preheader: registers the template shortcodes with the | |
| 533 | + * given render context, then resolves them. Output is forced to a single | |
| 534 | + * plain-text line because subjects must not contain HTML/markup that some | |
| 535 | + * shortcodes (e.g. order details) emit. | |
| 536 | + * | |
| 537 | + * @param string $subject Raw subject after WooCommerce format_string(). | |
| 538 | + * @param YayMailTemplate $template Email template. | |
| 539 | + * @param array $args Shortcode executor data (template, render_data, settings, ...). | |
| 540 | + * @return string Subject with YayMail shortcodes resolved. | |
| 541 | + */ | |
| 542 | + public static function process_email_subject( $subject, $template, $args = [] ) { | |
| 543 | + $subject = (string) $subject; | |
| 544 | + | |
| 545 | + // Cheap guard: nothing to resolve when there is no shortcode marker. | |
| 546 | + if ( '' === $subject || false === strpos( $subject, '[' ) || ! $template instanceof YayMailTemplate ) { | |
| 547 | + return $subject; | |
| 548 | + } | |
| 549 | + | |
| 550 | + $template_name = $template->get_name(); | |
| 551 | + if ( ! $template_name ) { | |
| 552 | + return $subject; | |
| 553 | + } | |
| 554 | + | |
| 555 | + $shortcodes = yaymail_get_email_shortcodes( $template_name ); | |
| 556 | + new ShortcodesExecutor( $shortcodes, $args ); | |
| 557 | + | |
| 558 | + // $remove_breaks = true collapses newlines so multi-line shortcode output stays a single subject line. | |
| 559 | + $subject = trim( wp_strip_all_tags( do_shortcode( $subject ), true ) ); | |
| 560 | + | |
| 561 | + // Extension point: no shortcode restriction by default; lets integrators trim length, | |
| 562 | + // blank structural shortcodes, etc. $args carries template + render_data (incl. order). | |
| 563 | + return apply_filters( 'yaymail_email_subject', $subject, $template, $args ); | |
| 564 | + } | |
| 565 | + | |
| 566 | + /** | |
| 492 | 567 | * Output hidden preheader row at the top of the email body (Woo block-editor style). |
| 493 | 568 | * |
| 494 | 569 | * @param YayMailTemplate $template Email template. |
| 495 | 570 | * @param array $args Render context. |
| @@ -500,9 +575,9 @@ | ||
| 500 | 575 | } |
| 501 | 576 | |
| 502 | 577 | $template_name = $template->get_name(); |
| 503 | 578 | |
| 504 | - if ( str_starts_with( $template_name, 'pattern_' ) || 'yaymail_global_header_footer' === $template_name ) { | |
| 579 | + if ( str_starts_with( $template_name, 'pattern_' ) || in_array( $template_name, TemplatesData::GLOBAL_HEADER_FOOTER_TEMPLATE_IDS, true ) ) { | |
| 505 | 580 | return; |
| 506 | 581 | } |
| 507 | 582 | |
| 508 | 583 | $preheader = self::process_email_preheader( $template->get_preheader(), $template, $args ); |
| @@ -521,5 +596,5 @@ | ||
| 521 | 596 | if ( '' !== $preheader_html ) { |
| 522 | 597 | yaymail_kses_post_e( $preheader_html ); |
| 523 | 598 | } |
| 524 | 599 | } |
| 525 | -} | |
| 600 | +} | |