skip to Main Content

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 forms 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 a custom taxonomy I’ve created which is assigned to the campers post type.
  • min-price and max-price is pulling from an ACF field called price. price is of type number.
  • van-model is a ACF relationship field (called van_range_type). Each camper is assigned a model. The return format of this field is object.

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:

  1. wheel-base (works)
  2. wheel-base and min-price (works)
  3. wheel-base,min-price and max-price (works)
  4. min-price (works)
  5. max-price (works)
  6. min-price and max-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 checking isset().
  • 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


  1. Without setting this up in an environment, this is hard to test. With that being said, here are some thoughts:

    Undefined offset on the line $max_price = $price_range[1];

    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:

    if ( isset($_GET['price-range']) ){
      $price_range = $_GET['price-range'];
      $price_range = explode("-", $price_range);
      if( count($price_range) > 1 ){
        $min_price = $price_range[0];
        $max_price = $price_range[1];
      }
    }
    

    Undefined variable: wheel_base – although don’t understand why, as I’m
    only setting the variable after checking isset().

    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:

     array_key_exists( 'wheel-base', $_GET )
    

    instead of:

    isset( $_GET['wheel-base']
    

    Undefined variable: tax_query on line ‘tax_query’ => $tax_query,

    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:

    $tax_query = array();    
    if ($wheel_base){
      $tax_query[] =  array(
        'taxonomy' => 'wheel_base',
        'field' => 'slug',
        'terms' => $wheel_base,
      );
    }
    
    Login or Signup to reply.
  2. 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:

    1. PHP threw the first three notices because in your template, you defined the variables like so:

      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'];
      }
      

      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;.

    2. 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:

    • Undefined offset: 1 on the line with the $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 the selected attribute, and thus the $price_range value was 0 and so explode("-", $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

    1. 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 the van_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.

    2. Apparently you made a typo here: if ($min_price & $max_price) — you should use && (logical AND) and not & (bitwise AND).

    3. the_title() by default echo the output, so do not do echo the_title();.

    4. I’d change the if ( isset($van_model) ) to if ( ! 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!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search