Next JS Dynamic Metadata help
Answered
Ocicat posted this in #help-forum
OcicatOP
To my understanding You can generate metadata in both page and layout
If there is a layout with matadata at
/app/(content)/layout.tsx
I have a page at a deeper level it will overwrite the metadata.
Its doing that but unfortunately the values are undefined.
app/(content)/home/communities/[id]/page.tsx
If there is a layout with matadata at
/app/(content)/layout.tsx
import React from 'react'
import Navbar from '../components/Navbar'
import "../globals.css"
import QueryProvider from '../components/query-provider';
interface Metadata {
title: string;
description: string;
image: string;
url: string;
}
export const metadata = {
title: '***',
description: 'text',
image: '/images/image.png', // Add the path to your image
url: 'website/home', // Add your website URL
}
interface LayoutProps {
children: React.ReactNode;
metadata: Metadata;
}
export default function Layout({ children, metadata }: LayoutProps) {
return (...)I have a page at a deeper level it will overwrite the metadata.
Its doing that but unfortunately the values are undefined.
app/(content)/home/communities/[id]/page.tsx
import type { Metadata as NextMetadata } from 'next';
interface Metadata extends NextMetadata {
image: string;
url: string;
}
type Props = {
params: {
id: string;
communityName: string;
image: string;
}
}
export const generateMetadata = ({ params }: Props): Metadata => {
return {
title: `Text: ${params.communityName}`,
description: 't',
image: params.image,
url: `https://website/home/communities/${params.id}`,
}
}
interface CommunityData {
id: string;
timestamp: any; // Adjust the type based on your actual data structure
tags: string;
link: string;
[key: string]: any; // This allows for additional properties
}
export default async function community({ params }: Props ) {
const db = getFirestore(app);
let data: CommunityData = { id: '', timestamp: '', tags: '', link: '' };
const querySnapshot = await getDoc(doc(db, 'communities', params.id));
data = { ...querySnapshot.data(), id: querySnapshot.id } as CommunityData;
console.log(data.communityName);
console.log(data.description);
return (...)Answered by Ocicat
I kind of fix it.
I'm getting the title page working but all the other fields are not working.
In generateMetadata
I'm getting the title page working but all the other fields are not working.
In generateMetadata
export const generateMetadata = async ({ params }: Props): Promise<Metadata> => {
//get db code
return (
//data to return
)
} 43 Replies
OcicatOP
Any assistance is appreciated I was not able to write the formalities due to the character limit.
Welcome to all help
Thank you.
This is also the error I am facing
Welcome to all help
Thank you.
This is also the error I am facing
app/(content)/layout.tsx (30:26) @ title
⨯ TypeError: Cannot read properties of undefined (reading 'title')
at Layout (layout.tsx:31:44)
at stringify (<anonymous>)
digest: "3812174722"
28 | <html lang="en">
29 | <head>
> 30 | <title>{metadata.title}</title>
| ^I haven't tried this pattern yet, but it looks like the parent metadata is provided on the the 2nd parameter of the
generateMetadata function:oh wait sorry I'm misunderstanding your question
okay so you are not able to retrieve the raw
the head tag is automatically generated by next from the values of
metadata on the default export of a layout.tsx file.the head tag is automatically generated by next from the values of
metadata/generateMetadata so you won't need to worry about setting the actual title or anything related to metadata, unless you need to set your own tags on the head element.OcicatOP
My issue is
Page.tsx is not sending the metadata so Layout.tsx can display it.
Page.tsx will overwrite whats already on layout as its deeper in the folder hierarchy.
In layout.tsx I have static text but in page.tsx its dynamic. I am exporting it too.
I know its probably a wrong implementation of something or something missed on my end.
Page.tsx is not sending the metadata so Layout.tsx can display it.
Page.tsx will overwrite whats already on layout as its deeper in the folder hierarchy.
In layout.tsx I have static text but in page.tsx its dynamic. I am exporting it too.
I know its probably a wrong implementation of something or something missed on my end.
so the pages are trying to change the
title of the metadata but layout.tsx sets it as a static text?https://nextjs.org/docs/app/api-reference/functions/generate-metadata#template have you tried this yet?
or if you need to overwrite layout's
title metadata, you could use the [absolute field](https://nextjs.org/docs/app/api-reference/functions/generate-metadata#absolute) insteadOcicatOP
I can't use any of those examples as its static.
I need Dynamic and find out why its not getting passed to layout from page even tho its defined and generated there.
I need Dynamic and find out why its not getting passed to layout from page even tho its defined and generated there.
you could do the same thing with
generateMetadata, it returns the same type as the metadata object: MetadataOcicatOP
I have this
in page.tsx
in page.tsx
export const generateMetadata = ({ params }: Props): Metadata => {
return {
title: `Text: ${params.communityName}`,
description: 't',
image: params.image,
url: `https://website/home/communities/${params.id}`,
}
}here, do this:
layout.tsxexport const metadata = {
title: {
template: "%s MyAwesomeSite"
},
description: 'text',
image: '/images/image.png',
url: 'website/home',
}page.tsxexport const generateMetadata = ({ params }: Props): Metadata => {
return {
title: `Text: ${params.communityName}`,
description: 't',
image: params.image,
url: `https://website/home/communities/${params.id}`,
}
}or if you don't want to specify a template on
layout.tsx, you could use the absolute field:export const generateMetadata = ({ params }: Props): Metadata => {
return {
title: {
absolute: `Text: ${params.communityName}`,
},
description: 't',
image: params.image,
url: `https://website/home/communities/${params.id}`,
}
}please do read the docs
OcicatOP
Same problem
you're not supposed to set the title page on
layout.tsx, it's already managed by next through metadataOcicatOP
Yes exacly the same
app/(content)/layout.tsx (32:26) @ title
⨯ TypeError: Cannot read properties of undefined (reading 'title')
at Layout (layout.tsx:33:44)
at stringify (<anonymous>)
digest: "2754771648"
30 | <html lang="en">
31 | <head>
> 32 | <title>{metadata.title}</title>
| ^next doesn't give you the raw metadata as props to the layout, it's kept by next and is used to generate the head by itself, you don't need to do anything
OcicatOP
Yes I see layout.tsx has metadata
But if there's metadata made deeper in the directory it should overwrite it.
in this case I have page.tsx generating metadata.
But if there's metadata made deeper in the directory it should overwrite it.
in this case I have page.tsx generating metadata.
yes, next already handles that
you don't need to worry about metadata, next already handles that
OcicatOP
Yes
You are correct
You are correct
all you need to do is to remove the title tag and
metadata taken from LayoutPropOcicatOP
testing
OcicatOP
I chaged layout.tsx to
Still getting undefined
import React from 'react'
import Navbar from '../components/Navbar'
import "../globals.css"
import QueryProvider from '../components/query-provider';
export const metadata = {
title: '***',
description: 'text',
image: '/images/image.png', // Add the path to your image
url: 'website/home', // Add your website URL
}
export default function Layout({
children,
}: {
children: React.ReactNode
}) {
return (...)Still getting undefined
This allows page to generate the metadata
Which is a step forward.
But what ever page.tsx produces is undefined.
They work on the page.
They are retrieved from a DB
Which is a step forward.
But what ever page.tsx produces is undefined.
They work on the page.
They are retrieved from a DB
please be specific, what's returning
undefined?OcicatOP
export const generateMetadata = ({ params }: Props): Metadata => {
return {
title: `Text: ${params.communityName}`,
description: 'text',
image: params.image,
url: `https://website/home/communities/${params.id}`,
}
}Generatemetadata from page.tsx
??
I don't see any spots an
undefined could show up theredo you mean
params.communityName evaluates into undefined?from what I could tell from the code you shared above,
communityName should come from a dynamic routeplease do make sure that
communityName is defined as a dynamic route represented as a folder with brackets .../[communityName]/... around them, and you have the page.tsx file nested inside that folderOcicatOP
Yes
do you mean params.communityName evaluates into undefined?
do you mean params.communityName evaluates into undefined?
OcicatOP
generateMetadata is a static function that runs before the component is rendered. Because of this, it does not have direct access to the props that your component receives after fetching data in the component itself.
they clearly state that
generateMetadata is being passed [the params prop](https://nextjs.org/docs/app/api-reference/functions/generate-metadata#parameters)then you seem to be having an incorrect folder structure
you have to have a folder with the exact naming
[communityName] that hosts the file the page.tsx either directly inside of the folder, or inside of the subfolders inside that same folderOcicatOP
I kind of fix it.
I'm getting the title page working but all the other fields are not working.
In generateMetadata
I'm getting the title page working but all the other fields are not working.
In generateMetadata
export const generateMetadata = async ({ params }: Props): Promise<Metadata> => {
//get db code
return (
//data to return
)
} Answer
OcicatOP
Thank you for your help I will mark this as answer as it shows signs of meta data being generated to some extent.
Helped me to understand how the layout and page works in more detail I appreciate your time.
Thank you.
Helped me to understand how the layout and page works in more detail I appreciate your time.
Thank you.
good luck 👍 next time i'd suggest to clarify your questions, i was so confused as to what the problem really is