Skip to content

Commit

Permalink
Exclude unlisted blog posts
Browse files Browse the repository at this point in the history
  • Loading branch information
jodyheavener committed Aug 24, 2022
1 parent df419a3 commit be36a4b
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 31 deletions.
17 changes: 16 additions & 1 deletion packages/docusaurus-plugin-content-blog/src/blogUtils.ts
Expand Up @@ -33,6 +33,7 @@ import type {
BlogPost,
BlogTags,
BlogPaginated,
BlogPostFrontMatter,
} from '@docusaurus/plugin-content-blog';
import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types';

Expand Down Expand Up @@ -186,6 +187,16 @@ async function parseBlogPostMarkdownFile(blogSourceAbsolute: string) {
const defaultReadingTime: ReadingTimeFunction = ({content, options}) =>
readingTime(content, options).minutes;

function isHiddenForProduction({
type,
frontMatter,
}: {
type: 'draft' | 'unlisted';
frontMatter: BlogPostFrontMatter;
}): boolean {
return (process.env.NODE_ENV === 'production' && frontMatter[type]) ?? false;
}

async function processBlogSourceFile(
blogSourceRelative: string,
contentPaths: BlogContentPaths,
Expand Down Expand Up @@ -219,7 +230,10 @@ async function processBlogSourceFile(

const aliasedSource = aliasedSitePath(blogSourceAbsolute, siteDir);

if (frontMatter.draft && process.env.NODE_ENV === 'production') {
const draft = isHiddenForProduction({type: 'draft', frontMatter});
const unlisted = isHiddenForProduction({type: 'unlisted', frontMatter});

if (draft) {
return undefined;
}

Expand Down Expand Up @@ -326,6 +340,7 @@ async function processBlogSourceFile(
hasTruncateMarker: truncateMarker.test(content),
authors,
frontMatter,
unlisted,
},
content,
};
Expand Down
1 change: 1 addition & 0 deletions packages/docusaurus-plugin-content-blog/src/frontMatter.ts
Expand Up @@ -33,6 +33,7 @@ const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({
description: Joi.string().allow(''),
tags: FrontMatterTagsSchema,
draft: Joi.boolean(),
unlisted: Joi.boolean(),
date: Joi.date().raw(),

// New multi-authors front matter:
Expand Down
16 changes: 11 additions & 5 deletions packages/docusaurus-plugin-content-blog/src/index.ts
Expand Up @@ -112,6 +112,9 @@ export default async function pluginContentBlog(
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
const blogTagsListPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
const blogPosts = await generateBlogPosts(contentPaths, context, options);
const listedBlogPosts = blogPosts.filter(
(blogPost) => !blogPost.metadata.unlisted,
);

if (!blogPosts.length) {
return {
Expand All @@ -125,8 +128,8 @@ export default async function pluginContentBlog(
}

// Colocate next and prev metadata.
blogPosts.forEach((blogPost, index) => {
const prevItem = index > 0 ? blogPosts[index - 1] : null;
listedBlogPosts.forEach((blogPost, index) => {
const prevItem = index > 0 ? listedBlogPosts[index - 1] : null;
if (prevItem) {
blogPost.metadata.prevItem = {
title: prevItem.metadata.title,
Expand All @@ -135,7 +138,9 @@ export default async function pluginContentBlog(
}

const nextItem =
index < blogPosts.length - 1 ? blogPosts[index + 1] : null;
index < listedBlogPosts.length - 1
? listedBlogPosts[index + 1]
: null;
if (nextItem) {
blogPost.metadata.nextItem = {
title: nextItem.metadata.title,
Expand All @@ -145,15 +150,15 @@ export default async function pluginContentBlog(
});

const blogListPaginated: BlogPaginated[] = paginateBlogPosts({
blogPosts,
blogPosts: listedBlogPosts,
blogTitle,
blogDescription,
postsPerPageOption,
basePageUrl: baseBlogUrl,
});

const blogTags: BlogTags = getBlogTags({
blogPosts,
blogPosts: listedBlogPosts,
postsPerPageOption,
blogDescription,
blogTitle,
Expand Down Expand Up @@ -242,6 +247,7 @@ export default async function pluginContentBlog(
items: sidebarBlogPosts.map((blogPost) => ({
title: blogPost.metadata.title,
permalink: blogPost.metadata.permalink,
unlisted: blogPost.metadata.unlisted,
})),
},
null,
Expand Down
Expand Up @@ -90,6 +90,10 @@ declare module '@docusaurus/plugin-content-blog' {
* Marks the post as draft and excludes it from the production build.
*/
draft?: boolean;
/**
* Marks the post as unlisted and visibly hides it unless directly accessed.
*/
unlisted?: boolean;
/**
* Will override the default publish date inferred from git/filename. Yaml
* only converts standard yyyy-MM-dd format to dates, so this may stay as a
Expand Down Expand Up @@ -222,6 +226,10 @@ declare module '@docusaurus/plugin-content-blog' {
readonly frontMatter: BlogPostFrontMatter & {[key: string]: unknown};
/** Tags, normalized. */
readonly tags: Tag[];
/**
* Marks the post as unlisted and visibly hides it unless directly accessed.
*/
readonly unlisted?: boolean;
};
/**
* @returns The edit URL that's directly plugged into metadata.
Expand Down Expand Up @@ -409,7 +417,7 @@ declare module '@docusaurus/plugin-content-blog' {

export type BlogSidebar = {
title: string;
items: {title: string; permalink: string}[];
items: {title: string; permalink: string; unlisted: boolean}[];
};

export type BlogContent = {
Expand Down
Expand Up @@ -11,7 +11,8 @@ import {useBlogPost} from '@docusaurus/theme-common/internal';

export default function BlogPostPageMetadata(): JSX.Element {
const {assets, metadata} = useBlogPost();
const {title, description, date, tags, authors, frontMatter} = metadata;
const {title, description, date, tags, authors, frontMatter, unlisted} =
metadata;

const {keywords} = frontMatter;
const image = assets.image ?? frontMatter.image;
Expand Down Expand Up @@ -39,6 +40,7 @@ export default function BlogPostPageMetadata(): JSX.Element {
content={tags.map((tag) => tag.label).join(',')}
/>
)}
{unlisted && <meta name="robots" content="noindex, nofollow" />}
</PageMetadata>
);
}
Expand Up @@ -9,11 +9,14 @@ import React from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
import {translate} from '@docusaurus/Translate';
import {useLocation} from '@docusaurus/router';
import {isSamePath} from '@docusaurus/theme-common/internal';
import type {Props} from '@theme/BlogSidebar/Desktop';

import styles from './styles.module.css';

export default function BlogSidebarDesktop({sidebar}: Props): JSX.Element {
const {pathname} = useLocation();
return (
<aside className="col col--3">
<nav
Expand All @@ -27,17 +30,25 @@ export default function BlogSidebarDesktop({sidebar}: Props): JSX.Element {
{sidebar.title}
</div>
<ul className={clsx(styles.sidebarItemList, 'clean-list')}>
{sidebar.items.map((item) => (
<li key={item.permalink} className={styles.sidebarItem}>
<Link
isNavLink
to={item.permalink}
className={styles.sidebarItemLink}
activeClassName={styles.sidebarItemLinkActive}>
{item.title}
</Link>
</li>
))}
{sidebar.items
.filter((item) => {
if (item.unlisted && !isSamePath(item.permalink, pathname)) {
return false;
}

return true;
})
.map((item) => (
<li key={item.permalink} className={styles.sidebarItem}>
<Link
isNavLink
to={item.permalink}
className={styles.sidebarItemLink}
activeClassName={styles.sidebarItemLinkActive}>
{item.title}
</Link>
</li>
))}
</ul>
</nav>
</aside>
Expand Down
Expand Up @@ -7,23 +7,34 @@

import React from 'react';
import Link from '@docusaurus/Link';
import {useLocation} from '@docusaurus/router';
import {isSamePath} from '@docusaurus/theme-common/internal';
import {NavbarSecondaryMenuFiller} from '@docusaurus/theme-common';
import type {Props} from '@theme/BlogSidebar/Mobile';

function BlogSidebarMobileSecondaryMenu({sidebar}: Props): JSX.Element {
const {pathname} = useLocation();
return (
<ul className="menu__list">
{sidebar.items.map((item) => (
<li key={item.permalink} className="menu__list-item">
<Link
isNavLink
to={item.permalink}
className="menu__link"
activeClassName="menu__link--active">
{item.title}
</Link>
</li>
))}
{sidebar.items
.filter((item) => {
if (item.unlisted && !isSamePath(item.permalink, pathname)) {
return false;
}

return true;
})
.map((item) => (
<li key={item.permalink} className="menu__list-item">
<Link
isNavLink
to={item.permalink}
className="menu__link"
activeClassName="menu__link--active">
{item.title}
</Link>
</li>
))}
</ul>
);
}
Expand Down
7 changes: 7 additions & 0 deletions website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md
@@ -0,0 +1,7 @@
---
title: Unlisted blog post
unlisted: true
tags: [blog]
---

This unlisted blog post should always be directly accessible in any environment, but in production the sidebar link and pagination should only be visible when on the page itself
3 changes: 2 additions & 1 deletion website/_dogfooding/dogfooding.config.js
Expand Up @@ -72,7 +72,8 @@ const dogfoodingPluginInstances = [
frontMatter.hide_reading_time
? undefined
: defaultReadingTime({content, options: {wordsPerMinute: 5}}),
sortPosts: 'ascending',
// TODO: undo this
sortPosts: 'descending',
}),
],

Expand Down
1 change: 1 addition & 0 deletions website/docs/api/plugins/plugin-content-blog.md
Expand Up @@ -193,6 +193,7 @@ Accepted fields:
| `date` | `string` | File name or file creation time | The blog post creation date. If not specified, this can be extracted from the file or folder name, e.g, `2021-04-15-blog-post.mdx`, `2021-04-15-blog-post/index.mdx`, `2021/04/15/blog-post.mdx`. Otherwise, it is the Markdown file creation time. |
| `tags` | `Tag[]` | `undefined` | A list of strings or objects of two string fields `label` and `permalink` to tag to your post. |
| `draft` | `boolean` | `false` | A boolean flag to indicate that the blog post is work-in-progress. Draft blog posts will only be displayed during development. |
| `unlisted` | `boolean` | `false` | A boolean flag to indicate that the blog post should be accessible if linked to directly, but visibly hidden on the site otherwise and ignored by search engines. Unlisted blog posts are fully visible in development. |
| `hide_table_of_contents` | `boolean` | `false` | Whether to hide the table of contents to the right. |
| `toc_min_heading_level` | `number` | `2` | The minimum heading level shown in the table of contents. Must be between 2 and 6 and lower or equal to the max value. |
| `toc_max_heading_level` | `number` | `3` | The max heading level shown in the table of contents. Must be between 2 and 6. |
Expand Down

0 comments on commit be36a4b

Please sign in to comment.