diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit.php index b1f053e3fcd..a7891bb257d 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit.php @@ -41,9 +41,9 @@ protected function _prepareLayout() 'back_button', $this->getLayout()->createBlock('adminhtml/widget_button') ->setData([ - 'label' => Mage::helper('catalog')->__('Back'), - 'onclick' => Mage::helper('core/js')->getSetLocationJs($this->getUrl('*/*/', ['store' => $this->getRequest()->getParam('store', 0)])), - 'class' => 'back', + 'label' => Mage::helper('catalog')->__('Back'), + 'onclick' => Mage::helper('core/js')->getSetLocationJs($this->getUrl('*/*/', ['store' => $this->getRequest()->getParam('store', 0)])), + 'class' => 'back', ]), ); } else { @@ -51,9 +51,9 @@ protected function _prepareLayout() 'back_button', $this->getLayout()->createBlock('adminhtml/widget_button') ->setData([ - 'label' => Mage::helper('catalog')->__('Close Window'), - 'onclick' => 'window.close()', - 'class' => 'cancel', + 'label' => Mage::helper('catalog')->__('Close Window'), + 'onclick' => 'window.close()', + 'class' => 'cancel', ]), ); } @@ -63,9 +63,9 @@ protected function _prepareLayout() 'reset_button', $this->getLayout()->createBlock('adminhtml/widget_button') ->setData([ - 'label' => Mage::helper('catalog')->__('Reset'), - 'onclick' => Mage::helper('core/js')->getSetLocationJs($this->getUrl('*/*/*', ['_current' => true])), - 'class' => 'reset', + 'label' => Mage::helper('catalog')->__('Reset'), + 'onclick' => Mage::helper('core/js')->getSetLocationJs($this->getUrl('*/*/*', ['_current' => true])), + 'class' => 'reset', ]), ); @@ -73,9 +73,9 @@ protected function _prepareLayout() 'save_button', $this->getLayout()->createBlock('adminhtml/widget_button') ->setData([ - 'label' => Mage::helper('catalog')->__('Save'), - 'onclick' => 'productForm.submit()', - 'class' => 'save', + 'label' => Mage::helper('catalog')->__('Save'), + 'onclick' => 'productForm.submit()', + 'class' => 'save', ]), ); } @@ -86,9 +86,9 @@ protected function _prepareLayout() 'save_and_edit_button', $this->getLayout()->createBlock('adminhtml/widget_button') ->setData([ - 'label' => Mage::helper('catalog')->__('Save and Continue Edit'), - 'onclick' => Mage::helper('core/js')->getSaveAndContinueEditJs($this->getSaveAndContinueUrl()), - 'class' => 'save continue', + 'label' => Mage::helper('catalog')->__('Save and Continue Edit'), + 'onclick' => Mage::helper('core/js')->getSaveAndContinueEditJs($this->getSaveAndContinueUrl()), + 'class' => 'save continue', ]), ); } @@ -98,21 +98,32 @@ protected function _prepareLayout() 'delete_button', $this->getLayout()->createBlock('adminhtml/widget_button') ->setData([ - 'label' => Mage::helper('catalog')->__('Delete'), - 'onclick' => Mage::helper('core/js')->getConfirmSetLocationJs($this->getDeleteUrl()), - 'class' => 'delete', + 'label' => Mage::helper('catalog')->__('Delete'), + 'onclick' => Mage::helper('core/js')->getConfirmSetLocationJs($this->getDeleteUrl()), + 'class' => 'delete', ]), ); } if ($this->getProduct()->isDuplicable()) { + if ($this->getProduct()->getMediaGalleryImages()->count() === 0) { + $onClickAction = Mage::helper('core/js')->getSetLocationJs($this->getDuplicateUrl(true)); + } else { + $skipImgOnDuplicate = $this->helper('catalog/image')->skipProductImageOnDuplicate(); + $onClickAction = "openDuplicateDialog('" . $this->getDuplicateUrl(false) . "','" . $this->getDuplicateUrl(true) . "'); return false;"; + + if ($skipImgOnDuplicate !== -1) { + $onClickAction = Mage::helper('core/js')->getSetLocationJs($this->getDuplicateUrl((bool) $skipImgOnDuplicate)); + } + } + $this->setChild( 'duplicate_button', $this->getLayout()->createBlock('adminhtml/widget_button') ->setData([ - 'label' => Mage::helper('catalog')->__('Duplicate'), - 'onclick' => Mage::helper('core/js')->getSetLocationJs($this->getDuplicateUrl()), - 'class' => 'add duplicate', + 'label' => Mage::helper('catalog')->__('Duplicate'), + 'onclick' => $onClickAction, + 'class' => 'add duplicate', ]), ); } @@ -191,9 +202,9 @@ public function getSaveUrl() public function getSaveAndContinueUrl() { return $this->getUrl('*/*/save', [ - '_current' => true, - 'back' => 'edit', - 'tab' => '{{tab_id}}', + '_current' => true, + 'back' => 'edit', + 'tab' => '{{tab_id}}', 'active_tab' => null, ]); } @@ -229,9 +240,9 @@ public function getDeleteUrl() /** * @return string */ - public function getDuplicateUrl() + public function getDuplicateUrl($skipImages = false) { - return $this->getUrl('*/*/duplicate', ['_current' => true]); + return $this->getUrl('*/*/duplicate', ['_current' => true, 'skipImages' => $skipImages ? 1 : 0]); } /** diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Catalog/ImageDuplicate.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Catalog/ImageDuplicate.php new file mode 100644 index 00000000000..91c33cb006b --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Catalog/ImageDuplicate.php @@ -0,0 +1,14 @@ + -1, 'label' => Mage::helper('adminhtml')->__('Always ask')], + ['value' => 0, 'label' => Mage::helper('adminhtml')->__('Copy images to the new product')], + ['value' => 1, 'label' => Mage::helper('adminhtml')->__('Duplicate product without images')], + ]; + } +} diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php index e3dd932327a..8adf4cd848e 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php @@ -822,6 +822,12 @@ public function duplicateAction() { $product = $this->_initProduct(); try { + $imgHelper = Mage::helper('catalog/image'); + + if($imgHelper->skipProductImageOnDuplicate() === -1){ + $product->setSkipImagesOnDuplicate((bool) $this->getRequest()->getParam('skipImages',true)); + } + $newProduct = $product->duplicate(); $this->_getSession()->addSuccess($this->__('The product has been duplicated.')); $this->_redirect('*/*/edit', ['_current' => true, 'id' => $newProduct->getId()]); diff --git a/app/code/core/Mage/Catalog/Helper/Image.php b/app/code/core/Mage/Catalog/Helper/Image.php index 25647ebfacd..8acf18ce264 100644 --- a/app/code/core/Mage/Catalog/Helper/Image.php +++ b/app/code/core/Mage/Catalog/Helper/Image.php @@ -20,6 +20,8 @@ class Mage_Catalog_Helper_Image extends Mage_Core_Helper_Abstract public const XML_NODE_PRODUCT_MAX_DIMENSION = 'catalog/product_image/max_dimension'; + public const XML_NODE_SKIP_IMAGE_ON_DUPLICATE_ACTION = 'catalog/product_image/images_on_duplicate_action'; + protected $_moduleName = 'Mage_Catalog'; /** @@ -650,4 +652,12 @@ public function validateUploadFile($filePath) return $mimeType !== null; } + + /** + * @return int + */ + public function skipProductImageOnDuplicate() + { + return Mage::getStoreConfigAsInt(self::XML_NODE_SKIP_IMAGE_ON_DUPLICATE_ACTION); + } } diff --git a/app/code/core/Mage/Catalog/Model/Product.php b/app/code/core/Mage/Catalog/Model/Product.php index 6c7b0497575..d6e196dfbcf 100644 --- a/app/code/core/Mage/Catalog/Model/Product.php +++ b/app/code/core/Mage/Catalog/Model/Product.php @@ -56,6 +56,8 @@ * @method bool getIsChangedWebsites() * @method bool getIsCustomOptionChanged() * @method bool getIsDefault() + * @method bool getSkipImagesOnDuplicate() + * @method $this setSkipImagesOnDuplicate(bool $value) * @method bool getIsDuplicate() * @method bool getIsMassupdate() * @method bool getIsRecurring() @@ -1365,6 +1367,12 @@ public function duplicate() ->setId(null) ->setStoreId(Mage::app()->getStore()->getId()); + if($newProduct->getSkipImagesOnDuplicate() == null && $this->_getImageHelper()->skipProductImageOnDuplicate() === -1){ + $newProduct->setSkipImagesOnDuplicate(false); + }else{ + $newProduct->setSkipImagesOnDuplicate((bool) $this->_getImageHelper()->skipProductImageOnDuplicate()); + } + Mage::dispatchEvent( 'catalog_model_product_duplicate', ['current_product' => $this, 'new_product' => $newProduct], @@ -1437,7 +1445,9 @@ public function duplicate() $newProduct->save(); $this->getOptionInstance()->duplicate($this->getId(), $newProduct->getId()); - $this->getResource()->duplicate($this->getId(), $newProduct->getId()); + $this->getResource() + ->setSkipImagesOnDuplicate($newProduct->getSkipImagesOnDuplicate()) + ->duplicate($this->getId(), $newProduct->getId()); // TODO - duplicate product on all stores of the websites it is associated with /*if ($storeIds = $this->getWebsiteIds()) { diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php index db2832c7987..9541d5e9d40 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php @@ -105,7 +105,7 @@ public function beforeSave($object) $value['images'] = Mage::helper('core')->jsonDecode($value['images']); } - if (!isset($value['values'])) { + if (!isset($value['values']) || $object->getSkipImagesOnDuplicate()) { $value['values'] = []; } @@ -113,7 +113,7 @@ public function beforeSave($object) $value['values'] = Mage::helper('core')->jsonDecode($value['values']); } - if (!is_array($value['images'])) { + if (!is_array($value['images']) || $object->getSkipImagesOnDuplicate()) { $value['images'] = []; } @@ -696,7 +696,7 @@ public function duplicate($object) $attrCode = $this->getAttribute()->getAttributeCode(); $mediaGalleryData = $object->getData($attrCode); - if (!isset($mediaGalleryData['images']) || !is_array($mediaGalleryData['images'])) { + if (!isset($mediaGalleryData['images']) || !is_array($mediaGalleryData['images']) || $object->getSkipImagesOnDuplicate()) { return $this; } diff --git a/app/code/core/Mage/Catalog/Model/Resource/Product.php b/app/code/core/Mage/Catalog/Model/Resource/Product.php index 582c8eab636..ea4dd162eb0 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Product.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Product.php @@ -28,6 +28,13 @@ class Mage_Catalog_Model_Resource_Product extends Mage_Catalog_Model_Resource_Ab */ protected $_productCategoryTable; + /** + * Used when duplicating product + * + * @var string + */ + protected $_skipImagesOnDuplicate = false; + /** * Initialize resource */ @@ -565,9 +572,22 @@ public function duplicate($oldId, $newId) { $adapter = $this->_getWriteAdapter(); $eavTables = ['datetime', 'decimal', 'int', 'text', 'varchar']; - + $mediaImageAttributeSkipIds = []; $adapter = $this->_getWriteAdapter(); + if($this->getSkipImagesOnDuplicate()){ + + /** + * @var int $attributeId + * @var Mage_Eav_Model_Entity_Attribute_Abstract $attribute + */ + foreach($this->getAttributesById() as $attributeId => $attribute){ + if($attribute->getFrontendInput() == 'media_image'){ + $mediaImageAttributeSkipIds[$attribute->getBackendType()][] = $attributeId; + } + } + } + // duplicate EAV store values foreach ($eavTables as $suffix) { $tableName = $this->getTable(['catalog/product', $suffix]); @@ -583,6 +603,10 @@ public function duplicate($oldId, $newId) ->where('entity_id = ?', $oldId) ->where('store_id > ?', 0); + if(isset($mediaImageAttributeSkipIds[$suffix])){ + $select->where('attribute_id NOT IN (?)', $mediaImageAttributeSkipIds[$suffix]); + } + $adapter->query($adapter->insertFromSelect( $select, $tableName, @@ -719,4 +743,22 @@ public function getCategoryIdsWithAnchors($object) return $this->_getReadAdapter()->fetchCol($select); } + + /** + * @param bool $newProductSkipImages + * @return $this + */ + public function setSkipImagesOnDuplicate(bool $newProductSkipImages){ + $this->_skipImagesOnDuplicate = $newProductSkipImages; + return $this; + } + + /** + * @return bool|string + */ + public function getSkipImagesOnDuplicate(){ + return $this->_skipImagesOnDuplicate; + } + + } diff --git a/app/code/core/Mage/Catalog/etc/config.xml b/app/code/core/Mage/Catalog/etc/config.xml index 07adebaca45..a5a78270ebb 100644 --- a/app/code/core/Mage/Catalog/etc/config.xml +++ b/app/code/core/Mage/Catalog/etc/config.xml @@ -810,6 +810,7 @@ 1800 210 5000 + -1 .html diff --git a/app/code/core/Mage/Catalog/etc/system.xml b/app/code/core/Mage/Catalog/etc/system.xml index add69a01d34..ac143082692 100644 --- a/app/code/core/Mage/Catalog/etc/system.xml +++ b/app/code/core/Mage/Catalog/etc/system.xml @@ -203,6 +203,16 @@ 1 validate-digits validate-greater-than-zero + + + 'Ask' option only affects Admin interface. Default for programmatical duplication is to persist images. + select + adminhtml/system_config_source_catalog_imageDuplicate + 50 + 1 + 1 + 1 + diff --git a/app/design/adminhtml/default/default/template/catalog/product/edit.phtml b/app/design/adminhtml/default/default/template/catalog/product/edit.phtml index 5fb4f6e9490..30a4faf538a 100644 --- a/app/design/adminhtml/default/default/template/catalog/product/edit.phtml +++ b/app/design/adminhtml/default/default/template/catalog/product/edit.phtml @@ -92,6 +92,38 @@ return 1; } + function openDuplicateDialog(keepImagesUrl,skipImagesUrl) { + var html = '

__('You can disable this message on'); ?>:
__('System'); ?> > __('Configuration'); ?> > __('Catalog Images'); ?> > __('Product Image'); ?>


'; + + function duplicateKeepImages(dialogWindow) { + dialogWindow.close(); + setLocation(keepImagesUrl); + } + function duplicateSkipImages(dialogWindow) { + dialogWindow.close(); + setLocation(skipImagesUrl); + } + + Dialog.confirm(html, { + width: 450, + height: 120, + draggable:true, + closable:true, + className:"magento", + windowClassName:"popup-window", + title:'__('Copy the images onto the new product?') ?>', + recenterAuto:false, + hideEffect:Element.hide, + showEffect:Element.show, + id:"duplicate-product", + buttonClass:"form-button", + okLabel:"__('Yes'); ?>", + ok: duplicateKeepImages.bind(this), + cancelLabel: "__('Duplicate product without images'); ?>", + cancel: duplicateSkipImages.bind(this), + }); + } + Event.observe(window, 'load', function() { var objName = 'getSelectedTabId() ?>'; if (objName) { diff --git a/app/locale/en_US/Mage_Adminhtml.csv b/app/locale/en_US/Mage_Adminhtml.csv index 0262cbb17b8..022a6b0aa5f 100644 --- a/app/locale/en_US/Mage_Adminhtml.csv +++ b/app/locale/en_US/Mage_Adminhtml.csv @@ -1312,3 +1312,10 @@ "{{base_url}} is not recommended to use in a production environment to declare the Base Unsecure URL / Base Secure URL. It is highly recommended to change this value in your Magento configuration.","{{base_url}} is not recommended to use in a production environment to declare the Base Unsecure URL / Base Secure URL. It is highly recommended to change this value in your Magento configuration." "Powered by OpenMage","Powered by OpenMage" "At least one currency has to be allowed.","At least one currency has to be allowed." +"You can disable this message on","You can disable this message on" +"Copy the images onto the new product?","Copy the images onto the new product?" +"Copy images to the new product","Copy images to the new product" +"Always ask","Always ask" +"Duplicate product without images","Duplicate product without images" +"Skip Images on Duplicate","Skip Images on Duplicate" +"'Ask' option only affects Admin interface. Default for programmatical duplication is to persist images.","'Ask' option only affects Admin interface. Default for programmatical duplication is to persist images."