@quintype/seo 1.40.8 → 1.40.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/index.cjs.js +450 -450
- package/dist/index.cjs.min.js +1 -0
- package/index.js +14 -14
- package/package.json +1 -1
- package/src/structured-data/structured-data-tags.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [1.40.10](https://github.com/quintype/quintype-node-seo/compare/v1.40.5...v1.40.10) (2022-07-29)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* Amphtml error ([#526](https://github.com/quintype/quintype-node-seo/issues/526)) ([24b6c61](https://github.com/quintype/quintype-node-seo/commit/24b6c616118f3db1a2cdda0d98d2827bf2a0d099))
|
|
11
|
+
* **embed-url:** use fallback when story elements are not there ([#530](https://github.com/quintype/quintype-node-seo/issues/530)) ([cf9ab06](https://github.com/quintype/quintype-node-seo/commit/cf9ab06d022a1b2d4c3d6843adcea32606712669))
|
|
12
|
+
* **video-structured-data:** use correct embed url ([#528](https://github.com/quintype/quintype-node-seo/issues/528)) ([abe449f](https://github.com/quintype/quintype-node-seo/commit/abe449fd7e75d45f9b9896444f3ef644ca2cf497))
|
|
13
|
+
|
|
14
|
+
### [1.40.9](https://github.com/quintype/quintype-node-seo/compare/v1.40.8...v1.40.9) (2022-07-12)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* **embed-url:** use fallback when story elements are not there ([#530](https://github.com/quintype/quintype-node-seo/issues/530)) ([cf9ab06](https://github.com/quintype/quintype-node-seo/commit/cf9ab06d022a1b2d4c3d6843adcea32606712669))
|
|
20
|
+
|
|
5
21
|
### [1.40.8](https://github.com/quintype/quintype-node-seo/compare/v1.40.5...v1.40.8) (2022-07-11)
|
|
6
22
|
|
|
7
23
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -5,12 +5,12 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var lodash = require('lodash');
|
|
6
6
|
var React = require('react');
|
|
7
7
|
var ReactDomServer = require('react-dom/server');
|
|
8
|
+
var get = require('lodash/get');
|
|
8
9
|
var url = require('url');
|
|
9
10
|
var dateFnsTz = require('date-fns-tz');
|
|
10
|
-
var quintypeJs = require('quintype-js');
|
|
11
|
-
var get = require('lodash/get');
|
|
12
11
|
var isUndefined = require('lodash/isUndefined');
|
|
13
12
|
var omitBy = require('lodash/omitBy');
|
|
13
|
+
var quintypeJs = require('quintype-js');
|
|
14
14
|
|
|
15
15
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
16
16
|
|
|
@@ -49,375 +49,185 @@ function isStoryPublic(story) {
|
|
|
49
49
|
return story.access === undefined || story.access === null || story.access === 'public';
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function
|
|
53
|
-
if (!story)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const { metadata = {} } = story.cards.find(card => card.id === cardId) || {};
|
|
57
|
-
const urlWithCardId = `${config["sketches-host"]}/${story.slug}?cardId=${cardId}`;
|
|
52
|
+
function showAmpTag({ ampStoryPages = true }, pageType, story) {
|
|
53
|
+
if (!ampStoryPages || pageType !== 'story-page') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
title: metadata["social-share"].title || story.headline,
|
|
62
|
-
description: metadata["social-share"].message || story.summary,
|
|
63
|
-
ogUrl: urlWithCardId,
|
|
64
|
-
ogTitle: metadata["social-share"].title || story.headline,
|
|
65
|
-
ogDescription: metadata["social-share"].message || story.summary
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
return metadata;
|
|
57
|
+
if (ampStoryPages === 'public' && !isStoryPublic(story)) {
|
|
58
|
+
return false;
|
|
69
59
|
}
|
|
70
60
|
|
|
71
|
-
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
72
63
|
|
|
73
|
-
|
|
64
|
+
const getDomain = (url, domainSlug) => {
|
|
65
|
+
const domain = domainSlug ? new URL(url).origin : '';
|
|
66
|
+
try {
|
|
67
|
+
return domain;
|
|
68
|
+
} catch (err) {
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
"page-title": pageTitle,
|
|
87
|
-
description,
|
|
88
|
-
keywords,
|
|
89
|
-
canonicalUrl: story["canonical-url"] || storyUrl,
|
|
90
|
-
ogUrl,
|
|
91
|
-
ogTitle: getOgTitle,
|
|
92
|
-
ogDescription,
|
|
93
|
-
storyUrl,
|
|
94
|
-
author: authors
|
|
95
|
-
};
|
|
73
|
+
/**
|
|
74
|
+
* StoryAmpTags adds the amphref to stories which support amp.
|
|
75
|
+
*
|
|
76
|
+
* @extends Generator
|
|
77
|
+
* @param {*} seoConfig
|
|
78
|
+
* @param {(boolean|"public")} seoConfig.ampStoryPages Should amp story pages be shown for all stories (true), not shown (false), or only be shown for public stories ("public"). Default: true
|
|
79
|
+
* @param {(boolean)} seoConfig.appendHostToAmpUrl If set to true, the url to be appended to the slug is computed based on the currentHostUrl and the domain slug, else the url is taken as the sketches host. Default: false
|
|
80
|
+
* @param {(boolean)} seoConfig.decodeAmpUrl If set to true, the storySlug that goes as the amp href url is decoded, else the storyslug is encoded. Default: false
|
|
81
|
+
* @param {...*} params See {@link Generator} for other Parameters
|
|
82
|
+
*/
|
|
83
|
+
function StoryAmpTags(seoConfig, config, pageType, data = {}, opts) {
|
|
96
84
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
85
|
+
const story = get__default["default"](data, ["data", "story"], {});
|
|
86
|
+
const { currentHostUrl = '', domainSlug } = data;
|
|
87
|
+
// TODO: Remove this condition and always make absolute URL if that's better for AMP discoverability.
|
|
88
|
+
const ampUrlAppend = seoConfig.appendHostToAmpUrl ? getDomain(currentHostUrl, domainSlug) || config['sketches-host'] : '';
|
|
89
|
+
const storySlug = seoConfig.decodeAmpUrl ? decodeURIComponent(story.slug) : encodeURIComponent(story.slug);
|
|
90
|
+
const ampUrl = story["story-template"] === "visual-story" ? `${ampUrlAppend}/${storySlug}` : `${ampUrlAppend}/amp/story/${storySlug}`;
|
|
91
|
+
|
|
92
|
+
if (showAmpTag(seoConfig, pageType, story)) {
|
|
93
|
+
return [{
|
|
94
|
+
tag: 'link',
|
|
95
|
+
rel: 'amphtml',
|
|
96
|
+
href: ampUrl
|
|
97
|
+
}];
|
|
98
|
+
} else {
|
|
99
|
+
return [];
|
|
100
100
|
}
|
|
101
|
+
}
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
/**
|
|
104
|
+
* AuthorTags adds the twitter:creator tag for story pages
|
|
105
|
+
*
|
|
106
|
+
* @extends Generator
|
|
107
|
+
* @param {*} seoConfig
|
|
108
|
+
* @param {...*} params See {@link Generator} for other Parameters
|
|
109
|
+
*/
|
|
110
|
+
function AuthorTags(seoConfig, config, pageType, data, { url }) {
|
|
111
|
+
if (pageType != "story-page" || pageType != "story-page-amp") return [];
|
|
112
|
+
|
|
113
|
+
return [{
|
|
114
|
+
name: "twitter:creator",
|
|
115
|
+
content: lodash.get(data, ["data", "story", "author-name"])
|
|
116
|
+
}];
|
|
103
117
|
}
|
|
104
118
|
|
|
105
|
-
function
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
"
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
119
|
+
function getTitle$1(config) {
|
|
120
|
+
return config["publisher-settings"] ? config["publisher-settings"]["title"] : config["publisher-name"];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function generateStaticData(config) {
|
|
124
|
+
const title = getTitle$1(config);
|
|
125
|
+
const themeConfig = config["theme-attributes"] || {};
|
|
126
|
+
const publicIntegrations = get__default["default"](config, ['public-integrations'], {});
|
|
127
|
+
const staticData = {
|
|
128
|
+
"twitter:site": title,
|
|
129
|
+
"twitter:domain": config["sketches-host"],
|
|
130
|
+
"twitter:app:name:ipad": themeConfig["twitter_app_name_ipad"],
|
|
131
|
+
"twitter:app:name:googleplay": themeConfig["twitter_app_name_googleplay"],
|
|
132
|
+
"twitter:app:id:googleplay": themeConfig["twitter_app_id_googleplay"],
|
|
133
|
+
"twitter:app:name:iphone": themeConfig["twitter_app_name_iphone"],
|
|
134
|
+
"twitter:app:id:iphone": themeConfig["twitter_app_id_iphone"],
|
|
135
|
+
"apple-itunes-app": themeConfig["apple_itunes_app"],
|
|
136
|
+
"google-play-app": themeConfig["google_play_app"],
|
|
137
|
+
"fb:app_id": get__default["default"](publicIntegrations, ['facebook', 'app-id']) || get__default["default"](themeConfig, ["fb_app_id"]),
|
|
138
|
+
"fb:pages": themeConfig["fb_pages"],
|
|
139
|
+
"og:site_name": title
|
|
126
140
|
};
|
|
127
141
|
|
|
128
|
-
return
|
|
142
|
+
return omitBy__default["default"](staticData, isUndefined__default["default"]);
|
|
129
143
|
}
|
|
130
144
|
|
|
131
|
-
function
|
|
132
|
-
|
|
145
|
+
function generateImageObject(config = {}) {
|
|
146
|
+
const { "theme-attributes": themeConfig = {} } = config;
|
|
147
|
+
return {
|
|
148
|
+
"@context": "http://schema.org",
|
|
149
|
+
"@type": "ImageObject",
|
|
150
|
+
"author": config['publisher-name'],
|
|
151
|
+
"contentUrl": themeConfig.logo,
|
|
152
|
+
"url": themeConfig.logo,
|
|
153
|
+
"name": "logo",
|
|
154
|
+
"width": themeConfig.logo && getQueryParams(themeConfig.logo).width,
|
|
155
|
+
"height": themeConfig.logo && getQueryParams(themeConfig.logo).height
|
|
156
|
+
};
|
|
157
|
+
}
|
|
133
158
|
|
|
134
|
-
|
|
135
|
-
const title =
|
|
136
|
-
const
|
|
137
|
-
const
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
159
|
+
function generateStructuredData(config = {}) {
|
|
160
|
+
const title = getTitle$1(config);
|
|
161
|
+
const { "theme-attributes": themeConfig, "social-links": socialLinks, "seo-metadata": seoMetadata = [] } = config;
|
|
162
|
+
const homePageSeo = seoMetadata.find(page => page["owner-type"] === "home") || {};
|
|
163
|
+
const { "page-title": pageTitle = "", description = "", keywords = "" } = get__default["default"](homePageSeo, ["data"], {});
|
|
164
|
+
if (!themeConfig || !themeConfig.logo) {
|
|
165
|
+
return {};
|
|
166
|
+
}
|
|
167
|
+
let enableStructuredDataForNewsArticle = themeConfig['structured_data_news_article'] || false;
|
|
168
|
+
if (config.hasOwnProperty('enableStructuredDataForNewsArticle') && typeof config.enableStructuredDataForNewsArticle !== "undefined") {
|
|
169
|
+
enableStructuredDataForNewsArticle = config.enableStructuredDataForNewsArticle;
|
|
170
|
+
}
|
|
141
171
|
|
|
142
172
|
return {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
173
|
+
organization: {
|
|
174
|
+
name: title,
|
|
175
|
+
url: config["sketches-host"],
|
|
176
|
+
logo: generateImageObject(config),
|
|
177
|
+
sameAs: socialLinks ? Object.values(socialLinks) : []
|
|
178
|
+
},
|
|
179
|
+
enableNewsArticle: !!enableStructuredDataForNewsArticle,
|
|
180
|
+
storyUrlAsMainEntityUrl: !!enableStructuredDataForNewsArticle,
|
|
181
|
+
enableVideo: !themeConfig['structured_data_enable_video'],
|
|
182
|
+
enableLiveBlog: !themeConfig['structured_data_enable_live_blog'],
|
|
183
|
+
website: {
|
|
184
|
+
url: config["sketches-host"],
|
|
185
|
+
searchpath: "search?q={query}",
|
|
186
|
+
queryinput: "required name=query",
|
|
187
|
+
name: pageTitle || title,
|
|
188
|
+
headline: description,
|
|
189
|
+
keywords
|
|
190
|
+
}
|
|
151
191
|
};
|
|
152
192
|
}
|
|
153
193
|
|
|
154
|
-
function
|
|
155
|
-
const
|
|
156
|
-
if (
|
|
157
|
-
|
|
194
|
+
function pickImageFromCard(story, cardId) {
|
|
195
|
+
const { metadata = {} } = story.cards.find(card => card.id === cardId) || {};
|
|
196
|
+
if (metadata && !lodash.isEmpty(metadata) && lodash.get(metadata, ["social-share", "image", "key"], false)) {
|
|
197
|
+
const alt = metadata["social-share"].image.attribution || metadata["social-share"].title || metadata["social-share"].message || getAttribution(story);
|
|
198
|
+
return {
|
|
199
|
+
image: new quintypeJs.FocusedImage(metadata["social-share"].image.key, metadata["social-share"].image.metadata || {}),
|
|
200
|
+
alt
|
|
201
|
+
};
|
|
158
202
|
}
|
|
159
|
-
return {};
|
|
160
203
|
}
|
|
161
204
|
|
|
162
|
-
function
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (lodash.isEmpty(seoData) && lodash.isEmpty(customSeo)) return;
|
|
205
|
+
function getAttribution(story) {
|
|
206
|
+
return story["hero-image-attribution"] || story.summary || lodash.get(story, ["alternative", "home", "default", "headline"]) || story.headline;
|
|
207
|
+
}
|
|
166
208
|
|
|
167
|
-
|
|
209
|
+
/**
|
|
210
|
+
* priority:
|
|
211
|
+
* 1. alternate social image
|
|
212
|
+
* 2. alternate hero image
|
|
213
|
+
* 3. hero image
|
|
214
|
+
* 4. "fallbackSocialImage" from seo config
|
|
215
|
+
* 5. logo_url from /api/v1/config > theme-attributes
|
|
216
|
+
* 5. logo from /api/v1/config > theme-attributes
|
|
217
|
+
* 6. undefined (meta tag won't get created)
|
|
218
|
+
*/
|
|
219
|
+
function pickImageFromStory({ story, config, seoConfig }) {
|
|
220
|
+
function getAlt(type, key, fallback) {
|
|
221
|
+
return lodash.get(story, ["alternative", `${type}`, "default", "hero-image", `${key}`], fallback);
|
|
222
|
+
}
|
|
168
223
|
|
|
169
|
-
const
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
return {
|
|
177
|
-
title,
|
|
178
|
-
"page-title": pageTitle,
|
|
179
|
-
description,
|
|
180
|
-
keywords: `${title},${config["publisher-name"]}`,
|
|
181
|
-
canonicalUrl: staticPageUrl,
|
|
182
|
-
ogUrl: staticPageUrl,
|
|
183
|
-
ogTitle,
|
|
184
|
-
ogDescription,
|
|
185
|
-
keywords: customSeo.keywords || keywords
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// The findRelevantConfig method call has no ownerId for home page.
|
|
190
|
-
// This causes the seoMetadata to be undefined.
|
|
191
|
-
// So the default value for the ownerId is set to null.
|
|
192
|
-
|
|
193
|
-
function getSeoData(config, pageType, data, url = {}, seoConfig = {}) {
|
|
194
|
-
function findRelevantConfig(ownerType, ownerId = null) {
|
|
195
|
-
const seoMetadata = config["seo-metadata"].find(page => page["owner-type"] === ownerType && page["owner-id"] === ownerId) || {};
|
|
196
|
-
const { sections = [] } = config;
|
|
197
|
-
const section = sections.find(section => ownerType == "section" && section.id === ownerId) || {};
|
|
198
|
-
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
199
|
-
if (seoMetadata.data || section.id || !lodash.isEmpty(customSeo)) {
|
|
200
|
-
const result = Object.assign({}, {
|
|
201
|
-
"page-title": customSeo["page-title"] || section.name,
|
|
202
|
-
title: customSeo.title || section.name,
|
|
203
|
-
canonicalUrl: customSeo["canonicalUrl"] || section["section-url"] || undefined
|
|
204
|
-
}, seoMetadata.data);
|
|
205
|
-
|
|
206
|
-
if (!result.description) {
|
|
207
|
-
const homeSeoData = config["seo-metadata"].find(page => page["owner-type"] === "home") || {
|
|
208
|
-
data: { description: "" }
|
|
209
|
-
};
|
|
210
|
-
result.description = customSeo.description || homeSeoData.data.description;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
result.ogTitle = customSeo.ogTitle || result.title;
|
|
214
|
-
result.ogDescription = customSeo.ogDescription || result.description;
|
|
215
|
-
return result;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (seoConfig.customTags && seoConfig.customTags[pageType]) {
|
|
220
|
-
return buildCustomTags(seoConfig.customTags, pageType);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function getShellSeoData(config) {
|
|
224
|
-
const seoMetadata = config["seo-metadata"].find(meta => meta["owner-type"] === "home") || {};
|
|
225
|
-
return Object.assign({}, seoMetadata.data, { canonicalUrl: SKIP_CANONICAL });
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
switch (pageType) {
|
|
229
|
-
case "home-page":
|
|
230
|
-
return findRelevantConfig("home");
|
|
231
|
-
case "section-page":
|
|
232
|
-
return findRelevantConfig("section", lodash.get(data, ["data", "section", "id"])) || getSeoDataFromCollection(config, data) || getSeoData(config, "home-page", data, url);
|
|
233
|
-
case "collection-page":
|
|
234
|
-
return getSeoDataFromCollection(config, data) || getSeoData(config, "home-page", data, url);
|
|
235
|
-
case "tag-page":
|
|
236
|
-
return buildTagsFromTopic(config, lodash.get(data, ["data", "tag"]), url, data) || getSeoData(config, "home-page", data, url);
|
|
237
|
-
case "story-page":
|
|
238
|
-
return buildTagsFromStory(config, lodash.get(data, ["data", "story"]), url, data) || getSeoData(config, "home-page", data, url);
|
|
239
|
-
case "visual-story":
|
|
240
|
-
return buildTagsFromStory(config, lodash.get(data, ["story"]), url, data) || getSeoData(config, "home-page", data, url);
|
|
241
|
-
case "story-page-amp":
|
|
242
|
-
return buildTagsFromStory(config, lodash.get(data, ["data", "story"]), url, data) || getSeoData(config, "home-page", data, url);
|
|
243
|
-
case "author-page":
|
|
244
|
-
return buildTagsFromAuthor(config, lodash.get(data, ["data", "author"], {}), url, data) || getSeoData(config, "home-page", data, url);
|
|
245
|
-
case "static-page":
|
|
246
|
-
return buildTagsFromStaticPage(config, lodash.get(data, ["data", "page"], {}), url, data) || getSeoData(config, "home-page", data, url);
|
|
247
|
-
case "shell":
|
|
248
|
-
return getShellSeoData(config);
|
|
249
|
-
default:
|
|
250
|
-
return getSeoData(config, "home-page", data, url);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function getSeoDataFromCollection(config, data) {
|
|
255
|
-
if (lodash.get(data, ["data", "collection", "name"])) {
|
|
256
|
-
let { name, summary } = lodash.get(data, ["data", "collection"]);
|
|
257
|
-
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
258
|
-
|
|
259
|
-
if (!summary) {
|
|
260
|
-
summary = (getSeoData(config, "home-page", data) || {}).description;
|
|
261
|
-
}
|
|
262
|
-
const title = customSeo.title || name;
|
|
263
|
-
const pageTitle = customSeo["page-title"] || name;
|
|
264
|
-
const ogTitle = customSeo.ogTitle || title;
|
|
265
|
-
const description = customSeo.description || summary;
|
|
266
|
-
const ogDescription = customSeo.ogDescription || summary;
|
|
267
|
-
return {
|
|
268
|
-
"page-title": pageTitle,
|
|
269
|
-
title,
|
|
270
|
-
ogTitle,
|
|
271
|
-
description,
|
|
272
|
-
ogDescription,
|
|
273
|
-
canonicalUrl: SKIP_CANONICAL
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const SKIP_CANONICAL = "__SKIP__CANONICAL__";
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* TextTags adds the majority of basic tags, such as
|
|
282
|
-
* * Canonical URLs
|
|
283
|
-
* * Title and Description
|
|
284
|
-
* * Keywords
|
|
285
|
-
*
|
|
286
|
-
* If the current URL contains a cardId in the query parameters, then the title and description will come from *card["social-share"]*
|
|
287
|
-
*
|
|
288
|
-
* @extends Generator
|
|
289
|
-
* @param {*} seoConfig
|
|
290
|
-
* @param {boolean} seoConfig.enableOgTags Add og tags for Facebook
|
|
291
|
-
* @param {boolean} seoConfig.enableTwitterCards Add twitter tags
|
|
292
|
-
* @param {boolean} seoConfig.enableNews Add tags for Google News, like news_keywords
|
|
293
|
-
* @param {Object} seoConfig.customTags Add tags for a custom page type. Usually looks like `{"custom-page": {"title": "value", "canonicalUrl": "value"}}`
|
|
294
|
-
* @param {...*} params See {@link Generator} for other Parameters
|
|
295
|
-
*/
|
|
296
|
-
function TextTags(seoConfig, config, pageType, data, { url }) {
|
|
297
|
-
const seoData = getSeoData(config, pageType, data, url, seoConfig);
|
|
298
|
-
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
299
|
-
|
|
300
|
-
if (!seoData) return [];
|
|
301
|
-
|
|
302
|
-
const currentUrl = `${config["sketches-host"]}${url.pathname}`;
|
|
303
|
-
|
|
304
|
-
const basicTags = {
|
|
305
|
-
description: customSeo.description || seoData.description,
|
|
306
|
-
title: customSeo.title || seoData.title,
|
|
307
|
-
keywords: customSeo.keywords || seoData.keywords
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
const ogUrl = customSeo.ogUrl || seoData.ogUrl || seoData.canonicalUrl || currentUrl;
|
|
311
|
-
const ogTags = seoConfig.enableOgTags ? {
|
|
312
|
-
"og:type": pageType === "story-page" || pageType === "story-page-amp" ? "article" : "website",
|
|
313
|
-
"og:url": ogUrl === SKIP_CANONICAL ? undefined : ogUrl,
|
|
314
|
-
"og:title": customSeo.ogTitle || seoData.ogTitle,
|
|
315
|
-
"og:description": customSeo.ogDescription || seoData.ogDescription
|
|
316
|
-
} : undefined;
|
|
317
|
-
|
|
318
|
-
const twitterTags = seoConfig.enableTwitterCards ? {
|
|
319
|
-
"twitter:card": "summary_large_image",
|
|
320
|
-
"twitter:title": customSeo.twitterTitle || seoData.ogTitle,
|
|
321
|
-
"twitter:description": customSeo.twitterDescription || seoData.ogDescription
|
|
322
|
-
} : undefined;
|
|
323
|
-
|
|
324
|
-
const allTags = Object.assign(basicTags, ogTags, twitterTags);
|
|
325
|
-
|
|
326
|
-
const commonTags = [{ tag: "title", children: customSeo.title || data.title || seoData["page-title"] }];
|
|
327
|
-
|
|
328
|
-
const canonical = seoData.canonicalUrl || currentUrl;
|
|
329
|
-
if (canonical != SKIP_CANONICAL) {
|
|
330
|
-
commonTags.push({ tag: "link", rel: "canonical", href: canonical });
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (pageType === "story-page" || pageType === "story-page-amp") {
|
|
334
|
-
commonTags.push({ name: "author", content: seoData.author });
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if ((pageType === "story-page" || pageType === "story-page-amp") && seoConfig.enableNews) {
|
|
338
|
-
commonTags.push({ name: "news_keywords", content: seoData.keywords });
|
|
339
|
-
if (lodash.get(data, ["data", "story", "seo", "meta-google-news-standout"])) commonTags.push({ tag: "link", rel: "standout", href: seoData.storyUrl || currentUrl });
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
return commonTags.concat(objectToTags(allTags));
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
function getTitle$1(seoConfig, config, pageType, data, params) {
|
|
346
|
-
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
347
|
-
|
|
348
|
-
if (lodash.get(data, ["title"])) return customSeo.title || lodash.get(data, ["title"]);
|
|
349
|
-
|
|
350
|
-
if (lodash.get(data, ["data", "title"])) return customSeo.title || lodash.get(data, ["data", "title"]);
|
|
351
|
-
|
|
352
|
-
const seoData = getSeoData(config, pageType, data, undefined, seoConfig) || {};
|
|
353
|
-
return customSeo.title || seoData["page-title"];
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* StaticTags puts whatever tags you've passed to it
|
|
358
|
-
*
|
|
359
|
-
* @extends Generator
|
|
360
|
-
* @param {*} seoConfig
|
|
361
|
-
* @param {Object} seoConfig.staticTags List of tags to be added. ex: `{"viewport": "width=device-width,initial-scale=1.0"}`
|
|
362
|
-
* @param {...*} params See {@link Generator} for other Parameters
|
|
363
|
-
*/
|
|
364
|
-
function StaticTags(seoConfig, config, pageType, data, { url }) {
|
|
365
|
-
return objectToTags(seoConfig.staticTags || {});
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* AuthorTags adds the twitter:creator tag for story pages
|
|
370
|
-
*
|
|
371
|
-
* @extends Generator
|
|
372
|
-
* @param {*} seoConfig
|
|
373
|
-
* @param {...*} params See {@link Generator} for other Parameters
|
|
374
|
-
*/
|
|
375
|
-
function AuthorTags(seoConfig, config, pageType, data, { url }) {
|
|
376
|
-
if (pageType != "story-page" || pageType != "story-page-amp") return [];
|
|
377
|
-
|
|
378
|
-
return [{
|
|
379
|
-
name: "twitter:creator",
|
|
380
|
-
content: lodash.get(data, ["data", "story", "author-name"])
|
|
381
|
-
}];
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
function pickImageFromCard(story, cardId) {
|
|
385
|
-
const { metadata = {} } = story.cards.find(card => card.id === cardId) || {};
|
|
386
|
-
if (metadata && !lodash.isEmpty(metadata) && lodash.get(metadata, ["social-share", "image", "key"], false)) {
|
|
387
|
-
const alt = metadata["social-share"].image.attribution || metadata["social-share"].title || metadata["social-share"].message || getAttribution(story);
|
|
388
|
-
return {
|
|
389
|
-
image: new quintypeJs.FocusedImage(metadata["social-share"].image.key, metadata["social-share"].image.metadata || {}),
|
|
390
|
-
alt
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
function getAttribution(story) {
|
|
396
|
-
return story["hero-image-attribution"] || story.summary || lodash.get(story, ["alternative", "home", "default", "headline"]) || story.headline;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* priority:
|
|
401
|
-
* 1. alternate social image
|
|
402
|
-
* 2. alternate hero image
|
|
403
|
-
* 3. hero image
|
|
404
|
-
* 4. "fallbackSocialImage" from seo config
|
|
405
|
-
* 5. logo_url from /api/v1/config > theme-attributes
|
|
406
|
-
* 5. logo from /api/v1/config > theme-attributes
|
|
407
|
-
* 6. undefined (meta tag won't get created)
|
|
408
|
-
*/
|
|
409
|
-
function pickImageFromStory({ story, config, seoConfig }) {
|
|
410
|
-
function getAlt(type, key, fallback) {
|
|
411
|
-
return lodash.get(story, ["alternative", `${type}`, "default", "hero-image", `${key}`], fallback);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
const alt = getAttribution(story);
|
|
415
|
-
const fallbackSocialImage = lodash.get(seoConfig, ["fallbackSocialImage"]);
|
|
416
|
-
const altHeroImg = getAlt("home", "hero-image-s3-key", null);
|
|
417
|
-
const altSocialHeroImg = getAlt("social", "hero-image-s3-key", null);
|
|
418
|
-
const storyHeroImage = lodash.get(story, ["hero-image-s3-key"]);
|
|
419
|
-
const logo_url = lodash.get(config, ["theme-attributes", "logo_url"]);
|
|
420
|
-
const logo = lodash.get(config, ["theme-attributes", "logo"]);
|
|
224
|
+
const alt = getAttribution(story);
|
|
225
|
+
const fallbackSocialImage = lodash.get(seoConfig, ["fallbackSocialImage"]);
|
|
226
|
+
const altHeroImg = getAlt("home", "hero-image-s3-key", null);
|
|
227
|
+
const altSocialHeroImg = getAlt("social", "hero-image-s3-key", null);
|
|
228
|
+
const storyHeroImage = lodash.get(story, ["hero-image-s3-key"]);
|
|
229
|
+
const logo_url = lodash.get(config, ["theme-attributes", "logo_url"]);
|
|
230
|
+
const logo = lodash.get(config, ["theme-attributes", "logo"]);
|
|
421
231
|
|
|
422
232
|
if (altSocialHeroImg) {
|
|
423
233
|
const metadata = getAlt("social", "hero-image-metadata", {});
|
|
@@ -523,6 +333,18 @@ function ImageTags(seoConfig, config, pageType, data, { url = {} }) {
|
|
|
523
333
|
return tags;
|
|
524
334
|
}
|
|
525
335
|
|
|
336
|
+
/**
|
|
337
|
+
* StaticTags puts whatever tags you've passed to it
|
|
338
|
+
*
|
|
339
|
+
* @extends Generator
|
|
340
|
+
* @param {*} seoConfig
|
|
341
|
+
* @param {Object} seoConfig.staticTags List of tags to be added. ex: `{"viewport": "width=device-width,initial-scale=1.0"}`
|
|
342
|
+
* @param {...*} params See {@link Generator} for other Parameters
|
|
343
|
+
*/
|
|
344
|
+
function StaticTags(seoConfig, config, pageType, data, { url }) {
|
|
345
|
+
return objectToTags(seoConfig.staticTags || {});
|
|
346
|
+
}
|
|
347
|
+
|
|
526
348
|
const getSchemaContext = { "@context": "http://schema.org" };
|
|
527
349
|
|
|
528
350
|
function getSchemaType(type) {
|
|
@@ -829,8 +651,8 @@ function getEmbedUrl(cards) {
|
|
|
829
651
|
// coz we only need the embed url
|
|
830
652
|
// find is used for early exit
|
|
831
653
|
cards.find(card => {
|
|
832
|
-
const storyElements = card["story-elements"];
|
|
833
|
-
return storyElements.find(
|
|
654
|
+
const storyElements = get__default["default"](card, ["story-elements"], []);
|
|
655
|
+
return storyElements.find(elem => {
|
|
834
656
|
if (elem["embed-url"]) {
|
|
835
657
|
embedUrl = elem["embed-url"];
|
|
836
658
|
return true;
|
|
@@ -1073,136 +895,314 @@ function StructuredDataTags({ structuredData = {} }, config, pageType, response
|
|
|
1073
895
|
return tags;
|
|
1074
896
|
}
|
|
1075
897
|
|
|
1076
|
-
function
|
|
1077
|
-
if (!
|
|
1078
|
-
return false;
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
if (ampStoryPages === 'public' && !isStoryPublic(story)) {
|
|
1082
|
-
return false;
|
|
1083
|
-
}
|
|
898
|
+
function buildTagsFromStory(config, story, url = {}, data = {}) {
|
|
899
|
+
if (!story) return;
|
|
1084
900
|
|
|
1085
|
-
|
|
1086
|
-
}
|
|
901
|
+
function getStoryCardMetadata(cardId) {
|
|
902
|
+
const { metadata = {} } = story.cards.find(card => card.id === cardId) || {};
|
|
903
|
+
const urlWithCardId = `${config["sketches-host"]}/${story.slug}?cardId=${cardId}`;
|
|
1087
904
|
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
905
|
+
if (metadata && !lodash.isEmpty(metadata) && metadata["social-share"]) {
|
|
906
|
+
return {
|
|
907
|
+
title: metadata["social-share"].title || story.headline,
|
|
908
|
+
description: metadata["social-share"].message || story.summary,
|
|
909
|
+
ogUrl: urlWithCardId,
|
|
910
|
+
ogTitle: metadata["social-share"].title || story.headline,
|
|
911
|
+
ogDescription: metadata["social-share"].message || story.summary
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
return metadata;
|
|
1094
915
|
}
|
|
1095
|
-
};
|
|
1096
916
|
|
|
1097
|
-
|
|
1098
|
-
* StoryAmpTags adds the amphref to stories which support amp.
|
|
1099
|
-
*
|
|
1100
|
-
* @extends Generator
|
|
1101
|
-
* @param {*} seoConfig
|
|
1102
|
-
* @param {(boolean|"public")} seoConfig.ampStoryPages Should amp story pages be shown for all stories (true), not shown (false), or only be shown for public stories ("public"). Default: true
|
|
1103
|
-
* @param {(boolean)} seoConfig.appendHostToAmpUrl If set to true, the url to be appended to the slug is computed based on the currentHostUrl and the domain slug, else the url is taken as the sketches host. Default: false
|
|
1104
|
-
* @param {(boolean)} seoConfig.decodeAmpUrl If set to true, the storySlug that goes as the amp href url is decoded, else the storyslug is encoded. Default: false
|
|
1105
|
-
* @param {...*} params See {@link Generator} for other Parameters
|
|
1106
|
-
*/
|
|
1107
|
-
function StoryAmpTags(seoConfig, config, pageType, data = {}, opts) {
|
|
917
|
+
const seo = story.seo || {};
|
|
1108
918
|
|
|
1109
|
-
const
|
|
1110
|
-
const { currentHostUrl = '', domainSlug } = data;
|
|
1111
|
-
// TODO: Remove this condition and always make absolute URL if that's better for AMP discoverability.
|
|
1112
|
-
const ampUrlAppend = seoConfig.appendHostToAmpUrl ? getDomain(currentHostUrl, domainSlug) || config['sketches-host'] : '';
|
|
1113
|
-
const storySlug = seoConfig.decodeAmpUrl ? decodeURIComponent(story.slug) : encodeURIComponent(story.slug);
|
|
1114
|
-
const ampUrl = story["story-template"] === "visual-story" ? `${ampUrlAppend}/${storySlug}` : `${ampUrlAppend}/amp/story/${storySlug}`;
|
|
919
|
+
const storyUrl = story.url || `${config["sketches-host"]}/${story.slug}`;
|
|
1115
920
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
921
|
+
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
922
|
+
const authors = lodash.get(story, ["authors"], []).map(author => author.name);
|
|
923
|
+
const title = customSeo.title || seo["meta-title"] || story.headline;
|
|
924
|
+
const pageTitle = customSeo["page-title"] || seo["meta-title"] || story.headline;
|
|
925
|
+
const description = customSeo.description || seo["meta-description"] || story.summary;
|
|
926
|
+
const keywords = (customSeo.keywords || seo["meta-keywords"] || (story.tags || []).map(tag => tag.name)).join(",");
|
|
927
|
+
const ogUrl = customSeo.ogUrl || lodash.get(seo, ["og", "url"]) || storyUrl;
|
|
928
|
+
const getOgTitle = customSeo.ogTitle || lodash.get(story, ["alternative", "social", "default", "headline"], story.headline) || story.headline;
|
|
929
|
+
const ogDescription = customSeo.ogDescription || story.summary;
|
|
930
|
+
const storyMetaData = {
|
|
931
|
+
title,
|
|
932
|
+
"page-title": pageTitle,
|
|
933
|
+
description,
|
|
934
|
+
keywords,
|
|
935
|
+
canonicalUrl: story["canonical-url"] || storyUrl,
|
|
936
|
+
ogUrl,
|
|
937
|
+
ogTitle: getOgTitle,
|
|
938
|
+
ogDescription,
|
|
939
|
+
storyUrl,
|
|
940
|
+
author: authors
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
if (url.query && url.query.cardId) {
|
|
944
|
+
const storyCardMetadata = getStoryCardMetadata(url.query.cardId);
|
|
945
|
+
return Object.assign({}, storyMetaData, storyCardMetadata); //TODO rewrite in spread syntax, add babel plugin
|
|
1124
946
|
}
|
|
947
|
+
|
|
948
|
+
return storyMetaData;
|
|
1125
949
|
}
|
|
1126
950
|
|
|
1127
|
-
function
|
|
1128
|
-
|
|
951
|
+
function buildTagsFromTopic(config, tag, url = {}, data) {
|
|
952
|
+
if (lodash.isEmpty(tag)) return;
|
|
953
|
+
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
954
|
+
const tagName = customSeo.title || tag["meta-title"] || tag.name;
|
|
955
|
+
const pageTitle = customSeo["page-title"] || tagName;
|
|
956
|
+
const tagDescription = customSeo.description || tag["meta-description"];
|
|
957
|
+
const description = `Read stories listed under on ${tag.name}`;
|
|
958
|
+
const tagUrl = `${config["sketches-host"]}${url.pathname}`;
|
|
959
|
+
const canonicalSlug = tag["canonical-slug"] || url.pathname;
|
|
960
|
+
const canonicalUrl = `${config["sketches-host"]}${canonicalSlug}`;
|
|
961
|
+
const ogTitle = customSeo.ogTitle || tagName;
|
|
962
|
+
const ogDescription = customSeo.ogDescription || description;
|
|
963
|
+
const topicMetaData = {
|
|
964
|
+
title: tagName,
|
|
965
|
+
"page-title": pageTitle,
|
|
966
|
+
description: tagDescription || description,
|
|
967
|
+
keywords: tagName,
|
|
968
|
+
canonicalUrl,
|
|
969
|
+
ogUrl: tagUrl,
|
|
970
|
+
ogTitle,
|
|
971
|
+
ogDescription
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
return topicMetaData;
|
|
1129
975
|
}
|
|
1130
976
|
|
|
1131
|
-
function
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
const
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
"
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
977
|
+
function buildTagsFromAuthor(config, author, url = {}, data) {
|
|
978
|
+
if (lodash.isEmpty(author)) return;
|
|
979
|
+
|
|
980
|
+
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
981
|
+
const title = customSeo.title || author.name;
|
|
982
|
+
const pageTitle = customSeo["page-title"] || title;
|
|
983
|
+
const description = customSeo.description || author.bio || `View all articles written by ${title}`;
|
|
984
|
+
const ogTitle = customSeo.ogTitle || author.name;
|
|
985
|
+
const authorUrl = `${config["sketches-host"]}${url.pathname}`;
|
|
986
|
+
const ogDescription = customSeo.ogDescription || description;
|
|
987
|
+
|
|
988
|
+
return {
|
|
989
|
+
title,
|
|
990
|
+
"page-title": pageTitle,
|
|
991
|
+
description,
|
|
992
|
+
keywords: `${title},${config["publisher-name"]}`,
|
|
993
|
+
canonicalUrl: authorUrl,
|
|
994
|
+
ogUrl: authorUrl,
|
|
995
|
+
ogTitle,
|
|
996
|
+
ogDescription
|
|
1148
997
|
};
|
|
998
|
+
}
|
|
1149
999
|
|
|
1150
|
-
|
|
1000
|
+
function buildCustomTags(customTags = {}, pageType = "") {
|
|
1001
|
+
const configObject = customTags[pageType];
|
|
1002
|
+
if (configObject) {
|
|
1003
|
+
return configObject;
|
|
1004
|
+
}
|
|
1005
|
+
return {};
|
|
1151
1006
|
}
|
|
1152
1007
|
|
|
1153
|
-
function
|
|
1154
|
-
const
|
|
1008
|
+
function buildTagsFromStaticPage(config, page, url = {}, data) {
|
|
1009
|
+
const seoData = lodash.get(page, ["metadata", "seo"], {});
|
|
1010
|
+
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
1011
|
+
if (lodash.isEmpty(seoData) && lodash.isEmpty(customSeo)) return;
|
|
1012
|
+
|
|
1013
|
+
const { "meta-title": metaTitle, "meta-description": metaDescription, "meta-keywords": keywords } = seoData;
|
|
1014
|
+
|
|
1015
|
+
const title = customSeo.title || metaTitle || page.title;
|
|
1016
|
+
const pageTitle = customSeo["page-title"] || title;
|
|
1017
|
+
const description = customSeo.description || metaDescription;
|
|
1018
|
+
const ogTitle = customSeo.ogTitle || title;
|
|
1019
|
+
const staticPageUrl = `${config["sketches-host"]}${url.pathname}`;
|
|
1020
|
+
const ogDescription = customSeo.ogDescription || description;
|
|
1021
|
+
|
|
1155
1022
|
return {
|
|
1156
|
-
|
|
1157
|
-
"
|
|
1158
|
-
|
|
1159
|
-
"
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1023
|
+
title,
|
|
1024
|
+
"page-title": pageTitle,
|
|
1025
|
+
description,
|
|
1026
|
+
keywords: `${title},${config["publisher-name"]}`,
|
|
1027
|
+
canonicalUrl: staticPageUrl,
|
|
1028
|
+
ogUrl: staticPageUrl,
|
|
1029
|
+
ogTitle,
|
|
1030
|
+
ogDescription,
|
|
1031
|
+
keywords: customSeo.keywords || keywords
|
|
1164
1032
|
};
|
|
1165
1033
|
}
|
|
1166
1034
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1035
|
+
// The findRelevantConfig method call has no ownerId for home page.
|
|
1036
|
+
// This causes the seoMetadata to be undefined.
|
|
1037
|
+
// So the default value for the ownerId is set to null.
|
|
1038
|
+
|
|
1039
|
+
function getSeoData(config, pageType, data, url = {}, seoConfig = {}) {
|
|
1040
|
+
function findRelevantConfig(ownerType, ownerId = null) {
|
|
1041
|
+
const seoMetadata = config["seo-metadata"].find(page => page["owner-type"] === ownerType && page["owner-id"] === ownerId) || {};
|
|
1042
|
+
const { sections = [] } = config;
|
|
1043
|
+
const section = sections.find(section => ownerType == "section" && section.id === ownerId) || {};
|
|
1044
|
+
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
1045
|
+
if (seoMetadata.data || section.id || !lodash.isEmpty(customSeo)) {
|
|
1046
|
+
const result = Object.assign({}, {
|
|
1047
|
+
"page-title": customSeo["page-title"] || section.name,
|
|
1048
|
+
title: customSeo.title || section.name,
|
|
1049
|
+
canonicalUrl: customSeo["canonicalUrl"] || section["section-url"] || undefined
|
|
1050
|
+
}, seoMetadata.data);
|
|
1051
|
+
|
|
1052
|
+
if (!result.description) {
|
|
1053
|
+
const homeSeoData = config["seo-metadata"].find(page => page["owner-type"] === "home") || {
|
|
1054
|
+
data: { description: "" }
|
|
1055
|
+
};
|
|
1056
|
+
result.description = customSeo.description || homeSeoData.data.description;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
result.ogTitle = customSeo.ogTitle || result.title;
|
|
1060
|
+
result.ogDescription = customSeo.ogDescription || result.description;
|
|
1061
|
+
return result;
|
|
1062
|
+
}
|
|
1174
1063
|
}
|
|
1175
|
-
|
|
1176
|
-
if (
|
|
1177
|
-
|
|
1064
|
+
|
|
1065
|
+
if (seoConfig.customTags && seoConfig.customTags[pageType]) {
|
|
1066
|
+
return buildCustomTags(seoConfig.customTags, pageType);
|
|
1178
1067
|
}
|
|
1179
1068
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1069
|
+
function getShellSeoData(config) {
|
|
1070
|
+
const seoMetadata = config["seo-metadata"].find(meta => meta["owner-type"] === "home") || {};
|
|
1071
|
+
return Object.assign({}, seoMetadata.data, { canonicalUrl: SKIP_CANONICAL });
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
switch (pageType) {
|
|
1075
|
+
case "home-page":
|
|
1076
|
+
return findRelevantConfig("home");
|
|
1077
|
+
case "section-page":
|
|
1078
|
+
return findRelevantConfig("section", lodash.get(data, ["data", "section", "id"])) || getSeoDataFromCollection(config, data) || getSeoData(config, "home-page", data, url);
|
|
1079
|
+
case "collection-page":
|
|
1080
|
+
return getSeoDataFromCollection(config, data) || getSeoData(config, "home-page", data, url);
|
|
1081
|
+
case "tag-page":
|
|
1082
|
+
return buildTagsFromTopic(config, lodash.get(data, ["data", "tag"]), url, data) || getSeoData(config, "home-page", data, url);
|
|
1083
|
+
case "story-page":
|
|
1084
|
+
return buildTagsFromStory(config, lodash.get(data, ["data", "story"]), url, data) || getSeoData(config, "home-page", data, url);
|
|
1085
|
+
case "visual-story":
|
|
1086
|
+
return buildTagsFromStory(config, lodash.get(data, ["story"]), url, data) || getSeoData(config, "home-page", data, url);
|
|
1087
|
+
case "story-page-amp":
|
|
1088
|
+
return buildTagsFromStory(config, lodash.get(data, ["data", "story"]), url, data) || getSeoData(config, "home-page", data, url);
|
|
1089
|
+
case "author-page":
|
|
1090
|
+
return buildTagsFromAuthor(config, lodash.get(data, ["data", "author"], {}), url, data) || getSeoData(config, "home-page", data, url);
|
|
1091
|
+
case "static-page":
|
|
1092
|
+
return buildTagsFromStaticPage(config, lodash.get(data, ["data", "page"], {}), url, data) || getSeoData(config, "home-page", data, url);
|
|
1093
|
+
case "shell":
|
|
1094
|
+
return getShellSeoData(config);
|
|
1095
|
+
default:
|
|
1096
|
+
return getSeoData(config, "home-page", data, url);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
function getSeoDataFromCollection(config, data) {
|
|
1101
|
+
if (lodash.get(data, ["data", "collection", "name"])) {
|
|
1102
|
+
let { name, summary } = lodash.get(data, ["data", "collection"]);
|
|
1103
|
+
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
1104
|
+
|
|
1105
|
+
if (!summary) {
|
|
1106
|
+
summary = (getSeoData(config, "home-page", data) || {}).description;
|
|
1198
1107
|
}
|
|
1108
|
+
const title = customSeo.title || name;
|
|
1109
|
+
const pageTitle = customSeo["page-title"] || name;
|
|
1110
|
+
const ogTitle = customSeo.ogTitle || title;
|
|
1111
|
+
const description = customSeo.description || summary;
|
|
1112
|
+
const ogDescription = customSeo.ogDescription || summary;
|
|
1113
|
+
return {
|
|
1114
|
+
"page-title": pageTitle,
|
|
1115
|
+
title,
|
|
1116
|
+
ogTitle,
|
|
1117
|
+
description,
|
|
1118
|
+
ogDescription,
|
|
1119
|
+
canonicalUrl: SKIP_CANONICAL
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
const SKIP_CANONICAL = "__SKIP__CANONICAL__";
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* TextTags adds the majority of basic tags, such as
|
|
1128
|
+
* * Canonical URLs
|
|
1129
|
+
* * Title and Description
|
|
1130
|
+
* * Keywords
|
|
1131
|
+
*
|
|
1132
|
+
* If the current URL contains a cardId in the query parameters, then the title and description will come from *card["social-share"]*
|
|
1133
|
+
*
|
|
1134
|
+
* @extends Generator
|
|
1135
|
+
* @param {*} seoConfig
|
|
1136
|
+
* @param {boolean} seoConfig.enableOgTags Add og tags for Facebook
|
|
1137
|
+
* @param {boolean} seoConfig.enableTwitterCards Add twitter tags
|
|
1138
|
+
* @param {boolean} seoConfig.enableNews Add tags for Google News, like news_keywords
|
|
1139
|
+
* @param {Object} seoConfig.customTags Add tags for a custom page type. Usually looks like `{"custom-page": {"title": "value", "canonicalUrl": "value"}}`
|
|
1140
|
+
* @param {...*} params See {@link Generator} for other Parameters
|
|
1141
|
+
*/
|
|
1142
|
+
function TextTags(seoConfig, config, pageType, data, { url }) {
|
|
1143
|
+
const seoData = getSeoData(config, pageType, data, url, seoConfig);
|
|
1144
|
+
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
1145
|
+
|
|
1146
|
+
if (!seoData) return [];
|
|
1147
|
+
|
|
1148
|
+
const currentUrl = `${config["sketches-host"]}${url.pathname}`;
|
|
1149
|
+
|
|
1150
|
+
const basicTags = {
|
|
1151
|
+
description: customSeo.description || seoData.description,
|
|
1152
|
+
title: customSeo.title || seoData.title,
|
|
1153
|
+
keywords: customSeo.keywords || seoData.keywords
|
|
1199
1154
|
};
|
|
1155
|
+
|
|
1156
|
+
const ogUrl = customSeo.ogUrl || seoData.ogUrl || seoData.canonicalUrl || currentUrl;
|
|
1157
|
+
const ogTags = seoConfig.enableOgTags ? {
|
|
1158
|
+
"og:type": pageType === "story-page" || pageType === "story-page-amp" ? "article" : "website",
|
|
1159
|
+
"og:url": ogUrl === SKIP_CANONICAL ? undefined : ogUrl,
|
|
1160
|
+
"og:title": customSeo.ogTitle || seoData.ogTitle,
|
|
1161
|
+
"og:description": customSeo.ogDescription || seoData.ogDescription
|
|
1162
|
+
} : undefined;
|
|
1163
|
+
|
|
1164
|
+
const twitterTags = seoConfig.enableTwitterCards ? {
|
|
1165
|
+
"twitter:card": "summary_large_image",
|
|
1166
|
+
"twitter:title": customSeo.twitterTitle || seoData.ogTitle,
|
|
1167
|
+
"twitter:description": customSeo.twitterDescription || seoData.ogDescription
|
|
1168
|
+
} : undefined;
|
|
1169
|
+
|
|
1170
|
+
const allTags = Object.assign(basicTags, ogTags, twitterTags);
|
|
1171
|
+
|
|
1172
|
+
const commonTags = [{ tag: "title", children: customSeo.title || data.title || seoData["page-title"] }];
|
|
1173
|
+
|
|
1174
|
+
const canonical = seoData.canonicalUrl || currentUrl;
|
|
1175
|
+
if (canonical != SKIP_CANONICAL) {
|
|
1176
|
+
commonTags.push({ tag: "link", rel: "canonical", href: canonical });
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
if (pageType === "story-page" || pageType === "story-page-amp") {
|
|
1180
|
+
commonTags.push({ name: "author", content: seoData.author });
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
if ((pageType === "story-page" || pageType === "story-page-amp") && seoConfig.enableNews) {
|
|
1184
|
+
commonTags.push({ name: "news_keywords", content: seoData.keywords });
|
|
1185
|
+
if (lodash.get(data, ["data", "story", "seo", "meta-google-news-standout"])) commonTags.push({ tag: "link", rel: "standout", href: seoData.storyUrl || currentUrl });
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
return commonTags.concat(objectToTags(allTags));
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
function getTitle(seoConfig, config, pageType, data, params) {
|
|
1192
|
+
const customSeo = lodash.get(data, ["data", "customSeo"], {});
|
|
1193
|
+
|
|
1194
|
+
if (lodash.get(data, ["title"])) return customSeo.title || lodash.get(data, ["title"]);
|
|
1195
|
+
|
|
1196
|
+
if (lodash.get(data, ["data", "title"])) return customSeo.title || lodash.get(data, ["data", "title"]);
|
|
1197
|
+
|
|
1198
|
+
const seoData = getSeoData(config, pageType, data, undefined, seoConfig) || {};
|
|
1199
|
+
return customSeo.title || seoData["page-title"];
|
|
1200
1200
|
}
|
|
1201
1201
|
|
|
1202
1202
|
function tagToKey(tag) {
|
|
1203
1203
|
switch (tag.tag || "meta") {
|
|
1204
1204
|
case "meta":
|
|
1205
|
-
return `meta-${tag.name || "name"}-${tag.property || "property"}`;
|
|
1205
|
+
return `meta-${tag.name || tag.itemprop || "name"}-${tag.property || "property"}`;
|
|
1206
1206
|
case "link":
|
|
1207
1207
|
return `link-${tag.rel}`;
|
|
1208
1208
|
case "title":
|
|
@@ -1293,7 +1293,7 @@ class SEO {
|
|
|
1293
1293
|
}
|
|
1294
1294
|
|
|
1295
1295
|
getTitle(config, pageType, data, params = {}) {
|
|
1296
|
-
return getTitle
|
|
1296
|
+
return getTitle(this.seoConfig, config, pageType, data);
|
|
1297
1297
|
}
|
|
1298
1298
|
}
|
|
1299
1299
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var lodash=require("lodash"),React=require("react"),ReactDomServer=require("react-dom/server"),get=require("lodash/get"),url=require("url"),dateFnsTz=require("date-fns-tz"),isUndefined=require("lodash/isUndefined"),omitBy=require("lodash/omitBy"),quintypeJs=require("quintype-js");function _interopDefaultLegacy(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var React__default=_interopDefaultLegacy(React),ReactDomServer__default=_interopDefaultLegacy(ReactDomServer),get__default=_interopDefaultLegacy(get),isUndefined__default=_interopDefaultLegacy(isUndefined),omitBy__default=_interopDefaultLegacy(omitBy);function objectToTags(object){return lodash.entries(object).filter(([key,value])=>value).map(([key,value])=>({[getPropertyName(key)]:key,content:value}))}function getPropertyName(key){return key.startsWith("fb:")||key.startsWith("og:")?"property":"name"}function stripMillisecondsFromTime(date,timezone){const toReturn=date.toJSON();if(!toReturn)return toReturn;const zonedTime=timezone&&dateFnsTz.utcToZonedTime(date,timezone),formatZonedTime=zonedTime&&dateFnsTz.format(zonedTime,"yyyy-MM-dd'T'HH:mm:ssXXX",{timeZone:timezone}),formatToReturn=toReturn.split(".")[0]+"Z";return timezone?formatZonedTime:formatToReturn}function getQueryParams(url$1){const urlObj=new url.URL(url$1),search_params=new url.URLSearchParams(urlObj.search),getWidth=search_params.get("w")||"",getHeight=search_params.get("h")||"";return{width:getWidth,height:getHeight}}function isStoryPublic(story){return void 0===story.access||null===story.access||"public"===story.access}function showAmpTag({ampStoryPages:ampStoryPages=!0},pageType,story){return!(!ampStoryPages||"story-page"!==pageType)&&!("public"===ampStoryPages&&!isStoryPublic(story))}const getDomain=(url,domainSlug)=>{const domain=domainSlug?new URL(url).origin:"";try{return domain}catch(err){return""}};function StoryAmpTags(seoConfig,config,pageType,data={},opts){const story=get__default.default(data,["data","story"],{}),{currentHostUrl:currentHostUrl="",domainSlug:domainSlug}=data,ampUrlAppend=seoConfig.appendHostToAmpUrl?getDomain(currentHostUrl,domainSlug)||config["sketches-host"]:"",storySlug=seoConfig.decodeAmpUrl?decodeURIComponent(story.slug):encodeURIComponent(story.slug),ampUrl="visual-story"===story["story-template"]?`${ampUrlAppend}/${storySlug}`:`${ampUrlAppend}/amp/story/${storySlug}`;return showAmpTag(seoConfig,pageType,story)?[{tag:"link",rel:"amphtml",href:ampUrl}]:[]}function AuthorTags(seoConfig,config,pageType,data,{url:url}){return"story-page"!=pageType||"story-page-amp"!=pageType?[]:[{name:"twitter:creator",content:lodash.get(data,["data","story","author-name"])}]}function getTitle$1(config){return config["publisher-settings"]?config["publisher-settings"].title:config["publisher-name"]}function generateStaticData(config){const title=getTitle$1(config),themeConfig=config["theme-attributes"]||{},publicIntegrations=get__default.default(config,["public-integrations"],{}),staticData={"twitter:site":title,"twitter:domain":config["sketches-host"],"twitter:app:name:ipad":themeConfig.twitter_app_name_ipad,"twitter:app:name:googleplay":themeConfig.twitter_app_name_googleplay,"twitter:app:id:googleplay":themeConfig.twitter_app_id_googleplay,"twitter:app:name:iphone":themeConfig.twitter_app_name_iphone,"twitter:app:id:iphone":themeConfig.twitter_app_id_iphone,"apple-itunes-app":themeConfig.apple_itunes_app,"google-play-app":themeConfig.google_play_app,"fb:app_id":get__default.default(publicIntegrations,["facebook","app-id"])||get__default.default(themeConfig,["fb_app_id"]),"fb:pages":themeConfig.fb_pages,"og:site_name":title};return omitBy__default.default(staticData,isUndefined__default.default)}function generateImageObject(config={}){const{"theme-attributes":themeConfig={}}=config;return{"@context":"http://schema.org","@type":"ImageObject",author:config["publisher-name"],contentUrl:themeConfig.logo,url:themeConfig.logo,name:"logo",width:themeConfig.logo&&getQueryParams(themeConfig.logo).width,height:themeConfig.logo&&getQueryParams(themeConfig.logo).height}}function generateStructuredData(config={}){const title=getTitle$1(config),{"theme-attributes":themeConfig,"social-links":socialLinks,"seo-metadata":seoMetadata=[]}=config,homePageSeo=seoMetadata.find(page=>"home"===page["owner-type"])||{},{"page-title":pageTitle="",description:description="",keywords:keywords=""}=get__default.default(homePageSeo,["data"],{});if(!themeConfig||!themeConfig.logo)return{};let enableStructuredDataForNewsArticle=themeConfig.structured_data_news_article||!1;return config.hasOwnProperty("enableStructuredDataForNewsArticle")&&void 0!==config.enableStructuredDataForNewsArticle&&(enableStructuredDataForNewsArticle=config.enableStructuredDataForNewsArticle),{organization:{name:title,url:config["sketches-host"],logo:generateImageObject(config),sameAs:socialLinks?Object.values(socialLinks):[]},enableNewsArticle:!!enableStructuredDataForNewsArticle,storyUrlAsMainEntityUrl:!!enableStructuredDataForNewsArticle,enableVideo:!themeConfig.structured_data_enable_video,enableLiveBlog:!themeConfig.structured_data_enable_live_blog,website:{url:config["sketches-host"],searchpath:"search?q={query}",queryinput:"required name=query",name:pageTitle||title,headline:description,keywords:keywords}}}function pickImageFromCard(story,cardId){const{metadata:metadata={}}=story.cards.find(card=>card.id===cardId)||{};if(metadata&&!lodash.isEmpty(metadata)&&lodash.get(metadata,["social-share","image","key"],!1)){const alt=metadata["social-share"].image.attribution||metadata["social-share"].title||metadata["social-share"].message||getAttribution(story);return{image:new quintypeJs.FocusedImage(metadata["social-share"].image.key,metadata["social-share"].image.metadata||{}),alt:alt}}}function getAttribution(story){return story["hero-image-attribution"]||story.summary||lodash.get(story,["alternative","home","default","headline"])||story.headline}function pickImageFromStory({story:story,config:config,seoConfig:seoConfig}){function getAlt(type,key,fallback){return lodash.get(story,["alternative",`${type}`,"default","hero-image",`${key}`],fallback)}const alt=getAttribution(story),fallbackSocialImage=lodash.get(seoConfig,["fallbackSocialImage"]),altHeroImg=getAlt("home","hero-image-s3-key",null),altSocialHeroImg=getAlt("social","hero-image-s3-key",null),storyHeroImage=lodash.get(story,["hero-image-s3-key"]),logo_url=lodash.get(config,["theme-attributes","logo_url"]),logo=lodash.get(config,["theme-attributes","logo"]);if(altSocialHeroImg){const metadata=getAlt("social","hero-image-metadata",{});return{image:new quintypeJs.FocusedImage(altSocialHeroImg,metadata),alt:alt}}if(altHeroImg){const metadata=getAlt("home","hero-image-metadata",{});return{image:new quintypeJs.FocusedImage(altHeroImg,metadata),alt:alt}}if(storyHeroImage){const metadata=lodash.get(story,["hero-image-metadata"],{});return{image:new quintypeJs.FocusedImage(storyHeroImage,metadata),alt:alt}}return fallbackSocialImage?{image:fallbackSocialImage,alt:alt,includesHost:!0}:logo_url?{image:logo_url,alt:alt,includesHost:!0}:logo?{image:logo,alt:alt,includesHost:!0}:{image:void 0,alt:void 0}}function pickImageFromCollection(collection){const coverImage=lodash.get(collection,["metadata","cover-image"])||{};if(!coverImage["cover-image-s3-key"])return{};const alt=collection.summary||collection.name||null;return{image:new quintypeJs.FocusedImage(coverImage["cover-image-s3-key"],coverImage["cover-image-metadata"]||{}),alt:alt}}function pickImage({pageType:pageType,config:config,seoConfig:seoConfig,data:data,url:url}){if("story-page"===pageType&&url.query&&url.query.cardId){const story=lodash.get(data,["data","story"])||{};return pickImageFromCard(story,url.query.cardId)||pickImageFromStory({story:story,seoConfig:seoConfig,config:config})}if("visual-story"===pageType&&url.query&&url.query.cardId){const story=lodash.get(data,["story"])||{};return pickImageFromCard(story,url.query.cardId)||pickImageFromStory({story:story,seoConfig:seoConfig,config:config})}if("story-page"===pageType||"story-page-amp"===pageType){const story=lodash.get(data,["data","story"])||{};return pickImageFromStory({story:story,seoConfig:seoConfig,config:config})}if("visual-story"===pageType){const story=lodash.get(data,["story"])||{};return pickImageFromStory({story:story,seoConfig:seoConfig,config:config})}return lodash.get(data,["data","collection"])?pickImageFromCollection(lodash.get(data,["data","collection"])):{image:void 0,alt:void 0}}function ImageTags(seoConfig,config,pageType,data,{url:url={}}){const{image:image,alt:alt,includesHost:includesHost=!1}=pickImage({pageType:pageType,data:data,url:url,seoConfig:seoConfig,config:config});if(!image)return[];const tags=[];return seoConfig.enableTwitterCards&&(tags.push({name:"twitter:image",content:includesHost?image:`https://${config["cdn-image"]}/${image.path([16,9],{w:1200,auto:"format,compress",ogImage:!0,enlarge:!0})}`}),alt&&tags.push({property:"twitter:image:alt",content:alt})),seoConfig.enableOgTags&&(tags.push({property:"og:image",content:includesHost?image:`https://${config["cdn-image"]}/${image.path([40,21],{w:1200,auto:"format,compress",ogImage:!0,enlarge:!0})}`}),tags.push({property:"og:image:width",content:1200}),lodash.get(image,["metadata","focus-point"])&&tags.push({property:"og:image:height",content:630}),alt&&tags.push({property:"og:image:alt",content:alt})),tags}function StaticTags(seoConfig,config,pageType,data,{url:url}){return objectToTags(seoConfig.staticTags||{})}const getSchemaContext={"@context":"http://schema.org"};function getSchemaType(type){return{"@type":type}}function getSchemaPerson(name,url=""){return Object.assign({},getSchemaType("Person"),{givenName:name,name:name},url&&{url:url})}function getSchemaFooter({cssSelector:cssSelector}){return cssSelector?Object.assign({},getSchemaContext,getSchemaType("WPFooter"),{cssSelector:cssSelector}):{}}function getSchemaHeader({cssSelector:cssSelector}){return cssSelector?Object.assign({},getSchemaContext,getSchemaType("WPHeader"),{cssSelector:cssSelector}):{}}function getSchemaBlogPosting(card={},author={},headline="",image="",structuredData={},story={},timezone){const{website:{url:url=""}={}}=structuredData,orgUrl=lodash.get(structuredData,["organization","url"],"");return Object.assign({},getSchemaType("BlogPosting"),getSchemaMainEntityOfPage(`${url}/${story.slug}`),getSchemaPublisher(structuredData.organization,orgUrl),{dateModified:stripMillisecondsFromTime(new Date(card["card-updated-at"]),timezone),dateCreated:stripMillisecondsFromTime(new Date(card["card-added-at"]),timezone),datePublished:stripMillisecondsFromTime(new Date(card["card-updated-at"]),timezone),author:author,headline:headline,image:image})}function getSchemaPublisher(organization,orgUrl){const id={id:orgUrl};return{publisher:Object.assign({},getSchemaType("Organization"),getSchemaContext,organization,id)}}function getSchemaMainEntityOfPage(id){return{mainEntityOfPage:Object.assign({},getSchemaType("WebPage"),{"@id":id})}}function getSchemaMovieReview(movieObject={}){const movieCreatedAt=lodash.get(movieObject,["created-at"],null),actors=lodash.get(movieObject,["actors"],[]).map(actor=>getSchemaPerson(actor.name)),directors=lodash.get(movieObject,["directors"],[]).map(director=>getSchemaPerson(director.name)),producers=lodash.get(movieObject,["producers"],[]).map(producer=>getSchemaPerson(producer.name));return{actors:actors,directors:directors,name:lodash.get(movieObject,["name"],""),sameAs:lodash.get(movieObject,["sameAs"],""),description:lodash.get(movieObject,["meta-description"],""),producer:producers,image:lodash.get(movieObject,["photo","0","url"],""),dateCreated:movieCreatedAt?new Date(movieCreatedAt).toISOString():""}}function getSchemaWebsite(website={}){const{url:url,searchpath:searchpath,name:name,headline:headline,keywords:keywords,queryinput:queryinput}=website;return Object.assign({},getSchemaContext,getSchemaType("WebSite"),{url:url,interactivityType:"mixed",name:name,headline:headline,keywords:keywords,copyrightHolder:Object.assign({},getSchemaType("Organization"),{name:name}),potentialAction:{"@type":"SearchAction",target:`${url}/${searchpath}`,"query-input":queryinput}},getSchemaMainEntityOfPage(url))}function getSchemaListItem(position=0,name="",url=""){return Object.assign({},getSchemaType("ListItem"),{position:position,name:name,item:url})}function getSchemaBreadcrumbList(breadcrumbsDataList){const itemListElement=breadcrumbsDataList.map(({name:name="",url:url=""},index)=>getSchemaListItem(index+1,name,url));return Object.assign({},getSchemaContext,getSchemaType("BreadcrumbList"),{itemListElement:itemListElement})}function getMovieEntityTags(movieJson){return getSchemaMovieReview(movieJson)}function generateTagsForEntity(entity,ldJson){if(entity.type&&"movie"===entity.type.toLowerCase())return ldJson("Movie",getMovieEntityTags(entity))}function getLdJsonFields(type,fields){return Object.assign({},fields,getSchemaType(type),getSchemaContext)}function ldJson(type,fields){const json=JSON.stringify(getLdJsonFields(type,fields)).replace(/</g,"<").replace(/>/g,">");return{tag:"script",type:"application/ld+json",dangerouslySetInnerHTML:{__html:json}}}function imageUrl(publisherConfig,s3Key,width,height){const imageSrc=/^https?.*/.test(publisherConfig["cdn-image"])?publisherConfig["cdn-image"]:`https://${publisherConfig["cdn-image"]}`;return`${imageSrc}/${s3Key}?w=${width=width||""}&h=${height=height||""}&auto=format%2Ccompress&fit=max`}function generateCommonData(structuredData={},story={},publisherConfig={},timezone){const storyUrl=story.url||`${publisherConfig["sketches-host"]}/${story.slug}`,orgUrl=get__default.default(structuredData,["organization","url"],""),mainEntityUrl=Object.keys(story).length>0&&structuredData.storyUrlAsMainEntityUrl?storyUrl:get__default.default(structuredData,["organization","url"],""),imageWidth=1200,imageHeight=675;return Object.assign({},{headline:story.headline,image:[imageUrl(publisherConfig,story["hero-image-s3-key"],1200,675)],url:`${publisherConfig["sketches-host"]}/${story.slug}`,datePublished:stripMillisecondsFromTime(new Date(story["first-published-at"]),timezone)},getSchemaMainEntityOfPage(mainEntityUrl),getSchemaPublisher(structuredData.organization,orgUrl))}function authorData(authors=[],authorSchema=[],publisherConfig={}){return authorSchema.length>0?authorSchema.map(author=>getSchemaPerson(author.name,author.url)):authors.map(author=>{const authorUrl=author.slug?`${publisherConfig["sketches-host"]}/author/${author.slug}`:null;return getSchemaPerson(author.name,authorUrl)})}function getTextElementsOfCards(story){if(story&&story.cards)return story.cards.reduce((acc,currentCard)=>acc.concat(currentCard["story-elements"].filter(element=>"text"===element.type)),[])}function getPlainText(text=""){return text.replace(/<[^>]+>/g,"")}function getCompleteText(story,stripHtmlFromArticleBody){const textArray=[];getTextElementsOfCards(story).forEach(item=>{const textContent=stripHtmlFromArticleBody?getPlainText(item.text):item.text;textArray.push(textContent)});const completeCardText=textArray.join(".");return completeCardText}function articleSectionObj(story){if("video"!==story["story-template"])return{articleSection:get__default.default(story,["sections","0","display-name"],"")}}function generateArticleData(structuredData={},story={},publisherConfig={},timezone){const metaKeywords=story.seo&&story.seo["meta-keywords"]||[],authors=story.authors&&0!==story.authors.length?story.authors:[{name:story["author-name"]||""}],storyKeysPresence=Object.keys(story).length>0,imageWidth=1200,imageHeight=675,storyAccessType=storyAccess(story.access),authorSchema=structuredData.authorSchema&&structuredData.authorSchema(story)||[];return Object.assign({},generateCommonData(structuredData,story,publisherConfig,timezone),{author:authorData(authors,authorSchema,publisherConfig),keywords:metaKeywords.join(","),thumbnailUrl:imageUrl(publisherConfig,story["hero-image-s3-key"],1200,675),articleBody:storyKeysPresence&&getCompleteText(story,structuredData.stripHtmlFromArticleBody)||"",dateCreated:stripMillisecondsFromTime(new Date(story["first-published-at"]),timezone),dateModified:stripMillisecondsFromTime(new Date(story["last-published-at"]),timezone),name:storyKeysPresence&&story.headline||"",image:generateArticleImageData(story["hero-image-s3-key"],publisherConfig),isAccessibleForFree:storyAccessType,isPartOf:generateIsPartOfDataForArticle(story,publisherConfig)},articleSectionObj(story))}function generateArticleImageData(image,publisherConfig={}){const imageWidth=1200,imageHeight=675,articleImage=imageUrl(publisherConfig,image,1200,675);return Object.assign({},{"@type":"ImageObject",url:articleImage},getQueryParams(articleImage))}function storyAccess(access){return null===access||"public"===access||"login"===access||"subscription"!==access&&void 0}function generateIsPartOfDataForArticle(story={},publisherConfig={}){return Object.assign({},{"@type":"WebPage",url:`${publisherConfig["sketches-host"]}/${story.slug}`,primaryImageOfPage:generateArticleImageData(story["hero-image-s3-key"],publisherConfig)})}function generateIsPartOfDataForNewsArticle(story={},publisherConfig={},pageType="",structuredData={}){const publisherName=publisherConfig["publisher-name"],productId=`${publisherConfig["publisher-name"]}${structuredData.isShowcaseProduct?".com:showcase":".com:basic"}`,isPartOfData=generateIsPartOfDataForArticle(story,publisherConfig);return structuredData.isSubscriptionsEnabled?Object.assign(isPartOfData,{"@type":["WebPage","CreativeWork","Product"],name:publisherName,productID:productId}):"story-page-amp"===pageType&&structuredData.isAmpSubscriptionsEnabled?Object.assign({},{"@type":["WebPage","CreativeWork","Product"],name:publisherName,productID:productId,url:`${publisherConfig["sketches-host"]}/${story.slug}`,primaryImageOfPage:generateArticleImageData(story["hero-image-s3-key"],publisherConfig)}):isPartOfData}function generateHasPartData(storyAccess){return storyAccess?{}:{hasPart:[{"@type":"WebPageElement",isAccessibleForFree:storyAccess,cssSelector:".paywall"}]}}function generateNewsArticleData(structuredData={},story={},publisherConfig={},pageType=""){const{alternative:alternative={}}=story.alternative||{},storyAccessType=storyAccess(story.access);return Object.assign({},{alternativeHeadline:alternative.home&&alternative.home.default?alternative.home.default.headline:"",description:story.summary,isAccessibleForFree:storyAccessType,isPartOf:generateIsPartOfDataForNewsArticle(story,publisherConfig,pageType,structuredData)},generateHasPartData(storyAccessType))}function findStoryElementField(card,type,field,defaultValue){const elements=card["story-elements"].filter(e=>e.type==type||e.subtype==type);return elements.length>0?elements[0][field]:defaultValue}function generateLiveBlogPostingData(structuredData={},story={},publisherConfig={},timezone){const imageWidth=1200,imageHeight=675,authorSchema=structuredData.authorSchema&&structuredData.authorSchema(story)||[];return{headline:story.headline,description:story.summary||story.headline,author:story["author-name"],coverageEndTime:stripMillisecondsFromTime(new Date(story["last-published-at"]),timezone),coverageStartTime:stripMillisecondsFromTime(new Date(story["first-published-at"]),timezone),dateModified:stripMillisecondsFromTime(new Date(story["last-published-at"]),timezone),liveBlogUpdate:story.cards.map(card=>getSchemaBlogPosting(card,authorData(story.authors,authorSchema,publisherConfig),findStoryElementField(card,"title","text",story.headline),imageUrl(publisherConfig,findStoryElementField(card,"image","image-s3-key",story["hero-image-s3-key"]),1200,675),structuredData,story,timezone))}}function getEmbedUrl(cards){let embedUrl="";return cards.find(card=>{const storyElements=get__default.default(card,["story-elements"],[]);return storyElements.find(elem=>!!elem["embed-url"]&&(embedUrl=elem["embed-url"],!0))}),embedUrl}function generateVideoArticleData(structuredData={},story={},publisherConfig={},timezone){const metaKeywords=story.seo&&story.seo["meta-keywords"]||[],storyCards=get__default.default(story,["cards"],[]),embedUrl=getEmbedUrl(storyCards),socialShareMsg=get__default.default(story,["summary"],""),metaDescription=get__default.default(story,["seo","meta-description"],""),subHeadline=get__default.default(story,["subheadline"],""),headline=get__default.default(story,["headline"],""),imageWidth=1200,imageHeight=675,authorSchema=structuredData.authorSchema&&structuredData.authorSchema(story)||[];return Object.assign({},generateCommonData(structuredData,story,publisherConfig,timezone),{author:authorData(story.authors,authorSchema,publisherConfig),keywords:metaKeywords.join(","),dateCreated:stripMillisecondsFromTime(new Date(story["first-published-at"]),timezone),dateModified:stripMillisecondsFromTime(new Date(story["last-published-at"]),timezone),description:socialShareMsg||metaDescription||subHeadline||headline,name:story.headline,thumbnailUrl:[imageUrl(publisherConfig,story["hero-image-s3-key"],1200,675)],uploadDate:stripMillisecondsFromTime(new Date(story["last-published-at"]),timezone),embedUrl:embedUrl})}function generateWebSiteData(structuredData={},story={},publisherConfig={}){return getSchemaWebsite(structuredData.website)}function generateBreadcrumbListData(pageType="",publisherConfig={},data={}){const{"sketches-host":domain="",sections:sections=[]}=publisherConfig;let breadcrumbsDataList=[{name:"Home",url:domain}];function addCrumb(crumbsDataList=[],currentSection={}){if(!currentSection["parent-id"])return crumbsDataList;const parentSection=sections.find(section=>section.id===currentSection["parent-id"]);if(!parentSection)return crumbsDataList;const{"section-url":url="",name:name=""}=parentSection;return crumbsDataList.unshift({url:url,name:name}),addCrumb(crumbsDataList,parentSection)}function getSectionPageCrumbs(section={}){const{"section-url":url="",name:name=""}=section,crumbsDataList=[{url:url,name:name}];return addCrumb(crumbsDataList,section)}function getStoryPageCrumbs({headline:headline="",url:url="",sections:[storySection]}={}){let sectionCrumbsDataList=[];return storySection&&(sectionCrumbsDataList=getSectionPageCrumbs(storySection)),sectionCrumbsDataList.push({name:headline,url:url}),sectionCrumbsDataList}function getBreadCrumbs(breadcrumb={}){const crumbsDataList=[{url:breadcrumb.url,name:breadcrumb.name}];return addCrumb(crumbsDataList)}if(data.breadcrumbs&&"name"in data.breadcrumbs&&"url"in data.breadcrumbs)return breadcrumbsDataList=breadcrumbsDataList.concat(getBreadCrumbs(data.breadcrumbs)),getSchemaBreadcrumbList(breadcrumbsDataList);switch(pageType){case"section-page":breadcrumbsDataList=breadcrumbsDataList.concat(getSectionPageCrumbs(data.section));break;case"story-page":case"story-page-amp":breadcrumbsDataList=breadcrumbsDataList.concat(getStoryPageCrumbs(data.story))}return getSchemaBreadcrumbList(breadcrumbsDataList)}function StructuredDataTags({structuredData:structuredData={}},config,pageType,response={},{url:url}){const tags=[],{story:story={},timezone:timezone=null}=response.data||{},entities=get__default.default(response,["data","linkedEntities"],null)||[],{config:publisherConfig={}}=response;publisherConfig["publisher-settings"];const isStructuredDataEmpty=0===Object.keys(structuredData).length,enableBreadcrumbList=get__default.default(structuredData,["enableBreadcrumbList"],!0),structuredDataTags=get__default.default(structuredData,["structuredDataTags"],[]);let articleData={};if(isStructuredDataEmpty||(articleData=generateArticleData(structuredData,story,publisherConfig,timezone),structuredDataTags.map(type=>{pageType===type&&(tags.push(ldJson("Organization",structuredData.organization)),structuredData.website&&tags.push(ldJson("Website",Object.assign({},generateWebSiteData(structuredData,story,publisherConfig)))))})),isStructuredDataEmpty||"home-page"!==pageType||(tags.push(ldJson("Organization",structuredData.organization)),structuredData.website&&tags.push(ldJson("Website",Object.assign({},generateWebSiteData(structuredData,story,publisherConfig))))),!isStructuredDataEmpty&&enableBreadcrumbList&&tags.push(ldJson("BreadcrumbList",generateBreadcrumbListData(pageType,publisherConfig,response.data))),!isStructuredDataEmpty&&"story-page"===pageType){const newsArticleTags=generateNewsArticleTags();newsArticleTags?tags.push(storyTags(),newsArticleTags):tags.push(storyTags())}if(!isStructuredDataEmpty&&"story-page-amp"===pageType){const newsArticleTags=generateNewsArticleTags();newsArticleTags?tags.push(storyTags(),newsArticleTags):tags.push(storyTags())}if(!isStructuredDataEmpty&&structuredData.header&&tags.push(ldJson("WPHeader",getSchemaHeader(structuredData.header))),!isStructuredDataEmpty&&structuredData.footer&&tags.push(ldJson("WPFooter",getSchemaFooter(structuredData.footer))),entities.length>0)for(let entity of entities){const entityTags=generateTagsForEntity(entity,ldJson);entityTags&&tags.push(entityTags)}function generateNewsArticleTags(){if(structuredData.enableNewsArticle)return ldJson("NewsArticle",Object.assign({},articleData,generateNewsArticleData(structuredData,story,publisherConfig,pageType)))}function storyTags(){return structuredData.enableLiveBlog&&"live-blog"===story["story-template"]?ldJson("LiveBlogPosting",Object.assign({},generateLiveBlogPostingData(structuredData,story,publisherConfig,timezone))):structuredData.enableVideo&&"video"===story["story-template"]?ldJson("VideoObject",generateVideoArticleData(structuredData,story,publisherConfig,timezone)):"withoutArticleSchema"!==structuredData.enableNewsArticle?ldJson("Article",articleData):{}}return tags}function buildTagsFromStory(config,story,url={},data={}){if(!story)return;function getStoryCardMetadata(cardId){const{metadata:metadata={}}=story.cards.find(card=>card.id===cardId)||{},urlWithCardId=`${config["sketches-host"]}/${story.slug}?cardId=${cardId}`;return metadata&&!lodash.isEmpty(metadata)&&metadata["social-share"]?{title:metadata["social-share"].title||story.headline,description:metadata["social-share"].message||story.summary,ogUrl:urlWithCardId,ogTitle:metadata["social-share"].title||story.headline,ogDescription:metadata["social-share"].message||story.summary}:metadata}const seo=story.seo||{},storyUrl=story.url||`${config["sketches-host"]}/${story.slug}`,customSeo=lodash.get(data,["data","customSeo"],{}),authors=lodash.get(story,["authors"],[]).map(author=>author.name),title=customSeo.title||seo["meta-title"]||story.headline,pageTitle=customSeo["page-title"]||seo["meta-title"]||story.headline,description=customSeo.description||seo["meta-description"]||story.summary,keywords=(customSeo.keywords||seo["meta-keywords"]||(story.tags||[]).map(tag=>tag.name)).join(","),ogUrl=customSeo.ogUrl||lodash.get(seo,["og","url"])||storyUrl,getOgTitle=customSeo.ogTitle||lodash.get(story,["alternative","social","default","headline"],story.headline)||story.headline,ogDescription=customSeo.ogDescription||story.summary,storyMetaData={title:title,"page-title":pageTitle,description:description,keywords:keywords,canonicalUrl:story["canonical-url"]||storyUrl,ogUrl:ogUrl,ogTitle:getOgTitle,ogDescription:ogDescription,storyUrl:storyUrl,author:authors};if(url.query&&url.query.cardId){const storyCardMetadata=getStoryCardMetadata(url.query.cardId);return Object.assign({},storyMetaData,storyCardMetadata)}return storyMetaData}function buildTagsFromTopic(config,tag,url={},data){if(lodash.isEmpty(tag))return;const customSeo=lodash.get(data,["data","customSeo"],{}),tagName=customSeo.title||tag["meta-title"]||tag.name,pageTitle=customSeo["page-title"]||tagName,tagDescription=customSeo.description||tag["meta-description"],description=`Read stories listed under on ${tag.name}`,tagUrl=`${config["sketches-host"]}${url.pathname}`,canonicalSlug=tag["canonical-slug"]||url.pathname,canonicalUrl=`${config["sketches-host"]}${canonicalSlug}`,ogTitle=customSeo.ogTitle||tagName,ogDescription=customSeo.ogDescription||description,topicMetaData={title:tagName,"page-title":pageTitle,description:tagDescription||description,keywords:tagName,canonicalUrl:canonicalUrl,ogUrl:tagUrl,ogTitle:ogTitle,ogDescription:ogDescription};return topicMetaData}function buildTagsFromAuthor(config,author,url={},data){if(lodash.isEmpty(author))return;const customSeo=lodash.get(data,["data","customSeo"],{}),title=customSeo.title||author.name,pageTitle=customSeo["page-title"]||title,description=customSeo.description||author.bio||`View all articles written by ${title}`,ogTitle=customSeo.ogTitle||author.name,authorUrl=`${config["sketches-host"]}${url.pathname}`,ogDescription=customSeo.ogDescription||description;return{title:title,"page-title":pageTitle,description:description,keywords:`${title},${config["publisher-name"]}`,canonicalUrl:authorUrl,ogUrl:authorUrl,ogTitle:ogTitle,ogDescription:ogDescription}}function buildCustomTags(customTags={},pageType=""){const configObject=customTags[pageType];return configObject||{}}function buildTagsFromStaticPage(config,page,url={},data){const seoData=lodash.get(page,["metadata","seo"],{}),customSeo=lodash.get(data,["data","customSeo"],{});if(lodash.isEmpty(seoData)&&lodash.isEmpty(customSeo))return;const{"meta-title":metaTitle,"meta-description":metaDescription,"meta-keywords":keywords}=seoData,title=customSeo.title||metaTitle||page.title,pageTitle=customSeo["page-title"]||title,description=customSeo.description||metaDescription,ogTitle=customSeo.ogTitle||title,staticPageUrl=`${config["sketches-host"]}${url.pathname}`,ogDescription=customSeo.ogDescription||description;return{title:title,"page-title":pageTitle,description:description,keywords:`${title},${config["publisher-name"]}`,canonicalUrl:staticPageUrl,ogUrl:staticPageUrl,ogTitle:ogTitle,ogDescription:ogDescription,keywords:customSeo.keywords||keywords}}function getSeoData(config,pageType,data,url={},seoConfig={}){function findRelevantConfig(ownerType,ownerId=null){const seoMetadata=config["seo-metadata"].find(page=>page["owner-type"]===ownerType&&page["owner-id"]===ownerId)||{},{sections:sections=[]}=config,section=sections.find(section=>"section"==ownerType&§ion.id===ownerId)||{},customSeo=lodash.get(data,["data","customSeo"],{});if(seoMetadata.data||section.id||!lodash.isEmpty(customSeo)){const result=Object.assign({},{"page-title":customSeo["page-title"]||section.name,title:customSeo.title||section.name,canonicalUrl:customSeo.canonicalUrl||section["section-url"]||void 0},seoMetadata.data);if(!result.description){const homeSeoData=config["seo-metadata"].find(page=>"home"===page["owner-type"])||{data:{description:""}};result.description=customSeo.description||homeSeoData.data.description}return result.ogTitle=customSeo.ogTitle||result.title,result.ogDescription=customSeo.ogDescription||result.description,result}}if(seoConfig.customTags&&seoConfig.customTags[pageType])return buildCustomTags(seoConfig.customTags,pageType);function getShellSeoData(config){const seoMetadata=config["seo-metadata"].find(meta=>"home"===meta["owner-type"])||{};return Object.assign({},seoMetadata.data,{canonicalUrl:SKIP_CANONICAL})}switch(pageType){case"home-page":return findRelevantConfig("home");case"section-page":return findRelevantConfig("section",lodash.get(data,["data","section","id"]))||getSeoDataFromCollection(config,data)||getSeoData(config,"home-page",data,url);case"collection-page":return getSeoDataFromCollection(config,data)||getSeoData(config,"home-page",data,url);case"tag-page":return buildTagsFromTopic(config,lodash.get(data,["data","tag"]),url,data)||getSeoData(config,"home-page",data,url);case"story-page":return buildTagsFromStory(config,lodash.get(data,["data","story"]),url,data)||getSeoData(config,"home-page",data,url);case"visual-story":return buildTagsFromStory(config,lodash.get(data,["story"]),url,data)||getSeoData(config,"home-page",data,url);case"story-page-amp":return buildTagsFromStory(config,lodash.get(data,["data","story"]),url,data)||getSeoData(config,"home-page",data,url);case"author-page":return buildTagsFromAuthor(config,lodash.get(data,["data","author"],{}),url,data)||getSeoData(config,"home-page",data,url);case"static-page":return buildTagsFromStaticPage(config,lodash.get(data,["data","page"],{}),url,data)||getSeoData(config,"home-page",data,url);case"shell":return getShellSeoData(config);default:return getSeoData(config,"home-page",data,url)}}function getSeoDataFromCollection(config,data){if(lodash.get(data,["data","collection","name"])){let{name:name,summary:summary}=lodash.get(data,["data","collection"]);const customSeo=lodash.get(data,["data","customSeo"],{});summary||(summary=(getSeoData(config,"home-page",data)||{}).description);const title=customSeo.title||name,pageTitle=customSeo["page-title"]||name,ogTitle=customSeo.ogTitle||title,description=customSeo.description||summary,ogDescription=customSeo.ogDescription||summary;return{"page-title":pageTitle,title:title,ogTitle:ogTitle,description:description,ogDescription:ogDescription,canonicalUrl:SKIP_CANONICAL}}}const SKIP_CANONICAL="__SKIP__CANONICAL__";function TextTags(seoConfig,config,pageType,data,{url:url}){const seoData=getSeoData(config,pageType,data,url,seoConfig),customSeo=lodash.get(data,["data","customSeo"],{});if(!seoData)return[];const currentUrl=`${config["sketches-host"]}${url.pathname}`,basicTags={description:customSeo.description||seoData.description,title:customSeo.title||seoData.title,keywords:customSeo.keywords||seoData.keywords},ogUrl=customSeo.ogUrl||seoData.ogUrl||seoData.canonicalUrl||currentUrl,ogTags=seoConfig.enableOgTags?{"og:type":"story-page"===pageType||"story-page-amp"===pageType?"article":"website","og:url":ogUrl===SKIP_CANONICAL?void 0:ogUrl,"og:title":customSeo.ogTitle||seoData.ogTitle,"og:description":customSeo.ogDescription||seoData.ogDescription}:void 0,twitterTags=seoConfig.enableTwitterCards?{"twitter:card":"summary_large_image","twitter:title":customSeo.twitterTitle||seoData.ogTitle,"twitter:description":customSeo.twitterDescription||seoData.ogDescription}:void 0,allTags=Object.assign(basicTags,ogTags,twitterTags),commonTags=[{tag:"title",children:customSeo.title||data.title||seoData["page-title"]}],canonical=seoData.canonicalUrl||currentUrl;return canonical!=SKIP_CANONICAL&&commonTags.push({tag:"link",rel:"canonical",href:canonical}),"story-page"!==pageType&&"story-page-amp"!==pageType||commonTags.push({name:"author",content:seoData.author}),"story-page"!==pageType&&"story-page-amp"!==pageType||!seoConfig.enableNews||(commonTags.push({name:"news_keywords",content:seoData.keywords}),lodash.get(data,["data","story","seo","meta-google-news-standout"])&&commonTags.push({tag:"link",rel:"standout",href:seoData.storyUrl||currentUrl})),commonTags.concat(objectToTags(allTags))}function getTitle(seoConfig,config,pageType,data,params){const customSeo=lodash.get(data,["data","customSeo"],{});if(lodash.get(data,["title"]))return customSeo.title||lodash.get(data,["title"]);if(lodash.get(data,["data","title"]))return customSeo.title||lodash.get(data,["data","title"]);const seoData=getSeoData(config,pageType,data,void 0,seoConfig)||{};return customSeo.title||seoData["page-title"]}function tagToKey(tag){switch(tag.tag||"meta"){case"meta":return`meta-${tag.name||tag.itemprop||"name"}-${tag.property||"property"}`;case"link":return`link-${tag.rel}`;case"title":return"title";default:return Math.random().toString()}}class MetaTagList{constructor(tags){this.tags=tags}toString(){const uniqueTags=lodash.uniqBy(this.tags.reverse(),tagToKey).reverse();return ReactDomServer__default.default.renderToStaticMarkup(uniqueTags.map(tag=>React__default.default.createElement(tag.tag||"meta",lodash.omit(tag,"tag"))))}addTag(){return new MetaTagList(this.tags.concat([].slice.call(arguments)))}}class SEO{constructor(seoConfig={}){this.seoConfig=seoConfig,this.generators=(seoConfig.generators||[TextTags,ImageTags,AuthorTags,StaticTags,StructuredDataTags,StoryAmpTags]).concat(seoConfig.extraGenerators||[])}getMetaTags(config,pageType,data,params={}){return pageType=lodash.get(this.seoConfig,["pageTypeAliases",pageType],pageType),new MetaTagList(lodash.flatMap(this.generators,generator=>generator(this.seoConfig,config,pageType,data,params)))}getTitle(config,pageType,data,params={}){return getTitle(this.seoConfig,config,pageType,data)}}exports.AuthorTags=AuthorTags,exports.ImageTags=ImageTags,exports.MetaTagList=MetaTagList,exports.SEO=SEO,exports.StaticTags=StaticTags,exports.StoryAmpTags=StoryAmpTags,exports.StructuredDataTags=StructuredDataTags,exports.TextTags=TextTags,exports.generateStaticData=generateStaticData,exports.generateStructuredData=generateStructuredData;
|
package/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { flatMap, get, omit, uniqBy } from "lodash";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import ReactDomServer from"react-dom/server";
|
|
3
|
+
import ReactDomServer from "react-dom/server";
|
|
4
|
+
import { StoryAmpTags } from './src/amp-tags.js';
|
|
5
|
+
import { AuthorTags } from './src/author-tags.js';
|
|
6
|
+
import { generateStaticData, generateStructuredData } from './src/generate-common-seo';
|
|
7
|
+
import { ImageTags } from './src/image-tags.js';
|
|
8
|
+
import { StaticTags } from './src/static-tags.js';
|
|
9
|
+
import { StructuredDataTags } from './src/structured-data/structured-data-tags.js';
|
|
10
|
+
import { getTitle, TextTags } from './src/text-tags.js';
|
|
4
11
|
|
|
5
|
-
import {TextTags, getTitle} from './src/text-tags.js';
|
|
6
|
-
import {StaticTags} from './src/static-tags.js';
|
|
7
|
-
import {AuthorTags} from './src/author-tags.js';
|
|
8
|
-
import {ImageTags} from './src/image-tags.js';
|
|
9
|
-
import {StructuredDataTags} from './src/structured-data/structured-data-tags.js';
|
|
10
|
-
import {StoryAmpTags} from './src/amp-tags.js';
|
|
11
|
-
import {generateStaticData, generateStructuredData} from './src/generate-common-seo';
|
|
12
12
|
|
|
13
|
-
export {TextTags, StaticTags, AuthorTags, ImageTags, StructuredDataTags, StoryAmpTags, generateStaticData, generateStructuredData};
|
|
13
|
+
export { TextTags, StaticTags, AuthorTags, ImageTags, StructuredDataTags, StoryAmpTags, generateStaticData, generateStructuredData };
|
|
14
14
|
|
|
15
15
|
function tagToKey(tag) {
|
|
16
|
-
switch(tag.tag || "meta") {
|
|
17
|
-
case "meta": return `meta-${tag.name || "name"}-${tag.property || "property"}`;
|
|
16
|
+
switch (tag.tag || "meta") {
|
|
17
|
+
case "meta": return `meta-${tag.name || tag.itemprop || "name"}-${tag.property || "property"}`;
|
|
18
18
|
case "link": return `link-${tag.rel}`;
|
|
19
19
|
case "title": return `title`;
|
|
20
20
|
default: return Math.random().toString();
|
|
@@ -28,7 +28,7 @@ export class MetaTagList {
|
|
|
28
28
|
|
|
29
29
|
toString() {
|
|
30
30
|
const uniqueTags = uniqBy(this.tags.reverse(), tagToKey).reverse();
|
|
31
|
-
return ReactDomServer.renderToStaticMarkup(uniqueTags.map(tag => React.createElement(tag.tag || "meta", omit(tag, "tag"))))
|
|
31
|
+
return ReactDomServer.renderToStaticMarkup(uniqueTags.map(tag => React.createElement(tag.tag || "meta", omit(tag, "tag"))));
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
addTag() {
|
|
@@ -102,6 +102,6 @@ export class SEO {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
getTitle(config, pageType, data, params = {}) {
|
|
105
|
-
return getTitle(this.seoConfig, config, pageType, data, params)
|
|
105
|
+
return getTitle(this.seoConfig, config, pageType, data, params);
|
|
106
106
|
}
|
|
107
107
|
}
|
package/package.json
CHANGED
|
@@ -261,8 +261,8 @@ function getEmbedUrl(cards) {
|
|
|
261
261
|
// coz we only need the embed url
|
|
262
262
|
// find is used for early exit
|
|
263
263
|
cards.find((card) => {
|
|
264
|
-
const storyElements = card["story-elements"];
|
|
265
|
-
return storyElements.find((elem
|
|
264
|
+
const storyElements = get(card, ["story-elements"], []);
|
|
265
|
+
return storyElements.find((elem) => {
|
|
266
266
|
if (elem["embed-url"]) {
|
|
267
267
|
embedUrl = elem["embed-url"];
|
|
268
268
|
return true;
|