Get all old UIDs associated with a given document

Hi @sebastien.vassaux & @bart ,

I talked with Levi here in the team and he created a workaround for this when building our documentation website that re-directs to the correct page when you use the old UID. It basically involves running the query live if the UID is not in the static list, it searches the API and returns the document with the old UID. If the UID doesn't exist anywhere the standard 404 is returned.

Example

This example is in Next.js and using the REST API but the logic should work the same with whatever technology you are using.

First, we create a custom useUpdatedUidRedirect.js hook file that checks if the route exists in the link resolver and does the redirect to the correct page.

import { useEffect } from 'react'
import { linkResolver } from 'prismic-configuration'

const useUpdatedUidRedirect = (document, router) => {
  useEffect(() => {
    const route = router.asPath.split('/')
    const uid = getUidFromRoute(route)
    const urlParams = getParamsFromRoute(route)

    if (document.uid !== uid) {
      const forwardUrl = `${linkResolver(document)}${urlParams}`
      router.replace(forwardUrl)
    }
  }, [document])
}

const getUidFromRoute = (route) => (
  route[route.length - 1]
    .replace(/#.*$/, '')
    .replace(/\?.*$/, '')
)

const getParamsFromRoute = (route) => {
  const pageRoute = route[route.length - 1]
  if (pageRoute.includes('?')) return `?${pageRoute.split('?').pop()}`
  if (pageRoute.includes('#')) return `#${pageRoute.split('#').pop()}`
  return ''
}

export default useUpdatedUidRedirect

Then in our dynamic [uid].js file, we do a few things:

  1. Import the useRouter function from next.js router.
  2. We import our custom useUpdatedUidRedirect hook.
  3. Call the router.
  4. Create an if statement to return 404 if the document doesn't exist.
  5. Call the useUpdatedUidRedirect hook and pass it the document and router.
  6. In the getStaticPaths function we set fallback: true so that the check is run if the UID is not found.
import React from 'react'
import DefaultLayout from 'layouts'
import { Header, SliceZone } from 'components'
import { queryRepeatableDocuments } from 'utils/queries'
import { Client } from 'utils/prismicHelpers'

import { useRouter } from 'next/router'
import useUpdatedUidRedirect from 'utils/hooks/useUpdatedUidRedirect'

const Page = ({ doc, menu }) => {

  const router = useRouter()

  if (!doc) {
    return null
  }

  useUpdatedUidRedirect(doc, router)

  if (doc && doc.data) {
    return (
      <DefaultLayout>
        <div className="page">
          <Header menu={menu} />
          <SliceZone sliceZone={doc.data.page_content} />
        </div>
      </DefaultLayout>
    )
  }

  // Call the standard error page if the document was not found
  return null;
}


export async function getStaticProps({ params, previewData}) {
  const ref = previewData ? previewData.ref : null

  const client = Client()

  const doc = await client.getByUID('page', params.uid, ref ? { ref } : null) || {}
  const menu = await client.getSingle('menu', ref ? { ref } : null) || {}
  
  return {
    props: {
      menu,
      doc,
      preview: {
        activeRef: ref,
      }
    }
  }
};

export async function getStaticPaths() {
  const documents = await queryRepeatableDocuments((doc) => doc.type === 'page')
  return {
    paths: documents.map(doc => `/${doc.uid}`),
    fallback: true,
  }
}

export default Page

Let me know if this is clear or not. I will begin working on adding this to our Next.js example projects. I'm not sure if I should add it to the documentation though, maybe just here works, what do you think?

1 Like