You are here:  » Auto complete


Auto complete

Submitted by henk on Thu, 2013-03-21 13:43 in

Hi David,

Is this also possible in Wordpress

http://www.pricetapestry.com/node/5003

Thx
Henk

Submitted by support on Thu, 2013-03-21 14:15

Hello Henk,

Should be no problem - I'll give it a go shortly and post the details...

Cheers,
David.
--
PriceTapestry.com

Submitted by support on Thu, 2013-03-21 18:19

Hi Henk,

Works fine - first of all, create the same searchJSON.php in your Price Tapestry installation folder as described in the main thread on PriceTapestry.com here.

Then, simply use the following as a complete replacement for the Main / Search Form template in wp-admin > Settings > PriceTapestry.org:

<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>
<script type='text/JavaScript'>
  $(function() {
  $( "#pto_q" ).autocomplete({
    source: function( request, response ) {
      $.ajax({
        url: "/pt/searchJSON.php",dataType:"json",data:{q:request.term},
        success: function( data ) {
          response($.map( data.products, function( item ) { return { label:item.name, value:item.name}
          }));
        }
      });
      },
      minLength: 2,
      open: function() { $( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" ); },
      close: function() { $( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" ); }
    })
    .keydown(function(e){ if (e.keyCode === 13) { $("#pto_search").trigger('submit'); }
    });
  });
</script>
<div class='pto_search_form'>
<form name='pto_search' id='pto_search' method='GET' action='%ACTION%'>
<input type='text' size='35' name='pto_q' id='pto_q' value='%PTO_Q%' />
<input type='submit' value='Search' />
<br />Search or browse by <a href='%MERCHANTBASEHREF%'>merchant</a>, <a href='%CATEGORYBASEHREF%'>category</a> or <a href='%BRANDBASEHREF%'>brand</a>
</form>
</div>

If your associated Price Tapestry installation is not in /pt/ relative to the top level directory of your site edit /pt/searchJSON.php within the above as required, and that should do the trick!

Cheers,
David.
--
PriceTapestry.com

Submitted by henk on Fri, 2013-03-22 19:11

Hmm... it doesn't give result..

Thx
Henk

Submitted by support on Sat, 2013-03-23 12:08

Hi Henk,

Could you post the installation URL (WordPress page) where it should be running (I'll remove the link before publishing your reply) and I'll take a look using the FireFox JavaScript debugger which might reveal the problem...

Thanks,
David.
--
PriceTapestry.com

Submitted by henk on Sat, 2013-03-23 15:02

Hi David,

The link:

{link saved}

Thx
Henk

Submitted by support on Sat, 2013-03-23 15:15

Hello Henk,

I think I spotted the problem, I tried requesting your searchJSON.php script directly:

http://www.example.com/pt/searchJSON.php?q=A

(replace example.com with your domain name to try for yourself)

...and there is a PHP error included in the output, which will break JQuery's parsing of the response. The error message is:

Warning: Cannot modify header information - headers already sent by (output started at /home/{code saved}/public_html/pt/searchJSON.php:1) in /home/{code saved}/public_html/pt/searchJSON.php on line 3

...and that indicates that there is white space (either SPACE or new line characters) immediately at the start of searchJSON.php, so PHP cannot set the content-type header.

Now, this might be UTF-8 BOM (Byte Order Markers) getting in the way of things; so if you edit the file, and there is no obvious sign of anything infront of <?php then use your text editor's File > Save As... menu, and on the Save As.. dialog, look for an encoding type, and see if there is a UTF-8 No-BOM option displayed, choose that option, and re-upload the file and that should be all it is!

If still no joy, email me your searchJSON.php and I'll check it out for you...

Cheers,
David.
--
PriceTapestry.com

Submitted by henk on Sat, 2013-03-23 20:40

Hi David,

Thx i've got it running in the theme now it was one open space :)

Two things:

Can it in two places in theme and in the installation of pt.
And it gives strange results, is it looking in the whole product name?

Thx
Henk

Submitted by support on Mon, 2013-03-25 08:52

Hello Henk,

The code could be included in multiple search boxes on the same page, but each form / search box needs to have a unique ID to which the autocomplete JavaScript can be "attached". In addition, the JQuery includes need to be taken out of the search form HTML template and ideally placed into your standard header, so that they are automatically included on every page of your site (this should not have any performance implications as the files will be cached / you may have changed to local URLs anyway).

So in the first instance, remove from the template code the following lines, and insert into the standard header of your WordPress theme:

<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>

(if you're not sure what files to edit to add code to your page header let me know and I'll take a look for you, since it depends on how your theme is set-up...)

With that in place, now use as the Search Form template (wp-admin > Settings > PriceTapestry.org) the following slight modification, which includes an auto-increment ID "%AIID%" placeholder:

<script type='text/JavaScript'>
  $(function() {
  $( "#pto_q_%AIID%" ).autocomplete({
    source: function( request, response ) {
      $.ajax({
        url: "/pt/searchJSON.php",dataType:"json",data:{q:request.term},
        success: function( data ) {
          response($.map( data.products, function( item ) { return { label:item.name, value:item.name}
          }));
        }
      });
      },
      minLength: 2,
      open: function() { $( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" ); },
      close: function() { $( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" ); }
    })
    .keydown(function(e){ if (e.keyCode === 13) { $("#pto_search_%AIID%").trigger('submit'); }
    });
  });
</script>
<div class='pto_search_form'>
<form name='pto_search' id='pto_search_%AIID%' method='GET' action='%ACTION%'>
<input type='text' size='35' name='pto_q' id='pto_q_%AIID%' value='%PTO_Q%' />
<input type='submit' value='Search' />
<br />Search or browse by <a href='%MERCHANTBASEHREF%'>merchant</a>, <a href='%CATEGORYBASEHREF%'>category</a> or <a href='%BRANDBASEHREF%'>brand</a>
</form>
</div>

Finally, to add support for %AIID%, edit pto_search.php, and look for the following code at line 21:

  $html = $pto_html_search_form;

...and REPLACE with:

  $html = $pto_html_search_form;
  global $pto_aiid;
  if (!isset($pto_aiid)) $pto_aiid = 0;
  $pto_aiid++;
  $html = str_replace("%AIID%",$aiid,$html);

Regarding the autocomplete suggestions; the version of searchJSON.php described in the main thread first looks for names beginning with the text entered so far. When there are no results for an exact match at the beginning of a name, it goes on to re-query using an anywhere in the name match. If you wanted to limit suggestions to only names beginning exactly as entered, then you can use a cut-down searchJSON.php as follows:

<?php
  
require("includes/common.php");
  
header("Content-Type: application/json;");
  if (
$_GET["q"])
  {
    
$sql "SELECT DISTINCT(normalised_name) AS name
      FROM `"
.$config_databaseTablePrefix."products`
      WHERE name LIKE '"
.database_safe($_GET["q"])."%' LIMIT 5
      "
;
    
database_querySelect($sql,$products);
    print 
json_encode(array("totalResultsCount"=>count($products),"products"=>$products));
  }
  exit();
?>

Hope this helps!

Cheers,
David.
--
PriceTapestry.com

Submitted by henk on Mon, 2013-03-25 10:07

Hi david,

The pto is working now not in template, i have this as search form:

<div class='pto_search_form'>
<form name='pto_search' id='pto_search' method='GET' action='<?php echo home_url'/vergelijken/' ); ?>'>
<input type='text' size='35' name='pto_q' id='pto_q' value='<?php print (isset($_GET["pto_q"])?htmlentities($_GET["pto_q"],ENT_QUOTES):""); ?>' /><button type="submit" value="<?php _e('Search''blue_with_grey'?>"></button>
<input type='submit' value='<?php _e('''blue_with_grey'?>' />
</form>
</div>

Thx
Henk

Submitted by support on Mon, 2013-03-25 10:27

Hi Henk,

That looks fine - if you wanted that search form to have autocomplete as well as pto generated ones, just use a dummy id say "99", e.g.

<script type='text/JavaScript'>
  $(function() {
  $( "#pto_q_99" ).autocomplete({
    source: function( request, response ) {
      $.ajax({
        url: "/pt/searchJSON.php",dataType:"json",data:{q:request.term},
        success: function( data ) {
          response($.map( data.products, function( item ) { return { label:item.name, value:item.name}
          }));
        }
      });
      },
      minLength: 2,
      open: function() { $( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" ); },
      close: function() { $( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" ); }
    })
    .keydown(function(e){ if (e.keyCode === 13) { $("#pto_search_99").trigger('submit'); }
    });
  });
</script>
<div class='pto_search_form'>
<form name='pto_search' id='pto_search_99' method='GET' action='<?php echo home_url'/vergelijken/' ); ?>'>
<input type='text' size='35' name='pto_q' id='pto_q_99' value='<?php print (isset($_GET["pto_q"])?htmlentities($_GET["pto_q"],ENT_QUOTES):""); ?>' /><button type="submit" value="<?php _e('Search''blue_with_grey'?>"></button>
<input type='submit' value='<?php _e('''blue_with_grey'?>' />
</form>
</div>

Cheers,
David.
--
PriceTapestry.com

Submitted by Mark Hennessy on Sun, 2013-05-05 09:41

Just got this up and running...seems to be working great.

If a user selects one of the options from the auto complete, is it possible to take them straight to the product page and not the Shopping page?

Regards

Mark

Submitted by paddyman on Tue, 2013-10-29 21:14

Hi David,

I've implemented all code but it doesn't appear to be working. Anything I can do to test ?

Cheers

Adrian

Submitted by support on Wed, 2013-10-30 10:45

Hi Adrian,

Double check that there is no white space outside of the PHP tags in your /pt/searchJSON.php file as this will be output by the script and can break the JSON notation. In other words, make sure that the file beings with <?php and ends ?> with nothing outside of the delimiters. Also, check that the file has not been saved with UTF-8 "Byte Order Markers" as like white space, these will break the format! In your text editor used to create the file, on the Save As... dialog see if there is a character encoding option (normally a drop down) and if so, there should be an option that specifically states no byte order markers e.g. "UTF-8 NO BOM".

If that all looks good, make a manual request to searchJSON.php e.g.

www.yoursite.com/pt/searchJSON.php?q=keyword

...where keyword is something that you know will return results on your site and you should see the results returned in the JSON notation, however it may reveal an error which would indicate the problem.

If that all looks good, then the next thing to do would be to debug the JavaScript on the site. The easiest way to do this I find is with FireFox's built-in Error Console (Tools > Web Developer menu). Load your site, view the Error Console, and then click "Clear" to empty the log. Refresh your page, check back in the Error Console for anything that might be related to the jquery loader or other JavaScript executed on load, and then, if there is log output but not relevant click Clear once more, and then make a single key entry into the search box. Check back in the Error Console and that may reveal a JS related problem - if so and you're not sure where the problem lies let me know what is displayed and I'll check it out further with you...

Cheers,
David.
--
PriceTapestry.com

Submitted by paddyman on Wed, 2013-10-30 14:51

Thanks David.

Sorry, hadn't edited my pt installation directory as I've PT installed in a sub folder !!

Great mod by the way :)

Adrian

Submitted by paddyman on Thu, 2013-11-07 22:51

Hi David,

Trying to get this to work in the Search Widget which I have at the top of my page. Not going to have the regular search form appear in any page, so there will only be the widget. Autocomplete in the widget only looks to be working on a search page, if that makes sense. Here's my code

<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>
<script type='text/JavaScript'>
  $(function() {
  $( "#pto_q" ).autocomplete({
    source: function( request, response ) {
      $.ajax({
        url: "/pt/searchJSON.php",dataType:"json",data:{q:request.term},
        success: function( data ) {
          response($.map( data.products, function( item ) { return { label:item.name, value:item.name}
          }));
        }
      });
      },
      minLength: 2,
      open: function() { $( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" ); },
      close: function() { $( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" ); }
    })
    .keydown(function(e){ if (e.keyCode === 13) { $("#pto_search").trigger('submit'); }
    });
  });
</script>
<div class='pto_search_widget'>
<form name='pto_search' id='pto_search' method='GET' action='%ACTION%'>
<input type='text' class='pto_search_widget_q' name='pto_q' id='pto_q' value='%PTO_Q%' />
<input type='submit' value='Search' />
</form>
</div>

Any ideas?

Thanks

Adrian

Submitted by support on Fri, 2013-11-08 09:49

Hi Adrian,

Just in case there is any conflict, use an _w prefix on the id's for the widget version, e.g. pto_q_w and pto_search_w, have a go with:

<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>
<script type='text/JavaScript'>
  $(function() {
  $( "#pto_q_w" ).autocomplete({
    source: function( request, response ) {
      $.ajax({
        url: "/pt/searchJSON.php",dataType:"json",data:{q:request.term},
        success: function( data ) {
          response($.map( data.products, function( item ) { return { label:item.name, value:item.name}
          }));
        }
      });
      },
      minLength: 2,
      open: function() { $( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" ); },
      close: function() { $( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" ); }
    })
    .keydown(function(e){ if (e.keyCode === 13) { $("#pto_search_w").trigger('submit'); }
    });
  });
</script>
<div class='pto_search_widget'>
<form name='pto_search' id='pto_search_w' method='GET' action='%ACTION%'>
<input type='text' class='pto_search_widget_q' name='pto_q' id='pto_q_w' value='%PTO_Q%' />
<input type='submit' value='Search' />
</form>
</div>

If still no joy, Firefox's Error Console is good for debugging this kind of thing. Load the page, open Error Console (Tools > Web Developer > Error Console), click Clear to clear any existing errors, and then enter a letter into the search box and go back to the Error Console which might reveal the problem... If you're still not sure let me know of course and I'll check it out further for you...

Cheers,
David.
--
PriceTapestry.com

Submitted by paddyman on Fri, 2013-11-08 14:16

Hi David,

The error console pointed it out !!

I have PT installed in a sub directory and I hadn't changed the code in the line below

url: "/pt/searchJSON.php",dataType:"json",data:{q:request.term},

Many thanks :)

Adrian

Submitted by paddyman on Sat, 2013-11-09 13:58

Hi David,

As an addition to this, would it be possible to search my author field in the database as well as the products ?

Thanks

Adrian

Submitted by support on Sun, 2013-11-10 10:57

Hi Adrian,

Sure you could get searchJSON.php to return author:Author Name results. Have a go with something like the following, based on the original version from the original thread...

<?php
  require("includes/common.php");
  header("Content-Type: application/json;");
  if ($_GET["q"])
  {
    $sql = "SELECT DISTINCT(normalised_name) AS name
      FROM `".$config_databaseTablePrefix."products`
      WHERE name LIKE '".database_safe($_GET["q"])."%' LIMIT 5
      ";
    if (!database_querySelect($sql,$products))
    {
      $sql = "SELECT DISTINCT(normalised_name) AS name
        FROM `".$config_databaseTablePrefix."products`
        WHERE name LIKE '%".database_safe($_GET["q"])."%' LIMIT 5";
      database_querySelect($sql,$products);
    }
    $sql = "SELECT DISTINCT(author) AS name
      FROM `".$config_databaseTablePrefix."products`
      WHERE author LIKE '%".database_safe($_GET["q"])."%' LIMIT 5";
    if (database_querySelect($sql,$authors))
    {
      foreach($authors as $author)
      {
        $products[] = array("name"=>"author:".$author["name"]);
      }
    }
    print json_encode(array("totalResultsCount"=>count($products),"products"=>$products));
  }
  exit();
?>

Cheers,
David.
--
PriceTapestry.com

Submitted by paddyman on Sun, 2013-11-10 18:05

Hi David,

Had a go with that but autocomplete is not working for either products or authors. I'ld a look at the code but can't spot anything !!!

Thanks

ADrian

Submitted by support on Sun, 2013-11-10 18:24

Hi Adrian,

Corrected above - line 24 should be:

  $products[] = array("product"=>"author:".$author["name"]);

Cheers,
David.
--
PriceTapestry.com

Submitted by paddyman on Sun, 2013-11-10 19:55

Hi David,

Thanks for that. Still not fully working for me... products are fine, but not working for Author. Have checked my database and name of field is author.

Anything else you need from me ?

Thanks

Adrian

Submitted by support on Mon, 2013-11-11 08:45

Hi Adrian,

Are the author:Author Name results being included in the auto-complete but then no results when selecting one, or are they not appearing in the auto-complete at all?

Cheers,
David.
--
PriceTapestry.com

Submitted by paddyman on Mon, 2013-11-11 09:22

Hi David,

Author name results are not included in the auto-complete but products are.

Thanks

Adrian

Submitted by support on Mon, 2013-11-11 09:31

Hi Adrian,

I just checked locally using category instead - this line:

  $products[] = array("product"=>"author:".$author["name"]);

...should be:

  $products[] = array("name"=>"author:".$author["name"]);

(corrected above)

Cheers,
David.
--
PriceTapestry.com

Submitted by paddyman on Mon, 2013-11-11 15:03

Hi David,

That's working great now, great addition :)

Many thanks

Adrian

Submitted by koen on Fri, 2014-09-05 15:12

Hi David,

I would like to have the (autocompleted) search results pointed directly to the product page.. Therefore I changed line 6 of search.php, just like describerd in the orignal thread on http://www.pricetapestry.com/node/5003.
The code I used is:

 $q = (isset($_GET["q"])?tapestry_normalise($_GET["q"],":\."):"");
  $sql = "SELECT * FROM `".$config_databaseTablePrefix."products` WHERE normalised_name='".database_safe($q)."'";
  if (database_querySelect($sql,$rows))
  {
    header("Location: ".tapestry_productHREF($rows[0]));
    exit();
  }

This doesn't get me to the prducts page, I'm still being directed to the search results.
Can you help me on this one?

Thanks a lot!
Koen

Submitted by support on Sat, 2014-09-06 15:22

Hi Koen,

To redirect auto-complete search results in the plugin have a go editing the plugin file pto.php and look for the following code at line 191:

  pto_search_buildWhere();

...and REPLACE with:

  $sql = "SELECT * FROM `".$pto_config_databaseTablePrefix."products` WHERE normalised_name='".$wpdb->escape($pto_q)."'";
  if ($wpdb->query($sql))
  {
    header("Location: ".pto_common_productHREF($wpdb->last_result[0]));
    exit();
  }
  pto_search_buildWhere();

Hope this helps!

Cheers,
David.
--
PriceTapestry.com

Submitted by koen on Mon, 2014-09-08 18:45

Thanks, works great!