Next.js dynamic routes from nested content relationship

I asked another question about dynamic routes here, and Sam was super helpful for getting dynamic routing from content relationships figured out. Currently, I've got my pages directory structured like this:

└── pages
    └── [landing]
        └── [uid].tsx
        └── index.tsx

And my [uid].tsx template looks like this:

import React from 'react';

import { SEO } from 'components/seo/SEO';
import { SliceZone } from 'components/slice-zone/SliceZone';
import Prismic from 'prismic-javascript';

import { Client, queryWithLanguage, queryWithProductsDealers } from '../../lib/prismic';

export const Page = ({ document, city }: any) => {
  const { meta_title, meta_description, meta_keywords, social_image } = document.results[0].data;
  const slices = document.results[0].data;

  const title = `${city} ${meta_title}`;
  const description = `${city} ${meta_description}`;

  if (!slices) return null;
  return (
    <>
      <SEO
        title={title}
        description={description}
        keywords={meta_keywords}
        banner={social_image.url}
      />
      <SliceZone slices={slices} />
    </>
  );
};

export default Page;

export const getServerSideProps = async ({ params }: any) => {
  const { uid, landing } = params;

  const { id, data: dealer } = await Client.getByUID('dealer', landing, queryWithLanguage);
  const document = await Client.query(
    [
      Prismic.Predicates.at('my.landing.dealers.dealer', id),
      Prismic.Predicates.at('my.landing.uid', uid),
    ],
    {lang: 'en-us', fetchLinks: ['product.body', 'dealers.data']}
  );

  return {
    props: {
      document,
      city: dealer.dealer_location,
    },
  };
};

So, I'm getting the id of the dealer page that is requested in my params, and then I'm able to pull that data in to pass through getServerSideProps. That being said, I want to go one level deeper...

Essentially, I could have upwards of 75-100 different dealer documents, and each time I create a new page of the type landing I don't want to have to add all of those documents as individual content relationships. So, what I'm wondering is this: is it possible to have a single document, dealers_list for example, with a group field of content relationships that I can use for each dealer, and am I able to query those content relationships in my uid page, allowing for users to access my landing pages at both mysite.com/landing-page and mysite.com/sacramento-ca/interior-doors or mysite.com/denver-co/interior-doors defining the cities in my dealer_list document? See my other question for more clarity about my initial needs. Now that I've gotten that working I guess I'm a glutton for punishment and need more...

Thanks in advance!

Hey @jesse,

This seems interesting.

If I understand suppose in the end you'll have a site structure sort of like this (hypothetically):

.
.
├── landing-page
├── interior-doors
├── sacramento
│   ├── landing-page
│   └── interior-doors
├── detroit
│   ├── landing-page
│   └── interior-doors
└── new-york
    ├── landing-page
    └── interior-doors

What information will be associated with the city? Will it be just the name of the city?

And you want to have only one "landing page" document in your repo, and you want to have only one "interior doors" document in your repo? But you want those pages to be accessible via dozens of routes?

If that is the case, I have to warn you: you'll probably only be able to generate internal links to one version of the page. So, on /sacramento/landing-page, you won't be able to link to /sacramento/interior-doors with Prismic's link helpers. You'll only be able to link to /interior-doors. Because the link helper only looks at the linked document, it doesn't look at the document linked from — so it can't know that you're in Sacramento or Detroit. Furthermore, I don't think the Link Resolver or Route Resolver would be able to compute this hierarchy.

To accomplish this kind of linking, you'd probably need to code your own link component.

Let me know if this makes sense so far, and what info you need on the city.

Sam

Hi Sam! So, I actually figured out a more viable solution that allows for a lot more flexibility. I'll post my solution here for anyone else that needs it.

I have a repeatable type called dealer, and create a document for each, with a uid. Within my [landing]/[uid].tsx I call to two documents, the landing page that is requested i.e. interior-doors and the dealer uid that is requested, i.e. sacramento-ca:

export const getServerSideProps = async ({ params }: any) => {
  const { uid, landing } = params;

  const { data: document } = await Client.getByUID('landing', uid, {
    lang: 'en-us',
    fetchLinks: ['product.body'],
  });

  const { data: dealer } = await Client.getByUID('dealer', landing, {
    lang: 'en-us',
    fetchLinks: ['dealers_list.data'],
  });

  return {
    props: {
      document,
      dealer,
    },
  };
};

I then pass the props for the dealer into the page. Now, for SEO!

Within my dealers type, I have a group field called page_seo with a link called link, a meta_title, and a meta_description. For each landing page I want to have region specific routes I create a group, link to that landing page, and then have the meta_title and meta_description. Then, in [landing]/[uid].tsx I do this:

const { page_seo } = dealer;

const dealerMeta = page_seo.reduce((meta_content: string, results: SEOResultsProps) => {
    const path = results.link.uid == uid;
    if (path) {
      return {
        meta_title: results.meta_title,
        meta_description: results.meta_description,
      };
    }
    return meta_content;
  }, '');

and I'm able to pass the dealer specific meta into my SEO component, meta.meta_description etc, getting the content from the dealer document that's been requested. I hope this isn't confusing all written out; while it may be hacky it's getting the job done!

1 Like

Hey Jesse,

I think I understand the general gist of your solution. I'm glad you've got it working! It's an interesting case, and it's cool to see that you've figure out a way to scale it efficiently. Please let us know how it goes!

Sam

This issue has been closed due to inactivity. Flag to reopen.