I've been working with this tutorial that adds taxonomy filters to archive.php and it works, but the output is a new WP query that echoes post titles. How can modify the function so instead of creating a new query it would apply to the main query? Is there a filter for this? I know about pre_get_posts but since this uses ajax i'm not sure how to put it together.
Html form on archive.php
<form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php" method="POST" id="filter">
<?php
if( $terms = get_terms( array( 'taxonomy' => 'genre', 'orderby' => 'name' ) ) ) :
echo '<select name="genrefilter"><option value="">Select category...</option>';
foreach ( $terms as $term ) :
echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
endforeach;
echo '</select>';
endif;
?>
<?php
if( $terms = get_terms( array( 'taxonomy' => 'language', 'orderby' => 'name' ) ) ) :
echo '<select name="languagefilter"><option value="">Select category...</option>';
foreach ( $terms as $term ) :
echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
endforeach;
echo '</select>';
endif;
?>
<input type="text" name="price_min" placeholder="Min price" />
<input type="text" name="price_max" placeholder="Max price" />
<label>
<input type="radio" name="date" value="ASC" checked="checked" /> Date: Ascending
</label>
<label>
<input type="radio" name="date" value="DESC" selected="selected" /> Date: Descending
</label>
<label>
<input type="checkbox" name="featured_image" /> Only posts with featured images
</label>
<button>Apply filter</button>
<input type="hidden" name="action" value="myfilter">
<input type="hidden" name="post_type" value="<?php echo get_post_type();?>">
</form>
<div id="response"></div>
<script>
jQuery(function($){
$('#filter').submit(function(){
var filter = $('#filter');
$.ajax({
url:filter.attr('action'),
data:filter.serialize(), // form data
type:filter.attr('method'), // POST
beforeSend:function(xhr){
filter.find('button').text('Processing...'); // changing the button label
},
success:function(data){
filter.find('button').text('Apply filter'); // changing the button label back
$('#response').html(data); // insert data
}
});
return false;
});
});
</script>
functions.php
add_action('wp_ajax_myfilter', 'misha_filter_function'); // wp_ajax_{ACTION HERE}
add_action('wp_ajax_nopriv_myfilter', 'misha_filter_function');
function misha_filter_function(){
$args = array(
'post_type' => $_POST['post_type'],
'orderby' => 'date', // we will sort posts by date
'order' => $_POST['date'] // ASC or DESC
);
// for taxonomies / categories
if( isset( $_POST['genrefilter'] ) && isset( $_POST['languagefilter'] ) ) {
$args['tax_query'] = array(
'relation' => 'AND',
array(
'taxonomy' => 'genre',
'field' => 'id',
'terms' => $_POST['genrefilter']
),
array(
'taxonomy' => 'language',
'field' => 'id',
'terms' => $_POST['languagefilter']
),
);
}
// create $args['meta_query'] array if one of the following fields is filled
if( isset( $_POST['price_min'] ) && $_POST['price_min'] || isset( $_POST['price_max'] ) && $_POST['price_max'] || isset( $_POST['featured_image'] ) && $_POST['featured_image'] == 'on' )
$args['meta_query'] = array( 'relation'=>'AND' ); // AND means that all conditions of meta_query should be true
// if both minimum price and maximum price are specified we will use BETWEEN comparison
if( isset( $_POST['price_min'] ) && $_POST['price_min'] && isset( $_POST['price_max'] ) && $_POST['price_max'] ) {
$args['meta_query'][] = array(
'key' => '_price',
'value' => array( $_POST['price_min'], $_POST['price_max'] ),
'type' => 'numeric',
'compare' => 'between'
);
} else {
// if only min price is set
if( isset( $_POST['price_min'] ) && $_POST['price_min'] )
$args['meta_query'][] = array(
'key' => '_price',
'value' => $_POST['price_min'],
'type' => 'numeric',
'compare' => '>'
);
// if only max price is set
if( isset( $_POST['price_max'] ) && $_POST['price_max'] )
$args['meta_query'][] = array(
'key' => '_price',
'value' => $_POST['price_max'],
'type' => 'numeric',
'compare' => '<'
);
}
// if post thumbnail is set
if( isset( $_POST['featured_image'] ) && $_POST['featured_image'] == 'on' )
$args['meta_query'][] = array(
'key' => '_thumbnail_id',
'compare' => 'EXISTS'
);
// if you want to use multiple checkboxed, just duplicate the above 5 lines for each checkbox
$query = new WP_Query( $args );
if( $query->have_posts() ) :
while( $query->have_posts() ): $query->the_post();
echo '<h2>' . $query->post->post_title . '</h2>';
endwhile;
wp_reset_postdata();
else :
echo 'No posts found';
endif;
die();
}
I've been working with this tutorial that adds taxonomy filters to archive.php and it works, but the output is a new WP query that echoes post titles. How can modify the function so instead of creating a new query it would apply to the main query? Is there a filter for this? I know about pre_get_posts but since this uses ajax i'm not sure how to put it together.
Html form on archive.php
<form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php" method="POST" id="filter">
<?php
if( $terms = get_terms( array( 'taxonomy' => 'genre', 'orderby' => 'name' ) ) ) :
echo '<select name="genrefilter"><option value="">Select category...</option>';
foreach ( $terms as $term ) :
echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
endforeach;
echo '</select>';
endif;
?>
<?php
if( $terms = get_terms( array( 'taxonomy' => 'language', 'orderby' => 'name' ) ) ) :
echo '<select name="languagefilter"><option value="">Select category...</option>';
foreach ( $terms as $term ) :
echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
endforeach;
echo '</select>';
endif;
?>
<input type="text" name="price_min" placeholder="Min price" />
<input type="text" name="price_max" placeholder="Max price" />
<label>
<input type="radio" name="date" value="ASC" checked="checked" /> Date: Ascending
</label>
<label>
<input type="radio" name="date" value="DESC" selected="selected" /> Date: Descending
</label>
<label>
<input type="checkbox" name="featured_image" /> Only posts with featured images
</label>
<button>Apply filter</button>
<input type="hidden" name="action" value="myfilter">
<input type="hidden" name="post_type" value="<?php echo get_post_type();?>">
</form>
<div id="response"></div>
<script>
jQuery(function($){
$('#filter').submit(function(){
var filter = $('#filter');
$.ajax({
url:filter.attr('action'),
data:filter.serialize(), // form data
type:filter.attr('method'), // POST
beforeSend:function(xhr){
filter.find('button').text('Processing...'); // changing the button label
},
success:function(data){
filter.find('button').text('Apply filter'); // changing the button label back
$('#response').html(data); // insert data
}
});
return false;
});
});
</script>
functions.php
add_action('wp_ajax_myfilter', 'misha_filter_function'); // wp_ajax_{ACTION HERE}
add_action('wp_ajax_nopriv_myfilter', 'misha_filter_function');
function misha_filter_function(){
$args = array(
'post_type' => $_POST['post_type'],
'orderby' => 'date', // we will sort posts by date
'order' => $_POST['date'] // ASC or DESC
);
// for taxonomies / categories
if( isset( $_POST['genrefilter'] ) && isset( $_POST['languagefilter'] ) ) {
$args['tax_query'] = array(
'relation' => 'AND',
array(
'taxonomy' => 'genre',
'field' => 'id',
'terms' => $_POST['genrefilter']
),
array(
'taxonomy' => 'language',
'field' => 'id',
'terms' => $_POST['languagefilter']
),
);
}
// create $args['meta_query'] array if one of the following fields is filled
if( isset( $_POST['price_min'] ) && $_POST['price_min'] || isset( $_POST['price_max'] ) && $_POST['price_max'] || isset( $_POST['featured_image'] ) && $_POST['featured_image'] == 'on' )
$args['meta_query'] = array( 'relation'=>'AND' ); // AND means that all conditions of meta_query should be true
// if both minimum price and maximum price are specified we will use BETWEEN comparison
if( isset( $_POST['price_min'] ) && $_POST['price_min'] && isset( $_POST['price_max'] ) && $_POST['price_max'] ) {
$args['meta_query'][] = array(
'key' => '_price',
'value' => array( $_POST['price_min'], $_POST['price_max'] ),
'type' => 'numeric',
'compare' => 'between'
);
} else {
// if only min price is set
if( isset( $_POST['price_min'] ) && $_POST['price_min'] )
$args['meta_query'][] = array(
'key' => '_price',
'value' => $_POST['price_min'],
'type' => 'numeric',
'compare' => '>'
);
// if only max price is set
if( isset( $_POST['price_max'] ) && $_POST['price_max'] )
$args['meta_query'][] = array(
'key' => '_price',
'value' => $_POST['price_max'],
'type' => 'numeric',
'compare' => '<'
);
}
// if post thumbnail is set
if( isset( $_POST['featured_image'] ) && $_POST['featured_image'] == 'on' )
$args['meta_query'][] = array(
'key' => '_thumbnail_id',
'compare' => 'EXISTS'
);
// if you want to use multiple checkboxed, just duplicate the above 5 lines for each checkbox
$query = new WP_Query( $args );
if( $query->have_posts() ) :
while( $query->have_posts() ): $query->the_post();
echo '<h2>' . $query->post->post_title . '</h2>';
endwhile;
wp_reset_postdata();
else :
echo 'No posts found';
endif;
die();
}
You can't modify main query if you're doing AJAX, because during AJAX requests there is no main query created at all.
On the other hand, doing this search form using AJAX isn't the best idea - you can't get URL for filtered list for example.
So I would remove the AJAX part and do it like so:
<form action="" method="GET" id="filter">
<?php
if( $terms = get_terms( array( 'taxonomy' => 'genre', 'orderby' => 'name' ) ) ) :
echo '<select name="genrefilter"><option value="">Select category...</option>';
foreach ( $terms as $term ) :
echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
endforeach;
echo '</select>';
endif;
?>
<?php
if( $terms = get_terms( array( 'taxonomy' => 'language', 'orderby' => 'name' ) ) ) :
echo '<select name="languagefilter"><option value="">Select category...</option>';
foreach ( $terms as $term ) :
echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
endforeach;
echo '</select>';
endif;
?>
<input type="text" name="price_min" placeholder="Min price" />
<input type="text" name="price_max" placeholder="Max price" />
<label>
<input type="radio" name="date" value="ASC" checked="checked" /> Date: Ascending
</label>
<label>
<input type="radio" name="date" value="DESC" selected="selected" /> Date: Descending
</label>
<label>
<input type="checkbox" name="featured_image" /> Only posts with featured images
</label>
<button>Apply filter</button>
<input type="hidden" name="action" value="myfilter">
<input type="hidden" name="post_type" value="<?php echo get_post_type();?>">
</form>
<div id="response">
<?php
if ( have_posts() ) :
while( have_posts() ): the_post();
echo '<h2>' . get_the_title() . '</h2>';
endwhile;
else :
echo 'No posts found';
endif;
?>
</div>
And in your functions.php
add_action( 'pre_get_posts', function ( $query ) {
if ( ! is_admin() && is_archive() && $query->is_main_query() ) {
// modify the $query according to your needs
if ( isset( $_GET['genrefilter'] ) && isset( $_GET['languagefilter'] ) ) {
$query->set( 'tax_query', array(
'relation' => 'AND',
array(
'taxonomy' => 'genre',
'field' => 'term_id',
'terms' => $_GET['genrefilter']
),
array(
'taxonomy' => 'language',
'field' => 'term_id',
'terms' => $_GET['languagefilter']
),
) );
}
}
// put your other filters here
} );
PS. You shouldn't use <?php echo site_url() ?>/wp-admin/admin-ajax.php
. It should be <?php echo esc_attr( admin_url( 'admin-ajax.php' ) ); ?>