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: Metadata
OcicatOP
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.tsx
export const metadata = {
title: {
template: "%s MyAwesomeSite"
},
description: 'text',
image: '/images/image.png',
url: 'website/home',
}
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}`,
}
}
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
is it this same error?
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 LayoutProp
OcicatOP
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