0

I have three categories: Money, Space, Advice.

I use these on a post index page to filter through all of my posts by creating checkboxes for each category type.

@php $categories = get_categories() @endphp

@foreach($categories as $category)
    <div class="custom-control custom-control-inline custom-checkbox">
        <input type="checkbox" name="{{ $category->slug }}" value=".{{ $category->slug }}" class="custom-control-input" id="{{ $category->slug }}">
          <label class="custom-control-label" for="{{ $category->slug }}">{{ $category->name }}</label>
    </div>
@endforeach

This creates a checkbox list of every category in use.

Is there a way to limit get_the_categories() to specific post types?

For instance, if I have a post type called team-member I still want to use Money, Space, Advice for categorisation but I don't want filters to appear if the categories are unused for that post type.

However, using get_the_categories() would display used categories in any post type, this means that for a custom post type there may not be anything categorised but the filter would display, which is misleading.

So, I'm wondering if there's something like get_the_categories('team_member)?

4
  • Do you mean get_categories()? That's the correct function, and what you have in your code, but you mention get_the_categories() throughout your question. Feb 27 '19 at 12:24
  • That being said, no, there isn't a way to do what you're asking. Not without just writing raw SQL. It sounds like you'd be better off just using a separate taxonomy. Is that acceptable? Feb 27 '19 at 12:25
  • So, there's no way to get categories in use per post type? Feb 27 '19 at 12:30
  • Essentially, I just want 3 global categories, but if a post type doesn't have that category, it isn't worth filtering by it. Feb 27 '19 at 12:31
2

The problem is that categories don't store any information about which post types it's been used on, just the total count. So if you want to know if a category is being used for a particular post type, you need to query all the posts in that category, and check which post type they are. There isn't a WordPress function that does this, so you'd need to make one. The most efficient way to do this would be a probably be a custom SQL query.

function wpse_330111_get_categories_for_post_type( $post_type ) {
    global $wpdb;

    /**
     * The SQL query for getting categories based on which post type they've
     * been used on.
     */
    $query = $wpdb->prepare(
        "SELECT DISTINCT
            t.*, tt.*
        FROM
            $wpdb->terms t
        INNER JOIN
            $wpdb->term_taxonomy tt ON
                tt.term_id = t.term_id
        LEFT JOIN
            $wpdb->term_relationships tr ON
                tr.term_taxonomy_id = tt.term_taxonomy_id
        LEFT JOIN
            $wpdb->posts p ON
                p.ID = tr.object_id
        WHERE
            tt.taxonomy = 'category' AND
            p.post_status = 'publish' AND
            p.post_type = %s
        ",
        $post_type
    );

    $categories = $wpdb->get_results( $query );

    /**
     * If there's results, make sure to return a proper WP_Term object for each
     * category.
     */
    if ( ! empty( $categories ) ) {
        $categories = array_map( 'get_term', $categories );
    }

    return $categories;
}

That function will return any categories that are attached to a published post of a given post type:

$categories = wpse_330111_get_categories_for_post_type( 'team_member' );
7
  • Is there a reason this isn't a built in WordPress feature? Surely this is something a bunch of people would want to do? Also, if you don't mind me asking, did you just try this is raw SQL then make it a function, or are you just extremely aware of the WordPress table structure? If I wanted to do the same for tags would I have to do the same thing? Finally, can you see why I'm trying things in this way? Feb 27 '19 at 13:11
  • 1
    Sure, plenty of people want to do something like this. That's why there's entire plugins built for it. It's just not most people, which is who WordPress core tries to serve. I am pretty familiar with WP's database, so wrote that function mostly blind, but I did test it in WP and as SQL make sure it worked. If you want to do this for different taxonomies, then you could modify the function to accept a second argument for a taxonomy, then replace 'category' in the SQL with the provided taxonomy, Feb 27 '19 at 13:16
  • I genuinely thought this would be more straightforward, but I do forgot you can use raw SQL. Feb 27 '19 at 13:22
  • Well I explained the issue in my answer: WordPress doesn't store information about which post types a category has been used for. So any solution is going to involve a relatively complex query. Feb 27 '19 at 13:24
  • 1
    When answering on this site wpse_ is for "WordPress Stack Exchange", and numbers are the question ID, from the URL. This gives a safe prefix that won't conflict with anything if the user just pastes it straight into their site, as well as a hint to its source. Ideally you'd use your project's own prefix. Then actual function name is just a clear and unabbreviated description of what the function does. Clarity over brevity. I tend to follow WordPress' convention that functions that begin with get_ return a value, rather than generating output. Feb 27 '19 at 13:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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