SUMMARY
The method get_schema in EVO_Cal_Event_Structure_Schema builds the JSON-LD block by string
concatenation. It interpolates the event description, the post title and the location address
directly into JSON string literals without JSON-encoding them.
Any character that is illegal inside a JSON string, and any closing SCRIPT tag, produces a block
that does not parse. Google discards a malformed JSON-LD block wholesale rather than partially,
so the event silently loses its structured data.
The most important case needs no unusual content at all. An event body containing the core
WordPress gallery shortcode emits invalid JSON-LD.
HOW TO REPRODUCE
1. Create an event whose body contains nothing but the core gallery shortcode, in square brackets,
with the word gallery followed by an ids attribute listing four attachment IDs.
2. View the event on the front end.
3. Extract the block of type application slash ld plus json and run it through any JSON parser.
The parser reports: Invalid control character, at roughly line 10 column 227.
the Google Rich Results Test on the same URL reports no Event detected.
ROOT CAUSE
Lines 43 to 45 are the only sanitization applied to the description before it is interpolated:
line 43 str_replace of an apostrophe with an apostrophe
line 44 str_replace of a double quote with an apostrophe
line 45 preg_replace of carriage return or line feed with a space
Then line 236 concatenates the result straight into the JSON, as the description key followed by
a colon and the raw variable between two double quotes.
`class-calendar-event-schema.php`, lines 43-45, are the only sanitization applied to the description before it is interpolated:
“`php
43 $__schema_desc = str_replace(”’”,”’”, $__schema_desc); // no-op, both sides identical
44 $__schema_desc = str_replace(’”’,”’”, $__schema_desc);
45 $__schema_desc = preg_replace( ”/r|n/”, ” ”, $__schema_desc );
“`
Then line 236:
“`php
236 ”description”:”’.$__schema_desc.’”’.
“`
Three problems with that sanitizer:
1. Line 43 is a no-op. Both arguments to `str_replace` are the identical ASCII apostrophe, so it replaces `’` with `’`. It looks like it was meant to be an entity or a curly quote.
2. Line 45 strips `r` and `n` but **no other control character**. `t` (`U+0009`) and every other `U+0000`-`U+001F` codepoint pass straight through into a JSON string literal, where they are illegal per RFC 8259 §7.
3. Nothing handles `</script>`. Line 44 turning `”` into `’` does not help, since `</script>` contains no quotes.
Line 176 has the same defect for the location address:
“`php
176 $_schema_location .= ‘{”@type”:”Place”,’.$_name.’”address”:{”@type”: ”PostalAddress”,”streetAddress”:”’. str_replace(”,”,”,”, stripslashes($location_address) ).’”}}’;
“`
`$location_address` comes from `event_location` term meta and is interpolated with no control-character handling at all.
The post title at line 231 goes through `htmlspecialchars(…, ENT_QUOTES)`, which handles quotes but likewise passes control characters through untouched.