Autosuggest for WordPress search with jQuery autocomplete

First we register a custom route with the pages we want to search in.

/**
 * Search
 */
class Search {
	/**
	 * Construct
	 */
	public function __construct() {
		// REST API endpoint
		add_action( 'rest_api_init', array( $this, 'rest_route' ) );
	}

	/**
	 * Register rest route
	 *
	 * /wp-json/ventures/v1/posts/
	 */
	public function rest_route( $data ) {
		register_rest_route( 'ventures/v1', '/posts', array(
			'methods'  => 'GET',
			'callback' => array( $this, 'get_rest_api_data' ),
		) );
	}

	/**
	 * Callback function for custom REST API endpoint
	 */
	public function get_rest_api_data() {
		$data = array();

		$post_types = array(
			'page',
			'post',
			'location',
		);

		foreach ( $post_types as $post_type ) {
			$query = new WP_Query( array(
				'post_type'      => $post_type,
				'posts_per_page' => 100,
				'no_found_rows'  => true,
			) );

			if ( $query->have_posts() ) {
				while ( $query->have_posts() ) {
					$query->the_post();

					$data[] = array(
						'value' => get_permalink(),
						'label' => get_the_title(),
					);
				}
			}
		}

		wp_reset_postdata();

		return $data;
	}
}

We use some custom data in our JS.

wp_localize_script(
	'ventures',
	'ventures',
	array(
		'home_url'             => home_url( '/' ),
		'search_results_label' => __( 'Show all results', 'ventures' ),
	)
);

We can use this endpoint to search in.

/**
 * Search
 */
var searchResults = [];

$( '.js-toggle-search' ).on( 'click', function( e ) {
	e.preventDefault();

	$( '.pt-search__input' ).focus();

	// Get results
	$.getJSON( ventures.home_url + '/wp-json/ventures/v1/posts/', function( data ) {
		$.each( data, function( key, value ) {
			searchResults.push( {
				'value' : value.value,
				'label' : value.label,
			} );
		} )
	} );
} );

// Autocomplete
$( '.pt-search__input' ).autocomplete( {
	source: searchResults,
	minLength: 1,
	appendTo: '.pt-search__results',
	select: function( event, ui ) { 
		window.location.href = ui.item.value;

		return false;
	},
	focus: function( event, ui ) {
		return false;
	},
	open: function( event, ui ) {
		var value = $( '.pt-search__input' ).val();

		$( '.ui-autocomplete' ).append( '<li><p><a href="' + ventures.home_url + '?s=' + value + '">' + ventures.search_results_label + '</a></p></li>' );
	},
} ).data( 'ui-autocomplete' )._renderItem = function( ul, item ) {
	var expression = new RegExp( '(' + this.term + ')', 'gi' );

	var label = item.label.replace(
		expression,
		"<span class='pt-highlight'>$1</span>"
	);

	return $( '<li></li>' ).append( '<a>' + label + '</a>' ).appendTo( ul );
};