WordPress Custom search form with ACF custom fields and custom post type with taxonomies
If you ever been in a need of a Custom WordPress Search field, where you can search for example: for your custom post types, by custom taxonomies like category, or region, or maybe between dates, you are reading the right post! We will create a custom WP solution for this.
To avoid any inconvenience please note: Im pretty sure there are much better / cleaner approaches but it is working.
In rest of the post will try to general, but my case is specific to Events, where I had Custom taxonomies like : Regions, Categories, and added Advanced Custom Fields date fields every Event to determine Start & End date of the actual Event.
What we going to need:
- Custom Post type with taxonomies
- Advanced Search Form template to include anywhere on WP site
- Advanced Custom Fields plugin to create Date fields to our Events
- Assuming you know how to use any DatePicker
- Some custom function into functions.php which modifying the search query based on the passed string in URL
My Custom post type looks lie
Events (Custom Post type)
|Taxonomies|
|———-|—- Regions
|———-|—- Categories
Here is a superb guide how to create Custom Post Types & Taxonomies
Once thats done we should create a custom file that we can include anywhere in our template. I’m usually creating modules into a /inc directory (think it’s a good practice). For example create custom-search-form.php into /inc directory and include it into any of your templates like below:
<?php get_template_part('inc/custom-search-form'); ?>
Lets edit our custom-search-form.php module and place a Search form in it.
<div id="search"> <h2><?php _e('Search for an Event'); ?></h2> <form method="get" class="searchandfilter" id="advanced-searchform" role="search" action="<?php echo esc_url( home_url( '/' ) ); ?>"> <!-- This is telling the form submit it is going to be search --> <input type="hidden" name="s" value=""> <!-- This is limiting our Search for Events custom post type --> <input type="hidden" name="post_type" value="events" /> <!-- This is adding an extra 'advanced' string to the URL so we can make difference between normal and this custom search --> <input type="hidden" name="search" value="advanced"> <ul> <!-- Event regions Select field --> <li> <?php // Loop through Event Regions taxonomy and create a dropdown / select field from the values $taxonomy = 'event_regions'; //change to your taxonomy $args = array( 'orderby' => 'name', 'order' => 'ASC', 'hide_empty' => false ); $tax_terms = get_terms($taxonomy, $args); ?> <label for="event_regions">Regions</label> <select name="event_regions" id="event_regions" class="postform"> <option value="" selected="selected">All Regions</option> <?php if($tax_terms): ?> <?php foreach ($tax_terms as $tax_term): ?> <option value="<?php echo $tax_term->slug; ?>"><?php echo $tax_term->name; ?></option> <?php endforeach; ?> </ul> <?php endif; ?> </select> </li> <!-- // Event regions Select field --> <!-- Event Categories Select field --> <li> <?php // Loop through Event Categories taxonomy and create a dropdown / select field from the values $taxonomy = 'event_category'; //change to your taxonomy $args = array( 'orderby' => 'name', 'order' => 'ASC', 'hide_empty' => false ); $tax_terms = get_terms($taxonomy, $args); ?> <label for="event_category">Categories</label> <select name="event_category" id="event_category" class="postform"> <option value="" selected="selected">All Categories</option> <?php if($tax_terms): ?> <?php foreach ($tax_terms as $tax_term): ?> <?php $title = $tax_term->name; ?> <option value="<?php echo $tax_term->slug; ?>"><?php echo $title; ?></option> <?php endforeach; ?> </ul> <?php endif; ?> </select> </li> <!-- // Event Categories Select field --> <!-- Our Search Submit button --> <li> <input type="submit" value="Search Events"> </li> <!-- // Our Search Submit button --> <!-- Advanced Custom Field date fields --> <li> <label for="fromdate">Date from</label> <input type="text" name="fromdate" id="date_timepicker_start" data-beatpicker="true" data-beatpicker-position="['right','*']" data-beatpicker-format="['DD','MM','YYYY'],separator:'/'"/> <!-- Use any datepicker on these fields. I prefer Beatpicker. Date format does not matter too much now, set it to preferred in your country --> </li> <li> <label for="todate">Date to</label> <input type="text" name="todate" id="date_timepicker_end" data-beatpicker="true" data-beatpicker-position="['right','*']" data-beatpicker-format="['DD','MM','YYYY'],separator:'/'"> <!-- Use any datepicker on these fields. I prefer Beatpicker. Date format does not matter too much now, set it to preferred in your country --> </li> <!-- // Advanced Custom Field date fields --> <!-- Below is completely optional my URL to the Events Archive page --> <li> <?php $events_page = get_field('events_page', 'options'); $events_page_id = $events_page->ID; ?> <a href="<?php echo get_permalink($events_page_id); ?>">See all Events</a> </li> </ul> </form> </div>
If you made everything fine. Include the module into one of your page tempaltes to see if its showing up or not. This will not work yet, but after a form submission you should see something like that in the URL :
http://yourdomain.com/?s=&post_type=events&event_regions=london&event_category=somecategory&search=advanced&fromdate=2015%2F09%2F17&todate=2015%2F09%2F30
Lets see the magic! And create a function in functions.php to break down this URL and modify our search query for the search page.
function advanced_search_query( $query ) { // set up execution conditions to only run when its submitted from our Advanced Search form if ( isset( $_REQUEST['search'] ) && $_REQUEST['search'] == 'advanced' && !is_admin() && $query->is_search && $query->is_main_query() ) { // limit queery for custom post type $query->set( 'post_type', 'events' ); // Get query strings from URL and store the min a variable $_region = $_GET['event_regions'] != '' ? $_GET['event_regions'] : ''; $_category = $_GET['event_category'] != '' ? $_GET['event_category'] : ''; $_fromdate = $_GET['fromdate'] != '' ? $_GET['fromdate'] : ''; $_todate = $_GET['todate'] != '' ? $_GET['todate'] : ''; // if Region is not empty limit the taxonomy to the specified if( $_region != '' ) { $taxquery = array( array( 'taxonomy' => 'event_regions', 'field' => 'slug', 'terms' => $_region, 'operator'=> 'IN' ) ); $query->set( 'tax_query', $taxquery ); } // if Category is not empty limit the taxonomy to the specified if( $_category != '' ) { $taxquery = array( array( 'taxonomy' => 'event_category', 'field' => 'slug', 'terms' => $_category, 'operator'=> 'IN' ) ); $query->set( 'tax_query', $taxquery ); } // if from Date & to Date is not empty limit the query BETWEEN the two dates if ( $_fromdate != '' && $_todate !='') { // here we should convert our date format (whtever date format we used) into WP regular date format 'Ymd' $fromdate = date( 'Ymd', strtotime($_fromdate) ); $todate = date( 'Ymd', strtotime($_todate) ); $metaquery = array( array( 'key' => 'event_start_date', 'value' => array($fromdate, $todate), 'compare' => 'BETWEEN', 'type' => 'DATE' ) ); $query->set( 'meta_query', $metaquery ); } return; // always return } } add_action( 'pre_get_posts', 'advanced_search_query' );
Here we go. Hope that helps a few of you folks out there! If any problems, questions, fixes DO NOT hesitate to use the comments below.