How to show a tag archive of one post type only

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.

Read More

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.

Related posts

Leave a Reply

3 comments

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

  2. 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 🙂

  3. 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) {
            $i++;
            $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.