From b71384d1d975fb9c4e81267d6cfbedf6de8811da Mon Sep 17 00:00:00 2001 From: bernardhanna Date: Fri, 24 Jul 2026 17:12:11 +0100 Subject: [PATCH] Fix duplicate Key one-pagers title from Trix strong+br markup. Strip h2 and strong title variants (including line breaks inside) before inserting a single heading and bold locale note. Co-authored-by: Cursor --- app/TrainingResource.php | 65 ++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/app/TrainingResource.php b/app/TrainingResource.php index 86edd4852..0e39c8bc4 100644 --- a/app/TrainingResource.php +++ b/app/TrainingResource.php @@ -287,51 +287,44 @@ public function renderedPdfLinksSectionForLocale(?string $locale = null): string return $section; } - // Collapse any existing Key one-pagers title variants (h2 / strong / Trix wrappers) - // into a single h2, then place the locale note immediately after it. - $titlePattern = '/(?:<(?:div|p)[^>]*>\s*)?(?:]*(?:\bid=(["\'])key-one-pagers\1)?[^>]*>\s*Key one-pagers\s*<\/h2>|(?:<(?:strong|b)>\s*)Key one-pagers(?:\s*<\/(?:strong|b)>))(?:\s*<\/(?:div|p)>)?/iu'; - - if (preg_match($titlePattern, $section) === 1) { - $replaced = false; - $section = preg_replace_callback($titlePattern, function (array $matches) use ($headingHtml, $noteHtml, &$replaced) { - if ($replaced) { - return ''; - } - $replaced = true; - - return $headingHtml.$noteHtml; - }, $section) ?? $section; - - // If the note was already injected via placeholder before the title, drop the extra copy. - return $this->dedupeKeyOnePagersNote($section, $noteHtml); - } - - if (! str_contains($section, $noteHtml) && ! str_contains($section, '[[key_one_pagers_locale_note]]')) { - return $headingHtml.$noteHtml.$section; - } + $section = $this->stripKeyOnePagersTitleVariants($section); + // Remove any previously injected note copies so we add exactly one. + $section = $this->stripInjectedKeyOnePagersNotes($section); + $section = preg_replace('/<(?:div|p)[^>]*>\s*(?:|\s)*<\/(?:div|p)>/iu', '', $section) ?? $section; - return $headingHtml.$section; + return $headingHtml.$noteHtml.ltrim($section); } - protected function dedupeKeyOnePagersNote(string $section, string $noteHtml): string + /** + * Remove h2/strong/Trix title-only "Key one-pagers" blocks (including <br> inside). + */ + protected function stripKeyOnePagersTitleVariants(string $html): string { - $pos = strpos($section, $noteHtml); - if ($pos === false) { - return $section; - } + $patterns = [ + //

Key one-pagers

or plain h2 + '/]*>\s*Key one-pagers\s*<\/h2>/iu', + //
/

wrappers around strong/b title, allowing
inside + '/<(?:div|p)[^>]*>\s*<(?:strong|b)[^>]*>\s*Key one-pagers(?:\s|)*<\/(?:strong|b)>\s*<\/(?:div|p)>/iu', + // bare Key one-pagers
+ '/<(?:strong|b)[^>]*>\s*Key one-pagers(?:\s|)*<\/(?:strong|b)>/iu', + ]; - $afterFirst = substr($section, $pos + strlen($noteHtml)); - if (! str_contains($afterFirst, $noteHtml)) { - return $section; + foreach ($patterns as $pattern) { + $html = preg_replace($pattern, '', $html) ?? $html; } - return substr($section, 0, $pos + strlen($noteHtml)).str_replace($noteHtml, '', $afterFirst); + return $html; } - protected function hasKeyOnePagersHeading(string $html): bool + /** + * Remove earlier auto-injected locale note spans (English or translated). + */ + protected function stripInjectedKeyOnePagersNotes(string $html): string { - return preg_match('/]*\bid=(["\'])key-one-pagers\1[^>]*>/is', $html) === 1 - || preg_match('/]*>\s*Key one-pagers\s*<\/h2>/is', $html) === 1 - || preg_match('/<(?:strong|b)>\s*Key one-pagers\s*<\/(?:strong|b)>/is', $html) === 1; + return preg_replace( + '/(?:\s*)?]*>.*?<\/span>(?:\s*<\/em>)?/ius', + '', + $html + ) ?? $html; } }