@paroicms/server
Version:
The ParoiCMS server
146 lines • 6.9 kB
JavaScript
import { toAbsoluteUrl } from "@paroicms/internal-server-lib";
import { encodeLNodeId } from "@paroicms/public-anywhere-lib";
import { type } from "arktype";
import { getSiteFieldValue } from "../admin-backend/fields/load-fields.queries.js";
import { getHandleOfSiteField } from "../common/media-handles.helpers.js";
import { toMSourceMedia } from "../common/medias/to-media-values.js";
import { truncExcerptToWord } from "../helpers/excerpt.helpers.js";
import { loadOrFromRenderingCache } from "../liquidjs-tools/liquidjs-drop.js";
import { getFeaturedImageOf } from "../rendered-site/helpers/medias.helpers.js";
import { getUrlOfDocument } from "../rendered-site/page-route/make-url.js";
import { getPublicBreadcrumb } from "./breadcrumb.queries.js";
import { loadExcerpt } from "./excerpt.queries.js";
import { loadPublicFieldValues } from "./field-values.js";
import { makeImageAvailable, makeImageAvailableByHandle } from "./make-image-available.js";
const StringOrUndefinedAT = type("string|undefined");
const articleJsonLdTypes = new Set(["Article", "BlogPosting"]);
export async function makeJsonLdPayload(renderingContext, documentType, docValues, options) {
const { siteContext } = renderingContext;
const graph = [];
const siteUrl = toAbsoluteUrl(siteContext, "/");
const excerpt = await loadOrFromRenderingCache(renderingContext, `excerpt:${encodeLNodeId(docValues)}:full`, () => loadExcerpt(siteContext, renderingContext.tracker, {
lNodeId: docValues,
fieldTypes: documentType.fields ?? [],
}));
const url = options.url ??
(await loadOrFromRenderingCache(renderingContext, `url:${encodeLNodeId(docValues)}`, () => loadUrlOfDocument(renderingContext, docValues)));
const siteTitle = await loadOrFromRenderingCache(renderingContext, `siteFields:${docValues.language}:title`, async () => {
const title = await getSiteFieldValue(siteContext, {
fieldName: "title",
language: docValues.language,
publishedOnly: true,
});
return StringOrUndefinedAT.assert(title);
});
const absoluteUrl = toAbsoluteUrl(siteContext, url);
const isArticleType = articleJsonLdTypes.has(documentType.jsonLdType ?? "");
const description = excerpt
? truncExcerptToWord(excerpt, 160)
: docValues.metaDescription
? truncExcerptToWord(docValues.metaDescription, 160)
: undefined;
const pageEntity = {
"@type": documentType.jsonLdType ?? "WebPage",
"@id": `${absoluteUrl}/#webpage`,
url: absoluteUrl,
inLanguage: docValues.language,
isPartOf: { "@id": `${siteUrl}#website` },
};
if (isArticleType) {
pageEntity.headline = docValues.title;
}
else {
pageEntity.name = docValues.title;
}
if (description)
pageEntity.description = description;
if (docValues.publishDate)
pageEntity.datePublished = docValues.publishDate;
if (docValues.updatedAt)
pageEntity.dateModified = docValues.updatedAt;
if (isArticleType) {
const featuredImageId = await loadOrFromRenderingCache(renderingContext, `featuredImage:${encodeLNodeId(docValues)}`, async () => (await getFeaturedImageOf(renderingContext, {
nodeId: docValues.nodeId,
documentType,
}))?.id);
if (featuredImageId !== undefined) {
const ogMedia = await siteContext.mediaStorage.getMedia({ mediaId: featuredImageId });
if (ogMedia?.kind === "image") {
const imageVariant = await makeImageAvailable(renderingContext, toMSourceMedia(siteContext, ogMedia), { pixelRatio: 1, resizeRule: "1200x630" });
pageEntity.image = {
"@type": "ImageObject",
url: toAbsoluteUrl(siteContext, imageVariant.url),
width: imageVariant.rawWidth,
height: imageVariant.rawHeight,
};
}
}
const authorsField = documentType.fields?.find((f) => f.dataType === "labeling" && f.storedAs === "labeling" && f.taxonomy === "author");
if (authorsField) {
const fieldValues = await loadPublicFieldValues(renderingContext, {
typeName: docValues.type,
lNodeId: docValues,
fieldNames: [authorsField.name],
});
const authorTerms = fieldValues && typeof fieldValues === "object"
? fieldValues[authorsField.name]
: undefined;
if (authorTerms && Array.isArray(authorTerms) && authorTerms.length > 0) {
pageEntity.author = authorTerms.map((term) => {
const entry = { "@type": "Person", name: term.title };
if (term.url)
entry.url = toAbsoluteUrl(siteContext, term.url);
return entry;
});
}
}
const publisher = { "@type": "Organization", name: siteTitle };
const logoHandle = getHandleOfSiteField(siteContext, { fieldName: "logo" });
const logoImage = await makeImageAvailableByHandle(renderingContext, { handle: logoHandle }, { resizeRule: "x112x", pixelRatio: 1 });
if (logoImage) {
publisher.logo = {
"@type": "ImageObject",
url: toAbsoluteUrl(siteContext, logoImage.url),
width: logoImage.rawWidth,
height: logoImage.rawHeight,
};
}
pageEntity.publisher = publisher;
}
graph.push(pageEntity);
const breadcrumbItems = await loadOrFromRenderingCache(renderingContext, `breadcrumb:${encodeLNodeId(docValues)}`, () => getPublicBreadcrumb(renderingContext, docValues));
const listItems = breadcrumbItems
.filter((item) => item.url)
.map((item, index) => ({
"@type": "ListItem",
position: index + 1,
name: item.title ?? "",
item: toAbsoluteUrl(siteContext, item.url),
}));
if (listItems.length > 0) {
graph.push({
"@type": "BreadcrumbList",
itemListElement: listItems,
});
}
if (documentType.typeName === "home") {
graph.push({
"@type": "WebSite",
"@id": `${siteUrl}#website`,
name: siteTitle,
url: siteUrl,
inLanguage: docValues.language,
});
}
return graph;
}
async function loadUrlOfDocument(renderingContext, documentId) {
const { siteContext } = renderingContext;
const { url, dependencyKeys } = await getUrlOfDocument(siteContext, renderingContext.tracker, documentId, {
returnUrlDependencyKeys: true,
forPreview: renderingContext.isPreview,
});
renderingContext.addDependencyKey(...dependencyKeys);
return url;
}
//# sourceMappingURL=json-ld-payload.js.map