This commit is contained in:
2026-07-31 23:21:51 +02:00
parent f6b4b36df8
commit f14f2cfd98
294 changed files with 5880 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
import { resolveRoute } from '../content/index.js';
import { buildMetadata } from './buildMetadata.js';
import { readSiteMetaConfig } from './readSiteMetaConfig.js';
import { slugsAcrossLocales } from './slugsAcrossLocales.js';
/** plugin-seo stores the OG image as an upload relationship. */ function resolveOgImage(doc) {
const image = doc.meta?.image;
if (image && typeof image === 'object' && 'url' in image) {
return image.url ?? null;
}
return null;
}
/**
* Metadata for the page route, with every resolver already wired.
*
* `createMetadataGenerator` asks the client for resolvers because it can't know
* their collections. But for the plugin's own conventions it does know: pages
* live in one collection, the site name sits on SiteSettings, the OG image sits
* on the plugin-seo `meta` group, the home page is whatever System Pages points
* at, and — with `content` — entries live under their collection's archive page.
* Re-declaring all that in every project is copy-paste, so this resolves it.
*
* Reach for `createMetadataGenerator` instead when a route doesn't follow those
* conventions — custom image logic, a different global, hand-rolled paths.
*
* The plugin never calls getPayload, and Next calls generateMetadata without a
* payload, so the client keeps a small wrapper:
*
* ```ts
* const pageMetadata = createPageMetadata({ config: i18nConfig, baseUrl, content })
*
* export async function generateMetadata({ params }) {
* const { locale, slug } = await params
* return pageMetadata({ payload: await getPayload({ config }), locale, slug })
* }
* ```
*/ export function createPageMetadata(args) {
const { baseUrl, collection = 'pages', config, content, settingsSlug = 'site-settings', siteNameField = 'siteName' } = args;
return async function pageMetadata({ slug, locale, page, payload }) {
const site = await readSiteMetaConfig({
locale,
payload,
settingsSlug,
siteNameField
});
const base = {
baseUrl,
config,
homeSlug: site.homeSlug,
locale,
order: site.order,
separator: site.separator,
siteName: site.siteName
};
const route = await resolveRoute({
content,
locale,
page,
pagesSlug: collection,
payload,
segments: slug,
settingsSlug
});
// Unknown route (the page component will 404) — still return something
// coherent rather than throwing during metadata generation.
if (!route) {
return buildMetadata({
...base,
meta: null,
slugs: {}
});
}
const doc = route.doc;
// An entry sits under its archive, so its URLs need that segment — and the
// segment differs per locale, since it's the archive page's own slug.
const prefix = route.type === 'entry' ? await slugsAcrossLocales({
id: route.archive.id,
collection,
config,
payload
}) : undefined;
const slugs = await slugsAcrossLocales({
id: doc.id,
collection: route.type === 'entry' ? route.collection : collection,
config,
payload
});
// Page 2 of a listing is its own URL, not a variant of page 1.
const query = route.type === 'archive' && route.page > 1 ? `?page=${route.page}` : undefined;
return buildMetadata({
...base,
imageUrl: resolveOgImage(doc),
meta: doc.meta,
prefix,
query,
slugs
});
};
}
//# sourceMappingURL=createPageMetadata.js.map