openvibers/openvibe.blog Commits

Tag, author and category pages describe themselves: how many posts and the newest titles (they all read 'Posts tagged X on the blog.') (#67)

OP OpenVibers committed 24 days ago · 9fc977c5d1 · 2 files, +11 −1

Changes

ddiff --git a/server/http/public.js b/server/http/public.js
iindex e8bf320..de39900 100644
---- a/server/http/public.js
++++ b/server/http/public.js
@@@ -209,8 +209,14 @@ function createPublicRoutes(ctx) {
if (pager.outOfRange && total) return notFound(req, res);
const items = await reading.listItems(rows, { perBlogLinks: Boolean(blog) });
const canonical = seo.canonicalUrl(config.baseUrl, pager.page === 1 ? path : `${path}?page=${pager.page}`, { query: ['page'] });
++ // The meta description adds how many posts and the newest titles: "Posts tagged ai on The OpenVibe blog." alone
++ // (37 characters) said the same of every tag, author and category page.
++ const newest = items.slice(0, 2).map((it) => String((it.rev && it.rev.fields && it.rev.fields.title) || '').trim()).filter(Boolean).map((t) => `“${t}”`);
++ const counted = total ? ` ${total} post${total === 1 ? '' : 's'}${newest.length ? `, newest ${newest.join(' and ')}` : ''}.` : '';
++ const fullText = `${intro}${counted}`;
++ const description = fullText.length <= 160 ? fullText : `${fullText.slice(0, 159).replace(/\s+\S*$/, '')}…`;
send(req, res, 200, {
-- title: heading, description: intro, canonical,
++ title: heading, description, canonical,
decision: pageDecision(canonical, { empty: total === 0, query: ['page'] }),
theme: blog ? { slug: blog.theme, vars: blogs.themeVars(blog) } : null,
prev: pager.prev ? pager.prev.href : null, next: pager.next ? pager.next.href : null,
ddiff --git a/test/lifecycle.test.js b/test/lifecycle.test.js
iindex a8c9b1e..f3a5153 100644
---- a/test/lifecycle.test.js
++++ b/test/lifecycle.test.js
@@@ -104,6 +104,10 @@ const LONG = Array.from({ length: 120 }, (_, i) => `word${i}`).join(' ');
assert.match((await t.get('/sitemaps/blogs.xml')).text, /https:\/\/openvibe\.blog\/@alice</);
assert.match((await t.get('/@alice/tags/astronomy')).text, /First light/);
assert.match((await t.get('/tags/astronomy')).text, /First light/);
++ // A tag page's description counts its posts and names the newest, so no two tag pages read the same.
++ const tagDesc = ((await t.get('/@alice/tags/astronomy')).text.match(/<meta name="description" content="([^"]*)">/) || [])[1] || '';
++ assert.match(tagDesc, /^Posts tagged astronomy on .+\. \d+ posts?, newest “First light”/i, tagDesc);
++ assert.ok(tagDesc.length <= 160, tagDesc);
assert.match((await t.get('/@alice/categories/science')).text, /First light/, 'parent category includes children');
assert.match((await t.get('/@alice/authors/alice')).text, /First light/);
assert.match((await t.get('/@alice/first-light.json')).text, /"body_markdown"/);