What I did in this case was to rewrite both the model and the corresponding resource, so first rewrite the class Mage_Catalog_Model_Layer_Filter_Attribute
to be able to accept multiple values. In my case, I am using commas as a separator, so I can filter like ?my_attribute=1,2,3
In the method apply()
I parse the attribute to put the different values in an array:
public function apply(Zend_Controller_Request_Abstract $request, $filterBlock)
{
$filter = $request->getParam($this->_requestVar);
if (is_array($filter)) {
return $this;
}
// MP customized
$filter = explode(',', $filter);
if (count($filter) < 1) {
return $this;
} else if ($filter == '') {
return $this;
}
if (count($filter) == 1) {
$filter = $filter[0];
}
if ($filter == '') {
return $this;
}
if ($filter) {
$this->_initItems();
$this->_getResource()->applyFilterToCollection($this, $filter);
$text = '';
foreach ($filter as $att) {
($text == '') ? $text = $this->_getOptionText($att) : $text .= ', '.$this->_getOptionText($att);
}
if (count($filter) == 1) {
$text = $this->_getOptionText($filter);
}
$this->getLayer()->getState()->addFilter($this->_createItem($text, $filter));
}
// End MP customized
return $this;
}
Then in the file Mage_Catalog_Model_Resource_Eav_Mysql4_Layer_Filter_Attribute
you have to make sure that you are able to filter for multiple values in your query, so I rewrote the following method like this:
public function applyFilterToCollection($filter, $value)
{
$collection = $filter->getLayer()->getProductCollection();
$attribute = $filter->getAttributeModel();
$connection = $this->_getReadAdapter();
$tableAlias = $attribute->getAttributeCode() . '_idx';
$conditions = array(
"{$tableAlias}.entity_id = e.entity_id",
$connection->quoteInto("{$tableAlias}.attribute_id = ?", $attribute->getAttributeId()),
$connection->quoteInto("{$tableAlias}.store_id = ?", $collection->getStoreId()),
$connection->quoteInto("{$tableAlias}.value IN (?)", $value)
); // Added IN (?) notation for arrays
$collection->getSelect()->join(
array($tableAlias => $this->getMainTable()),
join(' AND ', $conditions),
array()
// MP Need distinct here to avoid getting the same config product from
// different basic products when filtering for different values
// in the same attribute
)->distinct(true);
return $this;
}
Like all of Magento, the answer's in the source — all you need to do is go digging (or hop to then end of this post).
First, find the class for the attribute source
$source = Mage::getResourceModel('catalog/product')
->getAttribute('color')
->getSource();
var_dump(get_class($source));
exit;
In modern versions of Magento, this should point to the class Mage_Eav_Model_Entity_Attribute_Source_Table
, which is located at
#File: app/code/core/Mage/Eav/Model/Entity/Attribute/Source/Table.php
class Mage_Eav_Model_Entity_Attribute_Source_Table extends Mage_Eav_Model_Entity_Attribute_Source_Abstract
{
//...
}
Next, we'll look for the definition of the getOptionId
method on this class and/or it's parent classes. We'll find it in the Mage_Eav_Model_Entity_Attribute_Source_Abstract
class
#File: app/code/core/Mage/Eav/Model/Entity/Attribute/Source/Abstract.php
public function getOptionId($value)
{
foreach ($this->getAllOptions() as $option) {
if (strcasecmp($option['label'], $value)==0 || $option['value'] == $value) {
return $option['value'];
}
}
return null;
}
Examining this method, we can see if works by foreach
ing over a list of options from the getAllOptions
method. So let's look at this method's definition.
#File: app/code/core/Mage/Eav/Model/Entity/Attribute/Source/Table.php
public function getAllOptions($withEmpty = true, $defaultValues = false)
{
$storeId = $this->getAttribute()->getStoreId();
if (!is_array($this->_options)) {
$this->_options = array();
}
if (!is_array($this->_optionsDefault)) {
$this->_optionsDefault = array();
}
if (!isset($this->_options[$storeId])) {
$collection = Mage::getResourceModel('eav/entity_attribute_option_collection')
->setPositionOrder('asc')
->setAttributeFilter($this->getAttribute()->getId())
->setStoreFilter($this->getAttribute()->getStoreId())
->load();
$this->_options[$storeId] = $collection->toOptionArray();
$this->_optionsDefault[$storeId] = $collection->toOptionArray('default_value');
}
$options = ($defaultValues ? $this->_optionsDefault[$storeId] : $this->_options[$storeId]);
if ($withEmpty) {
array_unshift($options, array('label' => '', 'value' => ''));
}
return $options;
}
Ah ha! Now we're on to something. This appears to be the method that loads all the option information. Specifically, we're interested in
$storeId = $this->getAttribute()->getStoreId();
So, Magento gets the store ID for the options to load from the attribute. This means you should be able to do something like the following (replacing color
and red
with your own variables, of course)
//get the attribute
$attribute = Mage::getResourceModel('catalog/product')
->getAttribute('color');
//set the store id on the attribute
$attribute->setStoreId(Mage_Core_Model_App::ADMIN_STORE_ID);
//get the source
$source = $attribute->getSource();
//get the id
$id = $source->getOptionId('red');
Best Answer
by default you cannot filter by color (or any dropdown attribute) like that. The cleanest way to do it is to get the option id for the
red
color.But this could backfire if you have 2 options with the same name.
There is also this option:
But it works only when you have the flat catalog enabled and when the
color
attribute is set to be "Used in product listing".I don't recommend this approach. It can get you into trouble.