Search code examples
javascriptmarkdownsvelte

Svelte markdown blog draft mode for posts


Good afternoon. I have a website on Svelt based on markdown files. I need to make sure that posts are not published, excluded from the list of posts, if there is published: false in the frontmetter of these posts

Let's start with the fact that I have a utility function that pulls these posts from md files

/*lib/utils/getPosts.js*/

// @ts-nocheck
export const getMarkdownPosts = async () => {
    const allPostFiles =
        import.meta.glob('/src/content/posts/*.md')
    const iterablePostFiles = Object.entries(allPostFiles)

    const allPosts = await Promise.all(
        iterablePostFiles.map(async ([path, resolver]) => {
            const { metadata } = await resolver()
            //const postPath = path.slice(11, -3)

            const postPath = path.split('/').at(-1)?.replace('.md', '')

            return {
                meta: metadata,
                path: postPath,
            }
        })
    )

    return allPosts
}

Then I have a server function in api/posts/+server.js


/*api/posts/+server.js*/

import { getMarkdownPosts } from '$lib/utils/getPosts'
import { json } from '@sveltejs/kit'

export const GET = async () => {
  const allPosts = await getMarkdownPosts()

  const sortedPosts = allPosts.sort((a, b) => {
    return new Date(b.meta.date) - new Date(a.meta.date)
  })

  return json(sortedPosts)
}

Here is the load function that serves to build the article page.

/*blog/[slug]/+page.js*/

export async function load({ params }){

    const post = await import(`../../../content/posts/${params.slug}.md`)
    const { title, date, categories, draft } = post.metadata
    const content = post.default

    return {
      content,
      title,
      date,
      categories
    }
}

I changed my server function (code below) and now it filters posts perfectly, without showing posts in the listing of posts where published: false is indicated in the frontmetter.


/*api/posts/+server.js*/

import { getMarkdownPosts } from '$lib/utils/getPosts'
import { json } from '@sveltejs/kit'

export const GET = async () => {
  const allPosts = await getMarkdownPosts()


  const sortedPosts = allPosts.sort((a, b) => {
    return new Date(b.meta.date) - new Date(a.meta.date)
  }).filter(post => post.meta.published === true)


  return json(sortedPosts)
}

But an article with the specified published: false will still be available via a direct link, like http://localhost:5173/blog/first-post . And you need this article not to be on the site at all, that is, a 404 error or something like that would be displayed. Can I take this?


Solution

  • In fact, as I thought, everything is much simpler. Since it is quite simple to remove posts from published: false from the general list of articles, it was just necessary to apply .filter(post => post.meta.published === true)

    Remove the posts altogether and output 404 instead, you can simply add such code to the load function in the file /*blog/[slug]/+page.js*/

        if (!post || !post.metadata.published) {
            throw error(404); // Couldn't resolve the post
        }
    

    So the whole code of this file looks like this:

    /*blog/[slug]/+page.js*/
    
    import { error } from '@sveltejs/kit';
    
    export async function load({ params }){
    
        const post = await import(`../../../content/posts/${params.slug}.md`)
        const { title, date, categories, published  } = post.metadata
        const content = post.default
    
        if (!post || !post.metadata.published) {
            throw error(404); // Couldn't resolve the post
        }
    
        return {
          content,
          title,
          date,
          categories,
          published
        }
    }