You could try using the terms_clauses
filter
function wpse156370_terms_clauses( $pieces, $taxonomies, $args ) {
global $wpdb;
$pieces['fields'] .= $wpdb->prepare( ', (SELECT COUNT(*) FROM '
. $wpdb->posts . ' p, ' . $wpdb->term_relationships . ' p_tr'
. ' WHERE p_tr.object_id = p.ID AND p_tr.term_taxonomy_id = tt.term_taxonomy_id'
. ' AND p.post_status = %s AND p.post_type = %s) AS post_count', 'publish', $args['type'] );
$pieces['orderby'] = ' HAVING post_count > 0 ' . $pieces['orderby'];
return $pieces;
}
and then around the get_categories
add_filter( 'terms_clauses', 'wpse156370_terms_clauses', 10, 3 );
$categories = get_categories( $args );
remove_filter( 'terms_clauses', 'wpse156370_terms_clauses', 10, 3 );
It’s a hack, misusing HAVING (and $pieces['orderby']
) as can’t refer to the post_count alias in the WHERE, but … seems to work.
To get the term links to differentiate add a query var to each, eg
echo "<a href="" . add_query_arg( "post_type', $post_type, get_term_link($cat) ) . "'>" , $cat->name , "</a>";
And then check for this in a pre_get_posts
action
function wpse156370_pre_get_posts($query) {
$taxonomy = 'art_categories';
$post_types = array( 'artists', 'educations' );
if ($query->is_main_query() && $query->is_tax( $taxonomy ) && ( $post_type = get_query_var( 'post_type' ) ) && in_array( $post_type, $post_types ) ) {
$query->set( 'post_type', $post_type );
}
}
add_action( 'pre_get_posts', 'wpse156370_pre_get_posts' );