Saturday, March 16, 2013

Polishing up the magento mini search

 Magento comes with a mini search form complete with search suggestions. To fetch and show the search suggestions magento uses the prototype Ajax.Autocompleter. This works well but it's not fully configured in the default magento setup. The aim of this post is to complement the magento search suggestions with the following:
  • limit the number of returned results - magento returns all results by default and this can generate a long list as well as adding some overhead
  • add a search indicator so the user knows that a search is in progress
  • highlight the search term in the returned results
  • remove the number of results that magento adds to each returned result

Preparing files for editing

To achieve the points above we'll need to edit some of the magento files. As it's not good to change the magento core files we'll copy these files to the local code pool. We'll need to copy the following files:
  • app/code/core/Mage/CatalogSearch/Model/Query.php to app/code/local/Mage/CatalogSearch/Model/
  • app/code/core/Mage/CatalogSearch/Block/Autocomplete.php to app/code/local/Mage/CatalogSearch/Block/
  • app/design/frontend/base/default/template/catalogsearch/form.mini.phtml to app/design/frontend/default/default/template/catalogsearch/
 In addition to the above files we will need to edit js/varien/js.js and add some css styling. You can add the css either to your theme's css files or directly in the updated form.mini.phtml file


Limit the number of results returned by magento

Limiting the number of results is quite simple. All we need to do is edit app/code/local/Mage/CatalogSearch/Model/Query.php and add a line to the getSuggestCollection function so it looks like the following:
    /**
     * Retrieve collection of suggest queries
     *
     * @return Mage_CatalogSearch_Model_Resource_Query_Collection
     */
    public function getSuggestCollection()
    {
        $collection = $this->getData('suggest_collection');
        if (is_null($collection)) {
            $collection = Mage::getResourceModel('catalogsearch/query_collection')
                ->setStoreId($this->getStoreId())
                ->setQueryFilter($this->getQueryText());
            //limit the number of returned results
            $collection->getSelect()->limit(10);
            $this->setData('suggest_collection', $collection);
        }
        return $collection;
    }
The code that limits the result numbers is on line 14.

Removing results numbers and adding highlights to results

Ajax.Autocompleter needs a ul returned containing the search suggestions. Magento creates the list in Mage/CatalogSearch/Block/Autocomplete.php in the _toHtml() function. Edit app/code/local/Mage/CatalogSearch/Block/Autocomplete.php and change the _toHtml function as below. You can also add other changes you want applied to the results list.
    protected function _toHtml()
    {
     //change html to return a list on error otherwise the loader image doesn't go away
        $html = '
    '; if (!$this->_beforeToHtml()) { return $html; } $suggestData = $this->getSuggestData(); if (!($count = count($suggestData))) { return $html; } $count--; //get the query text $query = $this->helper('catalogsearch')->getQueryText(); $html = '
    • '; foreach ($suggestData as $index => $item) { if ($index == 0) { $item['row_class'] .= ' first'; } if ($index == $count) { $item['row_class'] .= ' last'; } $text = $this->htmlEscape($item['title']); //get the first case insensitive query occurence in the text $pos = stripos($text,$query); $length = strlen($query); if ($pos !== false) { //get the actual case sensitive piece of text that matches the query and highlight it $replacement="".substr($text, $pos, $length).""; //replace the query in the text with the highlighted version $text = substr_replace($text,$replacement,$pos, $length); } $html .= '
    • '. $text.'
    • '; } $html.= '
    '; return $html; }

    Adding the search indicator element

    The autocompleter plugin can display a visual indicator while the ajax request is running. You can generate a loading indicator at preloaders.net. We'll need to add a div that will contain our progress indicator. To do this edit app/design/frontend/default/default/template/catalogsearch/form.mini.phtml and add the following somewhere inside the search form div (or in another place where you want it displayed):
    
    
    I've uploaded my indicator to the skin/frontend/default/default/images/ folder so I can reference it using the magento getSkinUrl function.
    I want my loading image to show over the search input so I added the css styles to the element to make sure it's positioned correctly and in front of the input.

    Updating the autocomplete javascript

    The last thing we need to do is update the javascript used to initialize the Ajax.Autocompleter. Open js/varien/js.js and search for the following lines of code:
            new Ajax.Autocompleter(
                this.field,
                destinationElement,
                url,
                {
                    paramName: this.field.name,
                    method: 'get',
                    minChars: 2,
    

    Add the following lines after the miChars line:
                    frequency: 0.5,
                    indicator: 'search-running',
    
    The frequency tells autocompleter how often it should poll the input for changes and the indicator is the id of the element that should be shown while the ajax request is running.

    That's it. Comments are always welcome.