101 lines
3.8 KiB
JavaScript
101 lines
3.8 KiB
JavaScript
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,
|
|
pageTitle: doc.title,
|
|
prefix,
|
|
query,
|
|
slugs
|
|
});
|
|
};
|
|
}
|
|
|
|
//# sourceMappingURL=createPageMetadata.js.map
|