skip to Main Content

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?

2

Answers


  1. Chosen as BEST ANSWER

    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
        }
    }
    
    

  2. Check out SvelteKit param matching!

    The steps to implement should be something like this:

    1. Change your blog route to blog/[slug=published]/+page.js
    2. In /src/params/, create a function that checks for a match:
    export async function published(value) {
        const post = await import(`../content/posts/${params.slug}.md`)
        const { published } = post?.metadata?.published 
        return published
    }
    
    1. If you want a custom 404 page for missing blog posts, create a new one in blog/[slug]/+error.svelte (notice that the path is slug, not slug=published)

    Disclaimers:

    • I haven’t tested the above code, so I’m not sure if you’ll have any problems with the async/await for the import. If you do, you can try eagerly importing them with Vite doing something like this:
    const blogposts = import.meta.glob('./../lib/test/**.json', {eager: true});
    
    • I was running some very similar code to what you have already for my organisation’s blog, and it was working well. However, about two months later, I replaced it with MDsveX. The advantage of this is you can just have your blog routes be markdown files named +page.md, and you can use JS imports to get functions and Svelte components into your markdown files.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search