Magento – Layered Navigation – altering URLs

layered-navigationurl

[No Extension pitches please (if I want to be spammed, I'll use the magento forum :D)]

I can see this/similar has been asked before (and elsewhere).
In most cases, I see people 'recommending' extensions – yet this should be doable with some code tweaks … so I thought I'd ask.

Attribute value Name in the URL, not the ID.

The normal filtered URL looks like this;
/[attribute_name]=[attribute_id]
/colour=4

I (and many others) would like to see;
/[attribute_name]=[attribute_value]
/colour=red

To do this, I need to alter (a "local" version of);
/app/code/[code|local]/Mage/Catalog/Model/Layer/Filter/Item.phtml

The default code is;

public function getUrl()
{
    $query = array(
        $this->getFilter()->getRequestVar()=>$this->getValue(),
        Mage::getBlockSingleton('page/html_pager')->getPageVarName() => null // exclude current page from urls
    );
    return Mage::getUrl('*/*/*', array('_current'=>true, '_use_rewrite'=>true, '_query'=>$query));
}

Yet any changes I make here seem to result in the filters not loading properly.

I've been trying this (and variants);

public function getUrl()
{
    if($this->getFilter()->getRequestVar() == 'attribute_1_name'){
    // do nothing
    }
    $query = array(
        $this->getFilter()->getRequestVar()=>$this->getValue(),
        Mage::getBlockSingleton('page/html_pager')->getPageVarName() => null // exclude current page from urls
    );
    return Mage::getUrl('*/*/*', array('_current'=>true, '_use_rewrite'=>true, '_query'=>$query));
}

(Even simply inserting an if (or if/else) condition results in the attributes not loading – nor the footer!)

Now I assume that I need to do the following;
1) Check for a value in the URL
2) Fetch a collection of filterable attributes
3) Look through that list for a match to the URL value
4) get that values ID
5) Pass that ID to magento in the return data.

But I've little clue on what api/funcs exist in magento to achieve this.

Further – I'm not sure if doing this will also update the links in the filter … it would be pointless to look in the URL for specific attribute values, if the links are pointing to URLs with only IDs … so will I need to also update whatever file handles the URL creation?

Thank you very much for any assistance you can give.

.
[No Extension pitches please (if I want to be spammed, I'll use the magento forum :D)]

Best Answer

In addition to changing the URL which is being rendered, you'll need to rewrite Mage_Catalog_Model_Layer_Filter_Attribute::apply():

/**
 * Apply attribute option filter to product collection
 *
 * @param   Zend_Controller_Request_Abstract $request
 * @param   Varien_Object $filterBlock
 * @return  Mage_Catalog_Model_Layer_Filter_Attribute
 */
public function apply(Zend_Controller_Request_Abstract $request, $filterBlock)
{
    $filter = $request->getParam($this->_requestVar);
    if (is_array($filter)) {
        return $this;
    }
    $text = $this->_getOptionText($filter);
    if ($filter && strlen($text)) {
        $this->_getResource()->applyFilterToCollection($this, $filter);
        $this->getLayer()->getState()->addFilter($this->_createItem($text, $filter));
        $this->_items = array();
    }
    return $this;
}

$this->_getResource()->applyFilterToCollection($this, $filter) is where the ID is passed in. Your change needs to map the option text to the ID prior to this. Something along the lines of the following will get you going:

public function apply(Zend_Controller_Request_Abstract $request, $filterBlock)
{
    $filter = $request->getParam($this->_requestVar);
    if (is_array($filter)) {
        return $this;
    }
    $filter = $this->getAttributeModel()->getSource()->getOptionId($filter);
    $text = $this->_getOptionText($filter);
    if ($filter && strlen($text)) {
        $this->_getResource()->applyFilterToCollection($this, $filter);
        $this->getLayer()->getState()->addFilter($this->_createItem($text, $filter));
        $this->_items = array();
    }
    return $this;
}

I'm a bit concerned as to what effect this will have on caching, etc. but at least this will head you down the road to a solution.

Related Topic