skip to Main Content

I have a product page at /products/[slug].js

and I use Incremental Static Generation for a wordpress/graphql site:

export async function getStaticProps(context) {

    const {params: { slug }} = context

    const {data} = await client.query(({
        query: PRODUCT_SLUG,
        variables: { slug }
    }));

    return {
        props: {
            categoryName: data?.productCategory?.name ?? '',
            products: data?.productCategory?.products?.nodes ?? []
        },
        revalidate: 1
    }

}

export async function getStaticPaths () {
    const { data } = await client.query({
        query: PRODUCT_SLUGS,
    })

    const pathsData = []

    data?.productCategories?.nodes && data?.productCategories?.nodes.map((productCategory) => {
        if (!isEmpty(productCategory?.slug)) {
            pathsData.push({ params: { slug: productCategory?.slug } })
        }
    })

    return {
        paths: pathsData,
        fallback: true,
    }
}

Everything works as expected except one thing. If I delete a product from wordpress which was previously published, NextJs serves the cached page instead of showing 404 - Not found page, and I think this is how it is supposed to work, meaning that if something isn’t rebuilt, show the previous (stale) page.

But how can I completely remove the cache for a specific product which has been deleted and it is not fetched again from the PRODUCT_SLUGS query ?

I have read the fallback options: true, false, blocking but none of them seems to work.

Is there a solution to this, either a next.config.js configuration or another work around ?

2

Answers


  1. So I ran into this same issue, although I am using GraphCMS. So here is what you need to do to fix:

        export async function getStaticProps(context) {
        const {params: { slug }} = context
    
        const {data} = await client.query(({
            query: PRODUCT_SLUG,
            variables: { slug }
        }));
    
        if (!data) {
            return {
                notFound: true
            }
        } else {
            return {
                props: {
                    categoryName: data?.productCategory?.name ?? '',
                    products: data?.productCategory?.products?.nodes ?? []
                },
                revalidate: 1
            }
        }
    }
    

    You need to return notFound: true in getStaticProps

    notFound – An optional boolean value to allow the page to return a 404 status and page.

    See this page in the docs https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation

    Then in getStaticPaths change fallback to fallback: "blocking". If you keep fallback: true it is going to serve the stale page since that built successfully.

    Login or Signup to reply.
  2. I think this is possible starting from [email protected] using this feature On-demand Incremental Static Regeneration
    https://nextjs.org/blog/next-12-1#on-demand-incremental-static-regeneration-beta

    basically you can define an api path in this way

    // pages/api/revalidate.js
    
    export default async function handler(req, res) {
      // Check for secret to confirm this is a valid request
      if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
        return res.status(401).json({ message: 'Invalid token' })
      }
      const PRODUCT_SLUGS = req.query.product_slug;
    
      try {
        await res.unstable_revalidate(`/products/${PRODUCT_SLUGS}`)
        return res.json({ revalidated: true })
      } catch (err) {
        // If there was an error, Next.js will continue
        // to show the last successfully generated page
        return res.status(500).send('Error revalidating')
      }
    }
    

    Using this api path you can invalidate the cache for a specific product

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search