From 32722987343d289eb31e886b28d47a0d61220ae2 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 11 Apr 2024 11:58:36 +0200 Subject: [PATCH] metadata: prefer og title rather than metadata title --- .../src/lib/metadata/resolve-metadata.test.ts | 36 +++++++++++++++++++ .../next/src/lib/metadata/resolve-metadata.ts | 31 ++++++++++------ 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/packages/next/src/lib/metadata/resolve-metadata.test.ts b/packages/next/src/lib/metadata/resolve-metadata.test.ts index 06b42fe46ea09..9cd6f2447bb4d 100644 --- a/packages/next/src/lib/metadata/resolve-metadata.test.ts +++ b/packages/next/src/lib/metadata/resolve-metadata.test.ts @@ -340,6 +340,42 @@ describe('accumulateMetadata', () => { }) }) + it('should prefer title and description from openGraph rather than metadata for twitter', async () => { + const metadataItems: MetadataItems = [ + [ + { + title: 'doc title', + openGraph: { + title: 'og-title', + description: 'og-description', + images: 'https://test.com', + }, + }, + null, + ], + ] + const metadata = await accumulateMetadata(metadataItems) + expect(metadata).toMatchObject({ + openGraph: { + title: { + absolute: 'og-title', + template: null, + }, + description: 'og-description', + images: [{ url: new URL('https://test.com') }], + }, + twitter: { + card: 'summary_large_image', + title: { + absolute: 'og-title', + template: null, + }, + description: 'og-description', + images: [{ url: new URL('https://test.com') }], + }, + }) + }) + it('should fill only the existing props from openGraph to twitter', async () => { const metadataItems: MetadataItems = [ [ diff --git a/packages/next/src/lib/metadata/resolve-metadata.ts b/packages/next/src/lib/metadata/resolve-metadata.ts index 3d698be4050b7..0109b19df27e3 100644 --- a/packages/next/src/lib/metadata/resolve-metadata.ts +++ b/packages/next/src/lib/metadata/resolve-metadata.ts @@ -545,11 +545,13 @@ export async function resolveMetadataItems({ type WithTitle = { title?: AbsoluteTemplateString | null } type WithDescription = { description?: string | null } -const hasTitle = (metadata: WithTitle | null) => !!metadata?.title?.absolute +const isTitleTruthy = (title: AbsoluteTemplateString | null | undefined) => + !!title?.absolute +const hasTitle = (metadata: WithTitle | null) => isTitleTruthy(metadata?.title) function inheritFromMetadata( - metadata: ResolvedMetadata, - target: (WithTitle & WithDescription) | null + target: (WithTitle & WithDescription) | null, + metadata: ResolvedMetadata ) { if (target) { if (!hasTitle(target) && hasTitle(metadata)) { @@ -568,11 +570,6 @@ function postProcessMetadata( ): ResolvedMetadata { const { openGraph, twitter } = metadata - // If there's no title and description configured in openGraph or twitter, - // use the title and description from metadata. - inheritFromMetadata(metadata, openGraph) - inheritFromMetadata(metadata, twitter) - if (openGraph) { // If there's openGraph information but not configured in twitter, // inherit them from openGraph metadata. @@ -586,8 +583,16 @@ function postProcessMetadata( const hasTwImages = Boolean( twitter?.hasOwnProperty('images') && twitter.images ) - if (!hasTwTitle) autoFillProps.title = openGraph.title - if (!hasTwDescription) autoFillProps.description = openGraph.description + if (!hasTwTitle) { + if (isTitleTruthy(openGraph.title)) { + autoFillProps.title = openGraph.title + } else if (metadata.title && isTitleTruthy(metadata.title)) { + autoFillProps.title = metadata.title + } + } + if (!hasTwDescription) + autoFillProps.description = + openGraph.description || metadata.description || undefined if (!hasTwImages) autoFillProps.images = openGraph.images if (Object.keys(autoFillProps).length > 0) { @@ -609,6 +614,12 @@ function postProcessMetadata( } } } + + // If there's no title and description configured in openGraph or twitter, + // use the title and description from metadata. + inheritFromMetadata(openGraph, metadata) + inheritFromMetadata(twitter, metadata) + return metadata }