Try the Demo

Magento

eCommerce Software for Online Growth

Magento Forum

Our new hosted solution for small & emerging businesses
   
Page 1 of 2
Overwrite images during import: a possible hack but an expected standard feature
 
mayerwin
Sr. Member
 
Avatar
Total Posts:  182
Joined:  2008-01-15
France
 

You may have been confronted to the fact that images get duplicated each time the import profile (Import All Products) is launched.

I have found THE line of code to hack to get rid of this behaviour.

The following modification will make Magento does not create a new image each time by appending a _d, where d is an increment.

In /app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php
Before $destFile = dirname($file) . $ioObject->dirsep(), (l460), Replace:

$destFile dirname($file) . $ioObject->dirsep()
                  . 
Varien_File_Uploader::getNewFileName($this->_getConfig()->getMediaPath($file));

With:

#BEGIN CUSTOM
        $destFile $file;
        
//$destFile = dirname($file) . $ioObject->dirsep()
        //          . Varien_File_Uploader::getNewFileName($this->_getConfig()->getMediaPath($file));
        #END CUSTOM

If this feature could be an option in future releases of Magento, that would be great.

 Signature 

I have finally found the best web hosting ever for Magento! 1 second max pageload with my website, for less than 15€ a month… And a very good support. I strongly advise you to try them : Rackspeed.de, there is even a 7 days free trial.
Erwin Mayer Foundation

 
Magento Community Magento Community
Magento Community
Magento Community
 
Benjamin Bellamy
Jr. Member
 
Total Posts:  18
Joined:  2008-06-26
Paris, France
 

Thank you for your hack, it helped a lot.

Unfortunatly it did not work on my server (Magento 1.1.6) :

The function that adds annoying “_2” to image files is called 3 times in /app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php .
In order to find it, just look for :

Varien_File_Uploader::getNewFileName

You will see it is called from :
- addImage
- _moveImageFromTmp
- _copyImage

Therefore I had to make 3 changes.

addImage

public function addImage(Mage_Catalog_Model_Product $product$file$mediaAttribute=null$move=false$exclude=true)
    
{
        $file 
realpath($file);

        if (!
$file{
            Mage
::throwException(Mage::helper('catalog')->__('Image not exists'));
        
}

        $pathinfo 
pathinfo($file);

        if (!isset(
$pathinfo['extension']) || !in_array($pathinfo['extension'], array('jpg','jpeg','gif','png'))) {
            Mage
::throwException(Mage::helper('catalog')->__('Invalid image file type'));
        
}


        $fileName       
Varien_File_Uploader::getCorrectFileName($pathinfo['basename']);
        
$dispretionPath Varien_File_Uploader::getDispretionPath($fileName);
        
$fileName       $dispretionPath DS $fileName;

        
// <HACK> just comment the two following lines :
        //$fileName = $dispretionPath . DS
        //          . Varien_File_Uploader::getNewFileName($this->_getConfig()->getTmpMediaPath($fileName));
        // </HACK>

        
$ioAdapter = new Varien_Io_File();
        
$ioAdapter->setAllowCreateFolders(true);
        
$distanationDirectory dirname($this->_getConfig()->getTmpMediaPath($fileName));

        try 
{
            $ioAdapter
->open(array(
                
'path'=>$distanationDirectory
            
));

            if (
$move{
                $ioAdapter
->mv($file$this->_getConfig()->getTmpMediaPath($fileName));
            
else {
                $ioAdapter
->cp($file$this->_getConfig()->getTmpMediaPath($fileName));
                
$ioAdapter->chmod($this->_getConfig()->getTmpMediaPath($fileName), 0777);
            
}
        }
        
catch (Exception $e{
            Mage
::throwException(Mage::helper('catalog')->__('Failed to move file: %s'$e->getMessage()));
        
}

        $fileName 
str_replace(DS'/'$fileName);

        
$attrCode $this->getAttribute()->getAttributeCode();
        
$mediaGalleryData $product->getData($attrCode);
        
$position 0;
        if (!
is_array($mediaGalleryData)) {
            $mediaGalleryData 
= array(
                
'images' => array()
            );
        
}

        
foreach ($mediaGalleryData['images'as &$image{
            
if (isset($image['position']) && $image['position'$position{
                $position 
$image['position'];
            
}
        }

        $position
++;
        
$mediaGalleryData['images'][] = array(
            
'file'     => $fileName,
            
'position' => $position,
            
'label'    => '',
            
'disabled' => (int) $exclude
        
);

        
$product->setData($attrCode$mediaGalleryData);

        if (!
is_null($mediaAttribute)) {
            $this
->setMediaAttribute($product$mediaAttribute$fileName);
        
}

        
return $fileName;
    
}

_moveImageFromTmp

protected function _moveImageFromTmp($file)
    
{
        $ioObject 
= new Varien_Io_File();
        
$destDirectory dirname($this->_getConfig()->getMediaPath($file));
        try 
{
            $ioObject
->open(array('path'=>$destDirectory));
        
catch (Exception $e{
            $ioObject
->mkdir($destDirectory0777true);
            
$ioObject->open(array('path'=>$destDirectory));
        
}

        
if (strrpos($file'.tmp') == strlen($file)-4{
            $file 
substr($file0strlen($file)-4);
        
}

        
// <HACK> just comment the two following lines and add the third one :
        //$destFile = dirname($file) . $ioObject->dirsep()
        //          . Varien_File_Uploader::getNewFileName($this->_getConfig()->getMediaPath($file));
        
$destFile $file;
        
//</HACK>

        
$ioObject->cp(
            
$this->_getConfig()->getTmpMediaPath($file),
            
$this->_getConfig()->getMediaPath($destFile)
        );

        return 
str_replace($ioObject->dirsep(), '/'$destFile);
    
}

_copyImage

protected function _copyImage($file)
    
{
        $ioObject 
= new Varien_Io_File();
        
$destDirectory dirname($this->_getConfig()->getMediaPath($file));
        
$ioObject->open(array('path'=>$destDirectory));

        
// <HACK> just comment the two following lines and add the third one :
        //$destFile = dirname($file) . $ioObject->dirsep()
        //          . Varien_File_Uploader::getNewFileName($this->_getConfig()->getMediaPath($file));
        
$destFile $file;

        
// for a mysterious reason moving files does not work so let's copy it instead :
        //$ioObject->mv(
        
$ioObject->cp(
            
$this->_getConfig()->getMediaPath($file),
            
$this->_getConfig()->getMediaPath($destFile)
        );
        
// </HACK>

        
return str_replace($ioObject->dirsep(), '/'$destFile);
    
}

Hope it helps !

 Signature 

Benjamin Bellamy

 
Magento Community Magento Community
Magento Community
Magento Community
 
mayerwin
Sr. Member
 
Avatar
Total Posts:  182
Joined:  2008-01-15
France
 

Oh, I see, I forgot to mention a hack I did previously at the same time for multiple images import, in:
/www/suiclean/app/code/core/Mage/Catalog/Model/Convert/Adapter/Product.php

Replace:
    
$product->addImageToMediaGallery(Mage::getBaseDir('media') . DS 'import' $file$fields);
With:
    
$product->addImageToMediaGallery(Mage::getBaseDir('media') . DS 'import' $file$fieldsfalsetrue);

The “true” value in the end is actually what will make the function _moveImageFromTmp to be called by addImageToMediaGallery, so without it Magento will only copy the file (function _copyImage), and since I didn’t hack this function each time you’ll launch the import a new file will be created in the temp folder, with an undesirable index appended and replicated in the final directory.

To make sure everything works fine with my hack you therefore need to enable moveImage instead of copyImage, thanks to the code above, and also delete everything in the /media/tmp folder (the advantage of moving the files is that you don’t have images remaining and getting duplicated in the tmp folder, which is not useful at all and takes space).

Anyway thanks Benjamin for your insight! Now things should be clearer to everybody.

 Signature 

I have finally found the best web hosting ever for Magento! 1 second max pageload with my website, for less than 15€ a month… And a very good support. I strongly advise you to try them : Rackspeed.de, there is even a 7 days free trial.
Erwin Mayer Foundation

 
Magento Community Magento Community
Magento Community
Magento Community
 
hmpierson
Sr. Member
 
Total Posts:  88
Joined:  2008-11-15
 

Very nice.

Is there a way/a place to put your modifications so that they don’t get written over by an upgrade?

Naturally, as you state, having your code as an option (or even the new default) would be the best!

 
Magento Community Magento Community
Magento Community
Magento Community
 
mayerwin
Sr. Member
 
Avatar
Total Posts:  182
Joined:  2008-01-15
France
 

It should be possible to write a module that extend the class, by just copy/pasting the hacked functions. However the module should be upgraded at each Magento upgrade, so that in case the original function is upgraded, the module doesn’t bypass it…

I may have a look at the module creation process, but I can’t promise anything since I am very busy right now so go ahead if you have more time, it should not be complicated and still better than hacking magento core files at each upgrade…

 Signature 

I have finally found the best web hosting ever for Magento! 1 second max pageload with my website, for less than 15€ a month… And a very good support. I strongly advise you to try them : Rackspeed.de, there is even a 7 days free trial.
Erwin Mayer Foundation

 
Magento Community Magento Community
Magento Community
Magento Community
 
Benjamin Bellamy
Jr. Member
 
Total Posts:  18
Joined:  2008-06-26
Paris, France
 
hmpierson - 21 November 2008 10:26 AM

Very nice.
Is there a way/a place to put your modifications so that they don’t get written over by an upgrade?
Naturally, as you state, having your code as an option (or even the new default) would be the best!

Off course, one should never modify core files.
You have two solutions :

- the easy one : duplicate Media.php file in app/code/local/Mage/Catalog/Model/Product/Attribute/Backend/
But if this file is modified by an upgrade it won’t be on your server which may creates buggy behaviours…

- the hard one : create you own classe in app/code/local/MyCompany/Catalog/Model/Product/Attribute/Backend/

MyCompany_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Catalog_Model_Product_Attribute_Backend_Media
then only overload the functions you want to modify,
and at last you may have to edit app/etc/local.xml and add the proper items.

I have to admit I chose the easy way, and I’ll wait for Magento to implement this function…

Ben.

 Signature 

Benjamin Bellamy

 
Magento Community Magento Community
Magento Community
Magento Community
 
hmpierson
Sr. Member
 
Total Posts:  88
Joined:  2008-11-15
 

RE:
<i>
- the hard one : create you own classe in app/code/local/MyCompany/Catalog/Model/Product/Attribute/Backend/

MyCompany_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Catalog_Model_Product_Attribute_Backend_Media

then only overload the functions you want to modify,
and at last you <u>may</u> have to edit app/etc/local.xml and add the proper items. </i>

Thank you for your reply. I’m new to all this, and trying to wrap my head around exactly what and where to made modifications so that they will not be overriden by updates. It’s supposed to be easy and transparent, but nothing is yets.

 
Magento Community Magento Community
Magento Community
Magento Community
 
zadpro
Sr. Member
 
Avatar
Total Posts:  247
Joined:  2007-12-10
FL, USA
 

Does anybody know if this issue been resolved in version 1.2.0.2?

Thanks

 Signature 

ZadPro.com

Managing BargainCollection.com Powered by Magento 1.3.2.3

Follow BargainCollection on twitter

 
Magento Community Magento Community
Magento Community
Magento Community
 
zadpro
Sr. Member
 
Avatar
Total Posts:  247
Joined:  2007-12-10
FL, USA
 
zadpro - 22 January 2009 05:25 PM

Does anybody know if this issue been resolved in version 1.2.0.2?

Thanks

To answer my own question, No, it is still exists in version 1.2.0.2. I’m not surprised, because now I’m used to see Magento only ADDS features and never fix them.
Any way, your hack worked like a charm. Thanks

 Signature 

ZadPro.com

Managing BargainCollection.com Powered by Magento 1.3.2.3

Follow BargainCollection on twitter

 
Magento Community Magento Community
Magento Community
Magento Community
 
webscot
Sr. Member
 
Total Posts:  189
Joined:  2009-05-12
 

@mayerwin:

So the original HACK you posted should appear where exactly? There are two places in the Media.php file where the code exists that you HACK in your post at _moveImageFromTmp($file) at or about line 471and _copyImage($file) at or about line 495 in version 1.3.2.2. Should both of these be hacked to work or just one?

protected function _moveImageFromTmp($file)
    
{
        $ioObject 
= new Varien_Io_File();
        
$destDirectory dirname($this->_getConfig()->getMediaPath($file));
        try 
{
            $ioObject
->open(array('path'=>$destDirectory));
        
catch (Exception $e{
            $ioObject
->mkdir($destDirectory0777true);
            
$ioObject->open(array('path'=>$destDirectory));
        
}

        
if (strrpos($file'.tmp') == strlen($file)-4{
            $file 
substr($file0strlen($file)-4);
        
}

        
#BEGIN CUSTOM
        
$destFile $file;
        
//$destFile = dirname($file) . $ioObject->dirsep()
        //          . Varien_File_Uploader::getNewFileName($this->_getConfig()->getMediaPath($file));
        #END CUSTOM

        
$ioObject->mv(
            
$this->_getConfig()->getTmpMediaPath($file),
            
$this->_getConfig()->getMediaPath($destFile)
        );

        return 
str_replace($ioObject->dirsep(), '/'$destFile);
    
}

    
/**
     * Copy image and return new filename.
     *
     * @param string $file
     * @return string
     */
    
protected function _copyImage($file)
    
{
        
try {
            $ioObject 
= new Varien_Io_File();
            
$destDirectory dirname($this->_getConfig()->getMediaPath($file));
            
$ioObject->open(array('path'=>$destDirectory));
 
#BEGIN CUSTOM
        
$destFile $file;
        
//$destFile = dirname($file) . $ioObject->dirsep()
        //          . Varien_File_Uploader::getNewFileName($this->_getConfig()->getMediaPath($file));
        #END CUSTOM

            
if (!$ioObject->fileExists($this->_getConfig()->getMediaPath($file),true)) {
                
throw new Exception();
            
}
            $ioObject
->cp(
                
$this->_getConfig()->getMediaPath($file),
                
$this->_getConfig()->getMediaPath($destFile)
            );
        
catch (Exception $e{
            Mage
::throwException(
                
Mage::helper('catalog')->__('Failed to copy file %s. Please, delete media with non-existing images and try again.',
                    
$this->_getConfig()->getMediaPath($file))
            );
        
}

        
return str_replace($ioObject->dirsep(), '/'$destFile);
    
}

 
Magento Community Magento Community
Magento Community
Magento Community
 
Feldar
Member
 
Total Posts:  32
Joined:  2010-06-15
NJ, US
 

This fix still works in 1.4
I got error messages on my first attempt, turns out I forgot a semicolon after $destFile = $file in one spot…

 
Magento Community Magento Community
Magento Community
Magento Community
 
nikola99
Member
 
Total Posts:  47
Joined:  2010-04-09
 

Here’s a module that rewrites the core functionallity. It fixes these issues:
1) Image is added as excluded
2) Image with white space is not added
3) If an image is already assigned to a product it is added again.

Note: Replace [Namespace] and <Namespace> with your company name.

app/etc/modules/<Namespace>_ProductImport.xml

<?xml version="1.0"?>
<config>
    <
modules>
        <
[Namespace]_ProductImport>
            <
active>true</active>
            <
codePool>local</codePool>
        </
[Namespace]_ProductImport>
    </
modules>
</
config>

...

app/code/local/<Namespace>/ProductImport/etc/config.xml

<?xml version="1.0"?>
<config>
    <
modules>
        <
[Namespace]_ProductImport>
            <
version>0.1.0</version>
        </
[Namespace]_ProductImport>
    </
modules>
    <global>
        <
models>
            <
catalog>
                <
rewrite>
                    <!-- 
Override Mage_Catalog_Model_Convert_Adapter_Product -->
                    <
convert_adapter_product>[Namespace]_ProductImport_Model_Product</convert_adapter_product>
                </
rewrite>
            </
catalog>
        </
models>
    </global>
</
config>

 
Magento Community Magento Community
Magento Community
Magento Community
 
nikola99
Member
 
Total Posts:  47
Joined:  2010-04-09
 

Continued.

/app/code/local/<Namespace>/ProductImport/Model/Product.php

<?php
class <Namespace>_ProductImport_Model_Product extends Mage_Catalog_Model_Convert_Adapter_Product
{
    
/**
     * Save product (import). Changed to add the image as not excluded.
     *
     * @param array $importData
     * @throws Mage_Core_Exception
     * @return bool
     */
    
public function saveRow(array $importData)
    
{
        $product 
$this->getProductModel()
            ->
reset();

        if (empty(
$importData['store'])) {
            
if (!is_null($this->getBatchParams('store'))) {
                $store 
$this->getStoreById($this->getBatchParams('store'));
            
else {
                $message 
Mage::helper('catalog')->__('Skip import row, required field "%s" not defined''store');
                
Mage::throwException($message);
            
}
        }
        
else {
            $store 
$this->getStoreByCode($importData['store']);
        
}

        
if ($store === false{
            $message 
Mage::helper('catalog')->__('Skip import row, store "%s" field not exists'$importData['store']);
            
Mage::throwException($message);
        
}

        
if (empty($importData['sku'])) {
            $message 
Mage::helper('catalog')->__('Skip import row, required field "%s" not defined''sku');
            
Mage::throwException($message);
        
}
        $product
->setStoreId($store->getId());
        
$productId $product->getIdBySku($importData['sku']);

        if (
$productId{
            $product
->load($productId);
        
}
        
else {
            $productTypes 
$this->getProductTypes();
            
$productAttributeSets $this->getProductAttributeSets();

            
/**
             * Check product define type
             */
            
if (empty($importData['type']) || !isset($productTypes[strtolower($importData['type'])])) {
                $value 
= isset($importData['type']) ? $importData['type''';
                
$message Mage::helper('catalog')->__('Skip import row, is not valid value "%s" for field "%s"'$value'type');
                
Mage::throwException($message);
            
}
            $product
->setTypeId($productTypes[strtolower($importData['type'])]);
            
/**
             * Check product define attribute set
             */
            
if (empty($importData['attribute_set']) || !isset($productAttributeSets[$importData['attribute_set']])) {
                $value 
= isset($importData['attribute_set']) ? $importData['attribute_set''';
                
$message Mage::helper('catalog')->__('Skip import row, is not valid value "%s" for field "%s"'$value'attribute_set');
                
Mage::throwException($message);
            
}
            $product
->setAttributeSetId($productAttributeSets[$importData['attribute_set']]);

            foreach (
$this->_requiredFields as $field{
                $attribute 
$this->getAttribute($field);
                if (!isset(
$importData[$field]) && $attribute && $attribute->getIsRequired()) {
                    $message 
Mage::helper('catalog')->__('Skip import row, required field "%s" for new products not defined'$field);
                    
Mage::throwException($message);
                
}
            }
        }

        $this
->setProductTypeInstance($product);

        if (isset(
$importData['category_ids'])) {
            $product
->setCategoryIds($importData['category_ids']);
        
}

        
foreach ($this->_ignoreFields as $field{
            
if (isset($importData[$field])) {
                
unset($importData[$field]);
            
}
        }

        
if ($store->getId() != 0{
            $websiteIds 
$product->getWebsiteIds();
            if (!
is_array($websiteIds)) {
                $websiteIds 
= array();
            
}
            
if (!in_array($store->getWebsiteId(), $websiteIds)) {
                $websiteIds[] 
$store->getWebsiteId();
            
}
            $product
->setWebsiteIds($websiteIds);
        
}

        
if (isset($importData['websites'])) {
            $websiteIds 
$product->getWebsiteIds();
            if (!
is_array($websiteIds)) {
                $websiteIds 
= array();
            
}
            $websiteCodes 
explode(','$importData['websites']);
            foreach (
$websiteCodes as $websiteCode{
                
try {
                    $website 
Mage::app()->getWebsite(trim($websiteCode));
                    if (!
in_array($website->getId(), $websiteIds)) {
                        $websiteIds[] 
$website->getId();
                    
}
                }
                
catch (Exception $e{}
            }
            $product
->setWebsiteIds($websiteIds);
            unset(
$websiteIds);
        
}

        
foreach ($importData as $field => $value{
            
if (in_array($field$this->_inventoryFields)) {
                
continue;
            
}
            
if (in_array($field$this->_imageFields)) {
                
continue;
            
}

            $attribute 
$this->getAttribute($field);
            if (!
$attribute{
                
continue;
            
}

            $isArray 
false;
            
$setValue $value;

            if (
$attribute->getFrontendInput() == 'multiselect'{
                $value 
explode(self::MULTI_DELIMITER$value);
                
$isArray true;
                
$setValue = array();
            
}

            
if ($value && $attribute->getBackendType() == 'decimal'{
                $setValue 
$this->getNumber($value);
            
}
... 
Edit: Fixed errors as pointed out by JeremyFP

 
Magento Community Magento Community
Magento Community
Magento Community
 
nikola99
Member
 
Total Posts:  47
Joined:  2010-04-09
 

Continued.

/app/code/local/<Namespace>/ProductImport/Model/Product.php (continued)

if ($attribute->usesSource()) {
                $options 
$attribute->getSource()->getAllOptions(false);

                if (
$isArray{
                    
foreach ($options as $item{
                        
if (in_array($item['label']$value)) {
                            $setValue[] 
$item['value'];
                        
}
                    }
                } 
else {
                    $setValue 
false;
                    foreach (
$options as $item{
                        
if ($item['label'== $value{
                            $setValue 
$item['value'];
                        
}
                    }
                }
            }

            $product
->setData($field$setValue);
        
}

        
if (!$product->getVisibility()) {
            $product
->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE);
        
}

        $stockData 
= array();
        
$inventoryFields = isset($this->_inventoryFieldsProductTypes[$product->getTypeId()])
            ? 
$this->_inventoryFieldsProductTypes[$product->getTypeId()]
            
: array();
        foreach (
$inventoryFields as $field{
            
if (isset($importData[$field])) {
                
if (in_array($field$this->_toNumber)) {
                    $stockData[$field] 
$this->getNumber($importData[$field]);
                
}
                
else {
                    $stockData[$field] 
$importData[$field];
                
}
            }
        }
        $product
->setStockData($stockData);

        
$imageData = array();
        foreach (
$this->_imageFields as $field{
            
if (!empty($importData[$field]) && $importData[$field] != 'no_selection'{
                
if (!isset($imageData[$importData[$field]])) {
                    $imageData[$importData[$field]] 
= array();
                
}
                $imageData[$importData[$field]][] 
$field;
            
}
        }
        
        
/* Start Modification */
        
$currentImageCollection $product->getMediaGalleryImages();
        
$currentImages = array();
        foreach(
$currentImageCollection as $image{
            $currentImages[] 
'/' basename($image['file']);
        
}

        
foreach ($imageData as $file => $fields{
            
// Make the first image the Base, Small and Thumbnail if there are no exising images and this is the only image for this record
            
if(count($imageData) == && !count($currentImages)) {
                $fields 
= array('image''thumbnail''small_image');
             
}             
             
if(!in_array(trim($file), $currentImages)) {
                 
try {
                     $product
->addImageToMediaGallery(Mage::getBaseDir('media') . DS 'import' trim($file), $fieldsfalsefalse);
                
}
                
catch (Exception $e{}
            }
        }
        
/* End Modification */

        
$product->setIsMassupdate(true);
        
$product->setExcludeUrlRewrite(true);

        
$product->save();

        return 
true;
    
}
}

Hope this helps.

Edit: Fixed another problem (as per http://www.magentocommerce.com/boards/viewthread/70720/#t203756). Now the first image is set as Base, Small and Thumbnail
Edit: Fixed errors as pointed out by JeremyFP

 
Magento Community Magento Community
Magento Community
Magento Community
 
JeremyFP
Jr. Member
 
Total Posts:  24
Joined:  2009-09-25
 

nikola99, there are some bugs in that PHP. Looks like a find/replace gone wrong.

Replace curre[Namespace]mage with currentImage on lines 194-198 (case sensitive, for all you folks playing at home).
Replace co[Namespace]nue with continue on lines 119, 122, & 127.

 Signature 

Demdaco Willow Tree Nativity Sets, Angels & Figurines

 
Magento Community Magento Community
Magento Community
Magento Community
 
nikola99
Member
 
Total Posts:  47
Joined:  2010-04-09
 

JeremyFP,
Thanks for pointing those out! It was indeed find/replace gone wrong smile.

 
Magento Community Magento Community
Magento Community
Magento Community
Magento Community
Magento Community
    Back to top
Page 1 of 2
 
© Copyright 2012 Magento Inc.
Privacy Policy|Terms of Service
Magento Community Count
704132 users|1730 users currently online|497373 forum posts