Typeahead and bloodhound autocomplete code snippet with WordPress Ajax.

This blog post cover typehead and bloodhound autocomplete script with a WordPress ajax code.
The code example will render the post title list from the WordPress posts table. The example covers Javascript code, HTML basic code, and WordPress Ajax function.

HTML Code: You can update this code according to your input field.


<div>
label>Autocomplete Search</label>
<input type="text" id="txt_search_string" name="txt_search_string" class="typeahead tt-input" autocomplete="off"/>
<input type="hidden" id="txt_search_id" name="txt_search_id" />
</div>


Javascript code and enqueue script: This code must include in a separate Javascript file. You can merge within your existing javascript file. I am sharing code the javascript file enqueue script as well. For Ajax security. The script is using WordPress nonce. Please take care of this code as well, while using this code snippet.

wp_enqueue_script( 'custom-script-theme', get_template_directory_uri() . '/js/custom-script.js', array( 'jquery' ), false, true );
$ajax_nonce = wp_create_nonce( "custom-ajax-security" );
wp_localize_script('custom-script-theme', 'custom_ajax_object', array( 'custom_ajaxurl' => admin_url( 'admin-ajax.php' ), 'ajax_nonce' => $ajax_nonce ) );
var categories = new Bloodhound({
	datumTokenizer: Bloodhound.tokenizers.obj.whitespace('text'),
	queryTokenizer: Bloodhound.tokenizers.whitespace,
	remote: {
		url: custom_ajax_object.custom_ajaxurl,
		replace: function (url, query) {
			return url +'?action=AutocompleteSearch&txt_search_string='+jQuery('#txt_search_string').val()+'&ajax_nonce_security='+custom_ajax_object.ajax_nonce;
		},
		wildcard: '%QUERY',
		filter: function (categories) {
			return jQuery.map(categories, function (category) {
				return {
					label: category.label,
					value: category.value,
				};
			});
		}
	}
});
categories.initialize();
jQuery('#txt_search_string').typeahead({
	minLength: 3,
},{
	limit:50,
	display: function(data) { return data.label + ' (' + data.value + ')'; },
	source: categories.ttAdapter(),
	templates:{
		pending:  '
<h3 class="league-name">Loding...</h3>

',
		suggestion: function(data) {
			return '

<strong>' + data.label + ' (' + data.value + ') </strong>

';
		},
		notFound: '
<h3 class="league-name">No data found</h3>

',
	}
	
}).bind('typeahead:select', function(ev, suggestion) {
  //console.log(suggestion);
  jQuery('#txt_search_id').val(suggestion.value); // hidden input value
});

WordrPress Ajax code:

add_action('wp_ajax_AutocompleteSearch', 'custom_auto_search_ajax');
add_action('wp_ajax_nopriv_AutocompleteSearch', 'custom_auto_search_ajax');
function custom_auto_search_ajax(){
	
	global $wpdb;
	global $current_marketplace_id;
	
	$searchString = strtolower( $_REQUEST['txt_search_string'] );
	
	$data_list = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}posts WHERE lower(post_title) LIKE '%".$searchString."%' LIMIT 0, 50", ARRAY_A);
	
	
	$return_array = array();
	$counter = 0;
	foreach( $data_list as $data_value ){
		
		$return_array[$counter]['value'] = $data_value['ID'];
		$return_array[$counter]['label'] = $data_value['post_title'];
		
		$counter++;
	}
	
	echo json_encode( $return_array );
	
	die();
}

WordPress Template: This is a basic example Template for WordPress’s twentynineteen theme.

<?php
/**
 * Template Name: Typehead
*/
get_header();
?>
<style>
.site-content {
 overflow: inherit;
}
.typeahead,
.tt-query,
.tt-hint {
  width: 396px;
  height: 30px;
  padding: 8px 12px;
  font-size: 24px;
  line-height: 30px;
  border: 2px solid #ccc;
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px;
  outline: none;
}
.tt-menu {
  width: 422px;
  margin: 12px 0;
  padding: 8px 0;
  background-color: #fff;
  border: 1px solid #ccc;
  border: 1px solid rgba(0, 0, 0, 0.2);
  -webkit-border-radius: 8px;
     -moz-border-radius: 8px;
          border-radius: 8px;
  -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
     -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
          box-shadow: 0 5px 10px rgba(0,0,0,.2);
}

.tt-suggestion {
  padding: 3px 20px;
  font-size: 18px;
  line-height: 24px;
}

.tt-suggestion:hover {
  cursor: pointer;
  color: #fff;
  background-color: #0097cf;
}

.tt-suggestion.tt-cursor {
  color: #fff;
  background-color: #0097cf;

}

.tt-suggestion p {
  margin: 0;
}

</style>
	<section id="primary" class="content-area">
		<main id="main" class="site-main">

			<?php
			/* Start the Loop */
			while ( have_posts() ) :
				the_post();
			?>
			<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
				
				<header class="entry-header">
					<?php get_template_part( 'template-parts/header/entry', 'header' ); ?>
				</header>
				
				<div class="entry-content">
					<div style="position:relative;">
					<label>Autocomplete Search</label>
					<input type="text" id="txt_search_string" name="txt_search_string" class="typeahead tt-input" autocomplete="off"/>
					<input type="hidden" id="txt_search_id" name="txt_search_id" />
					</div>
					<?php
					the_content();

					wp_link_pages(
						array(
							'before' => '<div class="page-links">' . __( 'Pages:', 'twentynineteen' ),
							'after'  => '</div>',
						)
					);
					?>
				</div><!-- .entry-content -->	
				<footer>
				</footer>
			</article><!-- #post-<?php the_ID(); ?> -->
			
			<?php
				// If comments are open or we have at least one comment, load up the comment template.
				if ( comments_open() || get_comments_number() ) {
					comments_template();
				}

			endwhile; // End of the loop.
			?>
		</main><!-- #main -->
	</section><!-- #primary -->
<?php
get_footer();

More detail about typeheadand bloodhound
https://twitter.github.io/typeahead.js/examples/
https://github.com/twitter/typeahead.js