Schema.org JSON-LD Generator for Blog Posts: Build Guide
TL;DR: Schema.org JSON-LD is structured data, embedded in a <script type="application/ld+json"> tag, that tells search engines exactly what a page is rather than leaving them to infer it from the HTML. For a blog post, that means an Article or BlogPosting object with a headline, author, publish date, image, and description, which is what unlocks rich results such as article cards with a byline and date directly in search listings. Hand-writing this per post is exactly the kind of task that drifts out of sync with the actual content, so the better approach is generating it from the same front matter that already drives the page: title, description, date, author, and featured image. Build one generator function, call it from every post's layout, and validate the output against the structured data requirements search engines document before it ships. The payoff is not a ranking boost by itself; it is eligibility for the richer search result formats that tend to earn a higher click-through rate than a plain blue link.
What Is Schema.org JSON-LD, and Why Does It Matter for Blog Posts?
Schema.org is a shared vocabulary that search engines agreed to support for describing the content of a page in a structured, machine-readable way. JSON-LD is the format most commonly used to express it: a block of JSON, describing the page using Schema.org's vocabulary, embedded in a script tag that browsers ignore and search engines read.
For a blog post, this closes a gap that plain HTML leaves open. A search engine can guess that a page with an <h1> and several paragraphs is probably an article, but it has to guess at the author, the real publish date, as opposed to whatever date happens to appear in the visible text, and which image represents the post. JSON-LD states all of this explicitly, which is what makes a search engine confident enough to show a richer result, an article card with a byline, a date, and sometimes an image thumbnail, rather than a plain title and snippet.
Which Schema.org Type Should a Blog Post Actually Use?
Two types cover almost every blog post: Article and its more specific subtype BlogPosting. BlogPosting is the more precise choice for a post published as part of a blog, and using the more specific type when it fits is generally the safer choice, since it tells search engines exactly what they are looking at rather than the broader category.
Both share the same core required and recommended fields, so switching between them later, if you decide a more specific type fits better, does not mean rebuilding the generator, only changing the @type value it outputs.
What Fields Does a Valid Blog Post Schema Actually Need?
A minimal but genuinely useful BlogPosting object looks like this:
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "Schema.org JSON-LD Generator for Blog Posts: Build Guide",
"description": "Build a Schema.org JSON-LD generator that outputs valid Article structured data for every blog post automatically.",
"image": "https://yanni.uk/og/schema-jsonld-generator-blog-posts.png",
"datePublished": "2026-08-04",
"dateModified": "2026-08-04",
"author": {
"@type": "Person",
"name": "Yanni",
"url": "https://yanni.uk/about/"
},
"publisher": {
"@type": "Organization",
"name": "yanni.uk",
"logo": {
"@type": "ImageObject",
"url": "https://yanni.uk/logo.png"
}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://yanni.uk/technical-documentation/schema-jsonld-generator-blog-posts/"
}
}
headline, image, datePublished, and author are the fields that matter most for eligibility; publisher and mainEntityOfPage round it out to match the fully recommended shape search engines document. Leaving dateModified equal to datePublished on first publish is correct; update it only when the content actually changes later.
How Do You Generate JSON-LD Automatically from Front Matter?
Every field above already exists somewhere in a typical post's front matter, so the generator is mostly a mapping function, not new data entry:
function buildArticleSchema(post, siteUrl) {
return {
"@context": "https://schema.org",
"@type": "BlogPosting",
headline: post.title,
description: post.metaDescription,
image: `${siteUrl}/og/${post.slug}.png`,
datePublished: post.publishDate,
dateModified: post.updatedDate || post.publishDate,
author: {
"@type": "Person",
name: post.author || "Yanni",
url: `${siteUrl}/about/`,
},
publisher: {
"@type": "Organization",
name: "yanni.uk",
logo: {
"@type": "ImageObject",
url: `${siteUrl}/logo.png`,
},
},
mainEntityOfPage: {
"@type": "WebPage",
"@id": `${siteUrl}/technical-documentation/${post.slug}/`,
},
};
}
module.exports = { buildArticleSchema };
This function takes the same front matter object a page already loads to render its title and description, so there is no second source of truth to keep updated. If the OG image is generated the way covered in astro-cloudflare-pages-guide, the image field can point at exactly the file that pipeline produces, keeping the schema's image and the page's actual social preview image identical.
How Do You Inject the Generated Schema into Every Page?
Call the generator in the page layout and serialise the result into a script tag in the document head:
<script type="application/ld+json" set:html={JSON.stringify(buildArticleSchema(post, siteUrl))}></script>
Wiring it into a shared layout component, rather than pasting a schema block into every individual post file, is what makes this maintainable. Every post that flows through the layout gets correct, current schema automatically, and a change to the schema shape, adding a new recommended field, for instance, only needs to happen in one place.
How Do You Validate the Output Is Actually Correct?
A JSON-LD block that is syntactically valid JSON can still be semantically wrong, missing a required field or using the wrong type for a value, so validate against the actual specification rather than just confirming it parses.
node -e "
const { buildArticleSchema } = require('./schema.js');
const testPost = { title: 'Test Post', metaDescription: 'A description.', slug: 'test-post', publishDate: '2026-08-04' };
console.log(JSON.stringify(buildArticleSchema(testPost, 'https://yanni.uk'), null, 2));
" | python3 -m json.tool
Piping the output through a JSON formatter confirms it is at least valid JSON; from there, run the result through a structured data testing tool to confirm it matches what search engines expect for the type you are using, and fix any warnings about missing recommended fields before treating the generator as done.
How Do You Handle Author and Publisher Schema Correctly?
The author and publisher fields are where a lot of generated schema quietly breaks, usually because they get hardcoded once and never revisited when something about the site changes, like a new logo or a second author joining. Keep both as small, shared objects, a site config file, not a value inlined into every generator call, so a single update propagates to every post rather than needing to touch each one.
For a site with a single author, author can safely be a constant. For a site or portfolio with multiple contributors, pull it from the post's own front matter instead, the same way the generator function above reads post.author, so each post correctly attributes the person who actually wrote it.
How Does This Fit with Your Sitemap and SEO Audit Process?
Structured data is one more thing that can silently break: a field gets renamed in the front matter schema, and every post's JSON-LD starts omitting it without anyone noticing, because a missing recommended field does not throw an error, it just quietly reduces eligibility for rich results. Add a check for this to the same audit process covered in automated-seo-audits-claude-skills, verifying that every URL in the sitemap also has valid, complete JSON-LD, not just checking that the script tag is present.
Once a post's schema and metadata are correct, that is also the point to make sure the URL gets picked up quickly by search engines; the automation for pinging on publish is covered in indexnow-sitemap-automation.
How Do You Automate This Across a Whole Portfolio of Sites?
If more than one site publishes blog posts, the generator function is worth extracting into a small shared package rather than copying schema.js into every repository, the same way you would not want several slightly different versions of the same sitemap logic drifting apart over time. Package it properly, following the same structure covered in claude-plugin-from-scratch, and every site imports the same tested logic instead of maintaining its own copy.
Wire the generation and validation steps into whatever triggers a deploy, following the pipeline pattern in cicd-pipelines-claude-projects and the repository automation in github-integration-claude, so a post with broken or missing schema fails the build rather than shipping quietly. If a validation step runs through an MCP-based tool and starts failing unexpectedly, the general debugging steps in mcp-troubleshooting-guide apply to that connection the same way they would to any other MCP server.
Frequently Asked Questions
Does adding JSON-LD schema directly improve search rankings?
Not directly. Structured data is not itself a ranking factor in the way page speed or backlinks are. What it does is make a page eligible for richer result formats, an article card with a byline and date rather than a plain title and snippet, which tends to improve click-through rate even at the same ranking position. Better click-through rate is a real, measurable benefit; it is just not the same mechanism as a direct ranking boost.
What happens if a required field is missing from the generated schema?
The page usually still renders and the schema still parses as valid JSON, which is exactly why this fails silently. Search engines simply treat the page as ineligible for the rich result formats that need the missing field, without any visible error on the page itself. This is why validating against the actual specification, not just checking the JSON parses, matters as a build step rather than an occasional manual check.
Should every page on the site have BlogPosting schema, or just posts?
Just posts, and use the type that actually matches each page. A pricing page or an about page is not an article, and forcing BlogPosting schema onto it is inaccurate in a way that can cause search engines to trust the site's structured data less broadly. Match the schema type to the actual content type; product pages, FAQ pages, and blog posts each have their own appropriate Schema.org type.
How do I know if my JSON-LD is actually being read correctly by search engines?
Search engines that support rich results generally provide a way to test a specific URL and see exactly what structured data they detected and whether it is eligible for enhanced display. Run every new page type through that kind of check at least once when the generator is new, and periodically afterward as part of the audit process, since a template change can silently break schema for every post that uses it at once.