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.

Share it