Skip to content
This repository has been archived by the owner on Dec 9, 2024. It is now read-only.

Commit

Permalink
Merge pull request #113 from B77Mills/AddCustomContentMetadata
Browse files Browse the repository at this point in the history
Add ability to pass customMetadata to google structured data ld_json tag
  • Loading branch information
zarathustra323 authored Nov 1, 2021
2 parents c83e86c + e4a958d commit 830528f
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 43 deletions.
8 changes: 6 additions & 2 deletions packages/marko-web/components/page/layouts/content.marko
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$ const { id, type } = input;
$ const { structuredDataQueryFragment, buildStructuredData, id, type } = input;
$ const { document } = out.global;

<${document}
Expand All @@ -7,7 +7,11 @@ $ const { document } = out.global;
foot=input.foot
>
<@head>
<marko-web-content-page-metadata id=id />
<marko-web-content-page-metadata
id=id
structured-data-query-fragment=structuredDataQueryFragment
build-structured-data=buildStructuredData
/>
<${input.head} />
</@head>
<!-- Note: camelcased vars due to nest input of dynamic document. perhaps a marko bug -->
Expand Down
2 changes: 2 additions & 0 deletions packages/marko-web/components/page/layouts/marko.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
"<page>": {},
"<above-page>": {},
"<below-page>": {},
"@structured-data-query-fragment": "string",
"@build-structured-data": "function",
"@id": "number",
"@type": "string",
"@attrs": "object"
Expand Down
37 changes: 34 additions & 3 deletions packages/marko-web/components/page/metadata/content.marko
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import gql from "graphql-tag";
import { get } from "@parameter1/base-cms-object-path";
import { warn } from "@parameter1/base-cms-utils";
import buildStructuredData from "./google-structured-data/content";
import { warn, isFunction } from "@parameter1/base-cms-utils";
import { extractFragmentData } from "@parameter1/base-cms-web-common/src/utils";
import defaultBuildStructuredData from "./google-structured-data/content";

<!-- @todo This data should generated and saved to the content object as flat data, so no relationships are required. -->

$ const { id } = input;
$ const { id, structuredDataQueryFragment } = input;
$ const { spreadFragmentName, processedFragment } = extractFragmentData(structuredDataQueryFragment);
$ const queryFragment = gql`
fragment ContentPageMetadataFragment on Content {
id
type
siteContext {
url
path
canonicalUrl
noIndex
Expand All @@ -31,6 +34,10 @@ fragment ContentPageMetadataFragment on Content {
... on ContentVideo {
embedSrc
}
... on ContentPodcast {
fileSrc
fileName
}
... on Authorable {
authors {
edges {
Expand All @@ -41,6 +48,26 @@ fragment ContentPageMetadataFragment on Content {
}
}
}
... on Addressable {
address1
address2
city
state
zip
country
}
... on Contactable {
phone
tollfree
fax
website
title
mobile
publicEmail
}
... on ContentCompany {
email
}
images(input:{ pagination: { limit: 0 }, sort: { order: values } }) {
edges {
node {
Expand All @@ -49,9 +76,13 @@ fragment ContentPageMetadataFragment on Content {
}
}
}
${spreadFragmentName}
}
${processedFragment}
`;

$ const buildStructuredData = isFunction(input.buildStructuredData) ? input.buildStructuredData : defaultBuildStructuredData;

<if(id)>
<marko-web-query|{ node }| name="content" params={ id, queryFragment }>
$ const metadata = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,57 +20,92 @@ const getImages = (node) => {
module.exports = (node) => {
const publishedISOString = node.published ? (new Date(node.published)).toISOString() : undefined;
const updatedISOString = node.updated ? (new Date(node.updated)).toISOString() : undefined;
const siteUrl = get(node, 'siteContext.url');
const canonicalUrl = get(node, 'siteContext.canonicalUrl');

const defaultStruturedData = {
'@context': 'https://schema.org',
'@type': 'Article',
mainEntityOfPage: {
'@type': 'WebPage',
'@id': get(node, 'siteContext.canonicalUrl'),
},
headline: get(node, 'metadata.title'),
name: get(node, 'metadata.title'),
...(get(node, 'metadata.description') && { description: get(node, 'metadata.description') }),
...(get(node, 'metadata.image.src') && { thumbnailUrl: get(node, 'metadata.image.src') }),
...(getImages(node) && { image: getImages(node) }),
datePublished: publishedISOString,
dateModified: updatedISOString,
url: canonicalUrl,
...(siteUrl !== canonicalUrl && { url: siteUrl, isBasedOn: canonicalUrl }),
...(getAuthor(node) && { author: getAuthor(node) }),
};

if (node.type === 'video') {
const structuredData = JSON.stringify({
'@context': 'https://schema.org',
return JSON.stringify({
...defaultStruturedData,
'@type': 'VideoObject',
name: get(node, 'metadata.title'),
description: get(node, 'metadata.description'),
thumbnailUrl: get(node, 'metadata.image.src'),
uploadDate: publishedISOString,
contentUrl: get(node, 'siteContext.canonicalUrl'),
author: getAuthor(node),
embedUrl: get(node, 'embedSrc'),
});
return structuredData;
}

const newsArticleTypes = ['article', 'news'];
if (newsArticleTypes.includes(node.type)) {
const structuredData = JSON.stringify({
'@context': 'https://schema.org',
'@type': 'NewsArticle',
mainEntityOfPage: {
'@type': 'WebPage',
'@id': get(node, 'siteContext.canonicalUrl'),
},
if (node.type === 'podcast') {
// Set associatedMedia if audio file is present
const associatedMedia = (get(node, 'fileName') && get(node, 'fileSrc'))
? {
'@type': 'AudioObject',
contentUrl: get(node, 'fileSrc'),
name: get(node, 'fileName'),
}
: undefined;
return JSON.stringify({
...defaultStruturedData,
'@type': 'PodcastEpisode',
headline: get(node, 'metadata.title'),
image: getImages(node),
datePublished: publishedISOString,
dateModified: updatedISOString,
author: getAuthor(node),
description: get(node, 'metadata.description'),
...(associatedMedia && { associatedMedia }),
});
}

if (node.type === 'company') {
// Concat address1 && address2 if present
const streetAddresses = [];
if (get(node, 'address1')) streetAddresses.push(get(node, 'address1'));
if (get(node, 'address2')) streetAddresses.push(get(node, 'address2'));
const streetAddress = streetAddresses.join(' ');
// Display and set address info if present
const showAddress = (streetAddress || get(node, 'city') || get(node, 'state') || get(node, 'zip'));
const address = (showAddress)
? {
'@type': 'PostalAddress',
...(get(node, 'city') && { addressLocality: get(node, 'city') }),
...(get(node, 'state') && { addressLocality: get(node, 'state') }),
...(get(node, 'zip') && { postalCode: get(node, 'zip') }),
...(streetAddress && { streetAddress }),
}
: undefined;
// Set tollfree || phone if present
const telephone = get(node, 'tollfree') || get(node, 'phone');

return JSON.stringify({
...defaultStruturedData,
'@type': 'Organization',
address,
...(telephone && { telephone }),
...(get(node, 'metadata.image.src') && { logo: get(node, 'metadata.image.src') }),
...(get(node, 'email') && { email: get(node, 'email') }),
...(get(node, 'fax') && { faxNumber: get(node, 'fax') }),
});
return structuredData;
}

const standardArticleTypes = ['product', 'blog'];
if (standardArticleTypes.includes(node.type)) {
const structuredData = JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Article',
mainEntityOfPage: {
'@type': 'WebPage',
'@id': get(node, 'siteContext.canonicalUrl'),
},
if (['article', 'news'].includes(node.type)) {
return JSON.stringify({
...defaultStruturedData,
'@type': 'NewsArticle',
headline: get(node, 'metadata.title'),
image: getImages(node),
datePublished: publishedISOString,
dateModified: updatedISOString,
author: getAuthor(node),
description: get(node, 'metadata.description'),
});
return structuredData;
}

return undefined;
Expand Down
4 changes: 3 additions & 1 deletion packages/marko-web/components/page/metadata/marko.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
},
"<marko-web-content-page-metadata>": {
"template": "./content.marko",
"@id": "number"
"@id": "number",
"@structured-data-query-fragment": "string",
"@build-structured-data": "function"
},
"<marko-web-website-section-page-metadata>": {
"template": "./website-section.marko",
Expand Down

0 comments on commit 830528f

Please sign in to comment.