Dynamic data-driven pages with code components
Let’s say you already have data-fetching code components, either created by yourself, or from the Plasmic component store (such as components that show CMS or commerce data). You can build dynamic pages using your data-fetching code components with path parameters and query parameters.
Examples include:
- A blog with one page per post.
- A storefront with one page per product.
(If you are looking to pass dynamic data into simple static Plasmic designs that don’t use code components, see how to pass overrides to the component API.)
The approach is to take a single page designed in Plasmic, and communicate to it the URL parameters. This essentially uses that page as a template.
Example: statically generated /products/[slug] pages in Next.js or Gatsby
Here’s an example showing how to display a product at /products/[slug], using Next.js or Gatsby dynamic routes.
We’ll assume we’re fetching data using the data-fetching components in the Plasmic CMS.
Let’s say our page includes a Plasmic CMS data-fetching component instance. These components take “Filter field” and “Filter value” props that allow you to fetch specific elements from the CMS. This is specific to the Plasmic CMS data-fetching component—other data-fetching components will have different props.
In Plasmic studio, you can set “Filter field” to “slug” and bind “Filter value” to a dynamic value coming from the URL. To do so, first set the page path to “/products/[slug]” and set “slug” preview parameter to a product slug that exists in your model:
Then, set “Filter field” to “slug”, right click “Filter value” in CMS Data Loader props and hit “Use dynamic value”. You should see “Page route params”, which will let you pick the “slug” param that you added to the page path.
Code integration
In general, you will need to ensure the data from your framework’s router is passed into PlasmicRootProvider (if using Headless API) or PageParamsProvider (if using codegen).
You can find a complete example project at https://studio.plasmic.app/projects/bY35SmJJgVeJtcuAReMtgz.
App Router
If you’re using SSG in App Router, edit generateStaticParams in your catch-all route so Next.js knows which pages to generate.
import {ComponentRenderData,PlasmicComponent} from '@plasmicapp/loader-nextjs';import { notFound } from 'next/navigation';import { PLASMIC } from '../../plasmic-init';import { ClientPlasmicRootProvider } from '../../plasmic-init-client';interface Params {catchall: string[] | undefined;}interface LoaderPageProps {params: Promise<Params>;}export async function generateStaticParams(): Promise<Params[]> {const pages = await PLASMIC.fetchPages();const slugs = await getProductSlugs(); // ["sticker", "nice-shirt", ...]return [...pages.map((page) => ({catchall: page.path === '/' ? undefined : page.path.substring(1).split('/')})),...slugs.map((slug) => ({catchall: ['products', slug]}))];}async function getPageData(params: Promise<Params>): Promise<{ pagePath: string; componentData?: ComponentRenderData }> {const catchall = (await params).catchall;const pagePath = catchall ? `/${catchall.join('/')}` : '/';const componentData = await PLASMIC.maybeFetchComponentData(pagePath);return { pagePath, componentData };}export default async function Page({ params }: LoaderPageProps) {const { pagePath, componentData } = await getPageData(params);if (!componentData || componentData.entryCompMetas.length === 0) {notFound();}const pageMeta = componentData.entryCompMetas[0];const queryCache = await PLASMIC.unstable__getServerQueriesData(componentData,{pagePath,params: pageMeta.params,query: {}});return (<ClientPlasmicRootProviderprefetchedData={componentData}prefetchedQueryData={queryCache}pageRoute={pageMeta.path}pageParams={pageMeta.params}><PlasmicComponent component={pageMeta.displayName} /></ClientPlasmicRootProvider>);}
For codegen in App Router, use the same dynamic route setup and pass useParams() / useSearchParams() values into PageParamsProvider from a Client Component wrapper.