Multiple tag cloud filtering

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?

Related posts

1 comment

  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:

    <?php
        // 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; ?>
            </select>
        <?php endforeach; ?>
    
    </form>
    
    <?php
        // 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;
        }
    ?>
    
    <script>
    
        (function($) {
            // Hide the filter manager
            $form = $('#filter-manager');
            $form.find('select').on('change', function() {
                $form.submit();
            }).hide();
    
            // Pass the cloud clicks to the appropriate filter manager
            $('a[class*="tag-link"]').on('click', function(e) {
                e.preventDefault();
                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');
            });
        })(jQuery);
    
    </script>
    
    <?php
    
        // 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">
            <?php
                echo '<h2>' . get_the_title() . '</h2>';
                the_content();
            ?>
        </div>
    <?php
        endwhile;
    

Comments are closed.