Magento – How to set custom created attribute value for product

attribute-setattributesPHPproduct

I have a batch of products, which I need to add custom products for.
To do so, I have created a file in the root directory to call as import functionality.

Here, I created my own class to handle all the stuff in:
So I create a Attribute Set, a group and attributes, place the attributes in the group and the group in the Attribute set and assign the attributeSet to the Product.
This part works flawlessly, I can confirm this in the management tool.

The next part works fine too: adding the options to the attributes.
Although probably not the best code, it works flawlessly to add the options to the attributes.
Again, I can confirm this in the attributes and product management tool.

However, I now want to set the selected value for the attributes for my product.
This I've been messing with for over 5 hours now without any success whatsoever:
All I want is the the added attributes, which come from an external source e.g. 'special_color' and 'special_name' actually are set for the given product to 'green' and 'hardwood'.

But whatever I've tried, in the product management page, they all show nicely, as drop-down selections to be assigned manually, but not 1 set to the correct value for that attribute.

Below my function, Ive commented where it stopped working (basically just $product->setData):

function setOrAddOptionAttribute($arg_attribute, $arg_value, $product, $setid) {
    $attribute_model = Mage::getModel('eav/entity_attribute');
    $attribute_options_model = Mage::getModel('eav/entity_attribute_source_table');

    $attribute_code = $attribute_model->getIdByCode('catalog_product', $arg_attribute);
    $attribute = $attribute_model->load($attribute_code);

    $attribute_options_model->setAttribute($attribute);
    $options = $attribute_options_model->getAllOptions(false);

    // determine if this option exists
    $value_exists = false;
    $option_id = false;
    foreach($options as $option) {
        if ($option['label'] == $arg_value) {
            $option_id = $option['value'];
            $value_exists = true;
            echo 'EXIST!!!!! '.$arg_value . ' == '.$option_id;
            break;
        }
    }

    // if this option does not exist, add it.
    if (!$value_exists) {
        $attribute->setData('option', array(
            'value' => array(
                'option' => array($arg_value,$arg_value)
            )
        ));
        $attribute->save();
    }

    //experimental: get the value id for justcreated item
    $options = $attribute_options_model->getAllOptions(true);
    foreach($options as $option) {
        if ($option['label'] == $arg_value) {
            $option_id = $option['value'];
            break;
        }
    }

    echo '$product->setData($attribute->getId() ['.$attribute->getId().'], $option_id['.$option_id.'])';
    if($option_id){
        /* THIS TINY PART WONT WORK: */
     //   $product->load($product->getId());
        $product->setData($attribute->getId(), $option_id);
        $product->save();
    }
}

The $product that is passed into the setOrAddOptionAttribute function, originates from a loop with this data:

function getProducts(){
    return Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect(array('name','ean','sku'));
}

I've tried using the setData with the attribute_code ($arg_attribute) and actual value ($arg_value) as strings, got the appropriate Id's for them, and even combined them.
I also tried loading the product again but that doesn't change anything either.

I could use some serious help with this, please!
Even if it's just what to insert into the $product->setData? (id's, names, code)?

To me it seems the data is correctly set in the $product, considering I tried using

$product->setData('my_attribute_name_here', 'myvalue')

or

$product->setMyAttributeNameHere('myvalue')

and to fetch the set value using $product->getMyAttributeNameHere() to verify, which returns my set data.
However, it won't save to database.

I tried $product->save();
aswel as $product->getResource()->saveAttribute($product, $arg_attribute);

Nothing works tho, any suggestions?

[SOLVED]
Apparently doing a separate product load in the $products loop solved the problem.

foreach($products as $product) {
  $product = Mage::getModel('catalog/product')->load($product->getEntityId());
  ...
}

Best Answer

Ok, here's a test script I used to verify if newly added attributes are working, by setting defaults on a specific product. As you can see, I used Mage_Catalog_Model_Product->addAttributeUpdate(). This was done on a Magento 1.3, but the test script worked flawlessly. Perhaps it helps you to track down the issue.

<?php
/**
 * Setup test product for verification of functionality
 */
require_once(dirname(__FILE__).'/PATH/TO/app/Mage.php');
umask(0);
Mage::setIsDeveloperMode(true);
Mage::app('YOUR_STORE_CODE_HERE');

function lookupAttributeId($needle, $haystack)
{
    foreach($haystack AS $dict)
    {
        if( $dict['label'] == $needle)
            return $dict['value'];
    }

    return false;
}
function getAttributesByValueAsString($code, $values=array())
{
    $tmp = array();
    /** @var array $allOptions */
    $allOptions = Mage::getResourceModel('eav/entity_attribute_collection')
        ->setCodeFilter($code)
        ->getFirstItem()
        ->getSource()
        ->getAllOptions();

    foreach($values AS $value)
    {
        if( ($id = lookupAttributeId($value, $allOptions)) !== false )
            $tmp[] = $id;
        else
            fprintf(STDERR, 'Value %s not found%s', $value, PHP_EOL);
    }

    return implode(',', $tmp);
}
$product_id = 12167; // HARDCODED
/** @var Mage_Catalog_Model_Product $product */
$product = Mage::getModel('catalog/product')->load($product_id);
// Attributes below are specific for this store.
// first argument is attribute name, second is an array of labels. This
// specific attribute is a multi-select.
$attributesBevatGeen = getAttributesByValueAsString(
    'bevat_geen',
    array('Soja', 'Suiker')
);
$attributesIsWel = getAttributesByValueAsString(
    'is_wel',
    array('Organisch', 'Veganistisch')
);

// webonly is a boolean and therefore different.
$product->addAttributeUpdate('webonly', '1', 5);
$product->addAttributeUpdate('bevat_geen', $attributesBevatGeen, 5);
$product->addAttributeUpdate('is_wel', $attributesIsWel, 5);

// Reindex required for frontend. Should not affect backend as backend does
// direct EAV queries.
// won't include it, as indexes are quite different in 1.3 Magento.
// include(dirname(__FILE__). DIRECTORY_SEPARATOR . 'reindex.php');

printf('Product can be viewed at: %scatalog/product/view/id/%d%s', Mage::getBaseUrl(), $product_id, PHP_EOL);