製品属性とフィルタリングメカニズム
-
16-10-2019 - |
質問
TL; DR:複数の選択/ドロップダウン属性をフィルタリングする方法(マルチセレクトは面倒です)?または別の方法を使用しますか?
アルファベットの各文字に値(この場合は英語)に対応する製品の選択/ドロップダウン属性を考えてみましょう。最初のオプションのラベルは「a」、その値は1です。「b」は2、c "は3などです。
この属性は、制御層状ナビゲーションフィルターに割り当てられています。したがって、ユーザーは特定の値のリンクをクリックすると、追加できます ?my_attribute=2
リクエストパラメーターには、属性値が「b」である製品のみが表示されます。
代わりに、属性値が選択されたオプション以上の製品を表示する製品を表示したいと思います。したがって、ユーザーが階層型NAVの「B」リンクをクリックする場合、結果は「BZ」(2-26)のすべての製品になります。
URL構造: ?my_attribute=2&my_attribute_3&my_attribute=4...
ugいものになりますが、それはうまくいきませんが、アイデアはそこにあります。 ?my_attribute=2-26
明らかに理想的ですが、繰り返しますが、これはマゼントがしていることではありません。
不思議なことに、高度な検索を使用すると、このURL構造が提供されます(階層化されたNAVの代わりに高度な検索コントローラーを介して):
?my_attribute%5B%5D=7&my_attribute%5B%5D=8&my_attribute%5B%5D=9&my_attribute%5B%5D=10
これは実際、望ましい結果を提供します。ただし、この構造はカテゴリ/レイヤードページでは機能せず、高度な検索のみです。
私は、この時点でどちらがより良い道になるかを決めようとしています。階層化されたナビゲーションのすべての組み込みの有用性を放棄し、代わりに書き直す必要があります product_list
私の属性値に基づいてブロックのロードされた製品コレクション?または、自分のニーズに合わせて、高度な検索結果から機能を適応させる必要がありますか?
他の製品フィルターが期待どおりに機能し続けるように、階層化されたナビゲーション機能を単独で残すのが最善のようです。ただし、単一の属性から複数の値を同時に選択できるようには見えません。あるいは、回避策は、マルチセレクト属性を使用することであり、製品に「b」が割り当てられる場合、「BZ」からすべてのオプションを割り当てる必要があります。これは最大の瞬間的な結果を提供しますが(すべてがこれ以上修正せずに機能します)、それは確かに将来的に管理するのがエラーが発生し、不格好なずさんなソリューションです。
解決
この場合に私がしたことは、モデルと対応するリソースの両方を書き直すことでしたので、まずクラスを書き直します Mage_Catalog_Model_Layer_Filter_Attribute
複数の値を受け入れることができるように。私の場合、私はコンマをセパレーターとして使用しているので、 ?my_attribute=1,2,3
メソッドで apply()
属性を解析して、異なる値を配列に配置します。
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;
}
次に、ファイルに Mage_Catalog_Model_Resource_Eav_Mysql4_Layer_Filter_Attribute
クエリで複数の値をフィルタリングできることを確認する必要があるため、次の方法を書き直しました。
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;
}
他のヒント
これは、カスタム製品コレクションを備えた層状ナビゲーションです
<?php
require_once('app/Mage.php'); //Must have file to begin
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); //Initialize store
$catId = Mage::app()->getRequest()->getParam('categoryId'); //Pass categoryId in get variable
$storeId = Mage::app()->getWebsite(true)->getDefaultGroup()->getDefaultStoreId();
$page_no = Mage::app()->getRequest()->getParam('page_no');
$params = Mage::app()->getRequest()->getParams(); //Pass attributes in key=>value form to filter results.
$category = Mage::getModel('catalog/category')->load($catId);
$layer = Mage::getModel("catalog/layer");
$layer->setCurrentCategory($category);
$attributes = $layer->getFilterableAttributes(); //get all filterable attributes available in selected category layered navigation
$attr = array();
foreach ($attributes as $attribute) {
if ($attribute->getAttributeCode() == 'price') {
$filterBlockName = 'catalog/layer_filter_price';
} elseif ($attribute->getBackendType() == 'decimal') {
$filterBlockName = 'catalog/layer_filter_decimal';
} else {
$filterBlockName = 'catalog/layer_filter_attribute';
}
$attr[$attribute->getAttributeCode()] = $attribute->getFrontendLabel();
}
$filters = array_intersect_key($params, $attr);
$collection = $category->getProductCollection()
->addAttributeToFilter(
'status', array('eq' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED))
->addAttributeToSelect('*');
foreach ($filters as $key => $value) {
if($key == 'price'){
$priceFilter = explode('-', $value);
$collection->addAttributeToFilter('price', array('gteq' => $priceFilter[0]));
$collection->addAttributeToFilter('price', array('lteq' => $priceFilter[1]));
}
else{
$codeId = Mage::getResourceModel('eav/entity_attribute')
->getIdByCode('catalog_product', $key)
$collection->getSelect()->join(array('at_'.$key =>'catalog_product_index_eav'),'at_'.$key.'.entity_id = e.entity_id and at_'.$key.'.attribute_id = '.$codeId.' and at_'.$key.'.store_id = '.Mage::helper('mobile')->getStore()->getId())->where('at_'.$key.'.value = '.$value);
}
}
$collection->setPage($page_no, 10);
foreach($collection as $product){
echo $product->getName();
}