Adding Schema Data to Next.js Sites
Paul Grieselhuber
In the same spirit of last week's post about adding citations to Schema.org data, this post provides a quick and easy method for adding Schema.org data to a Next.js site.
In this project I am using Apollo to pull data via GraphQL from a Wordpress site (which ends up generating a static HTML site) - so assume standard WP post data structure. This method assumes you have called the Schema component in your Post (or similar) component in your Next.js app. So, call the Schema component as follows:
<Schema post={post} />
And the Schema component itself:
import Head from "next/head";
import { site, siteTitle } from "../../config";
function strip(html) {
const one = html.replace(/<\/?[^>]+(>|$)/gm, "");
const two = one.replace(/[\r\n]\s*[\r\n]/gm, "");
return two;
}
const Schema = ({ post }) => {
const {
title,
blurb,
featuredImage,
date,
modified,
slug,
commentCount,
author,
ratingCount,
ratingAverage,
citations,
} = post;
const published = new Date(date);
const copyrightYear = published.getFullYear();
let mediaDetails, sourceUrl;
if (featuredImage) {
sourceUrl = featuredImage.sourceUrl;
}
const citationsList = citations.map((citation, i) => {
return `{ "@type": "CreativeWork", "citation": ${JSON.stringify(
citation
)} }${i === citations.length - 1 ? "" : ","}\n`;
});
const citationsText = citationsList.join("");
const org = `{ "@id": "${site}#organization", "type": "Organization", "name":"${siteTitle}", "logo": {
"@type": "ImageObject",
"name": "${siteTitle} Logo",
"width": "230",
"height": "67",
"url": "${site}images/logo.png"
} }`;
return (
<Head>
<script type="application/ld+json">{`
{
"@context":"https://schema.org/",
"@type":"Article",
"name":"${title}",
${
ratingAverage > 4
? `"aggregateRating": {
"@type":"AggregateRating",
"ratingValue":${ratingAverage},
"reviewCount":${ratingCount}
},`
: ""
}
"about": "${blurb}",
"author": { "@type": "Person", "@id": "${site}author/${
author.slug
}", "name": "${author.name}" },
${
citationsText.length
? `"citation": [
${citationsText}
],`
: ""
}
"commentCount": ${commentCount},
"copyrightHolder": { "@id": "${site}#organization" },
"copyrightYear": ${copyrightYear},
"datePublished": "${date}",
"dateModified": "${modified}",
"description": "${blurb}",
"discussionUrl": "${site}articles/${slug}#comments",
"editor": { "@id": "${site}author/${author.slug}#author" },
"headline": "${title}",
${sourceUrl ? `"image": "${sourceUrl}",` : ""}
"inLanguage": "English",
"mainEntityOfPage": "${site}articles/${slug}",
"publisher": { "@id": "${site}#organization" },
"sourceOrganization": ${org},
"url": "${site}articles/${slug}"
}
`}</script>
</Head>
);
};
export default Schema;
You'll see a strip
function that I left in place in the example. I am trying to decide whether or not to include the post content
in the Schema data. If so, that function is used to clean up the HTML returned as content, so that we can include it in the JSON response.
Here is a gist of this snippet if you have any ideas on how to improve. PRs of course welcome.