news-catalyst / next-tinynewsdemo

Frontend for Tiny News Collective organizations
https://next-tinynewsdemo.vercel.app
1 stars 0 forks source link

Use next-seo for all SEO/social metadata #1137

Closed TylerFisher closed 2 years ago

TylerFisher commented 2 years ago

I used next-seo on my personal site and it was a lot cleaner than special-casing a bunch of stuff in <Layout>. I think we could really simplify what we're doing here by adopting it.

TylerFisher commented 2 years ago

Here's a complete rundown on how this should work.

What pages to add this to

We need to put next-seo on the following pages (from the context of pages/_sites/[site]:

Default setup

Unless otherwise specified below, this is the default value we should be setting on each page:

<NextSeo
  title={metadata.searchTitle}
  description={metadata.facebookDescription || metadata.searchDescription}
  canonical={metadata.siteUrl}
  openGraph={{
    title: {metadata.facebookTitle},
    description: {metadata.facebookDescription},
    url: {metadata.siteUrl},
    images: [
      {
        url: {metadata.defaultSocialImage},
        width: {metadata.defaultSocialImageWidth}, 
        height: {metadata.defaultSocialImageHeight},
      },
    ],
  }}
/>

Note that we're not always consistent about the name of the metadata prop. Sometimes we call it siteMetadata, sometimes we call it meta, sometimes we call it metadata. We should be more consistent about this, but that's another project. Just take a look at the props passed to the component to get the proper name in each case.

Special cases

These are guesses, I haven't tested these, but this should get you close.

Article pages

You should setup the <NextSeo> component in components/Article.js since you'll need to make some of the data computed there. This is the most complicated setup, and the most important. People mostly share articles, so we want to get all the data possible on these.

// prior to return statement, get your translation so it's easier to work with
const translation = article.article_translations[0];

// inside the return statement, add your <NextSeo> component

<NextSeo
  title={translation.searchTitle || translation.headline} // get the search title if defined, if not fall back to headline
  description={translation.searchDescription} // search description (labeled as just description in the sidebar) is required, so we can rely on it being there
  canonical={canonicalArticleUrl} // defined on line 24 of the component
  openGraph={{
    title: {translation.facebookTitle || translation.headline}, // get facebook title if defined, if not fall back to headline
    description: {translation.facebookDescription || translation.searchDescription}, // get FB description if defined, if not fall back to search description
    url: {canonicalArticleUrl},
    type: 'article',
    article: {
      publishedTime: {translation.first_published_at},
      modifiedTime: {translation.last_published_at},
      authors: {article.authors.map((a) => (`${metadata.siteUrl}/authors/${a.slug}`))}, // generate author URL for each author
      section: {article.category.category_translations[0].name}
      tags: {article.tags.map((t) => (t.translations[0].name))}, // get name of every tag in article
    },
    images: [
      {
        url: {mainImage.imageUrl},
        width: {mainImage.width}, 
        height: {mainImage.height},
      },
    ],
  }}
/>

Archive pages

Pretty straightforward, mostly use the default values.

<NextSeo
  title={`Article Archive page ${currentPageNumber} | metadata.searchTitle`}
  description={metadata.searchDescription}
  canonical={`${metadata.siteUrl}/articles/archive/${currentPageNumber}`}
  openGraph={{
    title: {`Article Archive page ${currentPageNumber} | metadata.searchTitle`},
    description: {metadata.facebookDescription || metadata.searchDescription},
    url: {meta.siteUrl},
    images: [
      {
        url: {meta.defaultSocialImage},
        width: {meta.defaultSocialImageWidth}, 
        height: {meta.defaultSocialImageHeight},
      },
    ],
  }}
/>

Author pages

<NextSeo
  title={`${authorName} | metadata.searchTitle`}
  description={metadata.searchDescription}
  canonical={`${metadata.siteUrl}/authors/${author.slug}`}
  openGraph={{
    title: {`${authorName} | metadata.searchTitle`},
    description: {metadata.facebookDescription || metadata.searchDescription},
    url: {`${metadata.siteUrl}/authors/${author.slug}`},
    images: [
      {
        url: {metadata.defaultSocialImage},
        width: {metadata.defaultSocialImageWidth}, 
        height: {metadata.defaultSocialImageHeight},
      },
    ],
  }}
/>

Category pages

<NextSeo
  title={`${props.title} | metadata.searchTitle`}
  description={metadata.searchDescription}
  canonical={`${metadata.siteUrl}/categories/${props.slug}`} // eh, looks like we're not passing the category slug as a prop. check out getStaticProps here and see if you can figure out how to pass the slug as a prop.
  openGraph={{
    title: {`${props.title} | metadata.searchTitle`},
    description: {metadata.facebookDescription || metadata.searchDescription},
    url: {`${metadata.siteUrl}/categories/${props.slug}`} // eh, looks like we're not passing the category slug as a prop. check out getStaticProps here and see if you can figure out how to pass the slug as a prop.
    images: [
      {
        url: {metadata.defaultSocialImage},
        width: {metadata.defaultSocialImageWidth}, 
        height: {metadata.defaultSocialImageHeight},
      },
    ],
  }}
/>

Static pages

<NextSeo
  title={`${localisedPage.headline} | metadata.searchTitle`}
  description={localisedPage.searchDescription}
  canonical={canonicalPageUrl} // defined on line 20
  openGraph={{
    title: {`${localisedPage.facebookTitle || localisedPage.headline} | localisedPage.searchTitle`},
    description: {localisedPage.facebookDescription || localisedPage.searchDescription},
    url: {canonicalPageUrl}
    images: [
      {
        url: {mainImage.imageUrl},
        width: {mainImage.width}, 
        height: {mainImage.height},
      },
    ],
  }}
/>