@quintype/seo 1.46.4-recipe-schema.5 → 1.46.4

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 CHANGED
@@ -2,6 +2,8 @@
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.46.4](https://github.com/quintype/quintype-node-seo/compare/v1.46.3...v1.46.4) (2024-08-14)
6
+
5
7
  ### [1.46.3](https://github.com/quintype/quintype-node-seo/compare/v1.46.2...v1.46.3) (2024-07-17)
6
8
 
7
9
  ### [1.46.2](https://github.com/quintype/quintype-node-seo/compare/v1.46.1...v1.46.2) (2024-06-12)
package/dist/index.cjs.js CHANGED
@@ -24,22 +24,6 @@ function objectToTags(object) {
24
24
  return lodash.entries(object).filter(([key, value]) => value).map(([key, value]) => ({ [getPropertyName(key)]: key, content: value }));
25
25
  }
26
26
 
27
- function extractTextFromHtmlString(html) {
28
- const regex = /<p>(.*?)<\/p>/g;
29
- const textContents = [];
30
-
31
- let match;
32
- while ((match = regex.exec(html)) !== null) {
33
- textContents.push(match[1]);
34
- }
35
-
36
- return textContents;
37
- }
38
-
39
- const getCardAttributes = (card, type) => {
40
- return card.metadata.attributes[type];
41
- };
42
-
43
27
  function getPropertyName(key) {
44
28
  return key.startsWith("fb:") || key.startsWith("og:") ? "property" : "name";
45
29
  }
@@ -569,28 +553,6 @@ function generateAuthorPageSchema(publisherConfig, data, url) {
569
553
  };
570
554
  }
571
555
 
572
- function generateRecipePageSchema(story) {
573
- const { headline, url, "author-name": authorName, description } = story;
574
-
575
- const cardsWithAttributes = story.cards.filter(card => getCardAttributes(card, "cardtype"));
576
- const cardWithIngredients = cardsWithAttributes.filter(card => getCardAttributes(card, "cardtype").includes("ingredients "));
577
- const ingredientsRichText = lodash.get(cardWithIngredients, ["0", "story-elements", "0", "text"], "");
578
- const ingredients = extractTextFromHtmlString(ingredientsRichText);
579
-
580
- return {
581
- "@context": "https://schema.org/",
582
- "@type": "Recipe",
583
- name: headline,
584
- url: url,
585
- author: {
586
- "@type": "Person",
587
- name: authorName
588
- },
589
- description: description,
590
- recipeIngredient: ingredients
591
- };
592
- }
593
-
594
556
  function getMovieEntityTags(movieJson) {
595
557
  return getSchemaMovieReview(movieJson);
596
558
  }
@@ -774,12 +736,20 @@ function findStoryElementField(card, type, field, defaultValue) {
774
736
  if (elements.length > 0) return elements[0][field];else return defaultValue;
775
737
  }
776
738
 
739
+ function getTextElementsOfOneCard(storyElements = []) {
740
+ return storyElements.filter(element => element.type === "text");
741
+ }
742
+
743
+ function getCompleteTextOfOneCard(storyElements, stripHtmlFromArticleBody) {
744
+ return getTextElementsOfOneCard(storyElements).map(item => stripHtmlFromArticleBody ? getPlainText(item.text) : item.text).join(".");
745
+ }
746
+
777
747
  function generateLiveBlogPostingData(structuredData = {}, story = {}, publisherConfig = {}, timezone) {
778
748
  const imageWidth = 1200;
779
749
  const imageHeight = 675;
780
750
  const authorSchema = structuredData.authorSchema && structuredData.authorSchema(story) || [];
781
751
  const storyKeysPresence = Object.keys(story).length > 0;
782
- const articleBody = storyKeysPresence && getCompleteText(story, structuredData.stripHtmlFromArticleBody) || "";
752
+ storyKeysPresence && getCompleteText(story, structuredData.stripHtmlFromArticleBody) || "";
783
753
  return {
784
754
  headline: story.headline,
785
755
  description: story.summary || story.headline,
@@ -788,16 +758,21 @@ function generateLiveBlogPostingData(structuredData = {}, story = {}, publisherC
788
758
  coverageStartTime: stripMillisecondsFromTime(new Date(story["first-published-at"]), timezone),
789
759
  dateModified: stripMillisecondsFromTime(new Date(story["last-published-at"]), timezone),
790
760
 
791
- 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"]), imageWidth, imageHeight), structuredData, story, timezone, articleBody))
761
+ liveBlogUpdate: story.cards.map(card => {
762
+ const storyElements = get__default["default"](card, ["story-elements"]);
763
+ const cardArticleBody = getCompleteTextOfOneCard(storyElements, structuredData.stripHtmlFromArticleBody) || "";
764
+
765
+ return 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"]), imageWidth, imageHeight), structuredData, story, timezone, cardArticleBody);
766
+ })
792
767
  };
793
768
  }
794
769
 
795
770
  function getEmbedUrl(cards) {
796
771
  const playerUrlMapping = {
797
772
  "dailymotion-embed-script": "dailymotion-url",
798
- instagram: "instagram-url",
773
+ "instagram": "instagram-url",
799
774
  "facebook-video": "facebook-url",
800
- tweet: "tweet-url",
775
+ "tweet": "tweet-url",
801
776
  "vimeo-video": "vimeo-url",
802
777
  "brightcove-video": "player-url"
803
778
  };
@@ -810,8 +785,7 @@ function getEmbedUrl(cards) {
810
785
  if (elem.metadata && elem.metadata[playerUrlField]) {
811
786
  return elem.metadata[playerUrlField];
812
787
  }
813
- }
814
- if (elem.type === "youtube-video" && elem.subtype === null) {
788
+ } if (elem.type === "youtube-video" && elem.subtype === null) {
815
789
  if (elem.url) {
816
790
  return elem.url;
817
791
  }
@@ -976,6 +950,7 @@ function StructuredDataTags({ structuredData = {} }, config, pageType, response
976
950
  const isStructuredDataEmpty = Object.keys(structuredData).length === 0;
977
951
  const enableBreadcrumbList = get__default["default"](structuredData, ["enableBreadcrumbList"], true);
978
952
  const structuredDataTags = get__default["default"](structuredData, ["structuredDataTags"], []);
953
+
979
954
  let articleData = {};
980
955
 
981
956
  if (!isStructuredDataEmpty) {
@@ -1004,17 +979,6 @@ function StructuredDataTags({ structuredData = {} }, config, pageType, response
1004
979
  if (!isStructuredDataEmpty && pageType === "story-page") {
1005
980
  const newsArticleTags = generateNewsArticleTags();
1006
981
  newsArticleTags ? tags.push(storyTags(), newsArticleTags) : tags.push(storyTags());
1007
- if (story["story-template"] === "recipe") {
1008
- const recipeTags = generateRecipePageSchema(story);
1009
- recipeTags.image = Object.assign({
1010
- "@type": "ImageObject"
1011
- }, generateArticleImageData(story["hero-image-s3-key"], publisherConfig));
1012
- recipeTags.video = Object.assign({
1013
- "@type": "VideoObject"
1014
- }, generateVideoArticleData(structuredData, story, publisherConfig, timezone));
1015
-
1016
- tags.push(ldJson("Recipe", recipeTags));
1017
- }
1018
982
  }
1019
983
 
1020
984
  if (!isStructuredDataEmpty && pageType === "story-page-amp") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quintype/seo",
3
- "version": "1.46.4-recipe-schema.5",
3
+ "version": "1.46.4",
4
4
  "description": "SEO Modules for Quintype",
5
5
  "main": "dist/index.cjs.js",
6
6
  "repository": "https://github.com/quintype/quintype-node-seo",
@@ -1,6 +1,6 @@
1
1
  import { get } from "lodash";
2
2
  import { getTitle } from "../generate-common-seo";
3
- import { extractTextFromHtmlString, getCardAttributes, stripMillisecondsFromTime } from "../utils";
3
+ import { stripMillisecondsFromTime } from "../utils";
4
4
  export const getSchemaContext = { "@context": "http://schema.org" };
5
5
 
6
6
  export function getSchemaType(type) {
@@ -151,27 +151,3 @@ export function generateAuthorPageSchema(publisherConfig, data, url) {
151
151
  },
152
152
  };
153
153
  }
154
-
155
- export function generateRecipePageSchema(story) {
156
- const { headline, url, "author-name": authorName, description } = story;
157
-
158
- const cardsWithAttributes = story.cards.filter((card) => getCardAttributes(card, "cardtype"));
159
- const cardWithIngredients = cardsWithAttributes.filter((card) =>
160
- getCardAttributes(card, "cardtype").includes("ingredients ")
161
- );
162
- const ingredientsRichText = get(cardWithIngredients, ["0", "story-elements", "0", "text"], "");
163
- const ingredients = extractTextFromHtmlString(ingredientsRichText);
164
-
165
- return {
166
- "@context": "https://schema.org/",
167
- "@type": "Recipe",
168
- name: headline,
169
- url: url,
170
- author: {
171
- "@type": "Person",
172
- name: authorName,
173
- },
174
- description: description,
175
- recipeIngredient: ingredients,
176
- };
177
- }
@@ -3,7 +3,6 @@ import { getQueryParams, stripMillisecondsFromTime } from "../utils";
3
3
  import { generateTagsForEntity } from "./entity";
4
4
  import {
5
5
  generateAuthorPageSchema,
6
- generateRecipePageSchema,
7
6
  getSchemaBlogPosting,
8
7
  getSchemaBreadcrumbList,
9
8
  getSchemaContext,
@@ -229,6 +228,16 @@ function findStoryElementField(card, type, field, defaultValue) {
229
228
  else return defaultValue;
230
229
  }
231
230
 
231
+ function getTextElementsOfOneCard(storyElements = []) {
232
+ return storyElements.filter((element) => element.type === "text");
233
+ }
234
+
235
+ function getCompleteTextOfOneCard(storyElements, stripHtmlFromArticleBody) {
236
+ return getTextElementsOfOneCard(storyElements)
237
+ .map((item) => (stripHtmlFromArticleBody ? getPlainText(item.text) : item.text))
238
+ .join(".");
239
+ }
240
+
232
241
  function generateLiveBlogPostingData(structuredData = {}, story = {}, publisherConfig = {}, timezone) {
233
242
  const imageWidth = 1200;
234
243
  const imageHeight = 675;
@@ -243,8 +252,11 @@ function generateLiveBlogPostingData(structuredData = {}, story = {}, publisherC
243
252
  coverageStartTime: stripMillisecondsFromTime(new Date(story["first-published-at"]), timezone),
244
253
  dateModified: stripMillisecondsFromTime(new Date(story["last-published-at"]), timezone),
245
254
 
246
- liveBlogUpdate: story.cards.map((card) =>
247
- getSchemaBlogPosting(
255
+ liveBlogUpdate: story.cards.map((card) => {
256
+ const storyElements = get(card, ["story-elements"]);
257
+ const cardArticleBody = getCompleteTextOfOneCard(storyElements, structuredData.stripHtmlFromArticleBody) || "";
258
+
259
+ return getSchemaBlogPosting(
248
260
  card,
249
261
  authorData(story.authors, authorSchema, publisherConfig),
250
262
  findStoryElementField(card, "title", "text", story.headline),
@@ -257,20 +269,20 @@ function generateLiveBlogPostingData(structuredData = {}, story = {}, publisherC
257
269
  structuredData,
258
270
  story,
259
271
  timezone,
260
- articleBody
261
- )
262
- ),
272
+ cardArticleBody
273
+ );
274
+ }),
263
275
  };
264
276
  }
265
277
 
266
278
  function getEmbedUrl(cards) {
267
279
  const playerUrlMapping = {
268
280
  "dailymotion-embed-script": "dailymotion-url",
269
- instagram: "instagram-url",
281
+ "instagram": "instagram-url",
270
282
  "facebook-video": "facebook-url",
271
- tweet: "tweet-url",
283
+ "tweet": "tweet-url",
272
284
  "vimeo-video": "vimeo-url",
273
- "brightcove-video": "player-url",
285
+ "brightcove-video": "player-url"
274
286
  };
275
287
 
276
288
  for (const card of cards) {
@@ -281,7 +293,7 @@ function getEmbedUrl(cards) {
281
293
  if (elem.metadata && elem.metadata[playerUrlField]) {
282
294
  return elem.metadata[playerUrlField];
283
295
  }
284
- }
296
+ };
285
297
  if (elem.type === "youtube-video" && elem.subtype === null) {
286
298
  if (elem.url) {
287
299
  return elem.url;
@@ -447,6 +459,7 @@ export function StructuredDataTags({ structuredData = {} }, config, pageType, re
447
459
  const isStructuredDataEmpty = Object.keys(structuredData).length === 0;
448
460
  const enableBreadcrumbList = get(structuredData, ["enableBreadcrumbList"], true);
449
461
  const structuredDataTags = get(structuredData, ["structuredDataTags"], []);
462
+
450
463
  let articleData = {};
451
464
 
452
465
  if (!isStructuredDataEmpty) {
@@ -475,23 +488,6 @@ export function StructuredDataTags({ structuredData = {} }, config, pageType, re
475
488
  if (!isStructuredDataEmpty && pageType === "story-page") {
476
489
  const newsArticleTags = generateNewsArticleTags();
477
490
  newsArticleTags ? tags.push(storyTags(), newsArticleTags) : tags.push(storyTags());
478
- if (story["story-template"] === "recipe") {
479
- const recipeTags = generateRecipePageSchema(story);
480
- recipeTags.image = Object.assign(
481
- {
482
- "@type": "ImageObject",
483
- },
484
- generateArticleImageData(story["hero-image-s3-key"], publisherConfig)
485
- );
486
- recipeTags.video = Object.assign(
487
- {
488
- "@type": "VideoObject",
489
- },
490
- generateVideoArticleData(structuredData, story, publisherConfig, timezone)
491
- );
492
-
493
- tags.push(ldJson("Recipe", recipeTags));
494
- }
495
491
  }
496
492
 
497
493
  if (!isStructuredDataEmpty && pageType === "story-page-amp") {
package/src/utils.js CHANGED
@@ -8,22 +8,6 @@ export function objectToTags(object) {
8
8
  .map(([key, value]) => ({ [getPropertyName(key)]: key, content: value }));
9
9
  }
10
10
 
11
- export function extractTextFromHtmlString(html) {
12
- const regex = /<p>(.*?)<\/p>/g;
13
- const textContents = [];
14
-
15
- let match;
16
- while ((match = regex.exec(html)) !== null) {
17
- textContents.push(match[1]);
18
- }
19
-
20
- return textContents;
21
- }
22
-
23
- export const getCardAttributes = (card, type) => {
24
- return card.metadata.attributes[type];
25
- };
26
-
27
11
  function getPropertyName(key) {
28
12
  return key.startsWith("fb:") || key.startsWith("og:") ? "property" : "name";
29
13
  }