Skip to content

Commit

Permalink
Merge pull request #54 from famous-smoke/47-add-ldjson-data
Browse files Browse the repository at this point in the history
47 add ldjson data
  • Loading branch information
bdeffleyfamous authored Jun 14, 2024
2 parents c440b8a + 8ee4f9b commit 873f05e
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 23 deletions.
10 changes: 7 additions & 3 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ module.exports = {
// allow reassigning param
'no-param-reassign': [2, { props: false }],
'linebreak-style': ['error', 'unix'],
'import/extensions': ['error', {
js: 'always',
}],
'import/extensions': [
'error',
{
js: 'always',
},
],
'object-curly-newline': 0,
},
};
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
"rules": {
"prettier/prettier": ["error"]
}
}
}
2 changes: 1 addition & 1 deletion .prettierrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 800
}
}
161 changes: 153 additions & 8 deletions best-cigars-guide/blocks/footer/footer.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,180 @@
import { getMetadata } from '../../scripts/aem.js';
import { loadFragment } from '../fragment/fragment.js';
import { isInternal, isCategory } from '../../scripts/scripts.js';
import { isInternal, isCategory, isArticlePage, fetchArticleInfo, fetchArticlesInCategory } from '../../scripts/scripts.js';
import { addLdJsonScript } from '../../scripts/linking-data.js';

function buildLdJson(container) {
function dateToISOString(input) {
let date;

try {
// Check if the input is a number (Unix timestamp)
if (typeof input === 'number') {
date = new Date(input * 1000);
} else if (typeof input === 'string') {
// Check if the string is a Unix timestamp
if (/^\d+$/.test(input)) {
date = new Date(parseInt(input, 10) * 1000);
} else {
// Otherwise, assume it's a date string
date = new Date(input);
}
} else {
return null; // Return null if the input is neither a number nor a string
}

// Check if the date is valid
if (date.isNaN) {
return null;
}
// Convert the Date object to ISO string format
return date.toISOString();
} catch (error) {
// Return null if there is an error
return null;
}
}

function createBreadcrumbsSchema() {
const breadcrumbDiv = document.querySelector('.breadcrumb #breadcrumbs');

if (!breadcrumbDiv) {
return null;
}

const spans = breadcrumbDiv.querySelectorAll('span');
const itemListElement = [];

spans.forEach((span, index) => {
const anchor = span.querySelector('a');
const position = index + 1;
const item = {
'@type': 'ListItem',
position,
item: {},
};

if (anchor) {
item.item['@id'] = anchor.href;
item.item.name = anchor.textContent;
} else {
item.item['@id'] = window.location.href;
item.item.name = span.textContent;
}

itemListElement.push(item);
});

const breadcrumbsSchema = {
'@type': 'BreadcrumbList',
itemListElement,
};

return breadcrumbsSchema;
}

async function createBlogPostingSchema() {
const articlesInCategory = await fetchArticlesInCategory();

if (!articlesInCategory) {
return null;
}
const blogPostings = [];

articlesInCategory.forEach((article) => {
const blogPosting = {
'@type': 'BlogPosting',
'@id': window.location.origin + article.path,
url: window.location.origin + article.path,
name: article.title.split('|')[0].trim(),
mainEntityOfPage: {
'@type': 'BlogPosting',
'@id': window.location.origin + article.path,
},
dateModified: dateToISOString(article.lastModified),
datePublished: dateToISOString(article.publishedDate),
author: {
'@type': 'Organization',
name: 'Famous Smoke Shop - Best Cigars Guide',
'@id': 'https://www.famous-smoke.com/best-cigars-guide',
url: 'https://www.famous-smoke.com/best-cigars-guide',
logo: `${window.location.origin}/best-cigars-guide/icons/famous-smoke-shop-logo.svg`,
},
image: `https://www.famous-smoke.com${article.image}`,
};
blogPosting.headline = blogPosting.name;
blogPostings.push(blogPosting);
});

return blogPostings.length > 0 ? blogPostings : null;
}

async function buildLdJson(container) {
// Base page LD+JSON
const ldJson = {
'@context': 'https://schema.org',
'@type': 'WebPage',
'@id': window.location.href,
url: window.location.href,
description: getMetadata('description'),
author: {
publisher: {
'@type': 'Organization',
'@id': 'https://www.famous-smoke.com',
name: 'Famous Smoke Shop - Best Cigars Guide',
'@id': 'https://www.famous-smoke.com/best-cigars-guide',
url: 'https://www.famous-smoke.com/best-cigars-guide',
logo: `${window.location.origin}/best-cigars-guide/icons/famous-smoke-shop-logo.svg`,
},
inLanguage: 'en-US',
};

// Change type for category pages
if (isCategory()) {
ldJson['@type'] = 'CollectionPage';

// Add BlogPosting Schema
const blogPostingSchema = await createBlogPostingSchema();
if (blogPostingSchema) {
ldJson.hasPart = blogPostingSchema;
}
}

// Add Article Page Data
if (isArticlePage()) {
// Add datePublished from metadata
const datePublished = dateToISOString(getMetadata('publisheddate'));
if (datePublished) {
ldJson.datePublished = datePublished;
}

// Add dateModified
const articleInfo = await fetchArticleInfo();
if (articleInfo) {
const lastModified = dateToISOString(articleInfo.lastModified);
ldJson.dateModified = lastModified;
}

// Add author
ldJson.author = ldJson.publisher;

// Add headline
ldJson.headline = articleInfo.title.split('|')[0].trim();

// Set mainEntityOfPage to identify this as a blog post not just a web page
ldJson.mainEntityOfPage = {
'@type': 'BlogPosting',
'@id': ldJson.url,
};
}

// Add image from metadata
const primaryImage = getMetadata('og:image');
if (primaryImage) {
ldJson.primaryImageOfPage = {
'@type': 'ImageObject',
contentUrl: getMetadata('og:image'),
};
ldJson.image = primaryImage;
}

// Add breadcrumb when available
const breadcrumbsSchema = createBreadcrumbsSchema();
if (breadcrumbsSchema) {
ldJson.breadcrumb = breadcrumbsSchema;
}

addLdJsonScript(container, ldJson);
Expand Down
12 changes: 4 additions & 8 deletions best-cigars-guide/blocks/sidebar/sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { fetchCategoryList, fetchArticleList } from '../../scripts/scripts.js';
// get the current category name
const currentCategoryPath = window.location.pathname.split('/').slice(0, 3).join('/');

async function getCategories() {
async function getCategoryArticles() {
const wrap = document.createElement('div');
wrap.className = 'sidebar-categories';

Expand All @@ -13,9 +13,7 @@ async function getCategories() {
const categoriesList = await fetchCategoryList();

categoriesList.forEach((category) => {
const categoryPath = category.path.split('/')
.slice(0, 3)
.join('/');
const categoryPath = category.path.split('/').slice(0, 3).join('/');

if (categoryPath === currentCategoryPath) {
heading.innerText = category.path
Expand All @@ -32,9 +30,7 @@ async function getCategories() {
const currentArticlePath = window.location.pathname;

articleList.forEach((article) => {
const articleCategoryPath = article.path.split('/')
.slice(0, 3)
.join('/');
const articleCategoryPath = article.path.split('/').slice(0, 3).join('/');

// List all the articles in this category, but not this article itself
if (articleCategoryPath === currentCategoryPath && article.path !== currentArticlePath) {
Expand All @@ -53,7 +49,7 @@ async function getCategories() {
}

export default async function decorate(block) {
const categories = await getCategories();
const categories = await getCategoryArticles();
block.prepend(categories);

return block;
Expand Down
53 changes: 52 additions & 1 deletion best-cigars-guide/scripts/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export async function fetchArticleList() {
const resp = await fetch(ARTICLE_INDEX_PATH);
if (resp.ok) {
const jsonData = await resp.json();
articleIndexData = jsonData.data.map((item) => ({ path: item.path, title: item.title }));
articleIndexData = jsonData.data.map((item) => ({ path: item.path, title: item.title, lastModified: item.lastModified, publishedDate: item.published, image: item.image }));
} else {
// eslint-disable-next-line no-console
console.error('Failed to fetch category article list:', resp.status);
Expand All @@ -59,6 +59,40 @@ export async function fetchArticleList() {
return articleIndexData;
}

/**
* Fetches article information.
* @returns {Promise<Array<Object>>} - A promise that resolves to an array of article path objects.
*/
export async function fetchArticleInfo() {
// Fetch article list
if (!articleIndexData) {
articleIndexData = await fetchArticleList();
}

// Get the current URL path
const currentPath = window.location.pathname;

// Find the article that matches the current URL path
const matchingArticle = articleIndexData.find((article) => article.path === currentPath);

return matchingArticle || null;
}

export async function fetchArticlesInCategory() {
// Fetch article list
if (!articleIndexData) {
articleIndexData = await fetchArticleList();
}

// Get the current category path
const currentCategoryPath = window.location.pathname.split('/').slice(0, 3).join('/');

// Find the articles that contain the current category path in their path
const matchingArticles = articleIndexData.filter((article) => article.path.includes(currentCategoryPath));

return matchingArticles.length > 0 ? matchingArticles : null;
}

/**
* Builds hero block and prepends to main in a new section.
* @param {Element} main The container element
Expand All @@ -74,6 +108,23 @@ function buildHeroBlock(main) {
}
}

export function isArticlePage() {
// Select the div with class 'breadcrumb'
const breadcrumbDiv = document.querySelector('.breadcrumb');

// Check if the breadcrumb div exists
if (breadcrumbDiv) {
// Select all span tags within the breadcrumb div
const spans = breadcrumbDiv.querySelectorAll('span');

// Check if there are exactly 3 span tags
if (spans.length === 3) {
return true;
}
}
return false;
}

/**
* check if this is a category listing page
*/
Expand Down
5 changes: 4 additions & 1 deletion helix-query.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ indices:
text:
select: main > div p
value: words(textContent(el), 0, 5000)
published:
select: head > meta[name="publisheddate"]
value: parseTimestamp(attribute(el, "content"), "ddd, DD MMM YYYY hh:mm:ss GMT")
categories:
include:
- /best-cigars-guide/best-cigars-by-country
Expand All @@ -66,4 +69,4 @@ indices:
value: parseTimestamp(headers["last-modified"], "ddd, DD MMM YYYY hh:mm:ss GMT")
text:
select: div.article-list
value: words(textContent(el), 0, 5000)
value: words(textContent(el), 0, 5000)

0 comments on commit 873f05e

Please sign in to comment.