In this guide, we'll set up structured data for blog posts and images using Payload and Next.js, ensuring Google can generate rich results for your site.
Structured data (also known as schema markup) helps search engines understand the content on your website.
In this guide, we'll set up structured data for blog posts and images using Payload and Next.js, ensuring Google can generate rich results for your site.
The first step is to create a dedicated directory for our schema files.
Inside your components folder, create a new directory called Schema
. In it, you'll create a new file called index.tsx
.
Since we'll most likely use these schema types across different parts of our site, we’ll store all of our schema definitions in this file for easy reusability.
At the top of index.tsx
, import the required types:
Next, we'll create a schema specifically for blog posts.
Breaking it down:
"@context"
specifies schema.org as the standard."@type": "BlogPosting"
tells search engines this is a blog post.headline
uses props.title
for the article title.datePublished
and dateModified
use the post’s timestamps.We can then include an image URL in an array using the image
property.
Next, we'll add our authors using the author
property. Please note that this will require a dedicated author field in your posts, so you may need to add this into posts config
file; commonly, this might look something like the following:
Further, you may need to also adjust your Users.ts
config and remove the postsByUser
join field if applicable.
If you had to take any of the above steps, it's necessary to run payload generate:types
.
Back in our Schema index.tsx
file, we'll set a new const for authors
.
According to Schema.org, BlogPosting
can also take the text of the article, but Google doesn’t use it, so you may not think it’s worth it— especially since you would need to create a function to take your Lexical rich text field and transpose it into something that's readable by web crawlers like plain text.
Next, we'll work on our image schema.
We'll export a new constant called imageSchema
. This constant will also take props
, but it will take it from Media
.
You only need to include:
contentUrl
: The image URLcreditText
: Some form of attribution (license, copyright, or credit)Since "creditText"
is required by the schema, we’ll also make it required on the backend.
To ensure every media item has creditText
, go to your Payload media uploads collection (Media.ts
) and underneath alt text we'll just create a new textfield that will be called creditText.
This would look like the following:
After this, navigate to your admin panel (http://localhost:3000/admin/login
), go to media, and add a credit text to an existing image.
Once that's saved, we can come back to our schema file and finish our image schema.
Now that we have our article and image schema, we can go to our (frontend)/posts/[slug]/page.tsx file
. We'll create a new const below our const post
that we'll call schema
, and set it equal to an array.
It would look something like the following:
Contrary to popular belief, schema does not need to be included in the <head>
tag, and it does not need to be all in the same container. There will be no impact to performance or recognition by Google either way.
So, we’ll use Next.js's <Script>
component, and not even try to get it into the <head>
.
Before we navigate to a page, make sure you have all the required information in a Payload post.
This would include:
Go to your Payload Admin UI, open a blog post, and ensure all necessary data is filled in. Now, navigate to the actual page and validate the schema by opening your browser's DevTools. Once you've located the script tag, copy it (Copy Element), and paste it into Google’s Rich Results Test.
If everything is set up correctly, Google will show you that your data has passed.
You might see non-critical warnings, like "Missing recommended fields" for images, but as long as no required fields are missing, your schema is valid.
There’s even more you can do with structured data, like creating an automatic image schema for every media item, or building out more advanced schema using Schema.org documentation.