I am writing a plugin which creates a custom post type and two associated custom taxonomies. The custom post type list/archive page should be filterable by terms in one or both taxonomies i.e not just a filter by one taxonomy term. The filters should be displayed as two separate tag clouds.

Does anyone have experience of implementing this functionality and can recommend any suitable plugins?

1 Answer 1


You don't really need a pre-built plugin for this or you may create your own slim plugin. This is how I'd tackle the problem:

  1. You need the app to remember an already selected filter and pass all filter values every time you change your selection.
  2. Therefore your safest bet is to build a form with as many <select> boxes as the taxonomies you want to filter.
  3. You will populate those boxes with all your terms and then hide the form. The <option> values will be equal to the term's slugs.
  4. You will then generate a standard term cloud using wp_tag_cloud and hook it to the hidden <select> filters using JavaScript.
  5. Every time you click on the link in the cloud, you will change the appropriate <select> box filter and submit the form.
  6. When the form is submitted, you will fetch the filter settings from $_GET and query and filter the posts using new WP_Query.
  7. You will display the queried posts. Easy!

Following is an example implementation. You can list as many taxonomies you want. Make sure you have jQuery loaded before trying to use it:

    // List all taxonomies you want to bind
    $taxonomies = array( 'genre', 'writer' );

    // Creates the supplementary $genres_list, $writers_list, ... taxonomies holding all their terms
    foreach( $taxonomies as $taxonomy )
        ${$taxonomy . 's_list'} = get_terms( $taxonomy, array() );

<!-- Create the hidden <select>s that will filter our data -->
<form method="GET" id="filter-manager">

    <?php foreach( $taxonomies as $taxonomy ): ?>
        <select id="<?= $taxonomy ?>_filter" name="<?= $taxonomy ?>_filter">
            <option value="">(none)</option>
        <?php foreach( ${$taxonomy . 's_list'} as $taxonomy_object ): ?>
            <?php $selected = ( isset( $_GET[$taxonomy . '_filter'] ) && $_GET[$taxonomy . '_filter'] === $taxonomy_object->slug ) ? ' selected="selected"' : ''; ?>
            <option value="<?= $taxonomy_object->slug ?>"<?= $selected ?>><?= $taxonomy_object->name ?></option>
        <?php endforeach; ?>
    <?php endforeach; ?>


    // Display the tag clouds for all taxonomies
    foreach( $taxonomies as $taxonomy ) {
        $cloud = wp_tag_cloud( array( 'taxonomy' => $taxonomy, 'echo' => false ) );

        // Add the taxonomy data to each link
        $cloud = preg_replace( '~>([^<]+)<~U', ' data-taxonomy="' . $taxonomy . '">$1<', $cloud );

        echo $cloud;


    (function($) {
        // Hide the filter manager
        $form = $('#filter-manager');
        $form.find('select').on('change', function() {

        // Pass the cloud clicks to the appropriate filter manager
        $('a[class*="tag-link"]').on('click', function(e) {
            var taxonomy = $(this).data('taxonomy');
            var $link = $(this);
            $form.find('select#' + taxonomy + '_filter option').filter( function() {
                return ( $(this).text() == $link.text() );
            }).prop('selected', true);
            $form.find('select#' + taxonomy + '_filter option').trigger('change');



    // Construct WP_Query args, change as you see fit
    $args = array(
        'post_type' => 'post',
        'posts_per_page' => -1

    // Creates the WP_Query that filters only the posts we want
    foreach( $taxonomies as $taxonomy )
        if ( isset( $_GET[$taxonomy . '_filter'] ) and (bool) $_GET[$taxonomy . '_filter'] === true )
            $args = array_merge( $args, array( $taxonomy => $_GET[$taxonomy . '_filter'] ) );

    $filtered_posts = new WP_Query( $args );

    // List filtered posts
    while( $filtered_posts->have_posts() ): $filtered_posts->the_post();
    <div class="post">
            echo '<h2>' . get_the_title() . '</h2>';

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.