Black Friday 2025
Meta Box

How to Create a Parent-Based Filter for Hierarchical Custom Post Types - Using MB Views

If your data already has a clear hierarchical structure, and you want a more intuitive way to group and display related items without adding extra fields or taxonomies, you can build a filter based on the parent posts easily with the help of MB Views. In this guide, we’ll explore how to do it.

To make it easier to visualize, let’s walk through a specific scenario.

Filter by parent posts

Each filter is a parent post of the class post type. And when a user clicks on a parent, its corresponding child posts will be displayed along with their details.

Video Version

Before Getting Started

Obviously, we’ll need to have a hierarchical custom post type, then use code and JavaScript in MB Views to build the filter. In addition, I also added some extra information for classes via custom fields. So, I recommend you use Meta Box AIO, to have both the framework and all the functionalities from extensions in it. Especially, we use:

  • MB Custom Post Type: to create a custom post type, in this case, it is the class.
  • MB Views: to create a template for building a filter based on parent posts.
  • MB Builder: to have UI in the backend, to create custom fields visually.

Now, let’s start.

Create a Custom Post Type and Custom Fields

Go to Meta Box > Post Types, and create a new one. I’ve had it already.

Go to Meta Box > Post Types, and create a new one

Remember to enable the option as below to make it hierarchical, allowing parent–child relationships.

Enable the option to make CPT hierarchical, allowing parent–child relationships.

Also, you should move to the Features tab to turn on the re-order post, which supports you rearrange posts just by dragging and dropping, including hierarchy posts.

Enable re-order feature

I’ve also created a field group for the class details with some fields. You can create them as you need. Then, I applied this field group to the class post type.

Fields for class post type

As a result, when you create a new class, you can see the custom fields that you can input data for them.

Fields in post editor

These are the posts we have.

Posts

To re-order them, just navigate to this tab, drag and drop the child post to the parent one you want.

Display Posts on a Page

We need to have a new page first.

Create a new page

Now, I’ll use MB Views to display classes on that page.

Navigate to the Views in Meta Box, and create a new view.

In the Template tab, I add code to display posts and their details on the page.

{% set posts = mb.get_posts({ post_type: 'class', posts_per_page: -1, orderby: 'menu_order', order: 'ASC' }) %}
{% for post in posts %}
{% endfor %}

Add code to get posts

It means we’ll get all the posts from the class post type, and use a loop to get all of them since there are many posts.

Inside the loop, we’ll insert fields to get the data we want for each post. I use the Insert Field button, then simply select the field I want to insert.

Insert fields to get data

After inserting all the fields you need, scroll down to the Settings section to set location for the template. I set the type as Singular and choose the created page to apply this template to it.

Set location for the template

On the frontend, all the data of the class is displayed. But it seems to need to be made more beautiful.

All the data displayed

Back to the created template, and modify the code a little bit. You can add some div tags and classes for styling easily.

Add div tags and classes for styling

Then, move to the next tab to add some CSS.

Add CSS to style

Now, we have a new look that is clearer and more attractive.

The new look of the page

Next, let’s go ahead to the key step of this tutorial.

Build the Filter Based on Parent Posts

To build and activate the filter, we’ll use JavaScript.

Set Logic for the Filter Tabs and Posts

Back to the created template, and add some parts of code:

Add code for the filter

In there:

  • (1) The line is to declare that we’ll use a JavaScript library to handle the filtering behavior.
  • (2) The part is to separate the parent posts.
  • (3) Loop through each of the parent post, and create the new buttons for parent posts relatively. The first one as active by default, meaning it is selected initially. Then, data-tab="tab-{{ parent.ID }} is to assign an ID to each tab, which will be used to connect it with its corresponding content below.
  • (4) I create another loop to generate the content for each tab. Each parent post has its own content block, and they are linked together using the same ID. This allows JavaScript to display the correct content when a tab is clicked.
  • (5) Inside the post loop, I add {% if post.post_parent == parent.ID %} to check and show only the post whose parent ID matches the current parent. This is the core logic behind the filter.

I also added some CSS for styling the new classes.

Handle the Interaction with JavaScript

Move to the JavaScript tab to add actions for the filter. The code will be run after all the HTML is rendered.

jQuery(document).ready(function ($) {
    $('.class-tabs').each(function () {
        var $container = $(this);
        $container.find('.tab-btn').on('click', function () {
            var tabId = $(this).data('tab');
            $container.find('.tab-btn').removeClass('active');
            $(this).addClass('active');
            $container.find('.tab-content').removeClass('active');
            $container.find('#' + tabId).addClass('active');
        });
    });
});

Add JavaScript for filter

Specifically:

  • $('.class-tabs').each(function () {: This code loops through each container on the page.
  • var $container = $(this): is to assigns the current one to the container, so all interactions inside it can be handled independently.

Then, when a button is clicked, the next part will be run.

First, var tabId = $(this).data('tab') is to get the ID of the tab that needs to be shown.

Then, I update the active state for the buttons, including removing the active class from all the buttons, and then add it to the clicked button. This ensures that only one tab is selected.

The same logic applies to the content: all tab contents are hidden, and only the one matching the selected tab ID is displayed.

I uploaded all the code on GitHub, so you can refer to it.

Now, on the page, you can see the buttons are the parent posts we have. The filter works well.

(gif)

Try to update the structure of the posts to check how the filter works.

Last Words

It's a simple yet powerful way to improve content navigation and help users find exactly what they're looking for.

For more WordPress customization tips for filtering and searching, you can have more guides from this tag. See you in the next tutorials!

Leave a Reply

Your email address will not be published. Required fields are marked *