1

I've built an Autocompleting search box for WordPress categories (it's actually a Custom Taxonomy), which works great (i.e it shows the categories when typed). However, when 1 key is typed, it will show all the results, regardless of the fact whether that string matches any of the categories.

Here is my PHP code (autocomplete.php, in the root of my theme directory):

<?php
include_once($_SERVER['DOCUMENT_ROOT'].'/wp-load.php' ); // I know the traditional way to do it is loading admin_ajax but I read this was exactly the same and didn't increase the overhead to the server
if (isset($_GET['term'])) { // I suspect the problem is something to with this
    $tradeList = get_terms('trade');
    $tradeNames = Array();
    foreach ($tradeList as $trade) {
        $tradeName = $trade->name;
        array_push($tradeNames, $tradeName);
    }
    echo json_encode($tradeNames);
}
?>

and my Javascript code:

$(document).ready(function() {
    $(".main-search-field").autocomplete({
        source: "/wp-content/themes/local_directory/autocomplete.php",
        minLength: 1
    }); 
});

and finally HTML:

<input type="text" class="main-search-field" name="search" id="search">

I realise this might be badly coded, if it is feel free to re-do it. But what I really need to know is how to get the autocomplete suggestions to be relevant to the string that is typed in the search box.

Thanks for any help :)

5
  • Your minLength: 1 is set to one, so that explains why you get so many results. Set it to 3 or 4.
    – gdaniel
    Commented Jul 15, 2014 at 21:02
  • @gdaniel yes that kind of helps but the problem is, that just delays the problem. I still get all the categories that exist for my Custom Taxonomy displayed, just instead of appearing when the first character is typed, they now appear a bit later, when the 3rd or 4th character is typed.
    – Tom Oakley
    Commented Jul 15, 2014 at 21:09
  • Looks like your script is adding all terms to the array. Where is the comparison? You either get all terms and then filter out with the words that were used in the search. Or you need use the searched words as parameters in the search itself. Your script simply gets all terms and adds them to an array.
    – gdaniel
    Commented Jul 15, 2014 at 21:13
  • That's what I was thinking but wasn't sure how to do the comparison (I'm not a PHP wizz, I know enough to get by but need help on the more tricky bits sometimes). Think you could quickly write up a comparison test? Be ace if you could :)
    – Tom Oakley
    Commented Jul 15, 2014 at 21:18
  • 1
    Because WordPress ajax is inherently slow (because it has to load the whole thing) I like to get the entire list of things I want to use autocomplete on and then compare against that rather than sending a request on every keyup, that's way it's basically instantaneous. Commented Jul 16, 2014 at 0:16

1 Answer 1

0

You get all terms because you're asking for all terms, in fact, the line

$tradeList = get_terms('trade');

just get all the terms, ignoring the 'term' query string passed to file.

If you want to get all the terms "filterd" you have to use the string in the query, something like:

include_once( '../../../wp-load.php' ); // adjust the path, of course
// or dirname( dirname( dirname( __FILE__ ) ) ) . '/wp-load.php';
$term = filter_input( INPUT_GET, 'term', FILTER_SANITIZE_STRING );
if ( empty( $term ) ) exit();
$trades = get_terms( 'trade', array( 'name__like' => $term, 'fields' => 'names' ) );
if ( ! empty( $trades ) && is_array( $trades ) ) {
  echo json_encode( $trades );
}

That said, note that by using settings in OP, everytime an user type a char in the input field, there is an ajax request to your server, so if user type 4 letters before make a choice, you'll have 4 additional http requests, so that code easily becomes a server killer.

So, if you want to use this approach, at least use an higher minLength argument.

An alternative is to get all terms, output them as javascript array and let the script make the filtering, something like:

$(document).ready(function() {
  var trades = <?php
  $trades = get_terms( 'trade', array( 'fields' => 'names' ) );
  echo '["' . implode( '","', $trades ) . '"]';
  ?>;
  $(".main-search-field").autocomplete({
    source: trades,
    minLength: 1
  }); 
});

Doing so there is no additional http request, there is no need of any autocomplete.php file and unless you have thousands of trades terms, this approach is probably better.

Notes

In the first approach, the rough including of wp-load.php is a bad practice, I know you are doing it to "don't overhead the server", but the bad news is that the overhead for the server don't decrease so much in this way: you'll load all the WordPress environment, all the plugins and the theme. In addition be aware that it makes your code unsuitable to be shared. If the code is only for you and you really want to use this approach, search for SHORTINIT constant and its usage (start here) and load wp-load.php hardcoding the location path (like I did) because $_SERVER['DOCUMENT_ROOT'] is not affordable, it may be not the expected value depending on how server is configured.

The second approach I suggested, saves you from the wp-load.php problem, and also saves your server from a great number of requests, but that PHP code echoed in the javascript is something really bad, I used only for sake of semplicity in this answer. You should put your javascript code in a separate js file and pass to it the terms using wp_localize_script.

2
  • Great! Thanks for taking the time to write that up, it helps a lot. I'll look into using wp_localize_script. Thanks :)
    – Tom Oakley
    Commented Jul 16, 2014 at 11:10
  • Hi @G.M., I've got another problem, if you could help me answer it, that'd be awesome, thanks :) wordpress.stackexchange.com/questions/154773/…
    – Tom Oakley
    Commented Jul 16, 2014 at 12:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.