# How to add a blog post index to your Vuepress site

Vuepress allows you to write Vue (opens new window) in your Markdown files which is ideal for us to use to add dynamic sections to a Vuepress site. It also gives you access to some site metadata (opens new window). The $site array contains an array called pages containing metadata of all your site's pages which is ideal for displaying an index of blog posts on a home page!

# Add some frontmatter

Firstly, for our code to be able to recognise which pages are blog posts, we need to add a boolean field to our blog posts' frontmatter (opens new window).

We can also add a "date" field to use to use order our posts by date posted.

So to each of our blog posts' markdown files, we can add the following at the top:

---
title:  "Your post's title"
blog:   true
date:   2019-04-16
---
1
2
3
4
5

You can also add categories, tags, etc. to your posts' frontmatter.

# Create a custom component

Next we can create a custom component at .vuepress/components/BlogPosts.vue that we will use to display the list of posts.

<template>
</template>

<script>
export default {
  props: {
    pages: Array
  },
};
</script>
1
2
3
4
5
6
7
8
9
10

We give the component a prop called pages that will contain the array of all our site's pages.

You can add the component to the page on which you want to display the list like this:

<BlogPosts :pages="$site.pages" />
1

# Filter your pages for blog posts

To display only blog posts and not all pages in our lists of posts, we can create a computed property called posts that will check whether the blog frontmatter value is true for a page.

Then we can use a v-for (opens new window) directive to loop through all of the pages in posts and display each of their titles:

<template>
  <ul>
    <li v-for="post in posts" :key="post.key">
      <div class="post">
        <router-link class="title" :to="post.path">
          {{ post.title }}
        </router-link>
      </div>
    </li>
  </ul>
</template>

<script>
export default {
  props: {
    pages: Array
  },
  computed: {
    posts: function() {
      return this.pages.filter(isBlogPost);
    }
  },
  methods: {
    isBlogPost(page) {
      return "blog" in page.frontmatter && page.frontmatter.blog;
    }
  }
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

Example output:

# Sort by date

Now you can start to do more sorting or filter on your pages. For example, to sort the posts by date descendingly:






 













 
 
 
 






 
 
 
 
 
 
 
 
 




<template>
  <ul>
    <li v-for="post in posts" :key="post.key">
      <div class="post">
        <router-link class="title" :to="post.path">
          {{ post.title }} ({{ post.date.toDateString() }})
        </router-link>
      </div>
    </li>
  </ul>
</template>

<script>
export default {
  props: {
    pages: Array
  },
  computed: {
    posts: function() {
      return this.pages
        .filter(this.isBlogPost)
        .map(this.convertPageDate)
        .sort(this.dateCompare());
    }
  },
  methods: {
    isBlogPost(page) {
      return "blog" in page.frontmatter && page.frontmatter.blog;
    },
    convertPageDate(page) {
      return { ...page, date: new Date(page.frontmatter.date) };
    },
    dateCompare(desc = true) {
      let multiplier = desc ? -1 : 1;
      return function(a, b) {
        return multiplier * (a.date - b.date);
      };
    }
  }
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

Example output:

Newsletter

If you'd like to subscribe to my blog, please enter your details below. You can unsubscribe at any time.

Powered by Buttondown.

Last Updated: 11/20/2023, 10:04:51 AM