CoursesSEO optimized content with Next.jsExtending the SEO schema types
Track
Work-ready Next.js

SEO optimized content with Next.js

Lesson
3

Extending the SEO schema types

Now you're setup for success, extend the fields made available to your authors.
Log in to mark your progress for each Lesson and Task

In the first lesson, you learned how to add some basic SEO fields to your schema. Now you're going to kick it up a notch with Open Graph fields and more granular controls over displaying documents in lists.

Update your seoType schema type to include description, image and a noIndex field
import { defineField, defineType } from "sanity";
export const seoType = defineType({
name: "seo",
title: "SEO",
type: "object",
fields: [
defineField({
name: "title",
description: "If provided, this will override the title field",
type: "string",
}),
defineField({
name: "description",
type: "text",
}),
defineField({
name: "image",
type: "image",
options: {hotspot: true}
}),
defineField({
name: "noIndex",
type: "boolean",
}),
],
});

You may wish to have separate title and description fields for Open Graph properties. But in this course you'll re-use these values.

Update PAGE_QUERY and POST_QUERY to include these new attributes, along with default values
src/sanity/lib/queries.ts
export const PAGE_QUERY =
defineQuery(`*[_type == "page" && slug.current == $slug][0]{
...,
"seo": {
"title": coalesce(seo.title, title, ""),
"description": coalesce(seo.description, ""),
"image": seo.image,
"noIndex": seo.noIndex == true
},
content[]{
...,
_type == "faqs" => {
...,
faqs[]->
}
}
}`);
Run the following to regenerate Types now that you've made schema and query changes
npm run typegen

With these fields now present in your schema types and queries, you can now render even more metadata in your route.

Note in the code below how the Open Graph image reuses the urlFor helper function to generate an image the correct width and height–and will also respect crop and hotspot data.

The value for noindex we only include in the metadata if it is set to true.

src/app/(frontend)/[slug]/page.tsx
// ...the rest of your route
export async function generateMetadata({
params,
}: RouteProps): Promise<Metadata> {
const { data: page } = await getPage(params);
if (!page) {
return {}
}
const metadata: Metadata = {
title: page.seo.title,
description: page.seo.description,
};
if (page.seo.image) {
metadata.openGraph = {
images: {
url: urlFor(page.seo.image).width(1200).height(630).url(),
width: 1200,
height: 630,
},
};
}
if (page.seo.noIndex) {
metadata.robots = "noindex";
}
return metadata;
}

Don't forget to update your individual post route as well.

Having a page set to noIndex typically means that you want the published document to exist as a route in your application—but you don't want it included in search results. Either on search engine results or within your website.

Nothing needs to change now with your page type documents, but if you were to include these fields in your post type documents, you'd likely want to update any query that looks up and renders many posts to exclude results where noIndex is true. For example:

Example only
*[_type == "post" && seo.noIndex != true]

You'll see an example of this later in the lesson Build a dynamic sitemap.

Now your Sanity Studio and application are capable of authoring, querying and rendering complex metadata for the most common SEO needs. You can continue to extend these fields for any other metadata requirements.

In the following lesson you'll take on another major SEO concern: redirects.

You have 3 uncompleted tasks in this lesson
0 of 3