Claude-blog blog-schema
git clone https://github.com/AgriciDaniel/claude-blog
T=$(mktemp -d) && git clone --depth=1 https://github.com/AgriciDaniel/claude-blog "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/blog-schema" ~/.claude/skills/agricidaniel-claude-blog-blog-schema && rm -rf "$T"
skills/blog-schema/SKILL.mdBlog Schema -- JSON-LD Structured Data Generation
Generates complete, validated JSON-LD schema markup for blog posts using the @graph pattern. Combines multiple schema types into a single script tag with stable @id references for entity linking.
Workflow
Step 1: Read Content
Read the blog post and extract all schema-relevant data:
- Title (headline)
- Author (name, job title, social links, credentials)
- Dates (datePublished, dateModified / lastUpdated)
- Description (meta description)
- FAQ section (question and answer pairs)
- Images (cover image URL, dimensions, alt text; inline images)
- Organization info (site name, URL, logo)
- Word count (approximate from content length)
- Tags/categories (for BreadcrumbList category)
- Slug (from filename or frontmatter)
Step 2: Generate BlogPosting Schema
Complete BlogPosting with all required and recommended properties:
{ "@type": "BlogPosting", "@id": "{siteUrl}/blog/{slug}#article", "headline": "Post title (max 110 chars)", "description": "Meta description (150-160 chars)", "datePublished": "YYYY-MM-DD", "dateModified": "YYYY-MM-DD", "author": { "@id": "{siteUrl}/author/{author-slug}#person" }, "publisher": { "@id": "{siteUrl}#organization" }, "image": { "@id": "{siteUrl}/blog/{slug}#primaryimage" }, "mainEntityOfPage": { "@type": "WebPage", "@id": "{siteUrl}/blog/{slug}" }, "wordCount": 2400, "articleBody": "First 200 characters of content as excerpt..." }
Required properties: @type, headline, datePublished, author, publisher, image. Recommended properties: description, dateModified, mainEntityOfPage, wordCount, articleBody (excerpt).
Step 3: Generate Person Schema
Author schema with stable @id for cross-referencing:
{ "@type": "Person", "@id": "{siteUrl}/author/{author-slug}#person", "name": "Author Name", "jobTitle": "Role or Title", "url": "{siteUrl}/author/{author-slug}", "sameAs": [ "https://twitter.com/handle", "https://linkedin.com/in/handle", "https://github.com/handle" ] }
Optional properties (include when available):
- Educational institution (Organization type)alumniOf
- Employer (reference to Organization @id if same entity)worksFor
Step 4: Generate Organization Schema
Blog's parent organization entity:
{ "@type": "Organization", "@id": "{siteUrl}#organization", "name": "Organization Name", "url": "{siteUrl}", "logo": { "@type": "ImageObject", "url": "{siteUrl}/logo.png", "width": 600, "height": 60 }, "sameAs": [ "https://twitter.com/org", "https://linkedin.com/company/org", "https://github.com/org" ] }
Logo requirements: must be a valid image URL. Google recommends logos be 112x112px minimum, 600px wide maximum. Rectangular logos preferred for BlogPosting publishers.
Step 5: Generate BreadcrumbList
Navigation breadcrumb schema showing content hierarchy:
{ "@type": "BreadcrumbList", "@id": "{siteUrl}/blog/{slug}#breadcrumb", "itemListElement": [ { "@type": "ListItem", "position": 1, "name": "Home", "item": "{siteUrl}" }, { "@type": "ListItem", "position": 2, "name": "Category Name", "item": "{siteUrl}/blog/category/{category-slug}" }, { "@type": "ListItem", "position": 3, "name": "Post Title", "item": "{siteUrl}/blog/{slug}" } ] }
If no category is available, use "Blog" as the second breadcrumb item with
{siteUrl}/blog as the URL.
Step 6: Generate FAQPage Schema
Extract Q&A pairs from the blog post's FAQ section:
{ "@type": "FAQPage", "@id": "{siteUrl}/blog/{slug}#faq", "mainEntity": [ { "@type": "Question", "name": "What is the question?", "acceptedAnswer": { "@type": "Answer", "text": "The complete answer text (40-60 words with statistic)." } } ] }
Important note: Google restricted FAQ rich results to government and health sites since August 2023. However, FAQ schema markup still provides value because:
- AI systems (ChatGPT, Perplexity, Gemini) extract FAQ data for citations
- It structures content for future rich result eligibility changes
- It improves content organization signals
Step 7: Generate VideoObject (if videos present)
For each YouTube video embedded in the post, generate a VideoObject schema:
{ "@type": "VideoObject", "@id": "{siteUrl}/blog/{slug}#video-{index}", "name": "Video title", "description": "Video description excerpt (first 200 chars)", "thumbnailUrl": "https://img.youtube.com/vi/{videoId}/hqdefault.jpg", "uploadDate": "{ISO 8601 date}", "contentUrl": "https://www.youtube.com/watch?v={videoId}", "embedUrl": "https://www.youtube.com/embed/{videoId}", "duration": "PT{M}M{S}S", "interactionStatistic": { "@type": "InteractionCounter", "interactionType": { "@type": "WatchAction" }, "userInteractionCount": {viewCount} } }
Add each VideoObject to the @graph array. Use
#video-1, #video-2 etc. for
the @id fragment. Extract video metadata from the embed's noscript fallback or
from YouTube Data API if available via blog-google.
Step 7.5: Generate ImageObject
Cover image schema for the post's primary image:
{ "@type": "ImageObject", "@id": "{siteUrl}/blog/{slug}#primaryimage", "url": "https://cdn.pixabay.com/photo/.../image.jpg", "width": 1200, "height": 630, "caption": "Descriptive caption matching alt text" }
Image requirements:
- URL must be crawlable and publicly accessible
- Width and height should reflect actual image dimensions
- Caption should match or closely align with the image alt text
- Preferred dimensions: 1200x630 (OG-compatible) or 1920x1080
Step 8: Validate & Warn
Check for deprecated schema types and apply validation rules:
NEVER use these deprecated types:
- HowTo - Deprecated September 2023 (Google no longer shows rich results)
- SpecialAnnouncement - Deprecated July 2025
- Practice Problem - Deprecated (education markup)
- Dataset - Deprecated for general use
- Sitelinks Search Box - Deprecated
- Q&A - Deprecated January 2026 (distinct from FAQPage)
Validation checks:
- All @id references resolve to entities within the @graph
- dateModified is equal to or after datePublished
- headline does not exceed 110 characters
- description is between 50-160 characters
- All URLs are absolute (not relative)
- Image dimensions are positive integers
- BreadcrumbList positions are sequential starting from 1
- FAQPage has at least 2 questions
AI citation optimization note: Pages using 3 or more schema types have approximately 13% higher AI citation likelihood. This skill generates up to 7 types (BlogPosting, Person, Organization, BreadcrumbList, FAQPage, ImageObject, VideoObject) to maximize both search engine understanding and AI extraction.
Step 9: Output
Combine all schemas into a single
<script> tag using the @graph pattern:
<script type="application/ld+json"> { "@context": "https://schema.org", "@graph": [ { "@type": "BlogPosting", ... }, { "@type": "Person", ... }, { "@type": "Organization", ... }, { "@type": "BreadcrumbList", ... }, { "@type": "FAQPage", ... }, { "@type": "VideoObject", ... }, { "@type": "ImageObject", ... } ] } </script>
@graph pattern benefits:
- Single script tag instead of multiple - cleaner HTML
- Entity linking via stable @id references (e.g., author references Person by @id)
- Google and AI systems parse @graph arrays correctly
- Easier to maintain and update as a single block
Output options:
- Embedded HTML - Ready to paste into
or before<head></body> - Standalone JSON - For CMS schema fields or API injection
- MDX component - If the project uses MDX, wrap in a component
Save the generated schema to the blog post file or to a separate schema file as the user prefers.