This repository has been archived by the owner on Mar 22, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from robbieaverill/issue/12-swatch-order
[#12] Fix for swatch ordering
- Loading branch information
Showing
15 changed files
with
502 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
language: php | ||
php: | ||
- 5.3 | ||
- 5.4 | ||
- 5.5 | ||
- 5.6 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<?php | ||
/** | ||
* Helper to provide sorting methods for attribute option values | ||
* | ||
* @category Mage | ||
* @package RobbieAverill_AttributeFix | ||
* @author Robbie Averill <[email protected]> | ||
*/ | ||
class RobbieAverill_AttributeFix_Helper_Data extends Mage_Core_Helper_Abstract | ||
{ | ||
/** | ||
* Sort the attribute options by their sort order | ||
* @param array $options | ||
* @return array | ||
*/ | ||
public function sortOptionValues($options) | ||
{ | ||
$optionIds = array_keys($options); | ||
$sortOrder = $this->getSortOrderForAttributeOptions($optionIds); | ||
|
||
foreach ($sortOrder as $optionId => &$value) { | ||
$value = $options[$optionId]; | ||
} | ||
|
||
return $sortOrder; | ||
} | ||
|
||
/** | ||
* Given an array of attribute option IDs, get their sort order | ||
* @param array $optionIds | ||
* @return array | ||
*/ | ||
public function getSortOrderForAttributeOptions($optionIds) | ||
{ | ||
$resource = Mage::getModel('core/resource'); | ||
$connection = $resource->getConnection('core/read'); | ||
|
||
$select = $connection->select() | ||
->from( | ||
['e' => $resource->getTableName('eav/attribute_option')], | ||
['option_id', 'sort_order'] | ||
) | ||
->where('option_id IN (' . implode(',', array_map('intval', $optionIds)) . ')') | ||
->order('sort_order'); | ||
|
||
$orders = $connection->fetchAll($select); | ||
|
||
$output = []; | ||
foreach ($orders as $order) { | ||
$output[$order['option_id']] = $order['sort_order']; | ||
} | ||
|
||
return $output; | ||
} | ||
} |
114 changes: 114 additions & 0 deletions
114
app/code/local/RobbieAverill/AttributeFix/Helper/Mediafallback.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
<?php | ||
/** | ||
* Extending the mediafallback helper to add sort_order for attribute option values | ||
* | ||
* @category Mage | ||
* @package RobbieAverill_AttributeFix | ||
* @author Robbie Averill <[email protected]> | ||
*/ | ||
class RobbieAverill_AttributeFix_Helper_Mediafallback extends Mage_ConfigurableSwatches_Helper_Mediafallback | ||
{ | ||
/** | ||
* Set child_attribute_label_mapping on products with attribute label -> product mapping | ||
* Depends on following product data: | ||
* - product must have children products attached | ||
* | ||
* @param array $parentProducts | ||
* @param $storeId | ||
* @return void | ||
*/ | ||
public function attachConfigurableProductChildrenAttributeMapping(array $parentProducts, $storeId) | ||
{ | ||
$listSwatchAttr = Mage::helper('configurableswatches/productlist')->getSwatchAttribute(); | ||
|
||
$parentProductIds = array(); | ||
/* @var $parentProduct Mage_Catalog_Model_Product */ | ||
foreach ($parentProducts as $parentProduct) { | ||
$parentProductIds[] = $parentProduct->getId(); | ||
} | ||
|
||
$configAttributes = Mage::getResourceModel('configurableswatches/catalog_product_attribute_super_collection') | ||
->addParentProductsFilter($parentProductIds) | ||
->attachEavAttributes() | ||
->setStoreId($storeId) | ||
; | ||
|
||
$optionLabels = array(); | ||
foreach ($configAttributes as $attribute) { | ||
$optionLabels += $attribute->getOptionLabels(); | ||
} | ||
|
||
foreach ($parentProducts as $parentProduct) { | ||
$mapping = array(); | ||
$listSwatchValues = array(); | ||
|
||
/* @var $attribute Mage_Catalog_Model_Product_Type_Configurable_Attribute */ | ||
foreach ($configAttributes as $attribute) { | ||
/* @var $childProduct Mage_Catalog_Model_Product */ | ||
if (!is_array($parentProduct->getChildrenProducts())) { | ||
continue; | ||
} | ||
|
||
foreach ($parentProduct->getChildrenProducts() as $childProduct) { | ||
|
||
// product has no value for attribute, we can't process it | ||
if (!$childProduct->hasData($attribute->getAttributeCode())) { | ||
continue; | ||
} | ||
$optionId = $childProduct->getData($attribute->getAttributeCode()); | ||
|
||
// if we don't have a default label, skip it | ||
if (!isset($optionLabels[$optionId][0])) { | ||
continue; | ||
} | ||
|
||
// normalize to all lower case before we start using them | ||
$optionLabels = array_map(function ($value) { | ||
return array_map('Mage_ConfigurableSwatches_Helper_Data::normalizeKey', $value); | ||
}, $optionLabels); | ||
|
||
// using default value as key unless store-specific label is present | ||
$optionLabel = $optionLabels[$optionId][0]; | ||
if (isset($optionLabels[$optionId][$storeId])) { | ||
$optionLabel = $optionLabels[$optionId][$storeId]; | ||
} | ||
|
||
// initialize arrays if not present | ||
if (!isset($mapping[$optionLabel])) { | ||
$mapping[$optionLabel] = array( | ||
'product_ids' => array(), | ||
); | ||
} | ||
$mapping[$optionLabel]['product_ids'][] = $childProduct->getId(); | ||
$mapping[$optionLabel]['label'] = $optionLabel; | ||
$mapping[$optionLabel]['default_label'] = $optionLabels[$optionId][0]; | ||
$mapping[$optionLabel]['labels'] = $optionLabels[$optionId]; | ||
|
||
if ($attribute->getAttributeId() == $listSwatchAttr->getAttributeId() | ||
&& !in_array($mapping[$optionLabel]['label'], $listSwatchValues) | ||
) { | ||
$listSwatchValues[$optionId] = $mapping[$optionLabel]['label']; | ||
} | ||
} // end looping child products | ||
} // end looping attributes | ||
|
||
|
||
foreach ($mapping as $key => $value) { | ||
$mapping[$key]['product_ids'] = array_unique($mapping[$key]['product_ids']); | ||
} | ||
|
||
/** | ||
* Start modification: sort the swatch values by their sort order | ||
* @author Robbie Averill <[email protected]> | ||
*/ | ||
$listSwatchValues = Mage::helper('attributefix')->sortOptionValues($listSwatchValues); | ||
/** | ||
* End moficiation | ||
* @author Robbie Averill <[email protected]> | ||
*/ | ||
|
||
$parentProduct->setChildAttributeLabelMapping($mapping) | ||
->setListSwatchAttrValues($listSwatchValues); | ||
} // end looping parent products | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
.../RobbieAverill/AttributeFix/Model/Resource/Catalog/Product/Attribute/Super/Collection.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
/** | ||
* Overridden to re-enable the attribute option sorting by relevance rather than by ID as changed | ||
* in the Magento core class. This class is to re-enable the ordering for swatches, since it extends | ||
* the attribute collection by class name. | ||
* | ||
* @category Mage | ||
* @package RobbieAverill_AttributeFix | ||
* @author Robbie Averill <[email protected]> | ||
*/ | ||
class RobbieAverill_AttributeFix_Model_Resource_Catalog_Product_Attribute_Super_Collection | ||
extends Mage_ConfigurableSwatches_Model_Resource_Catalog_Product_Attribute_Super_Collection | ||
{ | ||
/** | ||
* Get the override functionality - it's in a trait for re-usability | ||
*/ | ||
use RobbieAverill_AttributeFix_Model_Resource_Product_Type_Configurable_Attribute_CollectionCommon; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,120 +11,7 @@ class RobbieAverill_AttributeFix_Model_Resource_Product_Type_Configurable_Attrib | |
extends Mage_Catalog_Model_Resource_Product_Type_Configurable_Attribute_Collection | ||
{ | ||
/** | ||
* Load attribute prices information | ||
* | ||
* @return self | ||
* Get the override functionality - it's in a trait for re-usability | ||
*/ | ||
protected function _loadPrices() | ||
{ | ||
if ($this->count()) { | ||
$pricings = array( | ||
0 => array() | ||
); | ||
|
||
if ($this->getHelper()->isPriceGlobal()) { | ||
$websiteId = 0; | ||
} else { | ||
$websiteId = (int)Mage::app()->getStore($this->getStoreId())->getWebsiteId(); | ||
$pricing[$websiteId] = array(); | ||
} | ||
|
||
$select = $this->getConnection()->select() | ||
->from(array('price' => $this->_priceTable)) | ||
->where('price.product_super_attribute_id IN (?)', array_keys($this->_items)); | ||
|
||
if ($websiteId > 0) { | ||
$select->where('price.website_id IN(?)', array(0, $websiteId)); | ||
} else { | ||
$select->where('price.website_id = ?', 0); | ||
} | ||
|
||
$query = $this->getConnection()->query($select); | ||
|
||
while ($row = $query->fetch()) { | ||
$pricings[(int)$row['website_id']][] = $row; | ||
} | ||
|
||
$values = array(); | ||
|
||
foreach ($this->_items as $item) { | ||
$productAttribute = $item->getProductAttribute(); | ||
if (!($productAttribute instanceof Mage_Eav_Model_Entity_Attribute_Abstract)) { | ||
continue; | ||
} | ||
$options = $productAttribute->getFrontend()->getSelectOptions(); | ||
|
||
$optionsByValue = array(); | ||
foreach ($options as $option) { | ||
$optionsByValue[$option['value']] = $option['label']; | ||
} | ||
|
||
/** | ||
* Modification to re-enable the sorting by relevance for attribute options | ||
* @author Robbie Averill <[email protected]> | ||
*/ | ||
$toAdd = array(); | ||
foreach ($this->getProduct()->getTypeInstance(true) | ||
->getUsedProducts(array($productAttribute->getAttributeCode()), $this->getProduct()) | ||
as $associatedProduct) { | ||
|
||
$optionValue = $associatedProduct->getData($productAttribute->getAttributeCode()); | ||
|
||
if (array_key_exists($optionValue, $optionsByValue)) { | ||
$toAdd[] = $optionValue; | ||
} | ||
} | ||
|
||
// Add the attribute options, but in the relevant order rather than by ID | ||
foreach (array_intersect_key($optionsByValue, array_flip($toAdd)) as $optionValueKey => $optionValue) { | ||
// If option available in associated product | ||
if (!isset($values[$item->getId() . ':' . $optionValueKey])) { | ||
// If option not added, we will add it. | ||
$values[$item->getId() . ':' . $optionValueKey] = array( | ||
'product_super_attribute_id' => $item->getId(), | ||
'value_index' => $optionValueKey, | ||
'label' => $optionsByValue[$optionValueKey], | ||
'default_label' => $optionsByValue[$optionValueKey], | ||
'store_label' => $optionsByValue[$optionValueKey], | ||
'is_percent' => 0, | ||
'pricing_value' => null, | ||
'use_default_value' => true | ||
); | ||
} | ||
} | ||
/** | ||
* End attribute option order modification | ||
* @author Robbie Averill <[email protected]> | ||
*/ | ||
} | ||
|
||
foreach ($pricings[0] as $pricing) { | ||
// Addding pricing to options | ||
$valueKey = $pricing['product_super_attribute_id'] . ':' . $pricing['value_index']; | ||
if (isset($values[$valueKey])) { | ||
$values[$valueKey]['pricing_value'] = $pricing['pricing_value']; | ||
$values[$valueKey]['is_percent'] = $pricing['is_percent']; | ||
$values[$valueKey]['value_id'] = $pricing['value_id']; | ||
$values[$valueKey]['use_default_value'] = true; | ||
} | ||
} | ||
|
||
if ($websiteId && isset($pricings[$websiteId])) { | ||
foreach ($pricings[$websiteId] as $pricing) { | ||
$valueKey = $pricing['product_super_attribute_id'] . ':' . $pricing['value_index']; | ||
if (isset($values[$valueKey])) { | ||
$values[$valueKey]['pricing_value'] = $pricing['pricing_value']; | ||
$values[$valueKey]['is_percent'] = $pricing['is_percent']; | ||
$values[$valueKey]['value_id'] = $pricing['value_id']; | ||
$values[$valueKey]['use_default_value'] = false; | ||
} | ||
} | ||
} | ||
|
||
foreach ($values as $data) { | ||
$this->getItemById($data['product_super_attribute_id'])->addPrice($data); | ||
} | ||
} | ||
return $this; | ||
} | ||
use RobbieAverill_AttributeFix_Model_Resource_Product_Type_Configurable_Attribute_CollectionCommon; | ||
} |
Oops, something went wrong.