Paulund

Create Date Archives Page - VueJS WordPress Theme

In this tutorial, we're going to build a date archives page for your WordPress theme so that you can display a list of your previous posts sorted by date. If we were building a normal WordPress theme we could simply use the function wp_get_archives which returns the HTML to display the date archives. As we're using the VueJS and the REST API we can't just call this function, so we need to make a call to the API to get the data we need.

Archives REST API Endpoint

By default, there isn't an endpoint for WordPress to return the date archives so we need to create one. In a previous tutorial, we've created a plugin that will add a new endpoint to your WordPress site that will return JSON object of the data needed to build the date archives.

Add Route For Archive Page

First, we need to add a new route for the archive page, go back to your router index.js file and add a new Archive component.


import Archives from '@/components/pages/Archives.vue'

Then add a new route for the archives using the Archives component.


{
  name: 'Archives',
  path: '/archives',
  component: Archives
},

Create Archives Page

Create your new component inside the /src/components/pages folder. The HTML is going to be very simple we're going to have a title and then a list of each archive entry, this entry will have a link to the search page with the year and month from the archives data.


<template>
    <div id="archives-page">
        <h2 class="title is-2">Post Archives</h2>

        <ul class="list-archives">
            <li v-for="archive in archives">
                <router-link :to="{ path:'search-date', query: {year: archive.year, month: archive.month} }">{{ archive.year }}/{{ archive.month }} Posts ({{ archive.posts }})</router-link>
            </li>
        </ul>
    </div>
</template>

To get the data for the archives we need to use the library axios to query the URL created by the post Archives endpoint /wp-json/wp/v2/posts/archives. The return of the endpoint will then get stored inside the archives data point.


<script>
import axios from 'axios'

export default{
  data () {
    return {
      archives: []
    }
  },

  created () {
    this.getArchives()
  },

  methods: {
    getArchives () {
      axios.get(process.env.API_URL + '/wp-json/wp/v2/posts/archives')
      .then(response => {
        this.archives = response.data
      })
      .catch(e => {
        console.log(e)
      })
    }
  }
}
</script>

When the user clicks the Archives links they will be taken to a search page which will search for posts by year and month. So let's create the search page and query for posts within this month.

Search For Posts By Date

Add a search route for the search date page inside the router index.js file.


{
  name: 'SearchDate',
  path: '/search-date',
  component: Search
},

This route uses the same search page we created in the previous tutorial. Within this getPosts() function we need to add new IF statement to see what type of search we're doing, we can do this by using the route name and check if we're on the SearchDate name if (this.$route.name === 'SearchDate') {. We need to create 2 date objects, set the first object to the start of the query month and the second to the end of the month.


  var startDate = new Date()
  startDate.setYear(this.$route.query.year)
  startDate.setMonth(this.$route.query.month)
  startDate.setDate(1)

  var endDate = new Date()
  endDate.setYear(this.$route.query.year)
  endDate.setMonth(this.$route.query.month)
  endDate.setDate(32)

To query WordPress posts between date range we use the normal posts endpoint with the parameters before and after, the values need to be a DateTime of ISO format.


  axios.get(process.env.API_URL + '/wp-json/wp/v2/posts?after=' + startDate.toISOString() + '&before=' + endDate.toISOString())

The return of this will need be stored inside the posts variable. Below is the full code to the new Search page component.


<template>
    <div id="search">
        <h2 class="title is-2">Search results for: {{ searchTerm }}</h2>

        <search-form v-bind:defaultTerm="searchTerm"></search-form>
        <list-posts v-bind:posts="posts"></list-posts>
    </div>
</template>

<script>
import axios from 'axios'
import ListPosts from '../global/ListPosts.vue'
import SearchForm from '../forms/Search.vue'

export default {
  name: 'Search',
  data () {
    return {
      searchTerm: '',
      posts: []
    }
  },

  created () {
    this.getPosts()
  },

  methods: {
    getPosts () {
      if (this.$route.name === 'Search') {
        this.searchTerm = this.$route.params.searchTerm
        axios.get(process.env.API_URL + '/wp-json/wp/v2/posts?search=' + this.searchTerm)
        .then(response => {
          this.posts = response.data
          document.title = 'Search results for: ' + this.searchTerm
        })
        .catch(e => {
          console.log(e)
        })
      }

      if (this.$route.name === 'SearchDate') {
        var startDate = new Date()
        startDate.setYear(this.$route.query.year)
        startDate.setMonth(this.$route.query.month)
        startDate.setDate(1)

        var endDate = new Date()
        endDate.setYear(this.$route.query.year)
        endDate.setMonth(this.$route.query.month)
        endDate.setDate(32)

        axios.get(process.env.API_URL + '/wp-json/wp/v2/posts?after=' + startDate.toISOString() + '&before=' + endDate.toISOString())
        .then(response => {
          this.posts = response.data
          document.title = 'Search results for: ' + this.$route.query.year + '/' + this.$route.query.month
        })
        .catch(e => {
          console.log(e)
        })
      }
    }
  },

  components: {
    'list-posts': ListPosts,
    'search-form': SearchForm
  }
}
</script>