Structured Data with React and Contentful
Contentful
SEO
Recently in Contentful's Discord channel, a user posted asking for help on how to implement structured data on their site.
For those not familiar with structured data, it is a standardized markup that is added to the HTML of your webpage. It can help improve your SEO by providing important information about the content of your page. You can read more about how to format your structured data on https://schema.org/.
There are multiple ways to format your data, but the most common is JSON. There are multiple ways you could store this information in Contentful. The user in Discord was asking about storing as Rich Text. While Contentful does return it's Rich Text data as JSON, the format of the JSON is not configurable. This would make trying to get your structured data into the correct JSON format a nightmare.
Luckily, there are better options for rendering your structured data. I will cover one obvious way, and another option that isn't as obvious but what I prefer.
Structured Data as JSON Field
The obvious answer is store your structured data JSON in a JSON object field in Contentful.
The benefit is you get a specific field that will correctly structure your JSON. You can fully customize your structured data. From here, all you need to do is inject the field value into your script
tag in the head of your page and you are good to go.
Build Structured Data from Page
The second option, which is what I went with, was to create a separate component for your structured data. From there, I pass information about the page to the component to populate the JSON.
What I use on my site looks like the following:
import { SITE_OWNER_GITHUB, SITE_OWNER_LINKEDIN, SITE_OWNER_TWITTER, SITE_OWNER, SITE_URL } from '../../lib/constants'
export default function PostSchema({ post }) {
const url = `${SITE_URL}/blog/${post.slug}`;
return (
<script
defer
type="application/ld+json"
className="yoast-schema-graph yoast-schema-graph--main"
dangerouslySetInnerHTML={{__html: `
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "${url}"
},
"headline": "${post.title}",
"image": [
"${post.metaImage != null ? post.metaImage.url : null}"
],
"datePublished": "${post.publishDate}",
"dateModified": "${post.updatedAt}",
"author": {
"@type": "Person",
"name": "${post.author.name}",
"url": "${SITE_URL}/author/${post.author.slug}",
@id":"${SITE_URL}/author/${post.author.slug}#person",
"sameAs":
[
"${post.author.twitter}",
"${post.author.github}",
"${post.author.linkedin}"
]
},
"publisher": {
"@type": "Person",
"name": "${SITE_OWNER}",
"sameAs":
[
"https://twitter.com/${SITE_OWNER_TWITTER}",
"https://github.com/${SITE_OWNER_GITHUB}",
"https://www.linkedin.com/in/${SITE_OWNER_LINKEDIN}/",
"${SITE_URL}/about"
]
}
}
`}}
>
</script>
)
}
At the top, I import some constant values, like my Github, Twitter, and LinkedIn usernames.
From there I pass in the post object to populate missing fields for the post and author data.
From there, you just need to reference your component on your post page and pass in the post object itself.
<PostSchema post={post} />
Rendering the structured data this way has two advantages over the JSON object field:
- First, because most of the schema is set in code, we avoid any user error. Editors do not need to write out the entire schema in Contentful. This helps avoid JSON formatting errors. Also, we can make sure that the schema is in the same format for every single post.
- Second, this avoids any issues with data consistency. Since data in the schema is being pulled from the post itself, we avoid inconsistencies between fields like headline, publish date, etc.
And just like that, every post on your site has structured data.
Final Thoughts
Hopefully you found this helpful. This was the best way I thought to add structured data to my site. If you have taken a different approach that you like better, please let me know. I am always enjoy seeing what creative ways people have come up with to solve problems.
And if you have any questions about this post, or anything else Contentful related, feel free to reach out!