Support

Account

Home Forums ACF PRO Custom field filter updates URL but no filtering of posts?

Solving

Custom field filter updates URL but no filtering of posts?

  • Hello and thanks for taking a look at this question.

    I have been referring to this tutorial and code and having no luck.

    I have a custom post type (gallery) which I need to allow site users to filter by several custom field values. So far I’m just trying to get one filter to work when entering URL directly in the browser. At one point I had the checkboxes working for a single value on the page (not sure how), but it never has worked for more than one filter or more than one value within a single field, and now it’s not working at all.

    Though the URL updates properly, no filtering happens on the archive-gallery page. I’ve tried using the code in the tutorial, and the code attached below (they are different). I’ve tried changing the field I’m testing to a radio button instead of a checkbox, also with no success. I’ve also added $meta_query = [];” before “$meta_query = array(…” in the functions.php code below, otherwise I get a fatal error message when I try to filter anything.

    Any help much appreciated!!

    Here are all the specifics as I have them right now, just testing a single custom field :

    Field key: field_6174a76da315c
    Field name: type_of_art
    Field type: radio button
    Choices:
    visual : Visual
    literary : Literary
    performing : Performing
    other : Other

    in mu-plugins I have set up the custom post type:

    // Gallery post type
    	register_post_type('gallery', array(
    		'show_in_rest' => true,
     		'capability_type' => array('gallery item', 'gallery'),
    		'map_meta_cap' => true,
            'supports' => array('title', 'editor', 'excerpt', 'thumbnail', 'revisions', 'custom-fields', 'author'),
            'rewrite' => array('slug' => 'gallery'),
    		'has_archive' => true,
            'public' => true,
    		'taxonomies'  => array( 'post_tag', 'category' ),
    		'publicly_queryable' => true,
    		'labels' => array(
    			'name' => 'Gallery',
                'add_new_item' => 'Add New Gallery Item',
                'edit_item' => 'Edit Gallery Item',
                'all_items' => 'Gallery',
    			'singular_name' => 'Gallery Item',
    			'show_in_rest' => true,
    			'exclude_from_search' => false,
    		),
    			'menu_icon' => 'dashicons-art'
    	));

    in functions.php I have this:

    // array of filters (field key => field name)
            $GLOBALS['my_query_filters'] = array( 
                 'field_6174a76da315c' => 'type_of_art'
                 // 'field_618edb3358d2c' => 'filter_test',
    
        
            );
    
            // action
            add_action('pre_get_posts', 'my_pre_get_posts', 10, 1);
    
            function my_pre_get_posts( $query ) {
                
                // bail early if is in admin
                if( is_admin() ) return;
                
                
                // bail early if not main query
                // - allows custom code / plugins to continue working
                if( !$query->is_main_query() ) return;
                
                
                // get meta query
                $meta_query = $query->get('meta_query');
    
                
                // loop over filters
                foreach( $GLOBALS['my_query_filters'] as $key => $name ) {
                    
                    // continue if not found in url
                    if( empty($_GET[ $name ]) ) {
                        
                        continue;
                        
                    }
                    
                    
                    // get the value for this filter
                    // eg: http://www.website.com/events?city=melbourne,sydney
                    $value = explode(',', $_GET[ $name ]);
                    
                    
                    // append meta query
                    $meta_query = [];
                    $meta_query[] = array(
                        'key'       => $name,
                        'value'     => $value,
                        'compare'   => 'IN',
                    );
                    
                } 
                
                
                // update meta query
                $query->set('meta_query', $meta_query);

    And in my archive-gallery.php template file I have:

    <div id="archive-filters">
        <?php foreach( $GLOBALS['my_query_filters'] as $key => $name ): 
            
            // get the field's settings without attempting to load a value
            $field = get_field_object($key, false, false);
            
            
            // set value if available
            if( isset($_GET[ $name ]) ) {
                
                $field['value'] = explode(',', $_GET[ $name ]);
                
            }
            
            
            // create filter
            ?>
            <div class="filter" data-filter="<?php echo $name; ?>">
                <?php create_field( $field ); ?>
            </div>
            
        <?php endforeach; ?>
        </div>
    
        <script type="text/javascript">
        (function($) {
            
            // change
            $('#archive-filters').on('change', 'input[type="checkbox"]', function(){
    
                // vars
                var url = '<?php echo home_url('gallery'); ?>';
                    args = {};
                    
                
                // loop over filters
                $('#archive-filters .filter').each(function(){
                    
                    // vars
                    var filter = $(this).data('filter'),
                        vals = [];
                    
                    
                    // find checked inputs
                    $(this).find('input:checked').each(function(){
            
                        vals.push( $(this).val() );
            
                    });
                    
                    
                    // append to args
                    args[ filter ] = vals.join(',');
                    
                });
                
                
                // update url
                url += '?';
                
                
                // loop over args
                $.each(args, function( name, value ){
                    
                    url += name + '=' + value + '&';
                    
                });
                
                
                // remove last &
                url = url.slice(0, -1);
                
                
                // reload page
                window.location.replace( url );
                
    
            });
    
        })(jQuery);
        </script>
    
    </div>

    Debug shows no errors with this code. When I put
    localsite/gallery/?type_of_art=visual” in the browser, the archive page shows up with no posts filtered out.

  • I just reread my post and don’t see a way to edit it, so a quick clarification:

    When I said “I’ve tried using the code in the tutorial, and the code attached below (they are different).” I was referring to the code in the tutorial video and in the snippets attached below that; both from the page I linked to in my post.

  • Hi @amyk

    I’ve done something similar but used AJAX. I used taxonomies as checkboxes but you may be able to adjust to suit your needs.

    I had this in my template:

    
    <section class="collapse" id="filters">
    	<div class="container">
    		<div class="row">
    			<div class="col-12 col-md-3 pb-4">
    			<?php
                $brand = array(
                    'taxonomy'		=> 'brand',
                );
                $brands = get_categories( $brand );
                ?>
                <?php foreach($brands as $brand): ?>
                <div class="form-check">            
                    <label class=""><input type="checkbox" value="<?php echo $brand->term_id; ?>" class="form-check-input  brand" /><?php echo $brand->cat_name; ?></label>             
                    
                </div>
                <?php endforeach; ?>
                <a href="#" class="btn btn-outline-secondary d-block mx-auto" id="reset_brand">Reset Brands</a>  
    			</div><!-- /col-md-3 --> 
                
    			<div class="col-12 col-md-3 pb-4" id="checkboxes">
    			<?php
                $colour = array(
                    'taxonomy'		=> 'colour',
                );
                $colours = get_categories( $colour );
                ?>
                <?php foreach($colours as $colour): ?>
                <div class="form-check">              
                    <label class=""><input type="checkbox" value="<?php echo $colour->term_id; ?>" class="form-check-input  colour" /><?php echo $colour->cat_name; ?></label>                
                </div>
                <?php endforeach; ?>      
                <a href="#" class="btn btn-outline-secondary d-block mx-auto" id="reset_colour">Reset Colours</a>     
    			</div><!-- /col-md-3 -->  
                
    			<div class="col-12 col-md-3 pb-4">
    			<?php
                $finish = array(
                    'taxonomy'		=> 'finish',
                );
                $finishes = get_categories( $finish );
                ?>
                <?php foreach($finishes as $finish): ?>
                <div class="form-check">
                	<!--
                    <input type="checkbox" value="<?php echo $finish->term_id; ?>" class="form-check-input finish" />
                    <label class="form-check-label" for="<?php echo $finish->cat_name; ?>"><?php echo $finish->cat_name; ?></label>
                    -->                
                    <label class=""><input type="checkbox" value="<?php echo $finish->term_id; ?>" class="form-check-input  finish" /><?php echo $finish->cat_name; ?></label>                 
                </div>
                <?php endforeach; ?>
                <a href="#" class="btn btn-outline-secondary d-block mx-auto" id="reset_finish">Reset Finish</a>
    			</div><!-- /col-md-3 -->  
                
    			<div class="col-12 col-md-3 pb-4">
    			<?php
                $style = array(
                    'taxonomy'		=> 'style',
                );
                $styles = get_categories( $style );
                ?>
                <?php foreach($styles as $style): ?>
                <div class="form-check">              
                    <label class=""><input type="checkbox" value="<?php echo $style->term_id; ?>" class="form-check-input  style" /><?php echo $style->cat_name; ?></label>                  
                </div>
                <?php endforeach; ?>
                <a href="#" class="btn btn-outline-secondary d-block mx-auto" id="reset_style">Reset Style</a>
    			</div><!-- /col-md-3 -->                                                
    		</div><!-- /row -->
    	</div><!-- /container -->	   
    </section>   
    
    <section>
    	<div class="container-fluid pb-4">
    		<div class="row">
    			<div class="col-md-12">
    
    				<a class="float-right btn btn-outline-dark mb-3" data-toggle="collapse" href="#filters" role="button" aria-expanded="false" aria-controls="filters">Filter Kitchens <i class="far fa-caret-square-down"></i></a>
    
    			</div><!-- /col-md-12 -->														
    		</div><!-- /row -->    
    		<div class="row align-self-center" id="ajax_filter_kitchens">	
                
    			<?php      
                $args = array(
                    'post_type'			=> 'kitchens',
                    'posts_per_page'	=> -1,
                );
            
                $query = new WP_Query( $args );
                if( $query->have_posts() ) :
                    while( $query->have_posts() ): $query->the_post();
                        include __DIR__ . '/includes/loop-alt.php';
                    endwhile;
                    wp_reset_postdata();
                else :
                    echo 'No kitchens found matching your criteria.';
                endif;
                ?>
    		           
    		</div><!-- /row -->
    	</div><!-- /container -->	
    </section>    

    I didn’t want the default look of checkboxes, so added some CSS:

    /*** filter checkboxes ***/
    #filters label {
    	border:1px solid #ccc;
    	padding:10px;
    	margin:0 0 10px;
    	display:block; 
    }
    
    #filters label:hover {
    	background:#eee;
    	cursor:pointer;
    }
    #filters .form-check-input {
    	margin-left: 0;
    }
    #filters input[type=checkbox]{
    	opacity: 0;
    }
    #filters input[type="checkbox"]:checked label  {
    	background:#f00;
    }
    .selected {
    	background:#eee
    }
    .form-check {
        padding-left: 0;
    }

    In the footer or enqueue the script, I then had the following:

    
    <script type="text/javascript">
    //filter the kitchens
    jQuery(function($){
        filter_data();
    
        function filter_data()
        {
            $('.filter_data').html('<div id="loading" style="" ></div>');
            var action = 'filter_kitchens';		
    		
            var brand = get_filter('brand');
            var colour = get_filter('colour');
            var finish = get_filter('finish');
    		var style = get_filter('style');	
    		
    		$.ajax({
    			type        : "POST",
    			data		: { action:action, brand:brand, colour:colour, finish:finish, style:style},
    			dataType	: "html",
    			url			: '<?php echo admin_url('admin-ajax.php');?>', 
    
    			success     : function(data) {
    				//alert(this.data);
    				jQuery("#ajax_filter_kitchens").html(data);
    				console.log("action:" + action + " brand: " + brand + " colour: " + colour + " finish: " + finish + " style: " + style); //debug
    			},
    			error       : function(xhr, status, error) {
    				var err = eval("(" + xhr.responseText + ")");
    				alert(err.Message);
    			}
    		});
    		return false;
        }
    
        function get_filter(class_name)
        {
            var filter = [];
            $('.'+class_name+':checked').each(function(){
                filter.push($(this).val());
            });
            return filter;
        }
    
        $('.form-check-input').click(function(){
            filter_data();
        });
    	
    	$("#reset_brand").click(function(){
    		// get the current selected values
    		var brand = [];
    		$('.brand:checked').each(function(){
    			brand.push($(this).val());
    		});
    		
    		// loop through and remove the selected checkobox
    		var i;
    		for (i = 0; i < brand.length; i++) {
    			$(".brand:checkbox[value="+brand[i]+"]").parent().removeClass('selected'); //remove the highlighted lable
    			$(".brand:checkbox[value="+brand[i]+"]").prop("checked", false); //uncheck the hidden checkbox
    		}		
    		
    		// reset the array
    		brand = []; 
    		console.log(brand); //debug
    	
    		// update the filter
    	 	filter_data();			  
    	});	
    	
    	$("#reset_colour").click(function(){
    		// get the current selected values
    		var colour = [];
    		$('.colour:checked').each(function(){
    			colour.push($(this).val());
    		});
    		
    		// loop through and remove the selected checkobox
    		var i;
    		for (i = 0; i < colour.length; i++) {
    			$(".colour:checkbox[value="+colour[i]+"]").parent().removeClass('selected'); //remove the highlighted lable
    			$(".colour:checkbox[value="+colour[i]+"]").prop("checked", false); //uncheck the hidden checkbox
    		}		
    		
    		// reset the array
    		colour = []; 
    		console.log(colour); //debug
    	
    		// update the filter
    	 	filter_data();			  
    	});	
    	
    	$("#reset_finish").click(function(){
    		// get the current selected values
    		var finish = [];
    		$('.finish:checked').each(function(){
    			finish.push($(this).val());
    		});
    		
    		// loop through and remove the selected checkobox
    		var i;
    		for (i = 0; i < finish.length; i++) {
    			$(".finish:checkbox[value="+finish[i]+"]").parent().removeClass('selected'); //remove the highlighted lable
    			$(".finish:checkbox[value="+finish[i]+"]").prop("checked", false); //uncheck the hidden checkbox
    		}		
    		
    		// reset the array
    		finish = []; 
    		console.log(finish); //debug
    	
    		// update the filter
    	 	filter_data();			  
    	});		
    	
    	$("#reset_style").click(function(){
    		// get the current selected values
    		var style = [];
    		$('.style:checked').each(function(){
    			style.push($(this).val());
    		});
    		
    		// loop through and remove the selected checkobox
    		var i;
    		for (i = 0; i < style.length; i++) {
    			$(".style:checkbox[value="+style[i]+"]").parent().removeClass('selected'); //remove the highlighted lable
    			$(".style:checkbox[value="+style[i]+"]").prop("checked", false); //uncheck the hidden checkbox
    		}		
    		
    		// reset the array
    		style = []; 
    		console.log(style); //debug
    	
    		// update the filter
    	 	filter_data();			  
    	});		
    	
    	
    });
    </script>

    Finally, in my functions:

    
    ##########################
    # Ajax filter Kitchens
    ##########################
    function filter_kitchens() {
    	
    	$args = array(
    		'post_type'			=> 'kitchens',
    		'posts_per_page'	=> -1,
    	);
    
    	if( isset( $_POST['brand'] ) )
    		$args['tax_query'] = array(
    			array(
    				'taxonomy' => 'brand',
    				'field' => 'id',
    				'terms' => $_POST['brand']
    			)
    		);
    		
    	if( isset( $_POST['colour'] ) )
    		$args['tax_query'] = array(
    			array(
    				'taxonomy' => 'colour',
    				'field' => 'id',
    				'terms' => $_POST['colour']
    			)
    		);	
    		
    	if( isset( $_POST['finish'] ) )
    		$args['tax_query'] = array(
    			array(
    				'taxonomy' => 'finish',
    				'field' => 'id',
    				'terms' => $_POST['finish']
    			)
    		);
    		
    	if( isset( $_POST['style'] ) )
    		$args['tax_query'] = array(
    			array(
    				'taxonomy' => 'style',
    				'field' => 'id',
    				'terms' => $_POST['style']
    			)
    		);			
    
    	$query = new WP_Query( $args );
    	if( $query->have_posts() ) :
    		while( $query->have_posts() ): $query->the_post();
    			if(get_template_part('includes/loop-alt')): get_template_part('includes/loop-alt'); endif;
    		endwhile;
    		wp_reset_postdata();
    	else :
    		echo 'No kitchens found matching your criteria.';
    	endif;
    	
    	die();
    
    }
    // Fire AJAX action for both logged in and non-logged in users
    add_action('wp_ajax_filter_kitchens', 'filter_kitchens');
    add_action('wp_ajax_nopriv_filter_kitchens', 'filter_kitchens');

    May be way more than you need but you might be able to tailor to your needs.

  • Thanks Jarvis, I appreciate that you took the time to reply in detail. This is very interesting. I think I could learn a lot studying your code. Yesterday I moved on to trying a plugin (Search & Filter Pro) which also uses Ajax. I’m having some issues with it (it works fine on my local site but so far no luck on the live) so I may be back to trying to do it on my own if I can’t find a resolution. For now I’ll leave this open just in case…

Viewing 4 posts - 1 through 4 (of 4 total)

You must be logged in to reply to this topic.