Here is an idea.
In order to have something preselected for a configurable product you must rewrite Mage_Catalog_Block_Product_View_Type_Configurable::getJsonConfig
.
More exactly this part.
$preconfiguredFlag = $currentProduct->hasPreconfiguredValues();
if ($preconfiguredFlag) {
$preconfiguredValues = $currentProduct->getPreconfiguredValues();
$defaultValues = array();
}
Or this part
if ($preconfiguredFlag) {
$configValue = $preconfiguredValues->getData('super_attribute/' . $attributeId);
if ($configValue) {
$defaultValues[$attributeId] = $configValue;
}
}
You can add your custom logic around these lines of code.
I would go with this approach.
If after executing the code above defaultValues
is an empty array add your logic. If it's not empty it means that the use clicked on the 'edit' button from the cart and you shouldn't interfere with that.
Now the second part.
How to get the minimum price.
Here is an explanation about how to get the min and max price from the configurable product combinations.
Other than this, I can recommend you this extension. Among other features it allows you to set from the backend the default configuration for a configurable product just by selecting a simple product associated to the configurable one.
The downside of it is that you have to edit every configurable product to set this.
Note: It has been brought to my attention that this solution does not work for Magento 1.9.2. In order to save others wasted time I'd like to point this out at the top of this post. If I develop my own solution or find someone else's solution that works for 1.9.2 I will update this post at that time.
Notice: The solution laid out here extends a block class file in Magento's core library. I reviewed Magento's source code prior to this approach and determined that there was not a good event to observe to avoid this approach. If in a future version of Magento this sorting issue is resolved, you may undo these changes below simply by disabling the extension in it's app/etc/modules XML file.
Step 1: create the file app/etc/modules/FirstScribe_CatalogOptionSortFix.xml
Contents:
<?xml version="1.0"?>
<config>
<modules>
<FirstScribe_CatalogOptionSortFix>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_Catalog />
</depends>
</FirstScribe_CatalogOptionSortFix>
</modules>
</config>
Note: For step 2 and 3, create directories for these files as necessary. For example, you may already have the directory app/code/local, or you may not, depending on what extensions you have already installed on your site.
Step 2: Create the file app/code/local/FirstScribe/CatalogOptionSortFix/etc/config.xml
Contents:
<?xml version="1.0"?>
<!--
/**
* Magento 1.9.1.0 has a bug in that the configurable options are sorted by
* ID rather than position for the Configurable Product's front end view script.
* This extension addresses this problem.
*
* @category FirstScribe
* @package FirstScribe_CatalogOptionSortFix
* @version 2014.12.15
*/
-->
<config>
<modules>
<FirstScribe_CatalogOptionSortFix>
<version>1.0.0</version>
</FirstScribe_CatalogOptionSortFix>
</modules>
<global>
<blocks>
<catalog>
<rewrite>
<product_view_type_configurable>FirstScribe_CatalogOptionSortFix_Block_Product_View_Type_Configurable</product_view_type_configurable>
</rewrite>
</catalog>
</blocks>
</global>
</config>
Step 3: Create the file app/code/local/FirstScribe/CatalogOptionSortFix/Block/Product/View/Type/Configurable.php
Contents:
<?php
/**
* Magento 1.9.1.0 has a bug in that the configurable options are sorted by
* ID rather than position for the Configurable Product's front end view script.
* This extension addresses this problem.
*
* @category FirstScribe
* @package FirstScribe_CatalogOptionSortFix
* @version 2014.12.15
*/
class FirstScribe_CatalogOptionSortFix_Block_Product_View_Type_Configurable extends Mage_Catalog_Block_Product_View_Type_Configurable
{
/**
* @var Magento_Db_Adapter_Pdo_Mysql
*/
protected $_read;
/**
* @var string
*/
protected $_tbl_eav_attribute_option;
/**
* Composes configuration for js
*
* @version 2014.12.15 - Addition of this line:
* $info['options'] = $this->_sortOptions($info['options']);
*
* @return string
*/
public function getJsonConfig()
{
$attributes = array();
$options = array();
$store = $this->getCurrentStore();
$taxHelper = Mage::helper('tax');
$currentProduct = $this->getProduct();
$preconfiguredFlag = $currentProduct->hasPreconfiguredValues();
if ($preconfiguredFlag) {
$preconfiguredValues = $currentProduct->getPreconfiguredValues();
$defaultValues = array();
}
foreach ($this->getAllowProducts() as $product) {
$productId = $product->getId();
foreach ($this->getAllowAttributes() as $attribute) {
$productAttribute = $attribute->getProductAttribute();
$productAttributeId = $productAttribute->getId();
$attributeValue = $product->getData($productAttribute->getAttributeCode());
if (!isset($options[$productAttributeId])) {
$options[$productAttributeId] = array();
}
if (!isset($options[$productAttributeId][$attributeValue])) {
$options[$productAttributeId][$attributeValue] = array();
}
$options[$productAttributeId][$attributeValue][] = $productId;
}
}
$this->_resPrices = array(
$this->_preparePrice($currentProduct->getFinalPrice())
);
foreach ($this->getAllowAttributes() as $attribute) {
$productAttribute = $attribute->getProductAttribute();
$attributeId = $productAttribute->getId();
$info = array(
'id' => $productAttribute->getId(),
'code' => $productAttribute->getAttributeCode(),
'label' => $attribute->getLabel(),
'options' => array()
);
$optionPrices = array();
$prices = $attribute->getPrices();
if (is_array($prices)) {
foreach ($prices as $value) {
if(!$this->_validateAttributeValue($attributeId, $value, $options)) {
continue;
}
$currentProduct->setConfigurablePrice(
$this->_preparePrice($value['pricing_value'], $value['is_percent'])
);
$currentProduct->setParentId(true);
Mage::dispatchEvent(
'catalog_product_type_configurable_price',
array('product' => $currentProduct)
);
$configurablePrice = $currentProduct->getConfigurablePrice();
if (isset($options[$attributeId][$value['value_index']])) {
$productsIndex = $options[$attributeId][$value['value_index']];
} else {
$productsIndex = array();
}
$info['options'][] = array(
'id' => $value['value_index'],
'label' => $value['label'],
'price' => $configurablePrice,
'oldPrice' => $this->_prepareOldPrice($value['pricing_value'], $value['is_percent']),
'products' => $productsIndex,
);
$optionPrices[] = $configurablePrice;
}
}
// CALL SORT ORDER FIX
$info['options'] = $this->_sortOptions($info['options']);
/**
* Prepare formated values for options choose
*/
foreach ($optionPrices as $optionPrice) {
foreach ($optionPrices as $additional) {
$this->_preparePrice(abs($additional-$optionPrice));
}
}
if($this->_validateAttributeInfo($info)) {
$attributes[$attributeId] = $info;
}
// Add attribute default value (if set)
if ($preconfiguredFlag) {
$configValue = $preconfiguredValues->getData('super_attribute/' . $attributeId);
if ($configValue) {
$defaultValues[$attributeId] = $configValue;
}
}
}
$taxCalculation = Mage::getSingleton('tax/calculation');
if (!$taxCalculation->getCustomer() && Mage::registry('current_customer')) {
$taxCalculation->setCustomer(Mage::registry('current_customer'));
}
$_request = $taxCalculation->getDefaultRateRequest();
$_request->setProductClassId($currentProduct->getTaxClassId());
$defaultTax = $taxCalculation->getRate($_request);
$_request = $taxCalculation->getRateRequest();
$_request->setProductClassId($currentProduct->getTaxClassId());
$currentTax = $taxCalculation->getRate($_request);
$taxConfig = array(
'includeTax' => $taxHelper->priceIncludesTax(),
'showIncludeTax' => $taxHelper->displayPriceIncludingTax(),
'showBothPrices' => $taxHelper->displayBothPrices(),
'defaultTax' => $defaultTax,
'currentTax' => $currentTax,
'inclTaxTitle' => Mage::helper('catalog')->__('Incl. Tax')
);
$config = array(
'attributes' => $attributes,
'template' => str_replace('%s', '#{price}', $store->getCurrentCurrency()->getOutputFormat()),
'basePrice' => $this->_registerJsPrice($this->_convertPrice($currentProduct->getFinalPrice())),
'oldPrice' => $this->_registerJsPrice($this->_convertPrice($currentProduct->getPrice())),
'productId' => $currentProduct->getId(),
'chooseText' => Mage::helper('catalog')->__('Choose an Option...'),
'taxConfig' => $taxConfig
);
if ($preconfiguredFlag && !empty($defaultValues)) {
$config['defaultValues'] = $defaultValues;
}
$config = array_merge($config, $this->_getAdditionalConfig());
return Mage::helper('core')->jsonEncode($config);
}
/**
* Sort the options based off their position.
*
* @param array $options
* @return array
*/
protected function _sortOptions($options)
{
if (count($options)) {
if (!$this->_read || !$this->_tbl_eav_attribute_option) {
$resource = Mage::getSingleton('core/resource');
$this->_read = $resource->getConnection('core_read');
$this->_tbl_eav_attribute_option = $resource->getTableName('eav_attribute_option');
}
// Gather the option_id for all our current options
$option_ids = array();
foreach ($options as $option) {
$option_ids[] = $option['id'];
$var_name = 'option_id_'.$option['id'];
$$var_name = $option;
}
$sql = "SELECT `option_id` FROM `{$this->_tbl_eav_attribute_option}` WHERE `option_id` IN('".implode('\',\'', $option_ids)."') ORDER BY `sort_order`";
$result = $this->_read->fetchCol($sql);
$options = array();
foreach ($result as $option_id) {
$var_name = 'option_id_'.$option_id;
$options[] = $$var_name;
}
}
return $options;
}
}
Step 4: If enabled, refresh Magento's "Configuration" cache type under System -> Cache Management of the admin panel.
Extension overview
- Extend the Mage_Catalog_Block_Product_View_Type_Configurable class.
- Add a method to sort options by their
position
value by pulling this info from the database.
- Rewrite the getJsonConfig method to call our new function after having gathered the options for an attribute.
Best Answer
I cannot give you a clear answer, but I can give you a place to start.
The product listing uses the prices from the price index table
catalog_product_index_price
.When you sort by price, the column
min_price
is used for sorting.You can see that in
Mage_Catalog_Model_Resource_Product_Collection::addAttributeToSort
in theif($attribute == 'price')
section:Now the crazy part.
The price index table is populated by an indexer.
Each product type price is calculated a bit differently.
The classes that compute the prices are located in
app/code/core/Mage/Catalog/Model/Resource/Product/Indexer/Price
. each class corresponds to a product type. If there is no class for a specific product type (like virtual for example)Default.php
is used.For bundle products the class used is
app/code/core/Mage/Bundle/Model/Resource/Indexer/Price.php
and for downloadableapp/code/core/Mage/Downloadable/Model/Resource/Indexer/Price.php
Each class has a method called
reindexEntity
. That's the one that does the dirty job.That method calls different methods depending on the product type, that calculate and retrieves the prices.
In each class (specially Configurable, Grouped and Bundle) there are some huge queries to get the prices.
Unfortunately I cannot really explain what each query does because they look like dragons to me at a first glance.
But you can run indexer processes and log the queries and the results if you want to see what they do.
Also if you want to change the indexing process these are the classes and methods you need to change. But be very careful.