I don't know if this helps you much, but I did something like this using a custom script like this.
In my case I had to read the values from a CSV file, but anything goes as long as you are able to get your data into an array that looks like this:
$values = array(
array(
'value'=>'Some value',
'position'=>'3'
),
....
);
I also did this for the manufacturer
attribute but it works for any other attribute. Let's assume you have the array in the form described above. Here goes:
$manufacturer = Mage::getModel('eav/config')->getAttribute('catalog_product', 'manufacturer'); //get the main attribute
$storeViews = Mage::getModel('core/store')->getCollection()->addFieldToFilter('store_id', array('gt'=>0)); //get all stores
$ids = $storeViews->getAllIds();//get all store ids
$saveOptions = array();//init options to save
if ($manufacturer){
$_options = $manufacturer->getSource()->getAllOptions(false);//get all existing options so you won't add duplicates
$options = array();
foreach ($_options as $_option){ //format the existing options for save
$options[$_option['label']] = $_option['value'];
}
}
//read from the array to import $values
foreach ($values as $value){
if (!isset($options[$name])){//check if the option does not exist
$index = 'option_'.(count($toInsert) + 1);
$toInsert[$index] = array();//if it doesn't exist add it to import array
$toInsert[$index][0] = $value['value'];//set the option label for admin view
foreach ($ids as $store){
//empty values for stores - you can also set translated values if you need for each store
$toInsert[$index][$store] = '';
}
$toInsertOrder[$index] = $value['position'];//set the option position
}
}
Now you should have in the array $toInsert
the labels that need to be added, and in $toInsertOrder
the positions of the labels. just set the options to the attribute and save it.
$result = array('value' => $toInsert,'order' => $toInsertOrder);
$manufacturer->setData('option', $result);
$manufacturer->save();
Try passing an array as the media type. Theer is no need to iterate over each mediaType and setting them individually.
your code would thus be, which will be faster as well.
ini_set('memory_limit', '-1');
require 'app/Mage.php';
Mage::app();
echo "Loading catalog...\n";
$products = Mage::getModel('catalog/product')->setStoreId(13)->getCollection()->addAttributeToSelect('*');
echo count($products) . " products selected for image import.\n";
// Remove unset images, add image to gallery if exists
$importDir = Mage::getBaseDir('media') . DS . 'import/';
foreach ($products as $product) {
$sku = Mage::getModel('catalog/product')->load($product->getId())->getSku();
if (strstr($sku, " ")) {
echo "Sku $sku contains whitespace, skipping.\n";
continue;
}
$imgFile = $importDir . $sku . ".jpg";
// Add three image sizes to media gallery
$mediaArray = array(
'thumbnail',
'small_image',
'image'
);
if (file_exists($imgFile)) {
try {
$product->addImageToMediaGallery($imgFile, $mediaArray, false, false);
$product->save();
echo "Sku: $sku updated.\n";
} catch (Exception $e) {
echo $e->getMessage();
}
} else {
echo "Could not match image to $sku. Path was: {$filePath}\n";
break;
}
}
Anyways, I suspect your issue is related to the fact that your product->save was within the media loop of your original code.
For reference, the end-point of the mediaAttribute is this function, located in class Mage_Catalog_Model_Product_Attribute_Backend_Media
/**
* Set media attribute value
*
* @param Mage_Catalog_Model_Product $product
* @param string|array $mediaAttribute
* @param string $value
* @return Mage_Catalog_Model_Product_Attribute_Backend_Media
*/
public function setMediaAttribute(Mage_Catalog_Model_Product $product, $mediaAttribute, $value)
{
$mediaAttributeCodes = array_keys($product->getMediaAttributes());
if (is_array($mediaAttribute)) {
foreach ($mediaAttribute as $atttribute) {
if (in_array($atttribute, $mediaAttributeCodes)) {
$product->setData($atttribute, $value);
}
}
} elseif (in_array($mediaAttribute, $mediaAttributeCodes)) {
$product->setData($mediaAttribute, $value);
}
return $this;
}
Best Answer
You can always try the native import/export interface. Tools like Magmi (directly writing sql) will suffer in the long run, because import not imports a bit differently (repository->save() instead of direct sql as it was before) and because of the newly introduced interceptors it will be hard to build a sql-data-pump that will not break with 3rd party data-handling.