Advanced Custom Fields combined with Ultimate WP Query Search Filter

This plugin hasn’t been updated in a long time. Use it at your own risk.

If you’re like me, you love Advanced Custom Fields, for which I use the Pro version. I use it 99% of my projects because it’s just one of the best plugins to create custom meta fields for all sorts of post types and terms.

Another nice plugin is Ultimate WP Query Search Filter which allows you to easily create search forms with all types of meta/taxonomy queries. It works smooth out of the box, except for one thing, which was the core of my issue.

The issue

Searching in an ACF checkbox field with UWPQSF is impossible by default due to the fact that ACF stores its values in associative arrays, which UWPQSF doesn’t like since it assumes single values are used/stored.

The solution

Since UWPQSF can only search in single values out of the box, we need to reformat the search query so it accepts an array of values.

This solution works for me and is a tailored to my project, but it gives you a very good jumping off point if you want to achieve the same with different values/fields.

Introduction

For this explanation I use a ‘model site’ featuring profiles from models. You can search for city, sex, age and what kind of services they provide (hand model, swim suit model, fetish model, etc) where services are the checkboxes.

I use the ACF front-end form to let users submit a post (which is the profile). This post has an ACF called sex which is a taxonomy, which needed to have a condition logic option. ACF doesn’t offer this default so I created a custom option which enables this. This is explained in this support topic.

Since my taxonomy is now a meta field, the tax query is not used in my function below.

Steps to take

  1. prepare the UWPQSF search form
  2. create a function to override the search form
  3. retrieve the used search query before it’s executed
  4. place the meta_query in variables (optional)
  5. check if a checkbox is used in the search query and how often
  6. if more than 1 box is checked, we need to alter the query to accept more than 1 value
  7. get all the search values we don’t need to override (optional)
  8. get posts with new query
  9. feed our new parameters back into the search query

1. prepare the search form

For this example I use a form with 4 different meta fields, of which the first three are dropdowns and the last one is a checkbox. You can add the dropdowns like you’re used to. The checkbox is a bit special.

UWPQSF comes with a ‘general value’ option, which lets you create values for all custom values which are used by posts. If you generate the values with an ACF checkbox field, the results looks something like this:

  1. a:1:{i:0;s:6:"the_value";}::a:1:{i:0;s:6:"the_value";}

But there is a way around it. Go to your ACF settings for this specific field. Copy all the values from ACF and copy it to a text file. You now have a list something like

  1. value 1
  2. value 2
  3. value 3
  4. etc.

Reformat that list so it looks like this:

  1. value 1::value 1 | value 2::value 2 | value 3::value 3

Insert that line of code into the field where the generated values are placed. Then add the field.

2. create a function to override the search form

We start by adding the following code to functions.php. This is the default function to display any search results. With this in our functions.php we can now safely override the display of the search results but also manipulate the query which is used to search which results are shown.

  1. function customize_output($results, $arg, $id, $getdata ) {
  2.     $apiclass   = new uwpqsfprocess();
  3.     $query      = new WP_Query( $arg );
  4.     ob_start();
  5.     $result     = '';
  6.  
  7.     // The Loop
  8.     if ( $query->have_posts() ) {
  9.         while ( $query->have_posts() ) {
  10.             $query->the_post();
  11.             global $post;
  12.             //blah blah blah
  13.         }
  14.         echo  $apiclass->ajax_pagination($arg['paged'],$query->max_num_pages, 4, $id, $getdata);
  15.     } else {
  16.         echo 'no posts found';
  17.     }
  18.  
  19.     /* Restore original Post Data */
  20.     wp_reset_postdata();
  21.     $results = ob_get_clean();      
  22.     return $results;
  23. }
  24. add_filter('uwpqsf_result_tempt', 'customize_output', '', 4);

3. retrieve the search query before it’s executed

To retrieve the search query which is used we var_dump() the $arg variable which contains the search query, followed by an exit, which stops the rest of the code from being executed.

Add lines 2 and 3 of the following code to the code we added above.

  1. function customize_output($results , $arg, $id, $getdata ) {
  2.     echo '<pre>'; var_dump($arg); echo '</pre>'; 
  3.     exit;

UWPQSF search query
Search query dump
If you then do a search you see a nice ordered query of what variables were used in the search query. It looks like the image next to this text.

Since we only want to override the meta_query, which holds the search parameters for the meta queries and thus the checkboxes, the rest doesn’t really interest us.

The screenshot shows 2 dropdown options where no option is selected, aka all options are searched. See the value get_all_cmf_except_me. If you play around with your search options, you will see the values change in your output.

By using one of our meta fields, we now know which array is the checkbox. In my search form it’s the 4th (and last), which looks like the code below where 2 values are selected.

  1. [4]=>
  2.   array(3) {
  3.     ["key"]=>
  4.     string(11) "acf_field_name" // this is the name of meta_field
  5.     ["value"]=>
  6.     array(2) {
  7.       [0]=>
  8.       string(6) "value 1" // first selected value
  9.       [1]=>
  10.       string(6) "value 2" // second selected value
  11.     }
  12.     ["compare"]=>
  13.     string(2) "IN"
  14.   }

NOTE
If only 1 meta value is selected, the returned value is an array with 1 value (so lines 9 and 10 won’t be there in the screenshot above). If no values are selected at all this entire array is omitted from the query.

Reload the page and search the form with using at least one checkbox variable. Copy the entire output to a save place. We’ll need this later.

4. place the meta_query in variables (optional)

I prefer to have my values in ‘easy to understand’ variables, so I retrieve the values from the meta fields like this and place them in my own variables, which I can then easily re-use later on.

  1. $city           = $arg['meta_query'][1]['value'];
  2. $city_compare   = $arg['meta_query'][1]['compare'];
  3. $sex            = $arg['meta_query'][2]['value'];
  4. $sex_compare    = $arg['meta_query'][2]['compare'];
  5. $age            = $arg['meta_query'][3]['value'];
  6. $age_compare    = $arg['meta_query'][3]['compare'];

5. check if a checkbox is used in the search query and how often

To check if this checkbox is actually used, we need to check if the value is set. My checkbox was the fourth in the array, so we check if the 4th value in the array is set. And if it is set, we retrieve the values and place them in some custom variables to use later on.

  1. if ( isset($arg['meta_query'][4]['value']) ) {
  2.     $services_key       = $arg['meta_query'][4]['key'];
  3.     $services_compare   = $arg['meta_query'][4]['compare'];
  4.     $services_value     = $arg['meta_query'][4]['value']; // an array with the selected options
  5.     // more code to come
  6. }

Ok, now we know one or more options are selected but we need to find out how many are selected. We do this with this function. Add this to the code, where it says more code to come.

  1. if ( count($services_value) == 1 ) {
  2.     // do stuff when one value is checked
  3. } else {
  4.     // do stuff when more than one value is checked
  5. }

6. if more than one box is checked, we need to alter the query to accept more than one value

Since UWPQSF only accepts a string, we need to turn the array into a string if only one value is selected.
Replace // do stuff when one value is checked with the following code:

  1. $service_value = implode(',', $services_value); // turns array into a string
  2.  
  3. // make an array of the search query
  4. $services_array = array(
  5.     array(
  6.         'key'       => 'acf_field_name',
  7.         'value'     => $service_value,
  8.         'compare'   => 'LIKE',
  9.     ),
  10. );

If more than one value is selected, the search value is an array as mentioned in step 4; $services_value. Since UWPQSF only accepts a string for checkboxes, this array needs to be split into several arrays with one string/value each, because the meta_query accepts an array of key/value pair arrays as value, as described in the WordPress Codex.

So we take $services_value (which is an array, remember) and with foreach we create a new array for each search term, which we then again add to another array, which we can easily include later.

  1. $service_array = array();
  2. foreach ($services_value as $service_value) {
  3.     $service_array[] = array(
  4.         'key'       => 'acf_field_name',
  5.         'value'     => $service_value,
  6.         'compare'   => 'LIKE',
  7.     );
  8. }
  9.  
  10. // if you want to match posts which have all the values which were selected, 
  11. // use 'relation' => 'AND' (default, so not necessary to define).
  12.  
  13. // if you want to match posts which have either of the values which were selected, 
  14. // use 'relation' => 'OR'
  15.  
  16. // create a search array of arrays with search parameters 
  17. $services_array = array(
  18.     'relation' => 'OR',
  19.     $service_array
  20. );

7. get all the search values we don’t need to override (optional)

This next step is not perse necessary but I explained in step 4 why I do this.

  1. $search_term    = $arg['s'];
  2. $posts_per_page = $arg['posts_per_page'];
  3. $post_type      = $arg['post_type'];
  4. $post_status    = $arg['post_status'];
  5. $orderby        = $arg['orderby'];
  6. $order          = $arg['order'];
  7. $meta_key       = $arg['meta_key'];
  8. $meta_query     = array();
  9. $tax_query      = array();
  10. $compare        = '';
  11. $paged          = false;
  12. $meta_key       = NULL;

8. get posts with new query

If a checkbox is used, then $services_key is set (see step 4), so we can easily check this with the following code.

  1. if ( isset($services_key) ) {
  2.     // query for when checkboxes are used
  3. } else {
  4.     // query for when no checkboxes are used
  5. }

Now we need to build our new search query which we can use with our new variables and place it into a new array, which I have called $new_args. This will look something like this.

  1. $new_args = array(
  2.     'post_status'       => 'publish',
  3.     'post_type'         => $post_type,
  4.     'posts_per_page'    => $posts_per_page,
  5.     'meta_key'          => $meta_key,
  6.     'orderby'           => $orderby,
  7.     'order'             => $order,
  8.     'paged'             => $paged,
  9.     'meta_query'        => array(
  10.         'relation'      => 'AND',
  11.         array(
  12.             'key'       => 'sd_city',
  13.             'value'     => $city,
  14.             'compare'   => $city_compare,
  15.         ),
  16.         array(
  17.             'key'       => 'sd_sex',
  18.             'value'     => $sex,
  19.             'compare'   => $sex_compare,
  20.         ),
  21.         array(
  22.             'key'       => 'sd_age',
  23.             'value'     => $age,
  24.             'compare'   => $age_compare,
  25.         ),
  26.         $services_array // this is the array of search parameters we created in step 5
  27.     ),
  28.     's' => '',
  29. );

Lines 2-8 are the search parameters which are set in your UWPQSF settings. We retrieved these values in step 6.
Line 28 is the string search option, which I don’t use, hence it’s empty.

For the meta_query you see 4 different arrays; city, sex, age and the $services_array we built in step 5. These represent the 4 search options I set in my search form.

Replace // query for when checkboxes are used with the query above.

If no checkboxes are used, then we can use the original query. Replace // query for when no checkboxes are used with the query below.

  1. $new_args = $arg;

9. feed our new parameters back into the search query

One last thing to do. We need to feed our parameters back into the query used by UWPQSF.
Replace

  1. $wp_query   = new WP_Query( $arg );

With

  1. $wp_query   = new WP_Query( $new_args );

And there you have it. You should now be able to search in checkbox fields as well.

If you click to the next page, you’ll find a complete dump of my file. I placed all UWQPSF functions in a file which I included in functions.php. This is a dump from that page, minus the part in which I display the actual results, since it’s unrelated to this issue.