I have two filters on my page.
filter A
contains three fields. Markup below:
<form class="offers__form" role="search" action="<?php echo site_url('/search/'); ?>" method="get" id="searchform">
<fieldset class="offers__fieldset">
<select class="offers__select" name="wheel-base">
<option value="">Wheel base</option>
<option value="SWB">Short wheel base</option>
<option value="LWB">Long wheel base</option>
</select>
</fieldset>
<fieldset class="offers__fieldset">
<select class="offers__select" name="min-price">
<option value="">Min £ price</option>
<option value="5000">£5000</option>
<option value="10000">£10,000</option>
<option value="20000">£20,000</option>
<option value="30000">£30,000</option>
<option value="40000">£40,000</option>
</select>
</fieldset>
<fieldset class="offers__fieldset">
<select class="offers__select" name="max-price">
<option value="">Max £ price</option>
<option value="10000">£10,000</option>
<option value="20000">£20,000</option>
<option value="30000">£30,000</option>
<option value="40000">£40,000</option>
<option value="50000">£50,000</option>
</select>
</fieldset>
<fieldset class="offers__fieldset d-none">
<input type="hidden" name="p_type" value="campers" />
</fieldset>
<fieldset class="offers__fieldset">
<input class="offers__submit" type="submit" alt="Search" value="Search" />
</fieldset>
</form>
Filter B
has two fields. Markup below:
<form class="van__form" role="search" action="<?php echo site_url('/search/'); ?>" method="get" id="searchform">
<!-- van type -->
<fieldset class="van__fieldset van__type">
<select class="van__select" id="select_van_model" name="van-model">
<option value="">Van model</option>
<?php
if ( $range_query->have_posts() ) :
while ( $range_query->have_posts() ) : $range_query->the_post(); ?>
<option value="<?php the_title(); ?>">
<?php the_title(); ?>
</option>
<?php endwhile; wp_reset_postdata();
endif;
?>
</select>
</fieldset>
<!-- price range-->
<fieldset class="van__fieldset">
<select class="van__select" id="price_range" name="price-range">
<option value="0">£ Price range</option>
<option value="5000-10000">£5000 - £10,000</option>
<option value="10000-20000">£10,000 - £20,000</option>
<option value="20000-30000">£20,000 - £30,000</option>
<option value="30000-40000">£30,000 - £40,000</option>
<option value="40000-50000">£40,000 - £50,000</option>
</select>
</fieldset>
<fieldset class="van__fieldset d-none">
<input type="hidden" name="p_type" value="campers" />
</fieldset>
<!-- submit -->
<fieldset class="van__fieldset van__submit">
<input type="submit" value="Search" class="button button--search">
</fieldset>
</form>
Both of these form
s go to the /search
page on completion, where the results are displayed ini the URL. In WordPress pages, I have created a page called Search
which has the Search Page
template applied to it.
In the Search Page
template file (which is called template-search.php
), I have defined vars which get parameters from the URL and then defined meta queries
and tax queries
around this.
Here is a summary of where the data is pulling from:
wheel-base
is acustom taxonomy
I’ve created which is assigned to thecampers
post type.min-price
andmax-price
is pulling from anACF field
calledprice
.price
is of typenumber
.van-model
is aACF relationship
field (calledvan_range_type
). Each camper is assigned a model. The return format of this field isobject
.
A user doesn’t need to fill out all the fields in either filter A
or filter B
for results to show.
Let’s take Filter A
as an example. Since there’s three drop-downs, below are possible scenarios the user can go about to achieve results on the search page:
wheel-base
(works)wheel-base
andmin-price
(works)wheel-base
,min-price
andmax-price
(works)min-price
(works)max-price
(works)min-price
andmax-price
(works)
If a user fills out all wheel-base
,min-price
and max-price
fields, the URL will look something like this:
/search/?wheel-base=SWB&min-price=10000&max-price=40000&p_type=campers
So, the above filter works as intended. However, the issue comes into play when filter B
results are added to the URL. As mentioned, I have an ACF relationship
field called van_range_type
. When I select an option from the "Van model" drop-down, on my search page, I get undefined errors and no posts are returned (they do exist).
The undefined errors I get are:
Undefined offset
on the line$max_price = $price_range[1];
Undefined variable: wheel_base
– although don’t understand why, as I’m only setting the variable after checkingisset()
.Undefined variable: tax_query
on line'tax_query' => $tax_query,
Here is my template-search.php
file;
<?php
/*
* The template for displaying search results pages
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/#search-result
* Template Name: Search Page
*/
get_header();
/********************
* get data from url
********************/
if ( isset($_GET['wheel-base']) ){
$wheel_base = $_GET['wheel-base'];
}
if ( isset($_GET['min-price']) ){
$min_price = $_GET['min-price'];
}
if ( isset($_GET['max-price']) ){
$max_price = $_GET['max-price'];
}
if ( isset($_GET['van-model']) ){
$van_model = $_GET['van-model'];
}
if ( isset($_GET['price-range']) ){
$price_range = $_GET['price-range'];
$price_range = explode("-", $price_range);
$min_price = $price_range[0];
$max_price = $price_range[1];
}
if ( isset($_GET['p_type']) ){
$post_type= $_GET['p_type'];
}
/****************************
* configure queries based on
* return from url
****************************/
if ( isset($van_model) ){
$meta_query[] = array(
'key' => 'van_range_type',
'value' => '"' . $van_model . '"',
'compare' => '=',
);
}
// if both min and max price defined seperately
if ($min_price & $max_price){
$meta_query[] = array(
'key' => 'price',
'value' => [$min_price, $max_price],
'compare' => 'BETWEEN',
'type' => 'numeric',
);
}
// if only min price defined
if ($min_price){
$meta_query[] = array(
'key' => 'price',
'value' => $min_price,
'compare' => '>=',
'type' => 'numeric',
);
}
// if only max price defined
if ($max_price){
$meta_query[] = array(
'key' => 'price',
'value' => $max_price,
'compare' => '<=',
'type' => 'numeric',
);
}
if ($wheel_base){
$tax_query[] = array(
'taxonomy' => 'wheel_base',
'field' => 'slug',
'terms' => $wheel_base,
);
}
?>
<div class="searchResults">
<!-- results -->
<div class="searchResults__results">
<div class="container">
<div class="row">
<?php
global $post;
$args = [
'FIX_RANGE_QUERY' => true,
'post_type' => $post_type,
'post_status' => 'publish',
'orderby' => 'publish_date',
'order' => 'DESC',
'tax_query' => $tax_query,
'meta_query' => $meta_query
];
$query = new WP_Query( $args );
if($query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
echo the_title();
endwhile; wp_reset_postdata(); ?>
<?php else : ?>
<div class="searchResults__message">
<h2 class="searchResults__header display--2"><?php _e("No posts found"); ?></h2>
<p class="searchResults__standfirst">We couldn't find any results for your search query.</p>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php get_footer(); ?>
2
Answers
Without setting this up in an environment, this is hard to test. With that being said, here are some thoughts:
This may be caused in two instances. The first instance is if $_GET[‘price-range’] is passed an empty string the second is when $_GET[‘price-range’] = 0 (your default value).
You can add additional checking to handle these instances:
I suspect that the error you are getting is due to wheel-base not being a key of the $_GET array when you are attempting to check if has been defined. Your code above doesn’t show the wheel-base code in the filter form. Perhaps there is a typo?
I would use:
instead of:
seems to be because no value for wheel-base was passed, in which case, $tax_query is never created. You can define it as an empty array outside the scope of your if:
So I tried and tested your forms (filter A and filter B) and the Search Page template, and I noticed the following issues which some were already included in the question:
When I directly visited the Search page (at
example.com/search/
), i.e. without submitting either the filter A or filter B form, and there was also no query string in the current page URL, PHP threw these notices:Undefined variable: min_price
Undefined variable: max_price
Undefined variable: wheel_base
Undefined variable: tax_query
Undefined variable: meta_query
And it’s mainly because as I said, the current URL contained no query string/parameters (like
?wheel-base=SWB
), which means that$_GET
was an empty array. More specifically:PHP threw the first three notices because in your template, you defined the variables like so:
Which means, you are setting the variables only if the relevant GET/URL query parameter is set, e.g. the
$min_price
is set only if$_GET['min-price']
is set.So when it’s not set, then
$min_price
also didn’t get set which then caused PHP to throw the "undefined variable" notice when later on you tried to access the variable.And to avoid getting that notice, you should do something like
if ( isset( $min_price ) )
to ensure that the variable is set, or you could instead simply define the variable like so:$min_price = $_GET['min-price'] ?? 0;
.PHP threw the last two notices because:
$tax_query
is set only if$wheel_base
is set and not empty.$meta_query
is set only if$min_price
or$max_price
is set, and that they are not empty, or if$van_model
is set.So to avoid getting those notices, you could use
'tax_query' => $tax_query ?? []
and'meta_query' => $meta_query ?? []
in the$args
array, but a more proper way is define the variables before doing the$tax_query[] = ...
or$meta_query[] = ...
.When I submitted the filter A form without selecting any wheel base, PHP threw this notice:
$max_price = $price_range[1];
And that’s because the browser automatically selected the first option with
0
as the value (<option value="0">
) since there’s no option having theselected
attribute, and thus the$price_range
value was0
and soexplode("-", $price_range)
returned an array with only one item, which means$price_range[1]
didn’t exist, i.e. offset 1 was undefined.So just like the
$min_price
variable, you should ensure$price_range[1]
exists before attempting to use its value.Additional Issues and Fixes
ACF relationship field stores a list of (post/term) IDs in a serialized format like
a:2:{i:0;s:2:"35";i:1;s:2:"33";}
, so you should actually use'compare' => 'LIKE
in thevan_range_type
meta query clause.And because the relationship field stores an ID list, then in the filter B form, you should use
<option value="<?php the_ID(); ?>">
in the "Van model" dropdown.Apparently you made a typo here:
if ($min_price & $max_price)
— you should use&&
(logical AND) and not&
(bitwise AND).the_title()
by default echo the output, so do not doecho the_title();
.I’d change the
if ( isset($van_model) )
toif ( ! empty($van_model) )
to ensure that there’s a valid/non-empty van model before proceeding to adding the meta query clause.So I hope this answer helps you in understanding and fixing the issues in your code, and if you’re in a hurry, you can simply try my code — note that I posted it there because it would be much easier for you to compare the "before" and "after" code. 🙂 Happy coding!