SEO
Lesson 3

Adding SEO fields to your project

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.

Here's how you can organize your SEO fields:

schemas/post.ts
import { defineField, defineType } from "sanity";
 
export const post = defineType({
  name: "post",
  type: "document",
  fields: [
    // ... Previous fields
    defineField({
      name: "seoHideFromLists",
      type: "boolean",
      initialValue: false,
    }),
    defineField({
      name: "seoNoIndex",
      type: "boolean",
      initialValue: false,
    }),
  ],
});

Let's start with the seoHideFromLists field. This is a boolean field that allows you to hide pages from lists such as post or projects pages through querying the seoHideFromLists field.

queries/post.ts
const posts = await sanityClient.fetch(
  `*[_type == "post" && !seoHideFromLists]`
);

This is how you would query the post document type, and check if the seoHideFromLists field is false.

For example you may want to show a member of the marketing team the new post, without it being visible to the public. It can also work well with documents like webinars, if you want to form-gate them from a public-facing list.

Now let's move onto the seoNoIndex field. This is a boolean field that allows you to hide pages from search engines by adding a noindex tag. There are occasions where you may want to hide a page from search engines, for example a dynamic thankyou page you've created with a page builder shouldn't turn up in a Google search or it may skew your analytics.

Adding Open Graph fields

While metadata is used to set the title, description, and image for the page when it's displayed via a search engine, open graph fields are used to set the title, description, and image for the page when it's shared on social media.

schemas/post.ts
// ...previous schema
defineField({
  name: 'ogTitle',
  type: 'string',
}),
defineField({
  name: 'ogDescription',
  type: 'text',
  rows: 2,
}),
defineField({
  name: 'ogImage',
  type: 'image',
}),

From experience, the open graph fields are most useful when you're sharing content as part of a marketing campaign via social media platforms. Usually you want to tailor the message for a specific audience. However, following the pattern of overrides and fallbacks, if you don't use them, they will fall back to the title, description, and image fields.

Here's the example of all the different fields in action.

Note: it's possible to fallback through several fields at once, e.g see the open graph fields fallback for:

ogTitle -> seoTitle -> title.

/posts/[slug].tsx
import { Metadata } from "next";
import { client } from "@/lib/sanity/client";
 
// Fetch post data
async function getPostData(slug: string) {
  const post = await client.fetch(
    `
    *[_type == "post" && slug.current == $slug][0]{
      title,
      description,
      image,
      seoTitle,
      seoDescription, 
      seoImage,
      seoNoIndex,
      seoHideFromLists,
      ogTitle,
      ogDescription,
      ogImage
    }
  `,
    { slug }
  );
  return post;
}
 
// Generate metadata
export async function generateMetadata({ params }): Promise<Metadata> {
  const post = await getPostData(params.slug);
 
  return {
    title: post.seoTitle ?? post.title,
    description: post.seoDescription ?? post.description,
    robots: post.seoNoIndex ? "noindex" : "index",
    openGraph: {
      title: post.ogTitle ?? post.seoTitle ?? post.title,
      description:
        post.ogDescription ?? post.seoDescription ?? post.description,
      images: post.ogImage ?? post.seoImage ?? post.image,
    },
  };
}
 
// post page component
export default async function postPage({ params }) {
  const post = await getPostData(params.slug);
 
  if (!post) return null;
 
  return (
    <main>
      <h1>{post.title}</h1>
      {/* ...post content */}
    </main>
  );
}

The real benefit of this is that any member of the team can now add these fields to their schema, it's a one-size-fits-all solution that can be reused throughout all your document types, and it can be as hands-on or hands-off as you want.

In the next lesson, you will learn how to implement redirects using Next.js and Sanity. The lesson covers creating a redirect system, managing it through your Sanity Studio, and ensuring updates without site rebuilds.