Filtering custom post type on a combination of custom taxonomies and custom fields?

Best way to proceed is with ajax and a tax_query. Pre_get_posts filter only makes sense if you want to change the query on the template hierarchy, so the ‘standard’ taxonomy.php stuff.

This approach:

  1. make a page with that show the default list, so maybe ‘all’, just a simple post_type query. And a side menu with all your filters as links that can be clicked of course.

  2. make a php file that gets a specific term or terms through a tax_query, using $_GET, something like this:

    <?php
        define('WP_USE_THEMES', false);
        require_once('../../../wp-load.php');
        $gender = (isset($_GET['gender'])) ? $_GET['gender'] : 0;
        $args = array(
    'post_type' => 'artist',
    'tax_query' => array(
        array(
            'taxonomy' => 'artist_type',
            'field' => 'slug',
            'terms' => $gender
        )
    )
        );
        $tag_query = new WP_Query( $args );
        if ($tag_query->have_posts()) : while ($tag_query->have_posts()) :  $tag_query->the_post();
    

That’s just a starting example. Expand it with other variables through $_GET and check which ones are using in the url (?gender=male&voice=something).

Be sure this loop has the exact same html structure as you initially loaded stuff, so probably just a loop of item divs.

  1. Then use jquery to load the data in the file above, something like this:

    <script>
    jQuery(document).ready(function($) {
    var template_path = $('#template_path').html();
        $.querySort = {
        path_to_template: template_path,
        }
    
        $('.filter').click(function(){
    $(this).toggleClass('active');
            var term = $(this).attr('data-gender');
    var query = '?term=' + term;
        $('#data_wrapper').animate({opacity: 0}, function() {
            $('#data_wrapper').append('<div id="loader"></div>');  
            $("#data_wrapper").load($.querySort.path_to_template + '/ajax_load_terms.php' + query, function() {
                $('#loader').remove();
                $("#data_wrapper").animate({opacity: 1}, function() { });
            });
        });
        return false; //prevents a link from being clicked, if needed
    
    });
    </script>
    

See how it loads the file you just created, here ajax_load_terms.php. It adds the query to the url, and takes the term from the selector you click, which looks like this in my example:

    <a href="https://wordpress.stackexchange.com/questions/127978/javascript:void(0)" data-gender="[php echo your term here]">

Also note that the js needs to know the path to the ajax file, which it gets from a hidden div on you main page like this

    <div style="display: none" id="template_path"><?php bloginfo('template_url') ?></div>

I hope you get the direction and are able to figure out the holes in the code, if not give me a shout, it’s quite complicated by the looks of it, but it’s not really.

Good luck.