Here is what seams to work for me for to remove an attribute from the configurable product.
This is the scenario.
All the configurable products were created wrong with the attribute brand
as a configurable attribute for about 50 configurable products having about 200 simple associated products.
All the simple products associated to a configurable attribute have the same brand. The idea is to remove brand
from configurable attributes and assign it as a simple attribute to the configurable product with the value of one of the simple products.
Here is the code that does this. The code is ran one time only. It can be added in an upgrade script or a simple php file.
<?php
//==>this is required only if you use a simple php file
error_reporting(E_ALL | E_STRICT);
$mageFilename = 'app/Mage.php';
require_once $mageFilename;
Mage::setIsDeveloperMode(true);
ini_set('display_errors', 1);
umask(0);
Mage::app();
//<==
$brand = 'brand';
//get the attribute instance
$brandAttribute = Mage::getModel('eav/config')->getAttribute('catalog_product', $brand);
//if this attribute exists
if ($brandAttribute->getId()){
//make the attribute apply to al types of products in case it's not
$brandAttribute->setApplyTo(null);
$brandAttribute->save();
$resource = Mage::getSingleton('core/resource');
//get an object with access to direct queries
$connection = $resource->getConnection('core_write');
//get all configurable products - you can specify additional filters here
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('type_id', 'configurable');
foreach ($collection as $product){
//the configurable attributes are stored in the table 'catalog_product_super_attribute'
//remove the attribute references from that table.
//The constraints will take care of the cleanup.
$q = "DELETE FROM {$resource->getTableName('catalog_product_super_attribute')}
WHERE attribute_id = {$brandAttribute->getId()} AND product_id = {$product->getId()}";
$connection->query($q);
//get the simple products in the configurable product
$usedProducts = $product->getTypeInstance(true)->getUsedProducts(null, $product);
foreach ($usedProducts as $p){
//identify the first simple product that has a value for brand
//set that value to the configurable product.
if ($brandValue = $p->getData($brand)){
Mage::getSingleton('catalog/product_action')
->updateAttributes(array($product->getId()), array($brand=>$brandValue), 0);
break;
}
}
}
}
For the numbers listed above, this took about 15 seconds to run on my local machine (not a powerful one). I'm sure that this can be optimized. Most probably there is no need to get all simple products of a configurable product to get the brand
value, but I didn't bother.
In order to achieve this you need to override the block that displays the product grid in the category edit screen. This block is Mage_Adminhtml_Block_Catalog_Category_Tab_Product
.
For this, create a new module. Let's call it Easylife_Adminhtml
with the following files:
app/etc/modules/Easylife_Adminhtml.xml
- the module declaration file.
<?xml version="1.0"?>
<config>
<modules>
<Easylife_Adminhtml>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_Adminhtml />
</depends>
</Easylife_Adminhtml>
</modules>
</config>
app/code/local/Easylife/Adminhtml/etc/config.xml
- the module configuration file
<?xml version="1.0"?>
<config>
<modules>
<Easylife_Adminhtml>
<version>0.0.1</version>
</Easylife_Adminhtml>
</modules>
<global>
<blocks>
<adminhtml>
<rewrite>
<catalog_category_tab_product>Easylife_Adminhtml_Block_Catalog_Category_Tab_Product</catalog_category_tab_product><!-- override the default block with your ownw-->
</rewrite>
</adminhtml>
</blocks>
</global>
</config>
app/code/local/Easylife/Adminhtml/Block/Catalog/Category/Tab/Product.php
- the block override class.
<?php
class Easylife_Adminhtml_Block_Catalog_Category_Tab_Product extends Mage_Adminhtml_Block_Catalog_Category_Tab_Product{
protected function _prepareCollection()
{
if ($this->getCategory()->getId()) {
$this->setDefaultFilter(array('in_category'=>1));
}
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('name')
->addAttributeToSelect('sku')
->addAttributeToSelect('price')
->addAttributeToSelect('special_price')//add attributes you need
->addStoreFilter($this->getRequest()->getParam('store'))
->joinField('position',
'catalog/category_product',
'position',
'product_id=entity_id',
'category_id='.(int) $this->getRequest()->getParam('id', 0),
'left');
$this->setCollection($collection);
if ($this->getCategory()->getProductsReadonly()) {
$productIds = $this->_getSelectedProducts();
if (empty($productIds)) {
$productIds = 0;
}
$this->getCollection()->addFieldToFilter('entity_id', array('in'=>$productIds));
}
//simulate parent::parent::_prepareCollection() because you cannot call parent::_prepareCollection
if ($this->getCollection()) {
$this->_preparePage();
$columnId = $this->getParam($this->getVarNameSort(), $this->_defaultSort);
$dir = $this->getParam($this->getVarNameDir(), $this->_defaultDir);
$filter = $this->getParam($this->getVarNameFilter(), null);
if (is_null($filter)) {
$filter = $this->_defaultFilter;
}
if (is_string($filter)) {
$data = $this->helper('adminhtml')->prepareFilterString($filter);
$this->_setFilterValues($data);
}
else if ($filter && is_array($filter)) {
$this->_setFilterValues($filter);
}
else if(0 !== sizeof($this->_defaultFilter)) {
$this->_setFilterValues($this->_defaultFilter);
}
if (isset($this->_columns[$columnId]) && $this->_columns[$columnId]->getIndex()) {
$dir = (strtolower($dir)=='desc') ? 'desc' : 'asc';
$this->_columns[$columnId]->setDir($dir);
$this->_setCollectionOrder($this->_columns[$columnId]);
}
if (!$this->_isExport) {
$this->getCollection()->load();
$this->_afterLoadCollection();
}
}
return $this;
}
protected function _prepareColumns()
{
//add the special price collumn after the 'price' column
$this->addColumnAfter('special_price', array(
'header' => Mage::helper('catalog')->__('Special Price'),
'type' => 'currency',
'width' => '1',
'currency_code' => (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE),
'index' => 'special_price'
), 'price');
return parent::_prepareColumns();
}
}
Clear the cache and it should work. It worked for me.
Best Answer
In the same module that you used for special price (explained here) you can add you attribute set also.
Just add this to the collection init
->addAttributeToSelect('attribute_set_id')
and the corresponding column in_prepareColumns()
.