| @@ -3,8 +3,10 @@ | ||
| 3 | 3 | namespace YayMail\Utils; |
| 4 | 4 | |
| 5 | 5 | use YayMail\Constants\AttributesData; |
| 6 | 6 | use YayMail\Constants\TemplatesData; |
| 7 | +use YayMail\Shortcodes\ShortcodesExecutor; | |
| 8 | +use YayMail\YayMailTemplate; | |
| 7 | 9 | |
| 8 | 10 | defined( 'ABSPATH' ) || exit; |
| 9 | 11 | |
| 10 | 12 | /** |
| @@ -418,5 +420,181 @@ | ||
| 418 | 420 | |
| 419 | 421 | public static function replace_color_paths( $value ) { |
| 420 | 422 | return $value; |
| 421 | 423 | } |
| 422 | -} | |
| 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 | + /** | |
| 463 | + * Append invisible characters so inbox clients do not pull body text into the preview line. | |
| 464 | + * | |
| 465 | + * @param string $preheader Visible preheader text. | |
| 466 | + * @param int $target_length Approximate preview window (Gmail ~90–140, Outlook ~130). | |
| 467 | + * @return string | |
| 468 | + */ | |
| 469 | + public static function pad_preheader( $preheader, $target_length = 150 ) { | |
| 470 | + $preheader = trim( (string) $preheader ); | |
| 471 | + | |
| 472 | + if ( '' === $preheader ) { | |
| 473 | + return ''; | |
| 474 | + } | |
| 475 | + | |
| 476 | + /** | |
| 477 | + * Filter the target length for invisible preheader padding. | |
| 478 | + * | |
| 479 | + * @param int $target_length Default padding target length. | |
| 480 | + * @param string $preheader Visible preheader text. | |
| 481 | + */ | |
| 482 | + $target_length = (int) apply_filters( 'yaymail_email_preheader_pad_length', $target_length, $preheader ); | |
| 483 | + | |
| 484 | + if ( $target_length <= 0 ) { | |
| 485 | + return $preheader; | |
| 486 | + } | |
| 487 | + | |
| 488 | + $visible_length = mb_strlen( $preheader ); | |
| 489 | + | |
| 490 | + if ( $visible_length >= $target_length ) { | |
| 491 | + return $preheader; | |
| 492 | + } | |
| 493 | + | |
| 494 | + // Litmus preview-text hack: zero-width non-joiner + non-breaking space. | |
| 495 | + $pad_unit = "\u{200C}\u{00A0}"; | |
| 496 | + | |
| 497 | + return $preheader . str_repeat( $pad_unit, $target_length - $visible_length ); | |
| 498 | + } | |
| 499 | + | |
| 500 | + /** | |
| 501 | + * Process preheader text (YayMail shortcodes). | |
| 502 | + * | |
| 503 | + * @param string $preheader Raw preheader from template meta. | |
| 504 | + * @param YayMailTemplate $template Email template. | |
| 505 | + * @param array $render_data Render context. | |
| 506 | + * @return string Plain-text preheader for inbox preview. | |
| 507 | + */ | |
| 508 | + public static function process_email_preheader( $preheader, $template, $args = [] ) { | |
| 509 | + $preheader = trim( (string) $preheader ); | |
| 510 | + | |
| 511 | + if ( '' === $preheader || ! $template instanceof YayMailTemplate ) { | |
| 512 | + return ''; | |
| 513 | + } | |
| 514 | + | |
| 515 | + $template_name = $template->get_name(); | |
| 516 | + | |
| 517 | + if ( false !== strpos( $preheader, '[' ) && $template_name ) { | |
| 518 | + | |
| 519 | + $shortcodes = yaymail_get_email_shortcodes( $template_name ); | |
| 520 | + new ShortcodesExecutor( $shortcodes, $args ); | |
| 521 | + $preheader = do_shortcode( $preheader ); | |
| 522 | + }//end if | |
| 523 | + | |
| 524 | + $preheader = self::pad_preheader( wp_strip_all_tags( $preheader ) ); | |
| 525 | + | |
| 526 | + return $preheader; | |
| 527 | + } | |
| 528 | + | |
| 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 | + /** | |
| 567 | + * Output hidden preheader row at the top of the email body (Woo block-editor style). | |
| 568 | + * | |
| 569 | + * @param YayMailTemplate $template Email template. | |
| 570 | + * @param array $args Render context. | |
| 571 | + */ | |
| 572 | + public static function render_email_preheader( $template, $args = [] ) { | |
| 573 | + if ( ! $template instanceof YayMailTemplate ) { | |
| 574 | + return; | |
| 575 | + } | |
| 576 | + | |
| 577 | + $template_name = $template->get_name(); | |
| 578 | + | |
| 579 | + if ( str_starts_with( $template_name, 'pattern_' ) || in_array( $template_name, TemplatesData::GLOBAL_HEADER_FOOTER_TEMPLATE_IDS, true ) ) { | |
| 580 | + return; | |
| 581 | + } | |
| 582 | + | |
| 583 | + $preheader = self::process_email_preheader( $template->get_preheader(), $template, $args ); | |
| 584 | + | |
| 585 | + if ( '' === $preheader ) { | |
| 586 | + return; | |
| 587 | + } | |
| 588 | + | |
| 589 | + $preheader_html = yaymail_get_content( | |
| 590 | + 'templates/emails/email-preheader.php', | |
| 591 | + [ | |
| 592 | + 'preheader' => $preheader, | |
| 593 | + ] | |
| 594 | + ); | |
| 595 | + | |
| 596 | + if ( '' !== $preheader_html ) { | |
| 597 | + yaymail_kses_post_e( $preheader_html ); | |
| 598 | + } | |
| 599 | + } | |
| 600 | +} | |