#Filter an array of posts in astro and show only some
23 messages · Page 1 of 1 (latest)
Hi @spice meadow. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
Yes, that makes sense. To filter an array of posts and show only a subset based on the author name, you can use JavaScript's array methods like filter(). Here's how you can do this in Astro, using either content collections or Storyblok as the data source:
- Using Astro Content Collections:
---
import { getCollection } from 'astro:content';
// Get the current author name from the page params
const { author } = Astro.params;
// Fetch all blog posts
const allPosts = await getCollection('blog');
// Filter posts by author
const authorPosts = allPosts.filter(post => post.data.author === author);
---
<!-- Display the filtered posts -->
{authorPosts.map(post => (
<h2>{post.data.title}</h2>
<!-- Add more post details here -->
))}
This approach uses Astro's Content Collections API to fetch and filter posts Content Collections documentation (https://docs.astro.build/en/guides/content-collections/#querying-collections).
- Using Storyblok:
---
import { useStoryblokApi } from '@storyblok/astro';
const storyblokApi = useStoryblokApi();
// Get the current author name from the page params
const { author } = Astro.params;
// Fetch all blog posts
const { data } = await storyblokApi.get("cdn/stories", {
version: import.meta.env.DEV ? "draft" : "published",
content_type: 'blogPost'
});
// Filter posts by author
const authorPosts = data.stories.filter(post => post.content.author === author);
---
<!-- Display the filtered posts -->
{authorPosts.map(post => (
<h2>{post.content.title}</h2>
<!-- Add more post details here -->
))}
This approach uses the Storyblok API to fetch posts and then filters them based on the author Storyblok & Astro documentation (https://docs.astro.build/en/guides/cms/storyblok/#fetching-data).
In both cases, we're using the filter() method to create a new array (authorPosts) that only contains posts where the author matches the current page's author. This filtered array can then be used to display only the relevant posts on the author's page.
Remember to adjust the property names (like post.data.author or post.content.author) to match your actual data structure, as these may vary depending on how you've set up your content models.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@autumn wyvern Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@radiant frigate O, I forgot to mention that it's a multi-author blog, so each post is an array of authors, sometimes only one. So, after storyblok's resolve_relationship, you're actually looking for if say post.author.content.name, a parameter of the author, matches with the current author page
Let me check the knowledge base for you again. One moment! :books:
I understand. Thank you for providing that additional context about the multi-author blog structure. Let's adjust the approach to handle an array of authors for each post and match based on the author's name. Here's how you can modify the Storyblok example to accommodate this scenario:
---
import { useStoryblokApi } from '@storyblok/astro';
const storyblokApi = useStoryblokApi();
// Get the current author name from the page params
const { authorName } = Astro.params;
// Fetch all blog posts with resolved relationships
const { data } = await storyblokApi.get("cdn/stories", {
version: import.meta.env.DEV ? "draft" : "published",
content_type: 'blogPost',
resolve_relations: 'author'
});
// Filter posts by author name
const authorPosts = data.stories.filter(post =>
post.content.author.some(author => author.content.name === authorName)
);
---
<!-- Display the filtered posts -->
{authorPosts.map(post => (
<h2>{post.content.title}</h2>
<!-- Add more post details here -->
))}
In this updated example:
-
We use the
resolve_relationsoption when fetching data from Storyblok to ensure that the author relationships are resolved Storyblok & Astro documentation (https://docs.astro.build/en/guides/cms/storyblok/#fetching-data). -
In the
filter()function, we use thesome()method to check if any author in the post's author array matches the current author name. This handles cases where a post has multiple authors or just one. -
We're assuming that the author's name is stored in
author.content.name. Adjust this if your Storyblok content structure is different. -
Make sure to use the correct parameter name (e.g.,
authorName) in your dynamic route file name (like[authorName].astro) and when accessingAstro.params.
This approach will filter the posts and return only those where at least one of the authors matches the name of the current author page. It accommodates both single-author and multi-author posts.
Remember to adjust the property paths (like post.content.author) if they don't match your exact Storyblok content structure.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@autumn wyvern Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@radiant frigate the some() method looks like the cincher... let me try it. Thanks
Let me check the knowledge base for you again. One moment! :books:
You're welcome! I'm glad the some() method seems helpful for your multi-author blog scenario. The some() method is indeed a great choice for checking if at least one element in an array meets a certain condition, which is perfect for your use case of checking if any author in a post's author array matches the current author page.
If you have any more questions about implementing this in Astro or working with Storyblok data, feel free to ask. Good luck with your implementation!
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@autumn wyvern Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@radiant frigate this authorName from Astro.params, is the naming up to me and how does it map to a post author
Let me check the knowledge base for you again. One moment! :books:
Yes, the naming of authorName in Astro.params is up to you, and it's directly related to how you set up your dynamic routes in Astro. Let me explain how this works:
-
Dynamic Route Setup:
In Astro, you create dynamic routes by using square brackets in your file names. For example, if you want an author page, you might create a file namedsrc/pages/author/**authorName].astro. TheauthorNamepart is what you choose, and it will become the parameter name inAstro.params[Dynamic Routes** (https://docs.astro.build/en/guides/routing/#dynamic-routes). -
URL Structure:
With the above file, a URL like/author/john-doewould setAstro.params.authorNameto"john-doe". -
Mapping to Post Author:
How this maps to a post author depends on how you've structured your data in Storyblok. Typically, you'd want this to match thenameorslugfield of your author content type in Storyblok. For example:--- const { authorName } = Astro.params; // Assuming author.content.slug is used in Storyblok const authorPosts = data.stories.filter(post => post.content.author.some(author => author.content.slug === authorName) ); ---If you're using the author's name instead of a slug, you might need to format it to match your URL structure:
post.content.author.some(author => author.content.name.toLowerCase().replace(' ', '-') === authorName )
Remember, the key is to ensure that the authorName in your URL (which becomes Astro.params.authorName) matches how you're identifying authors in your Storyblok content.
If you need to adjust how the author is identified in the URL, you can change the file name (e.g., [authorSlug].astro or [authorId].astro) and update your filtering logic accordingly.
Dynamic Routes (https://docs.astro.build/en/guides/routing/#dynamic-routes)
</assistant_answer>
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@autumn wyvern Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@radiant frigate how would this work in a case where I'm using just one dynamic route such as [...slug].astro for every route... and in my case, the "author" page is /people/author-name
Let me check the knowledge base for you again. One moment! :books:
In the case where you're using a single dynamic route with [...slug].astro for all your routes, including the author pages, you can still achieve the desired functionality. Let's adapt the approach for your specific scenario where author pages are located at /people/author-name.
Here's how you can handle this in your [...slug].astro file:
---
import { useStoryblokApi } from '@storyblok/astro'
import StoryblokComponent from '@storyblok/astro/StoryblokComponent.astro'
const storyblokApi = useStoryblokApi()
const { slug } = Astro.params;
// Split the slug to check if it's a people/author page
const slugParts = slug.split('/');
const isPeoplePage = slugParts[0] === 'people';
const authorName = isPeoplePage ? slugParts[1] : null;
let content;
let authorPosts;
try {
if (isPeoplePage) {
// Fetch author data
const { data: authorData } = await storyblokApi.get(`cdn/stories/people/${authorName}`, {
version: import.meta.env.DEV ? "draft" : "published",
});
content = authorData.story.content;
// Fetch and filter blog posts for this author
const { data: postsData } = await storyblokApi.get("cdn/stories", {
version: import.meta.env.DEV ? "draft" : "published",
content_type: 'blogPost',
resolve_relations: 'author'
});
authorPosts = postsData.stories.filter(post =>
post.content.author.some(author => author.content.name === content.name)
);
} else {
// Handle other page types
const { data } = await storyblokApi.get(`cdn/stories/${slug}`, {
version: import.meta.env.DEV ? "draft" : "published",
});
content = data.story.content;
}
} catch (error) {
return Astro.redirect('/404')
}
---
<html lang="en">
<head>
<title>Storyblok & Astro</title>
</head>
<body>
<StoryblokComponent blok={content} />
{isPeoplePage && (
<div>
<h2>Posts by {content.name}</h2>
{authorPosts.map(post => (
<h3>{post.content.title}</h3>
<!-- Add more post details here -->
))}
</div>
)}
</body>
</html>
This approach does the following:
1. It uses the `**...slug].astro` file to handle all routes [Dynamic Routes** (<https://docs.astro.build/en/guides/routing/#rest-parameters>).
2. It checks if the current page is an author page by looking at the first part of the slug.
3. If it's an author page (`/people/author-name`), it fetches the author data and then fetches and filters the blog posts for that author.
4. For other pages, it simply fetches the content as before.
5. In the template, it renders the author's posts if it's an author page.
This solution allows you to use a single dynamic route file for all your pages while still providing the functionality to display author-specific content and filtered blog posts on the author pages.
Remember to adjust the content structure and field names to match your specific Storyblok setup. Also, consider implementing proper error handling and loading states for a better user experience.
**Storyblok & Astro documentation** (<https://docs.astro.build/en/guides/cms/storyblok/#fetching-data>)
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------