I have a site with multiple custom post types and taxonomies. The taxonomies are shared across all of the post types.

On the archive page of the 'videos' post type, I want to show a list of all of the 'country' tags that are associated with videos. When this link is clicked on, I'd like to be able to go to an archive for that country but that only shows the 'videos', not the other post types that may have the same country tag.

I also need to be able to do the same for other post types and taxonomies, e.g. when on the 'galleries' post type archive, a tag cloud is shown that links to the tag archive showing only the galleries.

I think that this should be easy, but I just can't figure it out!

Will I need to create archive templates that take arguments passed via the url? E.g. mysite.com/country/canada?type=video

..and then manipulate the get_tags function somehow? I really just can't get my head around this one.

Cheers for your help.


3 Answers 3


I've worked out a solution to this. I hope this can help someone else.

First add the following two functions to your functions.php (or plugin) file:

function get_terms_by_post_type( $taxonomies, $post_types ) {
    global $wpdb;
    $query = $wpdb->prepare( "SELECT t.*, COUNT(*) from $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id WHERE p.post_type IN('".join( "', '", $post_types )."') AND tt.taxonomy IN('".join( "', '", $taxonomies )."') GROUP BY t.term_id");
    $results = $wpdb->get_results( $query );
    return $results;

function show_post_type_terms($taxonomy, $posttype = null ) {
    global $post;
    if(!isset($posttype)) $posttype = get_post_type( $post->ID );
    $terms = get_terms_by_post_type( array($taxonomy), array($posttype) );
    echo '<ul>';
    foreach($terms as $term) {
        $output = '<li><a href="'.get_bloginfo('url').'/'.$taxonomy.'/'.$term->slug.'/?post_type='.$posttype.'">'.$term->name.'</a></li>';
        echo $output;
    echo '</ul>';

Now on your custom post type archive pages you can use <?php show_post_type_terms('country'); ?>, changing 'country' for the taxonomy that you wish to return.

The links created have a query appended to the end to return only the post type that you are currently viewing. If you are on a 'videos' archive page it will link to a taxonomy archive showing only video posts.


I think I can answer part of this. You need a filter in your functions.php to force the loop in your tag.php template to co-operate.

 * Function and filter to force tag.php (tag archives) to display only video custom post types. 
function add_custom_types_to_tag_archives( $query ) {
    if( is_tag() && empty( $query->query_vars['suppress_filters'] ) ) {
        $post_types = array( 'video' );
        $query->set( 'post_type', $post_types );
        return $query;
add_filter( 'pre_get_posts', 'add_custom_types_to_tag_archives' ); 

Hope this helps. It's my first go at answering a question on here :)

  • Thanks for the answer. Would this method mean that only 'video' would ever be shown on a tag.php template? I'll need to be able to do this for all post types. E.g. I have a 'galleries' post type that I will need to do the same thing for. I.e. the tag cloud on the 'galleries' archive links to a tag archive showing only galleries.
    – kdev
    Mar 28, 2012 at 8:39
  • I guess you edit the code above to show both videos and galleries and then change the query for your loop in tag.php to show only one or the other. I don't know what sort of conditional you would use in tag.php though. Sorry. Mar 29, 2012 at 7:07

OK, I have a partial answer to my own question.

I can use the following to output a list of taxonomy terms with links showing only the current post type:

$args = array( 'taxonomy' => 'country' );

$terms = get_terms('country', $args);

$count = count($terms); $i=0;

if ($count > 0) {
    $term_list = '<ul class="my_term-archive">';
    foreach ($terms as $term) {
        $term_list .= '<li><a href="/country/' . $term->slug . '/?post_type='.get_post_type( $post->ID ).'" title="' . sprintf('View all posts filed under %s', $term->name) . '">' . $term->name . '</a></li>';
    echo $term_list.'</ul>';

My remaining problem is that this still lists taxonomy terms that have no videos attached. E.g. maybe another post type has been given a 'country' tag of 'Canada'. Even if there are no 'videos' tagged with 'Canada', 'Canada' will still show up in this list.

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.