Question

The Magento front end search is not very good in my experience. I am having an issue when searching for SKUs.

I have changed the SKU attribute to be searchable, search settings are combined like and full text and all products are catalog,search.

So searching by SKU works if you type in the exact query, or maybe just the first few letters up a special character.

The problem is that a lot of our SKUs were set up with a dash in them. For example
some-sku-123

If I try to search sku123 no results will appear.

Is there a way to ignore dashes when doing the SQL search query or something similar?

Any ideas are appreciated.

This is for Magento 1.9

Was it helpful?

Solution

To make this work for both, the real SKU and the one without -, both have to be added to catalogsearch_result table because SQL-query for search results looks like this:

SELECT `s`.`product_id`, 0 AS `relevance`
FROM `catalogsearch_fulltext` AS `s`
INNER JOIN `catalog_product_entity` AS `e` ON e.entity_id = s.product_id
WHERE (s.store_id = 1) AND ((`s`.`data_index` LIKE '%sku-123%'))

I will not give an answer where you have to override core files and I'm still playing arround with catalog search reindexing process to find a way to make it work event-observer based.

As (temporarily?) solution that ends up in the same result as modifiying index process, you can do this:

  1. create a new searchable product attribute from backend, let's call it sku_search
  2. add an observer that listens to catalog_product_save_before to "autofill" this attribute
  3. Reindex Catalog Search Index
  4. DONE.

Observer code could look like this:

class My_Module_Model_Observer extends Mage_Core_Model_Observer
{
    public function setSkuSearchAttribute($observer)
    {
        $product = $observer->getProduct();
        $product->setSkuSearch(str_replace('-', '', $product->geSku()));
    }
}

I would add something, to prevent that this attribute is manually edited from backend, like another observer for catalog_product_edit_action with this code:

class My_Module_Model_Observer extends Mage_Core_Model_Observer
{
    public function lockProductAttribute(Varien_Event_Observer $observer)
    {
        $product = $observer->getProduct();
        $product->lockAttribute('sku_search');
    }
}

OTHER TIPS

In a custom module, rewrite the qetQueryText() method in Mage_CatalogSearch_Helper_Data.

Then, strip out the special characters of the query text before it is returned.

public function getQueryText()
{
    ...

    // This replaces all non-space and non-word characters with nothing
    $this->queryText = preg_replace("/[^ \w]+/", "", $this->queryText);

    return $this->_queryText;
}

You can achieve this by implementing custom extension. I have implement some kind of custom search methods that may help you in some way. It will work directly with Magento product table search not with full text.

Hope it helps.

public function search($searchedQuery, $storeId = null)
{
    if (is_null($storeId)) {
        $storeId = Mage::app()->getStore()->getId();
    }
    if (is_null($searchedQuery) || is_null($storeId)) {
        return null;
    }
    $productCollection = null;        
    $searchableAttributes = explode(',', $this->searchableAttributes() );
    $productIds = array();
    foreach ($searchableAttributes as $attributeId) {            
        $productIds = array_merge($productIds, $this->searchProducts($storeId));           
    }

    if (!count($productIds)) {
        return null;
    }
    $productCollection = $this->_prepareCollection();
    $productCollection
        ->addFilterByIds($productIds)
        ->addStoreFilter($storeId)
        ->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
        ->setVisibility(array(
            Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_SEARCH,
            Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH
        ))
    ;


    if (is_null($productCollection)) {
        return null;
    }
    $productCollection = $this->_postProcessCollection($productCollection);
    $productCollection->setOrder('name', Varien_Data_Collection::SORT_ORDER_ASC);
    $productCollection->setPageSize(10);
    return $productCollection;
}

public function getSearchedQuery()
{
    $q =  Mage::app()->getRequest()->getParam('q');
    if (is_null($q)) {
        $q = '';
    }
    return htmlspecialchars_decode(Mage::helper('core')->escapeHtml($q));
}

public function getSearchedWords()
{
    $q = $this->getSearchedQuery();
    $searchedWords = explode(' ', trim($q));
    for ($i = 0; $i < count($searchedWords); $i++) {
        if (strlen($searchedWords[$i]) < 2 || preg_match('(:)', $searchedWords[$i])) {
            unset($searchedWords[$i]);
        }
    }
    return $searchedWords;
}

protected function searchableAttributes() {
    return 'sku,name,description,short_description,meta_title';
}
protected function _getSearchableAttributesTypes()
{
    $attributes = array();
    $searchableAttributes = explode(',', $this->searchableAttributes() );
    if (count($searchableAttributes) !== 0) {
        foreach ($searchableAttributes as $attributeId) {
            $attribute = Mage::getModel('eav/entity_attribute')->load($attributeId);
            if ($attribute->getId()) {
                $attributes[$attributeId] = $attribute->getBackendType();
            }
        }
    }
    return $attributes;
}

public function searchProducts($storeId)
{
    $ids = array();
    $resource = Mage::getSingleton('core/resource');
    $db = $resource->getConnection('core_read');

    $searchedWords = $this->getSearchedWords();
    $attributes = $this->_getSearchableAttributesTypes();

    if (count($attributes) == 0) {
        return $ids;
    }
    //tbl= entity_type_collection with where entity_type_code = catalog_product
    $entityTypeId = 4;
    foreach ($attributes as $tableName) {
        if ($tableName != 'static') {
            $select = $db->select();

            if ($tableName == 'int') {
                $eaov = $resource->getTableName('eav/attribute_option_value');
                $cpei = $resource->getTableName('catalog/product') . '_' . $tableName;

                $select->from(array('cpei' => $cpei), array('cpei.entity_id'))
                    ->join(array('eaov' => $eaov), 'cpei.`value` = eaov.option_id', array())
                    ->where('cpei.entity_type_id=?', $entityTypeId)
                    ->where('cpei.store_id=0 OR cpei.store_id=?', $storeId)
                    ->where('cpei.attribute_id IN (' . implode(',', array_keys($attributes)) . ')');

                foreach ($searchedWords as $value) {
                    $select ->where('eaov.`value` LIKE "%' . addslashes($value) . '%"');
                }
            } else {
                $select
                    ->distinct()
                    ->from($resource->getTableName('catalog/product') . '_' . $tableName, 'entity_id')
                    ->where('entity_type_id=?', $entityTypeId )
                    ->where('store_id=0 OR store_id=?', $storeId)
                    ->where('attribute_id IN (' . implode(',', array_keys($attributes)) . ')');
                foreach ($searchedWords as $value) {
                    $select->where('`value` LIKE "%' . addslashes($value) . '%"');
                }
            }
            $ids = array_merge($ids, $db->fetchCol($select));
        }
        if ($tableName == 'static') {
            $select = $db->select();
            $select->distinct()
                ->from($resource->getTableName('catalog/product'), 'entity_id')
                ->where('entity_type_id=?', $entityTypeId);

            foreach ($searchedWords as $value) {
                $select->where('`sku` LIKE "%' . addslashes($value) . '%"');
            }
            $ids = array_merge($ids, $db->fetchCol($select));
        }
    }
    return array_unique($ids);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top