I have this directory structure:
- content/
- articles/
- 2020/
- 2019/
- 2018/
- projects/
I want to be able to fetch every .md file from the content/articles/ directory.
I have tried the following:
this.articles = await this.$content('articles/**/*').fetch();
this.articles = await this.$content('articles/*').fetch();
this.articles = await this.$content('articles/').fetch();
this.articles = await this.$content('articles').fetch();
Any ideas how I can achieve this?
Extra info:
My first step was to place all articles inside the articles directory and fetch them from there, and it worked perfectly. I'm now looking to further split my articles into year directories.
you can do $content('articles', { deep:true }).fetch()
_this option is available v1.3 onwards!_
explained in the docs here
Of coure, yes thank you. Sorry, I'd been searching through the docs for this, sorry I couldn't see it. Thank you!
Can I ask a follow up question? What would my pages directory look like?
- pages
- blog
- _id.vue
- projects
OR
- pages
- _year
index.vue
- _id
index.vue
- projects
Extra information:
I do not have plans to create dedicated page to display all blogs for a specific year, I.e. http://domain.com/blog/year.
I tried the above suggestion, when I went to https://domain.com/blog, it worked as expected where it displayed all blogs fro 2019 & 2020.
But when I click through to a blog, I.e. http://domain.com/blog/2020/example-1, it throws a 404. According to my sitemap, the URL is correct.
Could you offer anything based on this? Thanks in advance
I'm trying to search all of the subfolders in my content directory with $content('', { deep: true }). Content tries to POST to http://localhost:3000/_content//[object%20Object], which is obviously incorrect and reflects trying to treat { deep: true } as a string part of the path. What's the correct command to access all of the subfolders?
@JDomleo
const article = await this.$content('blog', { deep: true })
// If your file names are unique across all the directories then you can simply check for slug..
.where({ slug: 'filename' })
// or you can even check the path if your file name is duplicated for various years.. below is just an example
.where({ path: '/year/article' })
.fetch();
Also even if you do not are not planning to create a dedicated page for year itself, seems like you are still going for year/article format, so you will have to be careful there..
@jbnv Make sure your content module is updated to at least 1.3.0 because that is when the deep fetch was introduced..
Also seems like you are trying to fetch the root content directory. I stronly suggest you to put your files in some sub directory because even if doesn't make any sense now, you will realize later than doing so will be useful in many ways..
That is because if you plan to add some other type of content in future then your code will throw error for sure and also fetching content from specific folder would be more safer.
Thanks @TheLearneer! I wasn't able to get it to work with the year directory, so I've decided to leave it for now, the year directory wasn't important.
I found a solution that was nearly what I wanted but I'm happy with it.
- content/
- blog/
- 2020/
- 2021/
-projects/
-pages/
- blog/
- _slug.vue
- projects/
nuxt.config.js
generate: {
async routes () {
const { $content } = require('@nuxt/content');
const files = await $content('', { deep: true }).only(['slug', 'dir']).fetch();
return files.map(file => '/' + (file.dir.includes('blog') ? 'blog' : file.dir.includes('projects') ? 'projects' : '') + '/' + (file.slug === '/index' ? '/' : file.slug));
}
}
@/pages/blog/_slug.vue
async asyncData ({ $content, params }) {
const slug = params.slug || 'index';
let page = await $content('blog', { deep: true })
.where({ slug: slug })
.only(['title', 'date', 'slug', 'description', 'readingTime', 'body'])
.fetch();
page = page[0]; // This was catching me out, for some reason it was returning an array with one object inside it, so I hard coded to always return the first index.
return {
page
};
}
This solution allows me to keep the markdown files inside separate directories for their year, but the year is no longer in the URL.
E.g. @/content/blog/2020/example-1.md would appear at URL http://domain.com/blog/example-1 and I'm absolutely ok with that. Seems like the most logical solution. Thanks for your help @TheLearneer!
@JDomleo At this point I am not sure how exactly you want the url to be..
But the truth it you can make it work any way you like _with little bit of coding_!
I mean if you want http://domain.com/blog/year to list all the articles for that year, and then want http://domain.com/blog/example-1 to work, that is possible as well...
I don't know if that would be the best thing to do...
But rather my point is that you can make it work anyway you want :smile:
Anyways I am happy that you are happy with your code now! :heart:
Here's how I managed to resolve this on my end with the full path.
- content/
- blog/
- 2020/
- 2021/
-pages/
- blog/
- _slug.vue
First, I extended the routes via extendRoutes in nuxt config.
nuxt.config.js
router: {
extendRoutes (routes, resolve) {
routes.push({
name: 'custom',
path: '/blog/:year/:mon/:slug',
component: resolve(__dirname, 'pages/blog/_slug.vue')
})
}
},
and then on my _slug.vue, I just concatenated the year, mon, and slug parameters
async asyncData({ $content, params, error }) {
const slug =
params.year.concat('/', params.mon, '/', params.slug) || 'index'
const page = await $content('blog', slug)
.fetch()
// eslint-disable-next-line handle-callback-err
.catch((err) => {
error({ statusCode: 404, message: 'Page not found' })
})
return {
page
}
}
I don't want to change the URL structure of my blog so I had to do this. I hope this helps others, too.