Add tag listings

This commit is contained in:
Lewis Dale 2023-10-18 13:35:02 +01:00
parent eb62bfd1c9
commit 53707bb085
6 changed files with 175 additions and 94 deletions

110
src/_data/_postData.js Normal file
View File

@ -0,0 +1,110 @@
const fs = require('fs');
const merge = require('lodash/merge')
const wordpressPassword = process.env.WORDPRESS_PASSWORD;
const auth = Buffer.from(`lewis:${wordpressPassword}`).toString('base64');
class PostCache {
constructor() {
this.readCache();
}
readCache() {
if (!fs.existsSync(".cache")) {
fs.mkdirSync(".cache");
}
if (!fs.existsSync(".cache/wordpress_post_fetch.json")) {
this.last_read_date = null;
this.posts = {};
} else {
const data = JSON.parse(fs.readFileSync(".cache/wordpress_post_fetch.json"));
this.last_read_date = new Date(data.last_read_date);
this.posts = data.posts;
}
}
writeCache() {
fs.writeFileSync(".cache/wordpress_post_fetch.json", JSON.stringify(this, null, 2));
}
async fetchCommentsByType(type = "comment") {
const params = new URLSearchParams();
params.set("per_page", 100);
params.set("type", type);
if (this.last_read_date) {
params.set("modified_after", this.last_read_date.toISOString());
}
const response = await fetch(`https://cms.lewisdale.dev/wp-json/wp/v2/comments?${params.toString()}`, {
headers: {
"Authorization": `Basic ${auth}`
}
});
return await response.json()
}
async fetchComments() {
const likes = await this.fetchCommentsByType("like");
const mentions = await this.fetchCommentsByType();
const reposts = await this.fetchCommentsByType("repost");
const comments = [...likes, ...mentions, ...reposts];
comments.forEach(comment => {
if (this.posts[comment.post]) {
this.posts[comment.post].comments[comment.id] = comment;
}
});
}
async fetchPosts() {
const params = new URLSearchParams();
params.set("per_page", 100);
if (this.last_read_date) {
params.set("modified_after", this.last_read_date.toISOString());
}
const response = await fetch(`https://cms.lewisdale.dev/wp-json/wp/v2/posts?${params.toString()}`, {
headers: {
"Authorization": `Basic ${auth}`
}
});
const posts = await response.json();
posts.forEach(post => {
this.posts[post.id] = merge({ comments: {} }, this.posts[post.id], post);
});
}
async fetchLatest() {
await this.fetchPosts();
await this.fetchComments();
await this.fetchTags();
this.last_read_date = new Date();
this.writeCache();
}
async fetchTags() {
const params = new URLSearchParams();
params.set("per_page", 100);
const response = await fetch(`https://cms.lewisdale.dev/wp-json/wp/v2/tags?${params.toString()}`, {
headers: {
"Authorization": `Basic ${auth}`
}
});
const tags = await response.json();
this.tags = tags.reduce((tagMap, tag) => ({...tagMap, [tag.id]: tag }), {});
}
}
const cache = new PostCache();
module.exports = async function() {
await cache.fetchLatest();
return cache;
}

View File

@ -1,96 +1,7 @@
const EleventyFetch = require('@11ty/eleventy-fetch'); const postCache = require('./_postData');
const fs = require('fs');
const merge = require('lodash/merge')
const wordpressPassword = process.env.WORDPRESS_PASSWORD;
const auth = Buffer.from(`lewis:${wordpressPassword}`).toString('base64');
const dateSort = (a, b) => new Date(b.date) - new Date(a.date); const dateSort = (a, b) => new Date(b.date) - new Date(a.date);
class PostCache {
constructor() {
this.readCache();
}
readCache() {
if (!fs.existsSync(".cache")) {
fs.mkdirSync(".cache");
}
if (!fs.existsSync(".cache/wordpress_post_fetch.json")) {
this.last_read_date = null;
this.posts = {};
} else {
const data = JSON.parse(fs.readFileSync(".cache/wordpress_post_fetch.json"));
this.last_read_date = new Date(data.last_read_date);
this.posts = data.posts;
}
}
writeCache() {
fs.writeFileSync(".cache/wordpress_post_fetch.json", JSON.stringify(this, null, 2));
}
async fetchCommentsByType(type = "comment") {
const params = new URLSearchParams();
params.set("per_page", 100);
params.set("type", type);
if (this.last_read_date) {
params.set("modified_after", this.last_read_date.toISOString());
}
const response = await fetch(`https://cms.lewisdale.dev/wp-json/wp/v2/comments?${params.toString()}`, {
headers: {
"Authorization": `Basic ${auth}`
}
});
return await response.json()
}
async fetchComments() {
const likes = await this.fetchCommentsByType("like");
const mentions = await this.fetchCommentsByType();
const reposts = await this.fetchCommentsByType("repost");
const comments = [...likes, ...mentions, ...reposts];
comments.forEach(comment => {
if (this.posts[comment.post]) {
this.posts[comment.post].comments[comment.id] = comment;
}
});
}
async fetchPosts() {
const params = new URLSearchParams();
params.set("per_page", 100);
if (this.last_read_date) {
params.set("modified_after", this.last_read_date.toISOString());
}
const response = await fetch(`https://cms.lewisdale.dev/wp-json/wp/v2/posts?${params.toString()}`, {
headers: {
"Authorization": `Basic ${auth}`
}
});
const posts = await response.json();
posts.forEach(post => {
this.posts[post.id] = merge({ comments: {} }, this.posts[post.id], post);
});
}
async fetchLatest() {
await this.fetchPosts();
await this.fetchComments();
this.last_read_date = new Date();
this.writeCache();
}
}
const mapComment = comment => ({ const mapComment = comment => ({
author: { author: {
name: comment.author_name, name: comment.author_name,
@ -104,8 +15,7 @@ const mapComment = comment => ({
module.exports = async () => { module.exports = async () => {
const cache = new PostCache(); const cache = await postCache();
await cache.fetchLatest();
const posts = Object.values(cache.posts) const posts = Object.values(cache.posts)
.sort(dateSort) .sort(dateSort)
@ -120,7 +30,12 @@ module.exports = async () => {
comments[comment.type].push(mapComment(comment)); comments[comment.type].push(mapComment(comment));
return comments; return comments;
}, { like: [], reply: [], repost: [] }) }, { like: [], reply: [], repost: [] }),
tags: post.tags.map(tag => ({
name: cache.tags[tag].name,
slug: cache.tags[tag].slug,
link: cache.tags[tag].link
}))
})); }));
return posts; return posts;

15
src/_data/tags.js Normal file
View File

@ -0,0 +1,15 @@
const postCache = require('./_postData');
module.exports = async () => {
const cache = await postCache();
return Object.values(cache.tags).map(tag => {
const posts = Object.values(cache.posts).filter(post => post.tags.includes(tag.id));
return {
...tag,
posts,
}
});
};

View File

@ -12,6 +12,14 @@ eleventyComputed:
<div class="e-content stack-md"> <div class="e-content stack-md">
{{ content | safe }} {{ content | safe }}
</div> </div>
{% if post.tags | length %}
<ul role="list">
<h2>Tags:</h2>
{% for tag in post.tags %}
<li><a href="/post/tag/{{ tag.slug }}" rel="tag">#{{ tag.name }}</a></li>
{% endfor %}
</ul>
{% endif %}
</article> </article>
<section class="stack-sm"> <section class="stack-sm">

25
src/blog/tag.html Normal file
View File

@ -0,0 +1,25 @@
---
title: Blog
layout: base.njk
pagination:
data: tags
size: 1
alias: tag
eleventyComputed:
permalink: "/post/tag/{{ tag.slug }}/"
---
<main class="wrapper-md stack-lg">
<h1>Posts tagged “{{ tag.name }}”</h1>
<ol class="stack-xl" role='list'>
{% for item in tag.posts %}
<li class="stack-xs">
<h2><a href="/post/{{ item.slug }}">{{ item.title.rendered | safe }}</a></h2>
<time class="block">{{ item.date | parseDate | dateDisplay }}</time>
{{ item.excerpt.rendered | safe }}
<a href="/post/{{ item.slug }}" class="inline-block">Read more</a>
</li>
{% endfor %}
</ol>
</main>

View File

@ -0,0 +1,8 @@
li:has(a[rel="tag"]) {
display: inline-block;
margin-inline-end: 1ch;
&:not(:last-child):after {
content: ",";
}
}