Here is a shortcode that I developed for WordPress to enable AJAX searching of the post title without relying on AJAX. There is a big push to move away from using iQuery and just use native functions of the browser to achieve the same objectives.
My solution will detect when the shortcode is used and then only inject the CSS and JS dependent files when required. The returned results include a feature image if available and a snippet of the post content.
To embed the search control within a page/post use the shortcode [es-ajax-search] .
Call the main search functions from your functions.php file by inserting the following line at the start of your file.
1 |
include_once('inc/ajax-search.php'); |
You might want to change the path of where the CSS, JS PHP files reside in the code below. I create a directory called /inc, /css and /js directories under the child theme to store any custom code to keep it tidy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
namespace ES_AJAX_Search; function ajax_search_shortcode() { ob_start(); ?> <div class="search-wrapper"> <div id="overlay"> <div class="cv-spinner"> <span class="spinner"></span> </div> </div> <div class="search-input"> <input type="search" class="ajax-input" name="keyword" id="ajax_search" placeholder="Search..."> </div> <div class="search-results"> <ul id="ajax_results" class="ajax-results"></ul> </div> </div> <?php return ob_get_clean(); } add_shortcode('es-ajax-search', __NAMESPACE__ . '\ajax_search_shortcode'); function shortcode_scripts() { global $post; if (has_shortcode($post->post_content, 'es-ajax-search')) { wp_enqueue_style('es-ajax-search', get_stylesheet_directory_uri() . '/css/ajax-search.css', [], filemtime(get_stylesheet_directory() . '/css/ajax-search.css')); wp_enqueue_script('es-ajax-search', get_stylesheet_directory_uri() . '/js/ajax-search.js', [], filemtime(get_stylesheet_directory() . '/js/ajax-search.js'), true); wp_localize_script('es-ajax-search', 'esAjaxSearch', ['ajaxUrl' => admin_url('admin-ajax.php')]); } } add_action('wp_enqueue_scripts', __NAMESPACE__ . '\shortcode_scripts'); function ajax_search() { ob_start(); if (strlen($_POST['keyword']) > 0) { $the_query = new \WP_Query( array( 'posts_per_page' => 20, 'post_status' => 'publish', 's' => esc_attr($_POST['keyword']), 'no_found_rows' => true //'post_type' => 'post' ) ); if ($the_query->have_posts()) : foreach ($the_query->posts as $res) { echo '<li><div class="result-wrap"><div class="post-thumb">' . get_the_post_thumbnail($res->ID, 'post-thumbnail') . '</div><div class="post-text"><a href="' . esc_url(get_the_permalink($res->ID)) . '"><strong>' . $res->post_title . '</strong> - ' . wp_trim_words($res->post_content, 10) . '</a></div></li>'; } else : echo '<li>No results</li>'; endif; } $result = ob_get_clean(); wp_send_json([ 'posts' => $result, 'count' => count($the_query->posts) ]); } add_action('wp_ajax_ajax_search', __NAMESPACE__ . '\ajax_search'); add_action('wp_ajax_nopriv_ajax_search', __NAMESPACE__ . '\ajax_search'); |
Here is the jQuery free script for dealing with the AJAX calls. It uses the fetch API and displays a basic CSS spinner to show you the code is executing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
var ajaxResults = document.getElementById('ajax_results'), ajaxUrl = esAjaxSearch.ajaxUrl, overlay = document.getElementById('overlay'), searchInput = document.getElementById('ajax_search'); searchInput.addEventListener("search", ajaxSearchTrigger); searchInput.addEventListener("keyup", searchWordPress); function ajaxSearchTrigger(e) { ajaxResults.innerHTML = '' ajaxResults.style.height = 'unset' } function searchWordPress(e) { var sInput = e.target, delay = 500; if (sInput.value.length >= 3) { setTimeout(function() { overlay.style.display = 'block' fetch(ajaxUrl, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Cache-Control': 'no-cache', }, body: new URLSearchParams({ action: 'ajax_search', keyword: searchInput.value, }) }).then(response => response.json()) .then(response => { ajaxResults.innerHTML = response.posts if (response.count == 0) ajaxResults.style.height = 'unset' else ajaxResults.style.height = 'auto' }) .catch(err => console.log(err)) .then(always => { overlay.style.display = 'none' }); }, delay); } else { ajaxResults.innerHTML = '' } } |
Some CSS for styling the AJAX spinner and such.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
.ajax-results { list-style: none; margin: 0; position: absolute; background: white; padding: 0; width: 100%; overflow: auto; height: auto; max-height: 25rem; } .search-wrapper { position: relative; width: 100%; } #ajax_search { width: 100%; margin: 0; } .ajax-results li { margin: 0; border: solid 1px; padding: 1rem; } .result-wrap { display: flex; align-items: center; } .post-thumb { padding: 1rem; max-width: 10rem; } .post-text { font-size: 1rem; } #overlay { position: absolute; top: 0; z-index: 100; width: 100%; height: 100%; display: none; background: rgba(0, 0, 0, 0.6); } .cv-spinner { height: 100%; display: flex; justify-content: center; align-items: center; } .spinner { width: 40px; height: 40px; border: 4px #ddd solid; border-top: 4px var(--global--color-primary) solid; border-radius: 50%; animation: sp-anime 0.8s infinite linear; } @keyframes sp-anime { 100% { transform: rotate(360deg); } } .is-hide { display: none; } |
That’s it, jQuery free AJAX searching in WordPress using the fetch API. A modification that you might want to make it to include custom post types in the search result. I’ve also limited results returned to the first 20 which can also me modified to suit your needs.