Skip to content

Commit

Permalink
New live search feature
Browse files Browse the repository at this point in the history
Fixes #23
  • Loading branch information
ajaydsouza committed Sep 26, 2024
1 parent 6c1ef52 commit 8d0b161
Show file tree
Hide file tree
Showing 12 changed files with 279 additions and 15 deletions.
7 changes: 7 additions & 0 deletions includes/admin/settings/class-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,13 @@ public static function settings_general() {
'type' => 'checkbox',
'options' => true,
),
'enable_live_search' => array(
'id' => 'enable_live_search',
'name' => esc_html__( 'Enable live search', 'better-search' ),
'desc' => esc_html__( 'This option will enable the live search feature on the search form.', 'better-search' ),
'type' => 'checkbox',
'options' => false,
),
'track_popular' => array(
'id' => 'track_popular',
'name' => esc_html__( 'Enable search tracking', 'better-search' ),
Expand Down
4 changes: 0 additions & 4 deletions includes/class-better-search-core-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -479,10 +479,6 @@ public function pre_get_posts( $query ) {
if ( $this->is_search( $query ) || true === $query->get( 'better_search_query' ) ) {
$query_args = $this->query_args;

if ( empty( get_bsearch_query() ) ) {
$query->set( 'post__in', array( 0 ) );
}

$fields = array(
'date_query',
'tax_query',
Expand Down
2 changes: 1 addition & 1 deletion includes/class-better-search-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Better_Search_Query extends WP_Query {
* @param array|string $args The Query variables. Accepts an array or a query string.
*/
public function __construct( $args = array() ) {
$args = wp_parse_args( $args, array( 'is_better_search_query' => true ) );
$args = wp_parse_args( $args, array( 'better_search_query' => true ) );
$core_query = new Better_Search_Core_Query( $args );

add_filter( 'pre_get_posts', array( $core_query, 'pre_get_posts' ), 10 );
Expand Down
26 changes: 19 additions & 7 deletions includes/class-main.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ final class Main {
*/
public $display;

/**
* Live Search.
*
* @since 4.0.0
*
* @var object Live Search.
*/
public $live_search;

/**
* Gets the instance of the class.
*
Expand Down Expand Up @@ -112,11 +121,12 @@ private function __construct() {
* @since 3.3.0
*/
private function init() {
$this->language = new Frontend\Language_Handler();
$this->styles = new Frontend\Styles_Handler();
$this->tracker = new Tracker();
$this->shortcodes = new Frontend\Shortcodes();
$this->display = new Frontend\Display();
$this->language = new Frontend\Language_Handler();
$this->styles = new Frontend\Styles_Handler();
$this->tracker = new Tracker();
$this->shortcodes = new Frontend\Shortcodes();
$this->display = new Frontend\Display();
$this->live_search = new Frontend\Live_Search();

$this->hooks();

Expand Down Expand Up @@ -165,8 +175,10 @@ public function register_widgets() {
* @param \WP_Query $query Query object.
*/
public function load_seamless_mode( $query ) {
if ( $query->is_search() && bsearch_get_option( 'seamless' ) ) {
new \Better_Search_Core_Query( $query->query_vars );
if ( $query->is_search() ) {
if ( bsearch_get_option( 'seamless' ) || true === $query->get( 'better_search_query' ) ) {
new \Better_Search_Core_Query( $query->query_vars );
}
}
}

Expand Down
65 changes: 65 additions & 0 deletions includes/css/bsearch-live-search.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
.search-form, form[role="search"] {
position: relative;
}

.bsearch-autocomplete-results {
display: none;
}

.bsearch-autocomplete-results {
position: absolute;
z-index: 1000;
background: #fefefe;
border: 1px solid #ccc;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
max-height: 200px;
overflow-y: auto;
width: 100%;
top: 100%;
left: 0;
}

.bsearch-autocomplete-results ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
/* Align items vertically */
}

.bsearch-autocomplete-results li {
display: flex;
margin: 0 0 0 0 !important;
align-items: center;
padding: 5px;
border-bottom: 1px solid #eee;
cursor: pointer;
}

.bsearch-autocomplete-results li:hover {
background-color: #f0f0f0;
}

.bsearch-autocomplete-results a {
display: block;
width: 100%;
height: 100%;
text-align: left;
}

/* Ensuring ul does not affect the input field */
.search-form, form[role="search"] {
position: relative;
width: 100%;
/* Ensure it's responsive */
}

@media (max-width: 600px) {
.bsearch-autocomplete-results {
width: 100%;
/* Ensure results take full width */
max-height: 150px;
/* Adjust height for smaller screens */
}
}
1 change: 1 addition & 0 deletions includes/css/bsearch-live-search.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion includes/css/bsearch-styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
}

.bsearchform select, .bsearchform input[type="search"] {
/* styling */
background-color: #fff;
border: thin solid #999;
display: inline-block;
Expand Down
93 changes: 93 additions & 0 deletions includes/frontend/class-live-search.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php
/**
* Functions dealing with live search.
*
* @package Better_Search
*/

namespace WebberZone\Better_Search\Frontend;

if ( ! defined( 'WPINC' ) ) {
die;
}

/**
* Class Live_Search
*
* @since 4.0.0
*/
class Live_Search {

/**
* Constructor to initialize the class.
*/
public function __construct() {
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_action( 'wp_ajax_bsearch_live_search', array( $this, 'live_search' ) );
add_action( 'wp_ajax_nopriv_bsearch_live_search', array( $this, 'live_search' ) );
}

/**
* Enqueue the live search script.
*/
public function enqueue_scripts() {
if ( ! \bsearch_get_option( 'enable_live_search' ) ) {
return;
}

$minimize = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';

wp_enqueue_script(
'bsearch-live-search',
plugins_url( 'includes/js/better-search-live-search' . $minimize . '.js', BETTER_SEARCH_PLUGIN_FILE ),
array(),
BETTER_SEARCH_VERSION,
true
);
wp_localize_script(
'bsearch-live-search',
'bsearch_live_search',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
)
);

wp_enqueue_style(
'bsearch-live-search-style',
plugins_url( 'includes/css/bsearch-live-search' . $minimize . '.css', BETTER_SEARCH_PLUGIN_FILE ),
array(),
BETTER_SEARCH_VERSION
);
}

/**
* Live search function.
*/
public function live_search() {
$search_query = isset( $_POST['s'] ) ? sanitize_text_field( wp_unslash( $_POST['s'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing

$query = new \Better_Search_Query(
array(
'better_search_query' => true,
's' => $search_query,
'posts_per_page' => 5,
'post_type' => wp_parse_list( \bsearch_get_option( 'post_types' ) ),
'post_status' => 'publish',
)
);

$results = array();
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
$results[] = array(
'title' => get_the_title(),
'link' => get_permalink(),
);
}
}
wp_reset_postdata();

wp_send_json( $results );
}
}
4 changes: 3 additions & 1 deletion includes/frontend/class-styles-handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ public function __construct() {
*/
public static function register_styles() {

$minimize = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';

// Register bsearch-style as a placeholder to insert other styles.
wp_register_style(
'bsearch-style',
plugins_url( 'includes/css/bsearch-styles.min.css', BETTER_SEARCH_PLUGIN_FILE ),
plugins_url( 'includes/css/bsearch-styles' . $minimize . '.css', BETTER_SEARCH_PLUGIN_FILE ),
array(),
BETTER_SEARCH_VERSION
);
Expand Down
85 changes: 85 additions & 0 deletions includes/js/better-search-live-search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Save this as js/better-search-live-search.js in your plugin directory

document.addEventListener('DOMContentLoaded', function () {
const searchForms = document.querySelectorAll('.search-form, form[role="search"]');

searchForms.forEach(form => {
const searchInput = form.querySelector('input[name="s"]');
if (!searchInput) return;

const resultsContainer = document.createElement('div');
resultsContainer.className = 'bsearch-autocomplete-results';
searchInput.parentNode.insertBefore(resultsContainer, searchInput.nextSibling);

let debounceTimer;

searchInput.addEventListener('input', function () {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
const searchTerm = this.value;
if (searchTerm.length > 2) {
fetchResults(searchTerm, resultsContainer);
} else {
resultsContainer.innerHTML = '';
resultsContainer.style.display = 'none'; // Hide the container when input is less than 3 characters
}
}, 300);
});

// Hide autocomplete results when clicking outside the input field or results container
document.addEventListener('click', function (event) {
if (!form.contains(event.target) && !resultsContainer.contains(event.target)) {
resultsContainer.style.display = 'none'; // Hide the results container
}
});

// Keep the container open if clicking inside it or on the input
searchInput.addEventListener('focus', function () {
if (resultsContainer.innerHTML.trim() !== '') {
resultsContainer.style.display = 'block';
}
});
});

function fetchResults(searchTerm, resultsContainer) {
fetch(bsearch_live_search.ajax_url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cache-Control': 'no-cache'
},
body: new URLSearchParams({
action: 'bsearch_live_search',
s: searchTerm
}).toString()
})
.then(function (response) {
return response.json();
})
.then(function (results) {
displayResults(results, resultsContainer);
})
.catch(function (error) {
console.error('Error:', error);
});
}

function displayResults(results, resultsContainer) {
resultsContainer.innerHTML = ''; // Clear previous results
if (results.length > 0) {
resultsContainer.style.display = 'block'; // Show the container if results exist
const ul = document.createElement('ul');
results.forEach(result => {
const li = document.createElement('li');
const a = document.createElement('a');
a.href = result.link;
a.textContent = result.title;
li.appendChild(a);
ul.appendChild(li);
});
resultsContainer.appendChild(ul);
} else {
resultsContainer.style.display = 'none'; // Hide the container if no results
}
}
});
1 change: 1 addition & 0 deletions includes/js/better-search-live-search.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,11 @@ You can report security bugs through the Patchstack Vulnerability Disclosure Pro

= 4.0.0 =

* Features:
* New live search feature that shows search results as you type.

* Enhancements:
* Renamed Better_Search to Better_Search_Core_Query. Each of the methods now remove the filter from itself.
* Renamed Better_Search to Better_Search_Core_Query. Each of the methods now remove the filter from itself. It will also automatically parse wp_query parameters.


For previous changelog entries, please refer to the separate changelog.txt file or [Github Releases page](https://github.com/WebberZone/better-search/releases)
Expand Down

0 comments on commit 8d0b161

Please sign in to comment.