How to get all post ignoring the `per_page` param?

Hi, I’m trying to get all the post for my custom view. Then, I will filter to show what I need. What would be the best way to do this?

@josema.enzo Frontity does not have a native filter/sorting methods in the data object. However, using the JavaScript Array and Object methods, you should be able to perform these operations.

Happy Coding!!!

The problem is that state.source.post gives different results depending on how is loaded. If you open the DevTools>Console of this page http://tusjuegos.io/blog/ I’m printing the items and this is the output:
Total items: 50 Filtered items: 13

Now if you go to home and then go back to blog I got this items:
Total items: 100 Filtered items: 22

The component is a custom view that I made after getting help from this post:


const BlogList = ({ state }) => {
    const items = Object.keys(state.source.post).map(
        id => state.source.post[id]
    )
    const filteredItems = items
        .slice(0)
        // .sort((a, b) => a - b)
        .filter(({ type, id }) => {
            const item = state.source[type][id]
            return item.categories[0] === 2
        })
        .map(({ type, id }) => {
            const item = state.source[type][id]
            return <Item key={item.id} item={item} state={state} />
        })
    console.log(
        'Total items: ' + items.length,
        'Filtered items: ' + filteredItems.length
    )
    return items ? (
        <Container>
            {filteredItems}
        </Container>
    ) : null
}

I just need a way to get all the posts in all cases.

It seems like, when you navigate to the homepage, you are fetching the second page of the posts, and that’s why your Total items is 100. If you’re using mars-theme, we included this logic at the pagination of the <List /> component. This way, with useEffect, we fetch the next page once all the elements of the homepage finish loading.

Here you have the code I’m talking about at your own GitHub. If you want to have the same in your /blog/ you may want to reuse the pagination of mars-theme in your blog list or create your on logic with useEffect.

1 Like

I don’t want to touch the Pagination logic because it works well for the rest of the page. Instead of change that logic I need a way to fetch all the items/posts that are in my wordpress. Then I will care about filtering.

If you want to fetch all the posts of your WordPress you’ll need to change your handler and do something similar to what Orballo proposes at this topic (in this case is for tags). Something similar to this:

const response = await libraries.source.api.get({
  endpoint: "posts",
  params: {
    per_page: 100
  }
});

const pages = libraries.source.getTotalPages(response);

await libraries.source.populate({ state, response });

const requests = [];

for (let page = 2; page <= pages; page++) {
  requests.push(
    libraries.source.api.get({
      enpoint: "posts",
      params: {
        per_page: 100,
        page
      }
    })
  );
}

const responses = await Promise.all(requests);

await Promise.all(responses.map(response =>
  libraries.source.populate({ state, response })
));

It hasn’t been tested but something similar should work.

2 Likes

Hi again, sorry I didn’t reply at time because I could not solve the problem. I’m still have not solution for this. I’m gonna try to explain better what I want to achieve because probably I’m using an approach that is not the right one.

I have this site http://tusjuegos.io/. I have two type of content “games” and “articles”. By using the mars-theme I was able to list all the games very easy. The problem came when I had to create a new list of items that are categorized as articles which is actually the blog category.
I’ve opened another post about that before: How to create Custom Pages?

The problem
I don’t know how to list all the blog-posts/articles. As mentioned above I got different output listing the articles.

Approach 1
BlogList component must fetch only the items that are categorized as “article” and then I list them. I think this is the right one, but don’t know how to do it.

Approach 2
BlogList fetch all the wordpress items, then I filter with JavaScript the ones that are “article”. No pagination.

Approach 3
I filter with JavaScript the ones that are “article”. Then I use pagination to fetch more.

Can someone guide me on what approach I should follow and how to achieve it? I’m a bit lost.

Here is the full project https://github.com/ocio/tusjuegos/tree/master/packages/mars-theme/src/components

Hi @josema.enzo :slightly_smiling_face:

In this case, I’d consider moving “games” to a specific Custom Post Type, I think it could be cleaner.

Anyway, with the current setup, I’d recommend the Approach 1 as you say. I’ve seen that in your backend, all the articles are under the category article with id=2. In WordPress API you can filter posts by category with a query: https://wp.mysite.com/wp/v2/posts?categories=2 for example.

In your case, you can add this param to the handler you’re creating for the link /blog. So, in these lines of code, if you want to fetch all the articles without pagination, you could have a handler similar to this:

const blogListHandler = {
    pattern: '/blog/',
    priority: 5,
    func: async ({ route, params, state, libraries }) => {
        const { api, populate, getTotalPages } = libraries.source
        const response = await api.get({
            endpoint: 'posts',
            params: {
                per_page: 100,
                categories: 2,
                _embed: true,
            },
        })
        const firstItems = await populate({
            response,
            state,
        })
        const pages = getTotalPages(response)
        const requests = []

        for (let page = 2; page <= pages; page++) {
            requests.push(
                api.get({
                    endpoint: 'posts',
                    params: {
                        per_page: 100,
                        categories: 2,
                        page,
                        _embed: true
                    },
                })
            )
        }
        const responses = await Promise.all(requests)

        const newItems = await Promise.all(
            responses.map((response) => populate({ state, response }))
        )
        const items = firstItems.concat(newItems)

        // 4. add data to source
        const currentPageData = state.source.data['/blog/']
        const newPageData = {
            isBlogList: true,
            items,
        }

        Object.assign(currentPageData, newPageData)
    },
}

Once you have this handler, you can consume this data from the BlogList component with something just simple as this:

import React from 'react'
import { connect } from 'frontity'
import Item from './blog-list-item'

const BlogList = ({ state }) => {
    const data = state.source.get(state.router.link)

    return (
        <Container>
            {data.items.map(({ type, id }) => {
                const item = state.source[type][id]
                return <Item key={item.id} item={item} state={state} />
            })}
        </Container>
    )
}

export default connect(BlogList)

I’ve run a quick test and it seems to work. Apart from that, I’d consider creating the pagination and/or caching the REST API responses because, if there are a lot of articles, the loading time could be too high.

Let us know if this fix the problem and if not share the errors you’re encountering :slightly_smiling_face:

Yes, is working as expected. Thank you. Didn’t know about the Custom Post Type, will use it next time.

How would you do the same but with pagination? Because after 100 articles this would not work. And also, what would you recommend to cache those request to the wp api? I see that is the bottleneck of the page load in general.

They are pretty useful and one of the most used features in WordPress, so I’d say it’s a good idea to use them :slightly_smiling_face:.

For the pagination you could use something similar, if just as it is doesn’t work for you, to our postTypeArchive handler. You can check the code here.

We’re using the WP REST API Cache plugin in some webs, which is simple and it works great, so I’d try that one for this.

Hope this helps :slightly_smiling_face: