How to list posts of categories and its sub categories?

Iā€™m trying to find a way to include a list of posts of a category and its sub categories in my app. For example, this is the default behavior if you call /category/<parent_category> in a wp blog.

Using Frontity, I get a 404 not found if there are no posts in a specific category, even if it contains sub categories with posts (Frontity calls wp-json/wp/v2/categories?slug=... and then wp-json/wp/v2/posts?categories=<cat_id> where cat_id is the id of my parent category; the endpoint only returns the specific categoryā€™s posts).

Is there a way to include those posts?
Thank you!

Thatā€™s not a Frontity problem, but the default behaviour of the REST API.

The easiest way to solve it is to add the parent category to all the posts of the child categories. Is that possible in your case?

It would be possible, but Iā€™m honestly more interested in a solution where I can implement the workflow:

  1. Get id of parent category
  2. Get sub categories
  3. Fetch posts

ā€¦ so that I donā€™t have to assign them to the parent category. Would I have to adapt wp-source and the handlers in that case?
Seems that I have to fetch categories?parent=<parent_cat> and then fetch per category.

Yeah, I think so.

You can fetch posts from multiple categories at once using comma separated ids: ?categories=1,2,3.

Itā€™d be something like this:

const myCategoriesHandler = {
  pattern: "/category/(.*)?/:slug",
  func: async ({ route, params, state, libraries }) => {
    // Get the page of the current route.
    const { page } = libraries.source.parse(route);

    // Get the id of the parent category.
    const parentCatResponse = await libraries.source.api.get({
      endpoint: "categories",
      params: { slug: params.slug }
    });
    const [parentCat] = await libraries.source.populate({
      state,
      response: parentCatResponse
    });

    // Get the ids of all the child categories.
    const childCatsResponse = await libraries.source.api.get({
      endpoint: "categories",
      params: { parent: parentCat.id }
    });
    const childCats = await libraries.source.populate({
      state,
      response: childCatsResponse
    });
    const ids = childCats.map(cat => cat.id);
    ids.push(parentCat.id);

    // Get the posts from those categories.
    const postsResponse = await libraries.source.api.get({
      endpoint: "posts",
      params: { categories: ids.join(","), page, _embed: true }
    });
    const items = await libraries.source.populate({
      state,
      response: postsResponse
    });
    const total = libraries.source.getTotal(postsResponse);
    const totalPages = libraries.source.getTotalPages(postsResponse);

    // Populate state.source.data with the proper info about this URL.
    Object.assign(state.source.data[route], {
      id: parentCat.id,
      taxonomy: "category",
      items,
      total,
      totalPages,
      isArchive: true,
      isTaxonomy: true,
      isCategory: true
    });
  }
};

Take into account that you need to do 3 serial requests in order to get this info so you better cache your REST API with a CDN or at least a plugin :slight_smile:

5 Likes

Thatā€™s cool! Thanks for the code - Iā€™ll try it out!
Jep sure, didnā€™t know about WP Rest cache plugin, soundā€™s promising :slight_smile:

1 Like

Just so you know, WordPress 5.7 is going to include a new include_children option to retrieve the items of the children categories in the same request.

Trac ticket: #39494 (Make it possible for taxonomy query to include children in REST API) ā€“ WordPress Trac

3 Likes

I meet similar problem. when I visit ā€˜htttp://domain/category/top-category-nameā€™, it is ok. But when I visit ā€˜htttp://domain/category/child-category-nameā€™, it return 404. There are posts in both category .
I feel Frontity is too yong , It need a long way to run.
I feel a little frustrated when I deep in Frontity, I even consider to turn off to gastby now怂

Did you try using the include_children param? If it didnā€™t work, could you please explain why?

By the way, in my opinion this has to do more with way the REST API works than with Frontity. It would be better solved in the API once than in the each framework (Gatsby, Next, Frontityā€¦) multiple times.

I tried this yesterday but couldnā€™t get it running. For me, rest api - How to get all posts from parent and children categories? - WordPress Development Stack Exchange was working adapting functions.php for my theme:

// Add parent_category filter to REST API
function rest_filter_by_parent_category($args, $request) 
{
  if (isset($request['parent_category'])) {
    $parent_category = sanitize_text_field($request['parent_category']);
    $args['tax_query'] = [
      [
        'taxonomy'         => 'category', 
        'field'            => 'term_id', 
        'include_children' => true,
        'operator'         => 'IN',
        'terms'            => $parent_category, 
      ]
    ];
  }
  return $args;
}

add_filter('rest_post_query', 'rest_filter_by_parent_category', 10, 3);

I took the code above and adapted it to use the category (not parent_category) parameter. I might misunderstood the include_children parameter (tried several solutions with adding the parameter but in the end I got it working with the rest ā€œfilterā€). In any case I think this is more efficient than having multiple rest calls for this.

However, how I see @12732801 your issue, you try to access the child category directly? Whatā€™s happening if you call the url directly for your blog?