WordPress – Add AJAX Search

AJAX search allows users to dynamically search your site by displaying search results as users type in a search query. This tutorial will take you thru each of the steps to adding AJAX to your site.

Issue

Many times users are not sure what they are looking for. To discover what they seek, users may enter a term or two to see what is returned. Providing results interactively as users enter terms allows for easy discovery of your site.

Solution

I originally used a WordPress plugin for AJAX search support. However, due to the unique design of this web site, the plugin looked like a hack, even after overriding much of the plugin’s CSS. With some Googling, I found these blogs on how to add AJAX search without a plugin. Sam’s tutorial provided much of the code and Daniel’s blog went in-depth on the subject.

Being a WordPress newbie, I was still not sure where each bit of code belonged even after reading both tutorials a few times. But with persistence and a little additional Googling, I was able to put the pieces together and fashion the CSS to fully integrate the AJAX search results into my website. I also made a few changes to the PHP and JavaScript so that the search responded to my preferences.

The steps to adding AJAX search to your WordPress are as follows. Know that these files are in the current theme your site is using. It is best practice to create a child theme and modify the files within it so that these changes are not lost with updates to the parent theme.

  1. Add CSS to styles.css
  2. Add PHP code to functions.php
  3. Add JavaScript to ajaxSearch.js
  4. Add CSS and JavaScripts in Functions.php

CSS

Once you have everything working, come back to these CSS rules and edit them so that the search box and search results appear integrated with your site.


.searchInput {
    padding-left: 1em;
    margin: 0px auto 8px auto;
    box-sizing: border-box;
    height: 2em;
    width: 100%;

    /* Setting the radius to a very large value causes the left and right borders to become semi-circles. */
    border-radius: 999em;
    border: 1px solid rgb(255,165,0);

    color: rgb(255,165,0);
    background-color: rgba(255,165,0, 0.1);

    font-size:1em;
}

.searchResult a {
    /* Define the look of a glass button. */
    padding: 12px;
    margin: 0px 0px 4px 0px;
    box-sizing: border-box;

    border-radius: 25px;

    border-color: rgba(255,165,0, 0.2);
    border-width: 1px;
    border-style: solid;

    transition: all 0.25s;

    font-size: 1em;
    text-decoration: none;

    display: block;
}

.searchResult a:hover {
    /* Highlight the button on hover. */
    border-color: rgba(255,165,0, 0.7);
    border-style: solid;
    background-color: rgba(255,165,0, 0.2);
    transition: all 0.4s;
}

.searchResult a:active {
    /* Highlight the button on click. */
    border-color: rgba(255, 255, 125, 0.7);
    border-style: solid;
    background-color: #30308099;
    transition: all 0.4s;
}

.searchResultTitle
{
}

.searchResultExcerpt {
    color: rgb(255,165,0);
}

PHP

The PHP has two functions. Function wpb_search_form() creates the search form on pages/posts containing the shortcode and function gp_ajax_search() is called by the JavaScript to query WordPress and display the results.


/* ****************************************************************************
// Create search form on Page/Post containing shortcode.
**************************************************************************** */
function wpb_search_form()
{
    $form = '
    <div>
        <label class="screen-reader-text" for="s" style="visibility:hidden;">' . __('Search for:') . '</label>
        <input class="searchInput" type="text" placeholder="Search JayBrockway.us" value="' . get_search_query() . '" name="s" id="s" autofocus="autofocus" />
    </div>
    <div class="searchResults">
        <!-- Search results will be added here. -->
    </div>';

    return $form;
}

add_shortcode('wpbsearch', 'wpb_search_form');


/* ************************************************************************************************************************************************************
Query WordPress for search term.
************************************************************************************************************************************************************ */
function gp_ajax_search()
{
    // Get search term from search field
    $keyword = sanitize_text_field( $_POST[ 'query' ] );

    // Perform a keyword search.
    // For other types of search, see: https://developer.wordpress.org/reference/classes/wp_query/
    $query = new WP_Query ( array( 's' => $keyword, 'post_status' => 'publish', 'orderby' => 'title', 'order' => 'ASC') );

    // Check if there are results.
    if ( $query->have_posts() )
    {
        // Display each result.
        while ( $query->have_posts() )
        {
            $query->the_post();
            // Output a link to each result     This is where the post thumbnail, excerpt, or anything else could be added.  See https://wordpress.org/search/get_the
            echo '<div class="searchResult"><a href="' . get_permalink() . '"><span class="searchResultTitle">' . get_the_title() . '</span><br/><hr/>';
            echo'<p class="searchResultExcerpt">' . get_the_excerpt() . '</p>';
            echo'</a></div>';
        }
    }
    else
    {
        // Let the user know there are no results.
        echo '<p class="no-results">No results</p>';
    }

    // Reset query
    wp_reset_query();

    die();
}

/* We need to hook into both wp_ajax and wp_ajax_nopriv_ in order for
   the search to work for both logged in and logged out users. */
add_action( 'wp_ajax_gp_ajax_search', 'gp_ajax_search' );
add_action( 'wp_ajax_nopriv_gp_ajax_search', 'gp_ajax_search' );

JavaScript

The JavaScript is called each time there is a keyup event in the search box. To avoid sending too many search requests back to WordPress, the code waits 200ms to see if the user presses another key before sending the search request. It also waits until the user has entered at least 2 characters to avoid sending a search query that would return everything.


jQuery(document).ready( function($)
{
    // Set up variables for each of the search elements with the these class names.
    var $searchField = $('.searchInput'),
        $searchResults = $('.searchResults'),
        $loadingIcon = $('.loadingIcon'),
        termExists = "";

    // Add the results container and disable autocomplete on the search field.
    $searchField.attr('autocomplete', 'off');


    // Perform search on keyup in search field, hide/show loading icon.
    var timeoutID = null;
    $searchField.keyup(
    function()
    {
        $loadingIcon.css('display', 'block');

        // If the search field is not empty and contains more that two letters then perform the search after 200ms to avoid searching while user is typing.
        if (($searchField.val() !== "") && (2 < $searchField.val().length))
        {
            termExists = true;

            if (null != timeoutID)
                window.clearTimeout(timeoutID);

            timeoutID = window.setTimeout(doSearch(), 200);
        }
        else
        {
            termExists = false;
            $searchResults.empty();
            $loadingIcon.css('display', 'none');
        }
    });


    // Make search request.
    function doSearch()
    {
        var query = $searchField.val();

        $.ajax(
        {
            type: 'POST',
            url: myAjax.ajaxurl, // ajaxurl comes from the localize_script we added to functions.php
            data: {
                action: 'gp_ajax_search',
                query: query,
            },
            success: function(result)
            {
                if ( termExists )
                {
                    $searchResults.html(result);
                }
            },
            complete: function()
            {
                // Whether or not results are returned, hide the loading icon once the request is complete
                $loadingIcon.css('display', 'none');
            }
        });
    }
});

Functions.php

Add the JavaScript to WordPress so it will be loaded with each page and localize ajaxurl so it is available to the JavaScript.


// AJAX search
wp_enqueue_script( 'glassPanel-ajax-search', get_template_directory_uri() . '/javascripts/ajaxSearch.js', array( 'jquery' ), '1.0.0', true );
wp_localize_script( 'glassPanel-ajax-search', 'myAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );

Conclusion

WordPress has a large community base. Many of the questions new WordPress developers seek have already been answered in articles, blogs and community forums.