6

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

  • i am thinking that there should be a way to strip out the special characters from the SKU column when performing the search somehow without actually updating the rows. – mikebertiean Jun 8 '17 at 19:29
6
+50

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');
    }
}
| improve this answer | |
  • I like this idea, thanks! I will implement it like this – mikebertiean Jun 12 '17 at 14:26
  • sure thing thanks for the answer this worked exactly as needed. – mikebertiean Jun 14 '17 at 14:32
1

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;
}
| improve this answer | |
  • so this just removes special characters from my query string. does not answer my question – mikebertiean Jun 8 '17 at 20:03
0

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);
}
| improve this answer | |
  • can you explain a little bit the logic behind this code? – mikebertiean Jun 12 '17 at 14:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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