Creating a dynamic bootstrap tab menu for WordPress

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).

deneme bonusudeneme bonusu veren sitelerpulibet girişOnwin Güncel Giriştürkçe altyazılı pornocanlı bahis casino