UNPKG

@draftbox-co/gatsby-ghost-novela-theme

Version:

A Gatsby theme plugin for creating blogs from headless Ghost CMS.

332 lines (280 loc) 9.76 kB
/* eslint-disable no-console, import/no-extraneous-dependencies, prefer-const, no-shadow */ require("dotenv").config(); const fs = require("fs"); const log = (message, section) => console.log(`\n\u001B[36m${message} \u001B[4m${section}\u001B[0m\u001B[0m\n`); const path = require("path"); const createPaginatedPages = require("gatsby-paginate"); const templatesDirectory = path.resolve(__dirname, "../../templates"); const templates = { articles: path.resolve(templatesDirectory, "articles.template.tsx"), article: path.resolve(templatesDirectory, "article.template.tsx"), author: path.resolve(templatesDirectory, "author.template.tsx"), tag: path.resolve(templatesDirectory, "tag.template.tsx"), page: path.resolve(templatesDirectory, "page.template.tsx"), ampPage: path.resolve(templatesDirectory, "article.template.amp.tsx"), }; const query = require("../data/data.query"); const normalize = require("../data/data.normalize"); // ///////////////// Utility functions /////////////////// function buildPaginatedPath(index, basePath) { if (basePath === "/") { return index > 1 ? `${basePath}page/${index}` : basePath; } return index > 1 ? `${basePath}/page/${index}` : basePath; } function slugify(string, base) { const slug = string .toLowerCase() .normalize("NFD") .replace(/[\u0300-\u036F]/g, "") .replace(/[^a-z0-9]+/g, "-") .replace(/(^-|-$)+/g, ""); return `${base}/${slug}`.replace(/\/\/+/g, "/"); } function getUniqueListBy(array, key) { return [...new Map(array.map((item) => [item[key], item])).values()]; } const byDate = (a, b) => new Date(b.dateForSEO) - new Date(a.dateForSEO); // /////////////////////////////////////////////////////// module.exports = async ({ actions: { createPage }, graphql }, themeOptions) => { const { rootPath, basePath = "/", authorsPath = "/authors", authorsPage = true, // pageLength = 6, sources = {}, mailchimp = "", } = themeOptions; const { data } = await graphql(` query siteQuery { site { siteMetadata { siteUrl postsPerPage } } } `); const pageLength = data.site.siteMetadata.postsPerPage; // Defaulting to look at the local MDX files as sources. const { local = true, contentful = false } = sources; let authors; let articles; let tags; let pages; let ghostSettings; const dataSources = { ghost: { authors: [], articles: [], tags: [], pages: [] }, }; if (rootPath) { log("Config rootPath", rootPath); } else { log("Config rootPath not set, using basePath instead =>", basePath); } log("Config basePath", basePath); if (authorsPage) log("Config authorsPath", authorsPath); // ghost posts try { const ghostArticles = await graphql(query.ghost.articles); const ghostAuthors = await graphql(query.ghost.authors); const ghostTags = await graphql(query.ghost.tags); const ghostPages = await graphql(query.ghost.pages); const ghostSettingsData = await graphql(query.ghost.siteSettings); dataSources.ghost.articles = ghostArticles.data.articles.edges.map( normalize.ghost.articles ); // Normalize author here if required dataSources.ghost.authors = ghostAuthors.data.authors.edges.map( (author) => author.node ); dataSources.ghost.pages = ghostPages.data.pages.edges.map( normalize.ghost.articles ); dataSources.ghost.tags = ghostTags.data.tags.edges.map((tag) => tag.node); websiteTitle = ghostSettingsData.data.site.siteMetadata.siteTitle; } catch (error) { console.log(error); } // Combining together all the articles from different sources articles = [...dataSources.ghost.articles].sort(byDate); authors = [...dataSources.ghost.authors]; tags = [...dataSources.ghost.tags]; pages = [...dataSources.ghost.pages]; const articlesThatArentSecret = articles.filter((article) => !article.secret); log("Creating", "articles page"); createPaginatedPages({ edges: articlesThatArentSecret, pathPrefix: basePath, createPage, pageLength, pageTemplate: templates.articles, buildPath: buildPaginatedPath, context: { // authors, basePath, skip: pageLength, limit: pageLength, }, }); // /** // * Once the list of articles have bene created, we need to make individual article posts. // * To do this, we need to find the corresponding authors since we allow for co-authors. // */ articles.forEach((article, index) => { // /** // * We need a way to find the next artiles to suggest at the bottom of the articles page. // * To accomplish this there is some special logic surrounding what to show next. // */ let next = articlesThatArentSecret.slice(index + 1, index + 3); // If it's the last item in the list, there will be no articles. So grab the first 2 if (next.length === 0) next = articlesThatArentSecret.slice(0, 2); // If there's 1 item in the list, grab the first article if (next.length === 1 && articlesThatArentSecret.length !== 2) next = [...next, articlesThatArentSecret[0]]; if (articlesThatArentSecret.length === 1) next = []; createPage({ path: article.slug, component: templates.article, context: { article, // authors: authorsThatWroteTheArticle, basePath, permalink: `${data.site.siteMetadata.siteUrl}${article.slug}/`, slug: article.slug, id: article.id, title: article.title, canonicalUrl: article.canonical_url, mailchimp, next, }, }); }); // Generation of Amp Pages articles.forEach((article) => { createPage({ path: `${article.slug}/amp`, component: templates.ampPage, context: { slug: article.slug, title: websiteTitle, amp: true, }, }); }); // Genration of pages pages.forEach((article, index) => { // /** // * We need a way to find the next artiles to suggest at the bottom of the articles page. // * To accomplish this there is some special logic surrounding what to show next. // */ createPage({ path: article.slug, component: templates.page, context: { article, basePath, permalink: `${data.site.siteMetadata.siteUrl}${article.slug}/`, slug: article.slug, id: article.id, title: article.title, canonicalUrl: article.canonical_url, }, }); }); // /** // * By default the author's page is not enabled. This can be enabled through the theme options. // * If enabled, each author will get their own page and a list of the articles they have written. // */ // if (authorsPage) { // log('Creating', 'authors page'); // } // Authors Pages builder const articlesWithFlatAuthorNames = articles.map((article) => ({ ...article, authors: [...article.authors.map((author) => author.slug)], })); authors.forEach((author) => { // const articlesTheAuthorHasWritten = articlesThatArentSecret.filter( // (article) => // article.author.toLowerCase().includes(author.name.toLowerCase()) // ); const articlesTheAuthorHasWritten = articlesWithFlatAuthorNames.filter( (article) => article.authors.includes(author.slug) ); let modifiedAuthor = Object.keys(author).reduce( (acc, dec) => { if (dec === "twitter" && author[dec]) { return { ...acc, social: [ ...acc.social, { name: "twitter", url: `https://twitter.com/${author[dec]}`, }, ], [dec]: author[dec], }; } if (dec === "facebook" && author[dec]) { return { ...acc, social: [ ...acc.social, { name: "facebook", url: `https://facebook.com/${author[dec]}`, }, ], [dec]: author[dec], }; } return { ...acc, social: [...acc.social], [dec]: author[dec] }; }, { social: [] } ); const path = slugify(author.slug, authorsPath); createPaginatedPages({ edges: articlesTheAuthorHasWritten, pathPrefix: "author/" + author.slug, createPage, pageLength, pageTemplate: templates.author, buildPath: buildPaginatedPath, context: { author: modifiedAuthor, originalPath: path, // originalPath: author.slug, skip: pageLength, limit: pageLength, }, }); }); const articlesWithFlatTagNames = articles.map((article) => ({ ...article, flatTags: [...article.tags.map((tag) => tag.slug)], })); tags.forEach((tag) => { const articlesWithTag = articlesWithFlatTagNames.filter((article) => article.flatTags.includes(tag.slug) ); const path = slugify(tag.slug, "/tags"); createPaginatedPages({ edges: articlesWithTag, pathPrefix: "tag/" + tag.slug, createPage, pageLength, pageTemplate: templates.tag, buildPath: buildPaginatedPath, context: { tag: tag, originalPath: path, // originalPath: author.slug, skip: pageLength, limit: pageLength, }, }); }); };