Allow SVG Images in Magento Uploader

If you want to change the allowed image extensions for product images in Magento you will find out that they are hard coded in Mage/Catalog/Model/Product/Attribute/Backend/Media.php and Mage/Adminhtml/controllers/Catalog/Product/GalleryController.php

However, I found an observer that allows you to change them along with other configuration of the uploader. This post explains how to create an extension to allow uploading of SVG files. Foundations of Magento extension develoment are presumed.

Configuration in config.xml

<config>
    <adminhtml>
        <events>
            <catalog_product_gallery_prepare_layout>
                <observers>
                    <your_module>
                        <class>your_module/observer</class>
                        <method>setFlexUploaderConfig</method>
                        <type>singleton</type>
                    </your_module>
                </observers>
            </catalog_product_gallery_prepare_layout>
        </events>
    </adminhtml>
</config>

Your observer

class Your_Module_Model_Observer
{
    /**
     * Adds file types to allowed file types of file selector
     *
     * @see event catalog_product_gallery_prepare_layout
     * @see block Mage_Adminhtml_Block_Catalog_Product_Helper_Form_Gallery_Content
     * @param Varien_Event_Observer $observer
     */
    public function setFlexUploaderConfig(Varien_Event_Observer $observer)
    {
        /* @var $galleryBlock Mage_Adminhtml_Block_Catalog_Product_Helper_Form_Gallery_Content */
        $uploaderConfig = $observer->getBlock()->getUploader()->getConfig();
        $additionalExtensions = array('*.svg');
        $uploaderFileFilters = $uploaderConfig->getFilters();
        $uploaderFileFilters['vector_images'] = array(
                'label' => $this->__('Vector Images') . ' (' . join(', ', $additionalExtensions) . ')',
                'files' => $additionalExtensions
        );
        $uploaderConfig->setFilters($uploaderFileFilters);
    }
}

You can change the existing filter images instead of adding a new one as well, I just took the code from a module where I allowed video uploads, so an additional filter made sense. The filters define the dropdowns in the “open file” dialog.

For the server side validation you still need to override the gallery upload action:

config.xml

<config>
    <admin>
        <routers>
            <adminhtml>
                <args>
                    <modules>
                        <Your_Module before="Mage_Adminhtml">Your_Module_Adminhtml</Your_Module>
                    </modules>
                </args>
            </adminhtml>
        </routers>
    </admin>
</config>

Your controller:

class Your_Module_Adminhtml_Catalog_Product_GalleryController extends Mage_Adminhtml_Catalog_Product_GalleryController
{
    public static $allowedImageExtensions = array('jpg', 'jpeg', 'gif', 'png');
    public static $allowedVectorExtensions = array('svg');

    /**
     * Overridden to reconfigure the Uploader
     *
     * (non-PHPdoc)
     * @see Mage_Adminhtml_Catalog_Product_GalleryController::uploadAction()
     */
    public function uploadAction()
    {
        try {
            $uploader = new Mage_Core_Model_File_Uploader('image');


            // BEGIN change
            $uploader->setAllowedExtensions($this->_getAllowedExtensions());
            $uploader->addValidateCallback('catalog_product_image', $this, 'validateUploadImage');
            $uploader->addValidateCallback('svg_image', $this, 'validateUploadVector');
            // END change


            $uploader->setAllowRenameFiles(true);
            $uploader->setFilesDispersion(true);
            $result = $uploader->save(
                Mage::getSingleton('catalog/product_media_config')->getBaseTmpMediaPath()
            );

            Mage::dispatchEvent('catalog_product_gallery_upload_image_after', array(
                'result' => $result,
                'action' => $this
            ));

            /**
             * Workaround for prototype 1.7 methods "isJSON", "evalJSON" on Windows OS
             */
            $result['tmp_name'] = str_replace(DS, "/", $result['tmp_name']);
            $result['path'] = str_replace(DS, "/", $result['path']);

            $result['url'] = Mage::getSingleton('catalog/product_media_config')->getTmpMediaUrl($result['file']);
            $result['file'] = $result['file'] . '.tmp';
            $result['cookie'] = array(
                'name'     => session_name(),
                'value'    => $this->_getSession()->getSessionId(),
                'lifetime' => $this->_getSession()->getCookieLifetime(),
                'path'     => $this->_getSession()->getCookiePath(),
                'domain'   => $this->_getSession()->getCookieDomain()
            );

        } catch (Exception $e) {
            $result = array(
                'error' => $e->getMessage(),
                'errorcode' => $e->getCode());
        }

        $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
    }

    protected function _getAllowedExtensions()
    {
        return array_merge(self::$allowedImageExtensions, self::$allowedVectorExtensions);
    }
    public function validateUploadImage($file)
    {
        if (in_array(pathinfo($file, PATHINFO_EXTENSION), self::$allowedImageExtensions)) {
            return Mage::helper('catalog/image')->validateUploadFile($file);
        }
    }
    public function validateUploadVector($file)
    {
        if (in_array(pathinfo($file, PATHINFO_EXTENSION), self::$allowedVectorExtensions)) {
            //TODO throw exception if invalid file
            return;
        }
    }
}

This controller overrides the uploadAction of the original gallery controller. You see, that it is necessary to add a second validator and only use the original validator from Mage_Catalog_Helper_Image if the image has one of the file types supported by the GD extension. In the validateUploadVector method above you can add additional validation for SVG files and throw an Exception if the file is not a valid SVG.

Template changes

Additionally you will need to change your templates to display SVG files correctly, i.e. not using the thumbnail generation methods if the file is an SVG. Alternatively you could try to rewrite Mage_Catalog_Helper_Image::resize() to ignore SVG files.

Question and answer on Magento StackExchange