When we search any text in default magento it shows only products in the search result but I want to show the categories also when someone searches for a query string.
Like if query string is like catalogsearch/result/?q=brother
Then the result should contain category and products.
The result should also be formatted like first we show the category then it's products that match the query string then second category and it's products and so on. If category match not found show only products and if product match is not found then show categories which match the query string.
What I want is the list view which contains both categories and products just like http://www.ldproducts.com/ldpsearch/result/?q=officejet+pro+8000
Goto this URL and scroll till the bottom and you'll see what I exactly want.
Googled a lot but was unable to find the desired answer. I am not supposed to use any extension or make any changes on the phtml file(until it's damn mandatory).
My magento version is 1.9.0.1
-
desperately waiting for answers or comments– Ashwani ShuklaCommented Feb 9, 2016 at 8:49
-
I am working on this. Maybe you can wait till I am able to answer this. For more info, I did not find any extension which is free or paid for this sort of manipulation. To start with I am trying to reuse the concept of "Layers" as it displays "Categories" and the number of products - which are associated with those categories in default magento. Thanks!– ShivaniCommented Feb 9, 2016 at 9:00
-
@Shivani Thanks a lot, waiting for your answer. FYI: there is a extension mirasvit sphinx search.– Ashwani ShuklaCommented Feb 9, 2016 at 9:11
-
Yes I did take a look at Sphinx Search. However, I felt that needs quite a bit of customization to get what you want :)– ShivaniCommented Feb 9, 2016 at 9:21
-
@Shivani have you found any solution ?– Ashwani ShuklaCommented Feb 9, 2016 at 10:31
2 Answers
Interesting question, hence upvoting it. Below is the code for achieving the categories and the corresponding products as results. I have planned to reuse the FILTERS (Layered Navigation) concept to be able to display the categories and products as per the screenshots here:
These screenshots are currently not displaying the correct price, name etc. Hence this might need to be checked in the product collection that is present in the code written below. Hope you can figure out how to bring that and display it.
Step 1:
Create the below mentioned files.
- /app/code/local/Namespace/Modulename/Block/Catalog/Product/List.php
- /app/code/local/Namespace/Modulename/Block/CatalogSearch/Layer/Filter/Category.php
- /app/code/local/Namespace/Modulename/Block/CatalogSearch/Layer/State.php
- /app/code/local/Namespace/Modulename/Block/CatalogSearch/Layer.php
- /app/code/local/Namespace/Modulename/etc/config.xml
- /app/etc/modules/Namespace_Modulename.xml
- /app/design/frontend/rwd/default/layout/catalogsearch.xml
- /app/design/frontend/rwd/default/template/catalogsearch/ /app/design/frontend/rwd/default/template/catalogsearch/product/list.phtml /app/design/frontend/rwd/default/template/catalogsearch/layer/filter.phtml /app/design/frontend/rwd/default/template/catalogsearch/layer/state.phtml /app/design/frontend/rwd/default/template/catalogsearch/layer/view.phtml
See each file content as below:
1. /app/code/local/Namespace/Modulename/Block/Catalog/Product/List.php
<?php
class Namespace_Modulename_Block_Catalog_Product_List extends Mage_Catalog_Block_Product_List
{
/**
* return the search results with the category filters added
*
* @return Mage_Catalog_Model_Resource_Product_Collection|false
*/
public function getCategoryProductSearchResults()
{
$productCollection = $this->getData('product_collection');
return $productCollection;
}
}
2. /app/code/local/Namespace/Modulename/Block/CatalogSearch/Layer/Filter/Category.php
<?php
/**
* reuse existing magento default category filters
* in order to display the categories and the corresponding products
*/
class Namespace_Modulename_Block_CatalogSearch_Layer_Filter_Category extends Mage_Catalog_Block_Layer_Filter_Category
{
public $_filter;
/**
* Initialize filter template
*
*/
public function __construct()
{
parent::__construct();
$this->setTemplate('catalogsearch/layer/filter.phtml');
}
/**
* set product collection based on the search term
* add to the block and render the block HTML
*
* @param Mage_Catalog_Model_Category $_item
* @param string $count
*
* @return HTML
*/
public function getCategoryProductSearchResultHtml($_item, $count)
{
$block = '';
//form the search query once again based on the keyword to get the complete product collection
$term = Mage::helper('catalogsearch')->getQueryText();
$query = Mage::getModel('catalogsearch/query')->setQueryText($term)->prepare();
Mage::getResourceModel('catalogsearch/fulltext')->prepareResult(
Mage::getModel('catalogsearch/fulltext'),
$term,
$query
);
//get complete product collection based on the search term
$collection = Mage::getResourceModel('catalog/product_collection');
$collection->getSelect()->joinInner(
array('search_result' => $collection->getTable('catalogsearch/result')),
$collection->getConnection()->quoteInto(
'search_result.product_id=e.entity_id AND search_result.query_id=?',
$query->getId()
),
array('relevance' => 'relevance')
);
//add category filter for each category
$categoryId = $this->getCategoryId($_item);
$collection->joinField('category_id','catalog/category_product','category_id','product_id=entity_id',null,'left')
->addAttributeToFilter('category_id', array('in' => $categoryId));
Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($collection);
Mage::getSingleton('catalog/product_visibility')->addVisibleInSearchFilterToCollection($collection);
//$productIds = array();
//$productIds = $collection->getAllIds();
//Zend_Debug::dump($productIds);
//$this->_productCollection = $collection;
//$collection->printLogQuery(true);
if(count($collection))
{
$block = $this->getLayout()->createBlock('namespace_modulename/catalog_product_list')
->setProductCollection($collection)
->setTemplate('catalogsearch/product/list.phtml');
return $block->toHtml();
}
}
/**
* get the category id based on the name/label of the category filter
*
* @param Mage_Catalog_Model_Category $_item
* @return string
*/
public function getCategoryId($_item)
{
$categoryCollection = Mage::getModel('catalog/category')->getCollection()
->addAttributeToSelect('*')
->addAttributeToFilter('name', trim($_item->getLabel()))
;
foreach ($categoryCollection as $data)
{
return $data->getId();
}
}
}
3. /app/code/local/Namespace/Modulename/Block/CatalogSearch/Layer/State.php
<?php
/**
* reuse the concept of state_renderers from default magento
* change the template for search results page only
*/
class Namespace_Modulename_Block_CatalogSearch_Layer_State extends Mage_Catalog_Block_Layer_State
{
/**
* Initialize Layer State template
*
*/
public function __construct()
{
parent::__construct();
$this->setTemplate('catalogsearch/layer/state.phtml');
}
}
4. /app/code/local/Namespace/Modulename/Block/CatalogSearch/Layer.php
<?php
/**
* reuse the default magento layer concept
* add a new block if its a search page with new template
* load the existing block to display the HTML
*/
class Namespace_Modulename_Block_CatalogSearch_Layer extends Mage_CatalogSearch_Block_Layer
{
protected $_searchStateBlockName;
protected $_searchFilterHtmlBlockName;
/**
* Initialize blocks names
*/
protected function _initBlocks()
{
parent::_initBlocks();
$route = Mage::app()->getRequest()->getRouteName();
if ( $route == 'catalogsearch' )
{
$this->_searchStateBlockName = 'namespace_modulename/catalogsearch_layer_state';
$this->_searchFilterHtmlBlockName = 'namespace_modulename/catalogsearch_layer_filter_category';
}
}
/**
* Get search categories layered navigation state html
*
* @return string
*/
public function getSearchStateHtml()
{
if ( $this->_searchStateBlockName != NULL )
{
$searchStateBlock = $this->getLayout()->createBlock($this->_searchStateBlockName)->setLayer($this->getLayer());
$this->setChild('search_layer_state', $searchStateBlock);
}
return $this->getChildHtml('search_layer_state');
}
/**
* return the manipulated filter html from the PHTML for search
*
* @param Mage_Catalog_Model_Layer_Filter_Abstract|false $_filter
* @return HTML
*/
public function getSearchFilterHtml($_filter)
{
if ( $this->_searchStateBlockName != NULL )
{
$block = $this->getLayout()->createBlock($this->_searchFilterHtmlBlockName)
->setLayer($this->getLayer())
;
$block->_filter = $_filter;
return $block->toHtml();
}
}
}
5. /app/code/local/Namespace/Modulename/etc/config.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<Namespace_Modulename>
<version>1.0.0</version>
</Namespace_Modulename>
</modules>
<global>
<blocks>
<namespace_modulename>
<class>Namespace_Modulename_Block</class>
</namespace_modulename>
<catalog>
<rewrite>
<product_list>Namespace_Modulename_Block_Catalog_Product_List</product_list>
</rewrite>
</catalog>
<catalogsearch>
<rewrite>
<layer>Namespace_Modulename_Block_CatalogSearch_Layer</layer>
</rewrite>
</catalogsearch>
</blocks>
<helpers>
<namespace_modulename>
<class>Namespace_Modulename_Helper</class>
</namespace_modulename>
</helpers>
</global>
</config>
6. /app/etc/modules/Namespace_Modulename.xml
I am sure you can create this :-)
7. /app/design/frontend/rwd/default/layout/catalogsearch.xml
...
<catalogsearch_result_index translate="label">
<label>Quick Search Form</label>
<reference name="root">
<action method="setTemplate"><template>page/3columns.phtml</template></action>
</reference>
<reference name="left_first">
<block type="catalogsearch/layer" name="catalogsearch.leftnav" after="currency" template="catalog/layer/view.phtml">
<block type="core/text_list" name="catalog.leftnav.state.renderers" as="state_renderers" />
</block>
</reference>
<reference name="content">
<block type="catalogsearch/result" name="search.result" template="catalogsearch/result.phtml">
<!--block type="catalog/product_list" name="search_result_list" template="catalog/product/list.phtml"-->
<block type="namespace_modulename/catalog_product_list" name="search_result_list" template="catalogsearch/product/list.phtml">
<block type="namespace_modulename/catalogsearch_layer" name="modulename.catalogsearch.leftnav" after="currency" template="catalogsearch/layer/view.phtml">
<block type="core/text_list" name="catalog.leftnav.state.renderers" as="state_renderers" />
</block>
</block>
</block>
</reference>
</catalogsearch_result_index>
...
/app/design/frontend/rwd/default/template/catalogsearch/product/list.phtml
<?php echo $this->getChildHtml('modulename.catalogsearch.leftnav'); ?>
<?php
$_productCollection=$this->getCategoryProductSearchResults();
if (count($_productCollection))
{
$_helper = $this->helper('catalog/output');
?>
<div class="category-products">
<?php // Grid Mode ?>
<?php $_collectionSize = $_productCollection->count() ?>
<?php $_columnCount = $this->getColumnCount(); ?>
<ul class="products-grid products-grid--max-<?php echo $_columnCount; ?>-col">
<?php $i=0; foreach ($_productCollection as $_product): ?>
<?php /*if ($i++%$_columnCount==0): ?>
<?php endif*/ ?>
<li class="item<?php if(($i-1)%$_columnCount==0): ?> first<?php elseif($i%$_columnCount==0): ?> last<?php endif; ?>">
<a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $this->stripTags($this->getImageLabel($_product, 'small_image'), null, true) ?>" class="product-image">
<?php $_imgSize = 210; ?>
<img id="product-collection-image-<?php echo $_product->getId(); ?>"
src="<?php echo $this->helper('catalog/image')->init($_product, 'small_image')->resize($_imgSize); ?>"
alt="<?php echo $this->stripTags($this->getImageLabel($_product, 'small_image'), null, true) ?>" />
</a>
<div class="product-info">
<h2 class="product-name"><a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $this->stripTags($_product->getName(), null, true) ?>"><?php echo $_helper->productAttribute($_product, $_product->getName(), 'name') ?></a></h2>
<?php
// Provides extra blocks on which to hang some features for products in the list
// Features providing UI elements targeting this block will display directly below the product name
if ($this->getChild('name.after')) {
$_nameAfterChildren = $this->getChild('name.after')->getSortedChildren();
foreach ($_nameAfterChildren as $_nameAfterChildName) {
$_nameAfterChild = $this->getChild('name.after')->getChild($_nameAfterChildName);
$_nameAfterChild->setProduct($_product);
echo $_nameAfterChild->toHtml();
}
}
?>
<?php echo $this->getPriceHtml($_product, true) ?>
<?php if($_product->getRatingSummary()): ?>
<?php echo $this->getReviewsSummaryHtml($_product, 'short') ?>
<?php endif; ?>
<div class="actions">
<?php if(!$_product->canConfigure() && $_product->isSaleable()): ?>
<button type="button" title="<?php echo $this->quoteEscape($this->__('Add to Cart')) ?>" class="button btn-cart" onclick="setLocation('<?php echo $this->getAddToCartUrl($_product) ?>')"><span><span><?php echo $this->__('Add to Cart') ?></span></span></button>
<?php elseif($_product->getStockItem() && $_product->getStockItem()->getIsInStock()): ?>
<a title="<?php echo $this->quoteEscape($this->__('View Details')) ?>" class="button" href="<?php echo $_product->getProductUrl() ?>"><?php echo $this->__('View Details') ?></a>
<?php else: ?>
<p class="availability out-of-stock"><span><?php echo $this->__('Out of stock') ?></span></p>
<?php endif; ?>
<ul class="add-to-links">
<?php if ($this->helper('wishlist')->isAllow()) : ?>
<li><a href="<?php echo $this->helper('wishlist')->getAddUrl($_product) ?>" class="link-wishlist"><?php echo $this->__('Add to Wishlist') ?></a></li>
<?php endif; ?>
<?php if($_compareUrl=$this->getAddToCompareUrl($_product)): ?>
<li><span class="separator">|</span> <a href="<?php echo $_compareUrl ?>" class="link-compare"><?php echo $this->__('Add to Compare') ?></a></li>
<?php endif; ?>
</ul>
</div>
<?php
// Provides extra blocks on which to hang some features for products in the list
// Features providing UI elements targeting this block will display directly below the product name
if ($this->getChild('price.cart.after')) {
$_priceCartAfterChildren = $this->getChild('price.cart.after')->getSortedChildren();
foreach ($_priceCartAfterChildren as $_priceCartAfterChildName) {
$_priceCartAfterChild = $this->getChild('price.cart.after')->getChild($_priceCartAfterChildName);
$_priceCartAfterChild->setProduct($_product);
echo $_priceCartAfterChild->toHtml();
}
}
?>
</div>
</li>
<?php /*if ($i%$_columnCount==0 || $i==$_collectionSize): ?>
<?php endif*/ ?>
<?php endforeach ?>
</ul>
<script type="text/javascript">decorateGeneric($$('ul.products-grid'), ['odd','even','first','last'])</script>
</div>
<?php
// Provides a block where additional page components may be attached, primarily good for in-page JavaScript
if ($this->getChild('after')) {
$_afterChildren = $this->getChild('after')->getSortedChildren();
foreach ($_afterChildren as $_afterChildName) {
$_afterChild = $this->getChild('after')->getChild($_afterChildName);
//set product collection on after blocks
$_afterChild->setProductCollection($_productCollection);
echo $_afterChild->toHtml();
}
}
}
?>
/app/design/frontend/rwd/default/template/catalogsearch/layer/filter.phtml
<?php
/**
* Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE_AFL.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Magento to newer
* versions in the future. If you wish to customize Magento for your
* needs please refer to http://www.magento.com for more information.
*
* @category design
* @package rwd_default
* @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com)
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
*/
?>
<?php
/**
* Template for filter items block
*
* @see Mage_Catalog_Block_Layer_Filter
*/
?>
<ol>
<?php $count = 1; ?>
<?php foreach ($this->getItems() as $_item): ?>
<li>
<?php if ($_item->getCount() > 0): ?>
<?php /*<a href="<?php echo $this->urlEscape($_item->getUrl()) ?>">*/ ?>
<?php echo $_item->getLabel() ?>
<?php if ($this->shouldDisplayProductCount()): ?>
<span class="count">(<?php echo $_item->getCount() ?>)</span>
<?php endif; ?>
<?php echo $this->getCategoryProductSearchResultHtml($_item, $count); ?>
<?php /*</a>*/ ?>
<?php else: ?>
<span>
<?php echo $_item->getLabel(); ?>
<?php if ($this->shouldDisplayProductCount()): ?>
<span class="count">(<?php echo $_item->getCount() ?>)</span>
<?php endif; ?>
</span>
<?php endif; ?>
</li>
<?php endforeach ?>
</ol>
/app/design/frontend/rwd/default/template/catalogsearch/layer/state.phtml
This file MAY NOT be needed. I have kept it to just make sure the reusing of filters works correctly or not.
<?php
/**
* Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE_AFL.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Magento to newer
* versions in the future. If you wish to customize Magento for your
* needs please refer to http://www.magento.com for more information.
*
* @category design
* @package rwd_default
* @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com)
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
*/
?>
<?php
/**
* Category layered navigation state
*
* @see Mage_Catalog_Block_Layer_State
*/
?>
<?php
$_filters = $this->getActiveFilters();
$_renderers = $this->getParentBlock()->getChild('state_renderers')->getSortedChildren();
?>
<?php if(!empty($_filters)): ?>
<div class="currently">
<ol>
<?php foreach ($_filters as $_filter): ?>
<?php
$_rendered = false;
foreach ($_renderers as $_rendererName):
$_renderer = $this->getParentBlock()->getChild('state_renderers')->getChild($_rendererName);
if (method_exists($_renderer, 'shouldRender') && $_renderer->shouldRender($_filter)):
$_renderer->setFilter($_filter);
echo $_renderer->toHtml();
$_rendered = true;
break;
endif;
endforeach;
if (!$_rendered):
?>
<li>
<?php
$clearLinkUrl = $_filter->getClearLinkUrl();
if ($clearLinkUrl):
?>
<a class="btn-previous" href="<?php echo $_filter->getRemoveUrl() ?>" title="<?php echo Mage::helper('core')->quoteEscape($this->__('Previous')) ?>"><?php echo $this->__('Previous') ?></a>
<a class="btn-remove" title="<?php echo $this->escapeHtml($_filter->getFilter()->getClearLinkText()) ?>" href="<?php echo $clearLinkUrl ?>"><?php echo $this->escapeHtml($_filter->getFilter()->getClearLinkText()) ?></a>
<?php else: ?>
<a class="btn-remove" href="<?php echo $_filter->getRemoveUrl() ?>" title="<?php echo Mage::helper('core')->quoteEscape($this->__('Remove This Item')) ?>"><?php echo $this->__('Remove This Item') ?></a>
<?php endif; ?>
<span class="label"><?php echo $this->__($_filter->getName()) ?>:</span> <span class="value"><?php echo $this->stripTags($_filter->getLabel()) ?></span>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ol>
</div>
<?php endif; ?>
/app/design/frontend/rwd/default/template/catalogsearch/layer/view.phtml
<?php
/**
* Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE_AFL.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Magento to newer
* versions in the future. If you wish to customize Magento for your
* needs please refer to http://www.magento.com for more information.
*
* @category design
* @package rwd_default
* @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com)
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
*/
?>
<?php
/**
* Category layered navigation
*
* @see Mage_Catalog_Block_Layer_View
*/
?>
<?php if($this->canShowBlock()): ?>
<div class="block block-layered-nav<?php if (!$this->getLayer()->getState()->getFilters()): ?> block-layered-nav--no-filters<?php endif; ?>">
<?php /*<div class="block-title">
<strong><span><?php echo $this->__('Shop By') ?></span></strong>
</div>*/ ?>
<!--div class="block-content toggle-content"-->
<?php echo $this->getSearchStateHtml() ?>
<?php /*if ($this->getLayer()->getState()->getFilters()): ?>
<div class="actions"><a href="<?php echo $this->getClearUrl() ?>"><?php echo $this->__('Clear All') ?></a></div>
<?php endif;*/ ?>
<?php if($this->canShowOptions()): ?>
<!--p class="block-subtitle block-subtitle--filter"><?php //echo $this->__('Filter') ?></p>
<dl id="narrow-by-list"-->
<?php $_filters = $this->getFilters() ?>
<?php foreach ($_filters as $_filter): ?>
<?php if($_filter->getItemsCount()): ?>
<dd><?php echo $this->getSearchFilterHtml($_filter); ?></dd>
<?php endif; ?>
<?php endforeach; ?>
<!--/dl-->
<script type="text/javascript">decorateDataList('narrow-by-list')</script>
<?php endif; ?>
<!--/div-->
</div>
<?php endif; ?>
DISCLAIMER: I was able to work on this only to produce relevant results how the question was described above. To be able to display categories and products based on the search term. I am not sure if this will work to fetch only categories or only products. This needs to be checked based on our discussion in the chat.
As a note: currently the left navigation on the search page is not working as expected based on the code I have done. That also might need to be checked.
Hope this helps you and someone.
Happy Coding...
-
the code showed some error which I told you on chat. Please help me with the same Commented Feb 10, 2016 at 9:06
-
but this is not what I think I needed. I want results like this ldproducts.com/ldpsearch/result/?q=officejet+pro+8000 where categories and products both are shown matching the query string Commented Feb 10, 2016 at 13:01
-
according to your code I can see that you are displaying the categories of the products(that are in search result) and not individually. what akhil tried to say in his answer is somewhat similar to your code. Commented Feb 10, 2016 at 13:12
-
-
Hey Ashwani... Just trying to understand further.. So you want CATEGORY Search and PRODUCT Search both where upon displaying CATEGORY (should show few products from that specific category with those specific products that match the [query name/string]) and PRODUCTS as per default Magento. Am I right?– ShivaniCommented Feb 11, 2016 at 5:44
Hmm Big task..!! Not sure But this way could be quick & dirty way.
You did not mentioned as what category attribute need to use to display category in search result.
Let's suppose Category name
is the attribute & if this matches the search text string then this category should be display in search result.
Create one copy of this file in your theme directory.
/app/design/frontend/package_name/default/template/catalog/product/list.phtml
Now you have the collection of products based on search that in foreach loop.
Within this foreach you have to create arrays based on things like 'category name'=>'Product Name' & what are the things you need.
Now use these arrays to display like Category Name then it's product.
Note: Please note the product list pages use the same file. So take care the confliction.
-
in this way we will not be able to show the categories that match the query string but their products do not match the query string. please read the question again Commented Feb 10, 2016 at 12:15
-
Why your'e not able to do that. Can't you get the search string & category name & then see if category name having that search string? And if category matches then get all the products of that category. Commented Feb 10, 2016 at 13:00
-
what I want is different from what you are saying. I want to seach the categories exactly the same way as we search products. I just want the list view which shows both categories and products Commented Feb 10, 2016 at 13:20
-