…

of their bodytext (found 2026-11-10: 17 records). Left * in place, the frontend renders the JSON as visible text while Google * never sees it as structured data. This helper removes such paragraphs * from the HTML and returns the decoded nodes, ready to join the page's * JSON-LD @graph (their own @context is dropped - the graph carries one). * * Fail-safe: a paragraph that merely looks like JSON but does not decode * to a schema.org node stays in the HTML untouched. */ final class EmbeddedJsonLd { /** * @return array{html: string, nodes: list>} */ public static function extract(string $html): array { if ($html === '' || !str_contains($html, 'schema.org')) { return ['html' => $html, 'nodes' => []]; } $nodes = []; $clean = preg_replace_callback( '#]*>\s*(\{.+?\})\s*

#s', static function (array $match) use (&$nodes): string { $candidate = $match[1]; if (!str_contains($candidate, 'schema.org')) { return $match[0]; } $decoded = json_decode($candidate, true); if (!is_array($decoded)) { // RTE processing may have entity-encoded the quotes. $decoded = json_decode(html_entity_decode($candidate, ENT_QUOTES | ENT_HTML5), true); } if (!is_array($decoded) || empty($decoded['@type'])) { return $match[0]; } unset($decoded['@context']); $nodes[] = $decoded; return ''; }, $html ) ?? $html; return ['html' => trim($clean), 'nodes' => $nodes]; } }