Schema markup fails in two places: Google rejects it, or the block breaks the page. Both are cheap to avoid and both are usually found a week after publication, in Search Console, when the page has already been crawled.
Schema markup that passes validation is also markup that matches the page. The generator behind this post writes the block and checks the required fields before you paste it. The rest is a habit: describe what the page shows, one main thing per page, and keep the JSON valid HTML.
Start schema markup from the type
Schema markup begins with the type, and Schema.org has hundreds of them while search engines support a handful. The useful ones for a content site fit on one line: Organization, WebSite, Article, BreadcrumbList, FAQPage, Product, Review, Event, Recipe, JobPosting.
Ask the API which types it builds and what each one needs:
curl -s "https://api.globus.studio/v2/json_ld?list=1"
{"type": "article", "requires": ["headline"]}
The list is generated from the schema classes, so a type that appears there can be built. A type that does not appear is rejected with a message instead of a half-filled object.
Fill the required fields first
curl -s "https://api.globus.studio/v2/json_ld?type=article&data[headline]=Schema%20markup&data[datePublished]=2026-11-03&prettify=1"
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Schema markup",
"datePublished": "2026-11-03"
}
@context and @type come from the generator. Empty values are dropped, which matters for template code: a variable that was not filled in disappears from the output instead of appearing as null.
The required field is the minimum. A rich result also needs what the result displays: an image for a recipe, a price for a product, a date for an event. Validation cannot check that the data matches the page, and that is the rule search engines enforce by hand.
Nested objects and escapes
FAQ markup holds an array of questions. Send it as JSON in one parameter.
curl -s "https://api.globus.studio/v2/json_ld?type=faq&json=%7B%22mainEntity%22%3A%5B%7B%22question%22%3A%22Is%20it%20valid%3F%22%2C%22answer%22%3A%22Yes.%22%7D%5D%7D"
Both shapes work: question with answer, or question with acceptedAnswer.text. The output uses the same Question and Answer pair either way.
The script block is the place schema markup breaks pages. wrap=1 escapes angle brackets, ampersands and quotes as unicode escapes, so a product description that contains a closing script tag cannot close the element. If you build the block yourself, escape the same characters; a JSON encoder alone does not do it.
Where people get it wrong
Marking a blog post as a product to earn review stars is the classic mistake. It works until a reviewer looks at the page, and then it costs a manual action that removes every rich result on the site.
The second mistake is a breadcrumb that does not match the visible navigation. Breadcrumb markup is checked against the trail on the page, and an invented trail is a mismatch, not a shortcut.
The third is duplication. Two blocks that describe the same entity, one from a plugin and one from a template, produce conflicting data. Pick one source of truth and delete the other. On a WordPress site that usually means turning off one of the two.
A check before publishing
Open the page and view the source. The block should be one script element with type="application/ld+json", valid JSON inside, and no escaped HTML entities left in text fields. Then run Google's Rich Results Test on the URL. It reports the types it found and the fields it wanted.
Keep the test result next to the page in your notes. When the template changes, the result tells you what the block used to say.
Related reading
The JSON-LD generator API page documents every parameter, including validate=0 for assembling a fragment. For the text inside the markup, the readability metrics API scores the page before publication.
Further reading: Schema.org documents and Google's structured data policies.