Mathias Riis Sorensen
Mathias Riis Sorensen

Reputation: 860

Nextjs - Contentful - Tags - Dynamic pages

I would like to create dynamic pages when I click a tag in an article or elsewhere on my website.

I'm using Next.js, SSG, and fetching the articles containing the tags from Contentful with the following GraphQL queries:

export async function getArticles() {
  const articlesQuery = gql`
    {
      articleCollection(order: date_DESC) {
        items {
          title
          slug
          excerpt
          date
          contentfulMetadata {
            tags {
              name
              id
            }
          }
          featuredImage {
            title
            url
            width
            height
          }
          author {
            name
            photo {
              fileName
              url
              width
              height
            }
            title
            twitterProfile
            linkedInProfile
            slug
          }
        }
      }
    }
  `;
  return graphQLClient.request(articlesQuery);
}
export async function getArticle(slug) {
  const articleQuery = gql`
    query getArticle($slug: String!) {
      articleCollection(limit: 1, where: { slug: $slug }) {
        items {
          title
          slug
          excerpt
          date
          contentfulMetadata {
            tags {
              name
              id
            }
          }
          featuredImage {
            title
            url
            width
            height
          }
          author {
            name
            photo {
              fileName
              url
              width
              height
            }
            title
            twitterProfile
            linkedInProfile
            slug
          }
          content {
            json
            links {
              entries {
                block {
                  sys {
                    id
                  }
                  __typename
                  ... on VideoEmbed {
                    title
                    embedUrl
                  }
                  ... on CodeBlock {
                    description
                    language
                    code
                  }
                }
              }
              assets {
                block {
                  sys {
                    id
                  }
                  url
                  title
                  width
                  height
                }
              }
            }
          }
        }
      }
    }
  `;

  return graphQLClient.request(articleQuery, {
    slug,
  });
}

The contentfulMetadata is where the tags come from:

contentfulMetadata {
            tags {
              name
              id
            }
          }

This is my [id].jsx file:

import { getArticles, getArticle } from "@utils/contentful";

export async function getStaticPaths() {
  const data = await getArticles();

  return {
    paths: data.articleCollection.items.map((article) => ({
      params: { id: article.contentfulMetadata.tags[0].id },
    })),
    fallback: false,
  };
}

export async function getStaticProps(context) {
  const data = await getArticle(context.params.id);

  return {
    props: { article: data.articleCollection.items[0] },
  };
}

export default function TagPage({ article }) {
  return (
    <div>
      <h1>{article.contentfulMetadata.tags.id}</h1>
    </div>
  );
}

I get the following error: Error: Error serializing `.article` returned from `getStaticProps` in "/tags/[id]". Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value.

When console.log(data.articleCollection.items.contentfulMetadata.tags.id); or console.log(data.articleCollection.items.contentfulMetadata.tags[0].id); within getStaticPaths function it provides the following error: TypeError: Cannot read property 'tags' of undefined

Can anyone show how to create a dynamic page ([id].jsx) file, which shows the tag id as the header <h1> as well as all articles containing the same tag?

Upvotes: 0

Views: 683

Answers (1)

Salma Alam-Naylor
Salma Alam-Naylor

Reputation: 345

Contentful DevRel here 👋🏼.

article.contentfulMetadata.tags is an array, as an entry can have more than one tag. So you'll need to access the tag you want via article.contentfulMetadata.tags[0].id or article.contentfulMetadata.tags[desired_index].id and so on.

Here's an example GraphQL query:

query {
  blogPostCollection {
    items {
      contentfulMetadata {
        tags {
          id
          name
        }
      }
    }  
  }
}

And here's the response with tags as an array:

  "data": {
    "blogPostCollection": {
      "items": [
        {
          "contentfulMetadata": {
            "tags": [
              {
                "id": "salmastag",
                "name": "Salma s tag"
              }
            ]
          }
        },
        {
          "contentfulMetadata": {
            "tags": []
          }
        }
      ]
    }
  }
}

Notice how if a blog post doesn't have any PUBLIC tags assigned (the second entry in the response), an empty array is returned — you might want to do some safety checking in your code for this.

Upvotes: 2

Related Questions