How to Prevent HTML Entities from Leaking into JSON-LD

clean text into real Unicode characters before JSON encoding it. If a title still contains an HTML entity such as –, JSON encoding will preserve that entity as text instead of turning it into the intended punctuation.

Why it happens

HTML escaping and JSON escaping solve different problems. A value can be valid JSON and still contain the wrong text.

For example, a stored title might contain an encoded dash:

Example Title – Site Name

If that string is passed directly to a JSON encoder, the JSON remains syntactically valid, but consumers see the entity characters rather than an en dash.

Why this happens

The cause is usually double handling across output contexts:

  1. Content is stored or returned with HTML entities.

  2. The same value is reused for JSON-LD.

  3. The JSON encoder escapes JSON syntax, but it does not interpret HTML entities.

The fix is to normalize the text first, then let the correct encoder handle the final destination.

A safe PHP pattern

$title = html_entity_decode(
    wp_strip_all_tags($raw_title),
    ENT_QUOTES | ENT_HTML5,
    'UTF-8'
);

$schema = [
    '@context' => 'https://schema.org',
    '@type' => 'WebPage',
    'name' => $title,
];

$json = wp_json_encode(
    $schema,
    JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT
);

if (false !== $json) {
    echo $json;
}

This produces real text in the data structure and delegates JSON escaping to wp_json_encode().

Keep output contexts separate

The same character may look different in different outputs:

  • In JSON-LD text, use the decoded Unicode character.
  • In an HTML attribute, an entity such as & can be correct escaping for an ampersand.

  • In visible HTML text, use the platform’s normal HTML escaping function.

Do not copy the already escaped output from one context into another. Start with normalized data and escape once at the final boundary.

Common mistakes

Problem: The JSON validates, but the title displays entity text.
Fix: Decode HTML entities before building the schema array.

Problem: Decoding after JSON encoding breaks the serialized output.
Fix: Normalize values before calling the JSON encoder.

Problem: Every encoded ampersand is treated as a bug.
Fix: Check the destination. HTML attributes and JSON-LD require different escaping.

Problem: Raw strings are concatenated into a JSON script block.
Fix: Build a structured array and use the platform JSON encoder.

How to verify the result

  1. View the rendered page source.
  2. Find the application/ld+json block.

  3. Confirm the title contains the intended character, not entity text.

  4. Parse the JSON or run a structured-data validator.

  5. Add a regression test for punctuation, quotes, and ampersands.

Encode safely for the surrounding script element

When embedding JSON in an HTML script element, encode angle brackets as well as JSON syntax. JSON_HEX_TAG prevents text from introducing a literal closing script tag. An escaped Unicode sequence such as \u2013 is valid JSON for an en dash; inspect the parsed value rather than demanding literal punctuation in the raw source.

Valid encoding is not enough; the value must also be correct for its output context. The concrete next action is to trace one problematic field back to its raw source, normalize it once, and test the rendered JSON-LD.

Reference: PHP JSON encoding.

Leave a Reply