Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

All properties of nested metadata objects like openGraph get overriten even if only one was a duplicate #46899

Closed
1 task done
Confuze opened this issue Mar 7, 2023 · 7 comments
Labels
bug Issue was opened via the bug report template.

Comments

@Confuze
Copy link

Confuze commented Mar 7, 2023

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: linux
      Arch: x64
      Version: #1 SMP PREEMPT Tue Feb 14 19:45:58 UTC 2023
    Binaries:
      Node: 18.14.0
      npm: 8.19.2
      Yarn: N/A
      pnpm: N/A
    Relevant packages:
      next: 13.2.4-canary.5
      eslint-config-next: 13.2.3
      react: 18.2.0
      react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true), Metadata (metadata, generateMetadata, next/head, head.js)

Link to the code that reproduces this issue

https://github.com/Confuze/debug/tree/next-nested-metadata

To Reproduce

  1. Download the code
  2. npm run dev
  3. Go to localhost:3000 and check for an og:description meta tag in document source

Describe the Bug

If you have a metadata object in one file, for example this:

// app/layout.tsx
export const metadata: Metadata = {
  title: "foo",
  description: "foobar",
  openGraph: {
    title: "foo",
    description: "foobar"
  }
}

and then if you override any nested object in the metadata in a lower level file, for example like in here:

export const metadata: Metadata = {
  title: "bar",
  openGraph: { // nested object overriten here
    title: "bar",
  }
}

then nextjs will override the nested object itself and not its individual keys. As a result of this, any keys that were specified in the nested object in the higher level (app/layout.tsx) file but not in the nested object in the lower level (app/page.tsx) file will be completely lost, so the final merged metadata would be something like this:

{
  title: "bar",
  description: "foobar", // the regular description remains unchanged
  openGraph: {
    title: "foo",
    // but the open graph description gets deleted
  }
}

This causes the og:description meta tag not to be included in the document's head.

It's hard to describe this in words, so if this doesn't make much sense, try seeing the reproduction repo I've provided.

Expected Behavior

Nextjs should recursively override nested objects' keys and not the objects themselves so that the properties that weren't changed in a lower-level file remain unchanged and not deleted.

In the given example, the final merged metadata should be something like this:

{
  title: "bar",
  description: "foobar",
  openGraph: {
    title: "foo",
    description: "foobar"
  }
}

And the og:description meta tag should be included in the document's head.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

@Confuze Confuze added the bug Issue was opened via the bug report template. label Mar 7, 2023
@jee-r
Copy link

jee-r commented Mar 9, 2023

Hi I'm facing to a similar issue with generateMetadata()

I would like set default metadata for the whole website in app/layout.tsx

export async function generateMetadata({}): Promise<Metadata> {

  const defaultMetadatas: IMetadatas = await getCollectionData('metadata')
  const defaultMetadata: IMetadata = defaultMetadatas.data
  const apiUrl = process.env.API_URL;

  return {
    title: {
      default: defaultMetadata.title,
      template: '%s | ' + defaultMetadata.title,
    },
    description: defaultMetadata.description,
    openGraph: {
    	title: defaultMetadata.title,
			description: defaultMetadata.description,
			url: defaultMetadata.url,
			locale: defaultMetadata.locale,
			images: [
			  {
				  url: defaultMetadata.image,
				  width: 1200,
				  height: 630,
			  },
      ],
    },
    icons: {
      icon: [
        { url: "/favicon.svg", type: "image/svg+xml" },
        { url: "/favicon.png", type: "image/png" }
      ]
    }
  }
};

and overwrite them in app/[slug]/page.tsx

export async function generateMetadata(
	{ params }: { params: { slug: string } }): Promise<Metadata> {

	const apiQuery: string = "?filter[slug][_eq]=" + params.slug
	const pageData: Pages = await getCollectionData('Pages', apiQuery)

	const meta_description: string = pageData.data[0].meta_description || await meta_description_builder(pageData.data[0].content)

	const apiUrl = process.env.API_URL;

	const base_url: string = 'https://example.com/'

	const metadata_url: string = base_url + params.slug
	
	let metadata_images: { url: string; width: number; height: number; }[] = [];
	
	if (pageData.data[0].image) {
		metadata_images.push({
				url: apiUrl + '/assets/' + pageData.data[0].image + '.png' + "?width=1200&height=630&quality=75&format=png&fit=cover",
				width: 1200,
				height: 630,
		})
	}

	const openGraph = {
		title: pageData.data[0].title,
		description: meta_description,
		url: metadata_url,
		...(metadata_images.length > 0 && { images: metadata_images }),
	}

	return ({
			title: pageData.data[0].title,
			description: meta_description,
			openGraph,
	})
}

But they are not merged

@Confuze
Copy link
Author

Confuze commented Mar 9, 2023

By "they are not merged" you mean they don't change at all? Do only the defaults get used or do some properties get overwritten?

@jee-r
Copy link

jee-r commented Mar 9, 2023

I mean merged as specified in the docs https://beta.nextjs.org/docs/api-reference/metadata#ordering

Objects are merged together to form the final metadata output. Duplicate keys are replaced based on their ordering. Learn more about pages and layouts.

for instance if i set in app/layout.tsx

{
  openGraph: {
    title: "Default Title",
    description: "Desc from layout"
  } 
}

and then if i would overwrite my desc in app/[slug]/page.tsx

{
  openGraph: {
    description: "Custom desc for my page"
  }
}

I get only the updated desc (Custom desc for my page) but openGraph.title (Default Title) is removed on /myslug for instance.

@stefanprobst
Copy link
Contributor

according to #46434

We merged the first layer of properties, but we don't merge the deeper layers of those properties.

@casperiv0
Copy link
Contributor

I've created a function to deepmerge the metadata, see https://github.com/Dev-CasperTheGhost/caspertheghost.me/blob/main/src/lib/merge-seo.ts

@Confuze
Copy link
Author

Confuze commented Mar 17, 2023

according to #46434

We merged the first layer of properties, but we don't merge the deeper layers of those properties.

Thanks, I totally missed this one when creating this issue. The explanation they provided doesn't really convince me though.

One bad case might happen could be when you don't want to specify some property, but it might accidently deep merge with the few layers away topper level metadata, resulting in unexpected metadata.

It doesn't make much sense to me since since the top level metadata is merged anyways so you'd still have to remember about resetting the unwanted root options. Either way this issue is a duplicate so I'm closing it.

Thanks @Dev-CasperTheGhost for the function snippet. Definitely gonna come in handy.

@Confuze Confuze closed this as not planned Won't fix, can't repro, duplicate, stale Mar 17, 2023
@github-actions
Copy link
Contributor

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 17, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests

4 participants