I have a script that pulls in data from a 3rd party file. My import simply parses and inserts rows, which is working fine.
The problem comes with images.
When the import script runs, it first deletes all the current items and then the import begins, inserting all products and images into the gallery.
On the first import, everything is fine, the images go in and I see them on the frontend no problem. The problem comes with everytime I then re-import these products, it doesn't seem to delete all images, as when the products re-import, I see, for example the 4 images correct, then then loads of blank rows, like images should be there, but can't be found.
I don't want to see these blank lines, but I'm not sure why they are there.
Could it be because the images for the product are already in the catalogue?
I am really unsure what and why this is doing what it is.
Thanks
EDIT:
My code is:
require_once('app/Mage.php');
$app = Mage::app('default');
$product = Mage::getSingleton('catalog/product');
$txt_file = file_get_contents('test.txt');
$rows = explode("\n", $txt_file);
array_shift($rows);
foreach($rows as $row => $data)
{
//get row data
$row_data = explode('^', $data);
$info[$row]['uniqueid'] = $row_data[0];
$info[$row]['client'] = $row_data[1];
$info[$row]['make'] = $row_data[2];
$info[$row]['model'] = $row_data[3];
$info[$row]['adtext'] = $row_data[4];
//display images
$row_images = explode(',', $info[$row]['picturereference']);
foreach($row_images as $row_image)
{
$product->addImageToMediaGallery(Mage::getBaseDir('media') . DS . 'import/' . $row_image, array('image', 'small_image','thumbnail'), false, false);
}
$product->setStoreId(Mage::app()->getStore(true)->getWebsite()->getId());
$product->setWebsiteIds(array(Mage::app()->getStore(true)->getWebsite()->getId()));
$product->setId($info[$row]['id']);
$product->setSku(strtolower($info[$row]['make']).'-'.strtolower($info[$row]['model']));
$product->setName($info[$row]['make']);
$product->setDescription($info[$row]['adtext']);
try {
$product->save();
echo "Saved";
}
catch (Exception $ex) {
echo "<pre>".$ex."</pre>";
}
}
Is this because the addImageToMediaGallery is called on each iteration and adding all images to each product?
Thanks
Ok so I figured out my problem
Inside the foreach I moved the call to the getSingleton and I added the the following: $product = Mage::getModel('catalog/product');
I then, after each iteration, unset the following:
unset($product);
unset($info);
unset($stockData);
unset($row_images);
This seemed to fix my script and now imports each products images into the proper product rather than importing other and adding random blank entries
Thanks all
A few files you'll want to examine to break down addImageToMediaGallery and determine what exactly its doing.
app/code/core/Mage/Catalog/Model/Product.php - Contains the method your using, breaking it down more you'll find...
app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php - Contains more of the "bits and pieces" of addImageToMediaGallery like addImage etc.
Some possibilities to try would be either
A) determine if the files already exist and are attached to the product and ignoring them upon a second round of import. Perhaps looking for different file stamp. getMediaGalleryImages within Product.php.
B) clear the media files associated with the products BEFORE importing again? clearMediaAttribute and removeImage within Media.php.
I would also try the $move option set to true within your addImageToMediaGallery call as well.
/**
* Add image to media gallery
*
* #param string $file file path of image in file system
* #param string|array $mediaAttribute code of attribute with type 'media_image',
* leave blank if image should be only in gallery
* #param boolean $move if true, it will move source file
* #param boolean $exclude mark image as disabled in product page view
*/
public function addImageToMediaGallery($file, $mediaAttribute=null, $move=false, $exclude=true)
{
Another option would be to try to specify null for the second param, if you note the PHPDoc comments, leaving it blank will only be for the gallery which sounds like what you are wanting...
foreach($row_images as $row_image)
{
$product->addImageToMediaGallery(Mage::getBaseDir('media') . DS . 'import/' . $row_image, null, false, false);
}
Let me know if any of these help.
Give something like this a try:
//Check if gallery attribute exists then remove all images if it exists
//Get products gallery attribute
$attributes = $product->getTypeInstance()->getSetAttributes();
if (isset($attributes['media_gallery'])) {
$gallery = $attributes['media_gallery'];
//Get the images
$galleryData = $product->getMediaGallery();
foreach($galleryData['images'] as $image){
//If image exists
if ($gallery->getBackend()->getImage($product, $image['file'])) {
$gallery->getBackend()->removeImage($product, $image['file']);
}
}
}
This blog posting may also help, as its where I got the code snippet form also:
http://www.sharpdotinc.com/mdost/2010/03/02/magento-import-multiple-images-or-remove-images-durring-batch-import/
Related
CONTROLLER
public function updateproduct(Request $request, $id)
{
// dd($request->all());
$request->validate([
'name'=>'required',
'description'=>'required',
'price'=>'required|numeric',
'quantity'=>'required|numeric',
]);
$product = Product::where('id', $id)->first();
if(is_null($product)) {
$product = new Product();
}
$product->name=$request->name;
$product->description=$request->description;
$product->price=$request->price;
$product->quantity=$request->quantity;
if($request->hasfile('images')){
$existingimages = Image::where(['product_id'=> $product->id, 'source'=> 1])->get();
if($existingimages->count() > 0)
foreach($existingimages as $existingimage) {
$filename = public_path().'files/'.$existingimage->name;
if(file_exists($filename)){
unlink($filename);
$existingimage->delete();
}
}
foreach($request->file('images') as $file){
$name = rand(1,9999).'.'.$file->getClientOriginalName().$file->getClientOriginalExtension();
if($file->move(public_path().'/files/', $name)){
$updateImage = Image::firstWhere('product_id', $product->id);
$updateImage->images = $name;
$updateImage->source = 1;
$updateImage->save();
}
}
}
Please check updated question. Request you to correct me if I wrong. Right now it only updates 1 image and other images remains same. please help me with this.
Your code is somewhat confusing, I'm afraid.
Your request appears to allow for multiple images to be uploaded. Here :
if(file_exists($imagePath)){
unlink($imagePath);
}
you look like you're trying to delete any images that already exist, but when you store upload images you're assigning them a random name (which Laravel can already handle for you, by the way, so there's no need to do it yourself) so you're unlikely to be actually deleting them because there'll likely be no file at that location anyway.
Nowhere does your code actually delete any existing images from the database. Essentially what you want to do is :
If the upload has images, retrieve all the existing images for that product.
Delete the physical files for those existing images.
Delete the database entries for those existing images.
Upload your new images and save their details to the database.
Translating that into code means :
if($request->hasfile('images')){
// Delete any existing image files and database entries.
$existingimages = Image::where('product_id', $product->id)->get();
if($existingimages->count() > 0)
foreach($existingimages as $existingimage) {
$filename = public_path().'files/'.$existingimage->name;
unlink($filename);
$existingimage->delete();
}
}
// Carry on with your upload
}
It adds new images because you are using the Image::create method. If I understood correctly, you want to modify the images of your products in the image table.
Try to modify your code like :
$updateImage = Image::firstWhere('product_id', $product->id);
$updateImage->images = $name;
$updateImage->source = 1;
$updateImage->save();
I have simple products with custom options in my store. They work perfectly from the front end, but if I try to add an order from the admin section, The custom options do not show up.
I only have this problem if the type of custom option is a dropdown, multi select, radio buttons, or check boxes. If it is a text field, date or anything else, it works fine.
I am assumming i need to make some changes to something in the /www/app/design/adminhtml/default/default/template/sales/order/create area, but no clue what i should try.
Looking a bit further, I found this /www/app/code/core/Mage/Adminhtml/Block/Sales/Order/Create/Items/grid.php
/**
* Get Custom Options of item
*
* #param Mage_Sales_Model_Quote_Item $item
* #return array
*/
public function getCustomOptions(Mage_Sales_Model_Quote_Item $item)
{
$optionStr = '';
$this->_moveToCustomerStorage = true;
if ($optionIds = $item->getOptionByCode('option_ids')) {
foreach (explode(',', $optionIds->getValue()) as $optionId) {
if ($option = $item->getProduct()->getOptionById($optionId)) {
$optionValue = $item->getOptionByCode('option_' . $option->getId())->getValue();
$optionStr .= $option->getTitle() . ':';
$quoteItemOption = $item->getOptionByCode('option_' . $option->getId());
$group = $option->groupFactory($option->getType())
->setOption($option)
->setQuoteItemOption($quoteItemOption);
$optionStr .= $group->getEditableOptionValue($quoteItemOption->getValue());
$optionStr .= "\n";
}
}
}
return $optionStr;
}
The best way to find the correct template path is to turn on admin template hints.
By default magento does not provide a way to accomplish from the admin, but you can easily accomplish this using one of these methods Enable template path hint in admin pages - Magento
I am getting stuck with images not displaying with their products. When I create a product and insert an image with that product manually through (manage products) the image shows which is great.
However we have over 1000 product images which need to be uploaded, (all the product information is already up I just need to add the images)
I have exported the products CSV file and the working image address is /n/g/image1.jpg
I have then copied that but change the image to image2.jpg, image3.jpg etc. I then uploaded the new images into that folder directory on our server thinking that's enough.
I then upload the CSV file blow the cache and reindex the data however no new images show and worse the working image doesn't display.
I have filled in image, small_image and thumbnail details in the CSV. All images are correctly sized etc.
Further more can allow tell me where I can just have 1 image folder in the directory where all my images are stored?
Thanks
I'm using Magento version 1.7.0.2
First of all your image should store in media>import directory
then in your csv file just write in image column /imagename.jpg
it will find same imagename in import directory, if image exist then it will upload the image
EDIT
if you don't have import directory then simply create it
I'm sorry to say, but there is more going on behind the scenes with magento images that it simply putting a filename in the database and linking to your image. The cache generation alone is pretty complex. I believe you are going to have a hard time doing it the way you are attempting.
That being said, I do have a suggestion. Since your images are already on the server, I suggest you write a simple php script to tell magento to attach them to the product image. This could be automated, but i'll give you a small example below...
To attach an image, you would simply navigate to the url like this
http://yoursite.com/imageattacher.php?sku=YOURSKU&image=yourimagefilename.jpg
The script would be like this... create a file in your magento ROOT and call it imageattacher.php. Upload your images to the magento media import directory. I have not tested this but it should work.
<?php
// Initialize magento for use outside of core
umask(0);
require_once 'app/Mage.php';
Mage::app('admin');
// Get the variables from the URL
$sku = $_GET["sku"];
$imageName = $_GET["image"];
// get the image from the import dir
$import = Mage::getBaseDir('media') . DS . 'import/' . $imageName;
// Load the product by sku
$product = Mage::getModel('catalog/product')->loadByAttribute('sku',$sku);
// if the product exists, attempt to add the image to it for all three items
if ($product->getId() > 0)
{
// Add the images and set them for their respective usage (the radio button in admin)
$product->addImageToMediaGallery($import,array('image', 'small_image', 'thumbnail'),false,false);
// Make the changes stick
$product->save();
}
?>
See this http://www.danneh.org/2012/05/creating-products-programmatically-magento/
The issue in the end was that there wasn't an import folder under the media directory. The images were uploaded to this folder. The image column in the CSV was changed to /image1.jpg which allowed them to show on the website.
I had to import a bunch of Magento product images recently which were all named by SKU (eg 123456.jpg). This is the script I used to import them, parts of which are based on CarComp's answer. It will only work for numeric SKUs (eg 123456) but could be fairly easily modified to cater for alphanumeric ones.
<?php
require_once(__DIR__ . "/app/Mage.php");
Mage::app('admin');
class Sku_ImageLoader {
private $_uploadDir;
private $_imagePaths;
public function setUploadDirectory($dir = null) {
if (empty($dir)) {
if (isset($this->_uploadDir)) return $this;
$dir = 'upload';
}
$this->_uploadDir = Mage::getBaseDir('media') . DS . $dir;
// mkdir($this->_uploadDir . DS . "/loaded", 0770);
return $this;
}
public function load() {
$this->setUploadDirectory();
// Match product images like 123456.jpg
$pattern = '[0-9][0-9][0-9][0-9][0-9][0-9].{jpg,gif,png}';
chdir($this->_uploadDir);
$this->_imagePaths = glob($pattern, GLOB_BRACE);
return $this;
}
public function showFiles() {
$this->load();
echo "\r\n\r\nSorry, I wasn't able to upload the following image files in " . $this->_uploadDir . "\r\n\r\n<pre>\r\n";
print_r($this->_imagePaths);
return $this;
}
private function _addImage($path) {
$sku = (string)intval($path);
try {
echo "Loading SKU: {$sku} ... ";
$product = Mage::getModel('catalog/product')->loadByAttribute('sku',$sku);
// if the product exists, attempt to add the image to it for all three items
if (strpos(get_class($product), 'Catalog_Model_Product') !== false && $product->getId() > 0) {
$product->addImageToMediaGallery($path,array('image', 'small_image', 'thumbnail'),false,false);
$product->save();
echo " ok \r\n";
return true;
}
} catch (Exception $e) {
echo "Exception thrown for {$sku}: " . $e->getMessage() . "\r\n";
}
echo " (FAILED) \r\n";
return false;
}
private function _moveImage($path) {
// rename($path, 'loaded' . DS . $path);
unlink($path);
}
public function import() {
echo "<pre>\r\n";
if (!isset($this->_imagePaths)) $this->load();
foreach ($this->_imagePaths as $path) {
if ($this->_addImage($path)) {
$this->_moveImage($path);
}
}
return $this;
}
}
$u = new Sku_ImageLoader();
$u->import()->showFiles();
?>
In my site, the product image are duplicated many times? how to remove the repeat data in the database.
Eg: The correct product image is: product.jpg producta.jpg productb.jpg now, there are
product.jpg producta.jpg productb.jpg product.jpg producta.jpg productb.jpg. How to make them unique? thank you.
Just delete them? What is the exact problem? You have products with a lot of product images attached.
You can load the product, loop over the mediaGallery images, save the names in an array, remove all images when the name already exists and save the image. Something like this:
// get the media-gallery backend model to remove images
$attributes = $this->getTypeInstance(true)->getSetAttributes($this);
if (!isset($attributes['media_gallery'])) {
return $this;
}
$mediaGalleryAttribute = $attributes['media_gallery'];
/* #var $mediaGalleryAttribute Mage_Catalog_Model_Resource_Eav_Attribute */
$mediaGalleryAttribute->getBackend()->addImage($this, $file, $mediaAttribute, $move, $exclude);
Mage_Catalog_Model_Product_Attribute_Backend_Media::removeImage(Mage_Catalog_Model_Product $product, $file)
As the title says,i need to mass-assign products to a category and from the admin i can only edit one product at a time; i dont know why it just doesnt work to mass add them from the "category products" tab in the category page.
Thats why i need another method that's fast,like using phpMyAdmin or something alike.
Any help?
Thanks in advance!
I created a simple script to do this outside of Magento. Be sure to test this first on a single product and make sure it looks as you'd expect.
// Load Magento
require_once 'path/to/app/Mage.php';
Mage::app();
// $productIds is an array of the products you want to modify.
// Create it however you want, I did it like this...
$productsIds = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('sku', array('like' => 'something'))
->getAllIds();
// Array of category_ids to add.
$newCategories = array(20);
foreach ($productIds as $id) {
$product = Mage::getModel('catalog/product')->load($id);
$product->setCategoryIds(
array_merge($product->getCategoryIds(), $newCategories)
);
$product->save();
}
If you wish to overwrite a product's existing categories, change array_merge(...) to just $newCategories.
I would shy away from tackling this problem from the database side of things. If you do go that direction make sure and take lots of backups and do it during low usage.
The following thread on the Magento forum identifies the very same problem. One poster recommends a raw sql approach with example. Again, I would be careful - make sure you take backups.
The answer I like best from the thread (posted by Magento MVP):
Go into the category you don’t want them in, find the product list.
Click the check boxes on the products you want to remove and select
delete from the little dropdown.
Now go into the category where you
do want them, go to the product list. Select the NO dropdown so it
shows items not in the category. You might have to do a selective
search to limit stuff and do it in a couple iterations. Click the
check boxes and tell it to add stuff.
You may as well do this using the magento API
This is the script I use for mass adding products. sku.txt contains one sku per line.
<?php
$wsdlUrl = "magento-root/index.php/api/soap/?wsdl";
$proxy = new SoapClient($wsdlUrl);
$sessionId = $proxy->login('apiuser', 'apipasswd');
$listOfDiscountedSKUFile = "sku.txt";
function readinFile($filePath)
{
$fp = fopen($filePath,'r') or exit("Unable to open file!");
$dataItems = array();
while(!feof($fp))
{
$dataItems[] = trim(fgets($fp));
}
fclose($fp);
var_dump($dataItems);
return $dataItems;
}
function addToCategory($sku,$categoryId)
{
global $proxy,$sessionId;
$proxy->call($sessionId, 'category.assignProduct', array($categoryId, $sku));
}
function IsNullOrEmptyString($question){
return (!isset($question) || trim($question)==='');
}
$categoryId = 82;//e.g.
$listOfSKU = readinFile($listOfDiscountedSKUFile);
foreach($listOfSKU as $sku)
{
addToCategory($sku,$category);
}
?>
I managed to resolve the problem with the following code :
$write = Mage::getSingleton('core/resource')->getConnection('core_write');
$x = 1171;
$y = 2000;
$categoryID = 4;
$productPosition = 0;
while($x <= $y) {
$write->query("REPLACE INTO `catalog_category_product` (`category_id`, `product_id`, `position`) VALUES ($categoryID, $x++, $productPosition)");
}
echo "The job is done";
?>
I hope the code is clear for everyone,if it's not,reply and i'll try to explain it.
#nachito : here it is.