0

I'm trying to create a dynamic bootstrap tab menu for WordPress. I showed the categories as a menu on the front page. According to the menu title, the correct loop result does not appear and I click on the tabs but the relevant content does not work. So the tabs are not responding. I tried hard but I'm stuck here. Please can someone help?

click on the categories, the relevant content will be shown without refreshing the page.

<section class="my-5 px-5">
    <nav class="my-3 d-flex justify-content-center">
        <div class="nav nav-tabs" id="nav-tab" role="tablist">
            <?php $i = 0; ?>
            <?php
            $args = array(
                'post_type'    => 'customjob',
                'taxonomy'     => 'subjects',
                'orderby'      => 'name',
                'order'        => 'ASC',
                'parent'       => 0,
                'hide_empty'   => 0,
                'hierarchical' => 1,
                'show_count' => true,
            );
            $cats   = get_categories($args);
            foreach($cats as $cat) {
                ?>
                <a href="<?php echo get_category_link($cat->term_id); ?>" class="nav-link <?php if ($i == 1) { echo 'active'; } else { echo ' ';} ?>" id="nav-<?php echo $cat->name; ?>-tab" data-bs-toggle="tab" data-bs-target="#nav-<?php echo $cat->name; ?>" type="button" role="tab" aria-controls="nav-<?php echo $cat->name; ?>" aria-selected="<?php if ($i == 1) { echo 'true'; } else { echo 'false'; } ?>"><?php echo $cat->name; ?></a>
                <?php $i++; ?>
            <?php } ?>
        </div>
    </nav>
    <div class="row tab-content" id="nav-tabContent">
        <?php $the_query = new WP_Query(array( 'post_type' => array('customjob'), 'posts_per_page' => -1, 'orderby' => 'date' )); ?>
        <?php $i = 0; ?>
        <?php if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
            <?php $i++; ?>
            <div class="col-md-4 tab-pane <?php if ($i == 1) { echo 'fade show active'; } else { echo ' ';} ?>" id="nav-<?php echo $cat->name; ?>-tab" role="tabpanel" aria-labelledby="nav-<?php echo $cat->name; ?>-tab">
                <div class="tab-img img-s text-center px-5"><?php the_post_thumbnail(); ?><?php the_title(); ?></div>
            </div>
        <?php endwhile; wp_reset_postdata(); else : ''; endif; ?>
    </div>
</section>

1 Answer 1

0

The first thing that I notice is that you're using categories for tabs and posts for panels. If you want to have categories both as tabs and panels, then you should loop the categories twice so that you can use category term properties in the HTML elements' attributes.


Example To run the categories loop twice, you could do something like this.

First couple helper functions.

// in functions.php
function wpse_419644_tab_categories(): array {
    return get_categories([
        'post_type'    => 'customjob',
        'taxonomy'     => 'subjects',
        'orderby'      => 'name',
        'order'        => 'ASC',
        'parent'       => 0,
        'hide_empty'   => 0,
        'hierarchical' => 1,
        'show_count' => true,
    ]);
}

function wpse_419644_tab_category_posts(int $category_id): array {
    $query = new WP_Query([
        'cat' => $category_id,
        'post_type' => 'customjob',
        'posts_per_page' => 500, // Setting sufficiently high limit is better, if there are 1000's of posts -1 might grind the server to a halt
        'orderby' => 'date',
        'no_found_rows' => true, // pagination not needed here probably
    ]);

    return $query->posts;
}

And then the HTML loops

<?php
// in template file
$tab_categories = wpse_419644_tab_categories();
?>
<section class="my-5 px-5">
    <nav class="my-3 d-flex justify-content-center">
        <div class="nav nav-tabs" id="nav-tab" role="tablist">
            <?php foreach($tab_categories as $cat_index => $cat) : ?>
                <a href="<?php echo get_category_link($cat->term_id); ?>" 
                    class="nav-link <?php echo ($cat_index == 0) ? 'active': ''; ?>"
                    id="nav-<?php echo esc_attr($cat->slug); ?>-tab" 
                    data-bs-toggle="tab" 
                    data-bs-target="#nav-<?php echo esc_attr($cat->slug); ?>" 
                    type="button"
                    role="tab" 
                    aria-controls="<?php echo esc_attr($cat->slug); ?>-tab" 
                    aria-selected="<?php echo ($cat_index == 0) ? 'true': 'false'; ?>">
                    <?php echo esc_html($cat->name); ?>
                </a>
            <?php endforeach; ?>
        </div>
    </nav>
    <div class="row tab-content" id="nav-tabContent">
        <?php foreach($tab_categories as $cat_index => $cat) : ?>
            <div class="col-md-4 tab-pane <?php echo ($cat_index == 0) ? 'fade show active': ''; ?>" 
                id="<?php echo esc_attr($cat->slug); ?>-tab"
                role="tabpanel"
                aria-labelledby="nav-<?php echo  esc_attr($cat->slug); ?>-tab">
                <?php foreach(wpse_419644_tab_category_posts($cat->term_id) as $cat_post) : ?>
                    <div class="tab-img img-s text-center px-5">
                        <?php
                            echo get_the_post_thumbnail( $cat_post, 'post-thumbnail', [] );
                            echo get_the_title( $cat_post );
                        ?>
                    </div>
                <?php endforeach; ?>
            </div>
        <?php endforeach; ?>
    </div>
</section>

N.B. This code example is untested and may require additional tweaking.


Notes

When setting element ID's and other attributes you generally want to use slugs or (object) ID's in them instead of the human-readable titles (i.e. $cat->name). This way you don't get any undesirable characters in the attributes which might in some cases break the HTML.

It also highly recommended to use escape functions, such as esc_attr() and esc_html(), when echoing stuff to the front-end. Read more about escaping.

If you have to use conditionals when printing HTML attribute values, then the ternary operator is your friend. The $is_true ? true : false; syntax is more concise and easier to read than writing the whole if... else... format.

To keep your HTML as clean as possible I'd recommend defining helper functions for retrieving the data - categories etc. With helpers functions you don't have to mix query and rendering logics together in the same file, but can keep them separate. Additionally, the helpers makes your code reusable and easier to understand. The functions can be defined for example in your theme's functions.php file.

With WP_Query it is not strictly necessary to setup the loop when rendering the posts. Instead you can just get the post objects directly from the $query->posts array property (see the example helper functions above).

1
  • Hello Antti Koskinen. First of all, thank you for your interest. The categories appear as tabs, but unfortunately, when I click on the tabs, the relevant contents do not appear.
    – wws34
    Commented Nov 7, 2023 at 20:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.