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…
You must be logged in to reply to this topic.
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Cookie Policy. If you continue to use this site, you consent to our use of cookies.