The right way to create a custom search page for complex custom post types

I found a way to make this work. I was right with the thought that pre_get_posts was the way to go. First, I added an action:

// Filter the search page
add_filter('pre_get_posts', 'search_pre_get_posts');

Then I added the function. This function first checks that the context is correct. In my custom search form, I use a nonce. The nonce helps me verify that it’s my custom search that is being run, not the built in search. I then manipulate the query variables that will be sent to the query. I’m showing my full function here, which includes all of the validation and sanitization of variables, as well as how the query is manipulated:

/**
 * Filters for search of events
 *
 * When a search is initiated, this filter will check to see if it is an
 * event search. If so, it will process the search data associated with
 * event searches and add it to the $query object prior to it being used
 * to query the database.
 *
 * @param $query The query object generated for this page
 * @return void
 */
function search_pre_get_posts($query)
{
    // Verify that we are on the search page that that this came from the event search form
    if($query->query_vars['s'] != '' && is_search() && isset($_GET['prefix-submitted']) && $_GET['prefix-submitted'] && wp_verify_nonce($_GET['prefix-search-nonce'], 'prefix-search'))
    {
        // Always order by date
        $query->set('orderby', 'meta_value');
        $query->set('order', 'ASC');
        $query->set('meta_key', '_datetime-from');

        // Set the text string for the search
        $clean_text = (isset($_GET['prefix-text'])) ? wp_strip_all_tags($_GET['prefix-text']) : '';
        $query->set('s', $clean_text);

        // Validate dates
        $clean_from = (isset($_GET['prefix-from'])) ? $this->handle_date($_GET['prefix-from']) : false;
        $clean_to = (isset($_GET['prefix-to'])) ? $this->handle_date($_GET['prefix-to']) : false;

        // Validate taxonomies
        $clean_type = (isset($_GET['prefix-type'])) ? $this->handle_taxonomy_id($_GET['prefix-type'], 'prefix-type') : false;
        $clean_location = (isset($_GET['prefix-location'])) ? $this->handle_taxonomy_id($_GET['prefix-location'], 'prefix-location') : false;

        // Build meta_query variable based on date pieces
        if($clean_from && $clean_to)
        {
            $meta_query = array(
                array(
                    'key' => '_datetime-from',
                    'value' => array($clean_from, $clean_to),
                    'compare' => 'BETWEEN',
                    'type' => 'DATE'
                )
            );
        }
        elseif($clean_from)
        {
            $meta_query = array(
                array(
                    'key' => '_datetime-from',
                    'value' => $clean_from,
                    'compare' => '>=',
                    'type' => 'DATE'
                )
            );
        }
        elseif($clean_to)
        {
            $meta_query = array(
                array(
                    'key' => '_datetime-from',
                    'value' => $clean_from,
                    'compare' => '>=',
                    'type' => 'DATE'
                )
            );
        }
        else
            $meta_query = '';

        // Set the meta query
        $query->set('meta_query', $meta_query);

        // Build tax query based on taxonomy pieces
        if($clean_type && $clean_location)
        {
            $tax_query = array(
                'relation' => 'AND',
                array(
                    'taxonomy' => 'prefix-type',
                    'field' => 'id',
                    'terms' => $clean_type,
                    'operator' => 'IN'
                ),
                array(
                    'taxonomy' => 'prefix-location',
                    'field' => 'id',
                    'terms' => $clean_location,
                    'operator' => 'IN'
                )
            );
        }
        elseif($clean_type)
        {
            $tax_query = array(
                array(
                    'taxonomy' => 'prefix-type',
                    'field' => 'id',
                    'terms' => $clean_type,
                    'operator' => 'IN'
                )
            );
        }
        elseif($clean_location)
        {
            $tax_query = array(
                array(
                    'taxonomy' => 'prefix-location',
                    'field' => 'id',
                    'terms' => $clean_location,
                    'operator' => 'IN'
                )
            );
        }
        else
            $tax_query = '';

        // Set the tax query
        $query->set('tax_query', $tax_query);
    }
}

Leave a Comment