Zend certified PHP/Magento developer

Custom attribute created programmatically not working properly – Magento 1.9

I’m developing a module that creates configurable products, it’s simple products and the attributes used to create this configurable (if not exists). All seems fine, products are created, associated and the attribute seems to be created correctly. But the association is “broken”, the configurable product is not displayed in search or categories (even with ‘Catalog, Search’, status ‘Enabled’, in stock, etc).

I also found out that if I save the attribute created programatically again, in my admin panel, the link between simple products and their configurable disapear (they don’t show linked in the admin panel anymore).

All products (configurable and simple) are firstly created with this method:

private function createBaseProduct($sku)
    {
        $_product = Mage::getModel('catalog/product');
        $_product->setSku($sku);
        $_product->setAttributeSetId(4);
        $_product->setTypeId('simple');
        $_product->setWebsiteIDs(array(1));
        $_product->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH);
        $_product->setStatus(1);
        $_product->setTaxClassId(0);
        $_product->setStockData(array(
            'use_config_manage_stock' => 0,
            'manage_stock' => 1,
            'is_in_stock' => 1,
            'qty' => 100
        ));
        return $_product;
    }

In case the product is configurable, it then goes to this method:

private function setData($configurable, $configAttrCode)
    {
    --> new CustomAttribute($configAttrCode); // Create custom attribute if not exists
        $configurable->setTypeId('configurable');
        $configurable->setStockData(array(
            'use_config_manage_stock' => 0,
            'manage_stock' => 0,
            'is_in_stock' => 1,
            'qty' => 0,
        ));
    --> $configurable = $this->setAssociativeAttributes($configurable); 
        $configurableAttributesData = $configurable->getTypeInstance()->getConfigurableAttributesAsArray();
        $configurable->setCanSaveConfigurableAttributes(true);
        $configurable->setConfigurableAttributesData($configurableAttributesData);
        return $configurable;
    }

Where the class CustomAttribute is responsible for the custom attribute’s creation (if not exists). It works like this:

public function __construct($attrCode)
{   
    $attrData = array(
            'group'             => '',
            'type'              => 'varchar',
            'backend'           => '',
            'frontend'          => '',
            'label'             => ucfirst($attrCode),
            'input'             => 'select',
            'class'             => '',
            'source'            => '',
            'global'            => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
            'visible'           => true,
            'required'          => false,
            'user_defined'      => true,
            'default'           => '0',
            'searchable'        => false,
            'filterable'        => false,
            'comparable'        => false,
            'visible_on_front'  => false,
            'is_configurable'   => true,
            'unique'            => false,
        );
        $installer = new Mage_Eav_Model_Entity_Setup('core_setup');
        $installer->startSetup();
        $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, $attrCode, $attributeData);
        $this->addAttributeToDefaultSet();
        $installer->endSetup();
}

After that, the method setAssociativeAttributes() set the attributes IDs of the configurable product being created:

 private function setAssociativeAttributes()
    {
        $configurable->getTypeInstance()->setUsedProductAttributeIds($this->configurableAttrsIds);
        return $configurable;
    }

Then, the configurable product returned in setData() is saved using $product->save(). Later, simple product’s are created (using the createBaseProduct() method), and assigned to it’s custom attribute option (the option is also created if not exists):

private function setCustomAttribute($product, $attrCode, $optionLabel)
{
    $customAttribute = new CustomAttribute($attrCode);
    $customAttribute->addOptionIfNotExists($optionLabel, $attrCode);
    $optionId = $customAttribute->getOptionId($optionLabel);
    $product->setData($attrCode, $optionId);
}

Where $product is the child product being created and the method $customAttribute->addOptionIfNotExists() do:

public function addOptionIfNotExists($optionLabel, $attrCode)
    {
        $value['option'] = array($optionLabel);
        $order['option'] = 0;
        $optionData = array(
            'value' => $value,
            'order' => $order
        );
        $attribute = Mage::getSingleton('eav/config')
            ->getAttribute(Mage_Catalog_Model_Product::ENTITY, $attrCode);
        $attribute->setData('option', $optionData);
        $attribute->save();
    }

In the end, the simple product is associated to it’s configurable using this method:

public function associateChildProduct($configurableId, $childProduct)
    {
        $configurable = Mage::getModel('catalog/product')->load($configurableId); 
        $childProducts = $configurable->getTypeInstance()->getUsedProducts();
        array_push($childProducts, $childProduct);
        $childProductsIds = array();
        foreach($childProducts as $product) {
            array_push($childProductsIds, $product->getId());
        }
        Mage::getResourceSingleton('catalog/product_type_configurable')
            ->saveProducts($configurable, $childProductsIds);
    }

And all seems fine in the admin panel, but the configurable product isn’t displayed in search (if I try to access it via URL it opens correctly, even the variations are displayed).

Obs.: if I save the attribute via admin panel, delete simple products and create new ones using “Quick create” (with the same values) the configurable product is displayed in search and categories.