Create Product File Type Attribute in Magento 2: – In this blog we are going to create and manage product file type attribute in magento 2.
Follow the below steps in order to create file type attribute:
Step 1:
First of all we have to create a product attribute with input type “File”. Here I’m creating it by installer. So, create a InstallData.php file in /app/code/Vendor/Module/Setup directory and copy below code.
<?php namespace Vendor\Module\Setup; use Magento\Eav\Setup\EavSetupFactory; use Magento\Framework\Setup\InstallDataInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; use Magento\Eav\Model\Entity\Attribute\Set as AttributeSet; use Magento\Catalog\Model\ResourceModel\Product as ResourceProduct; class InstallData implements InstallDataInterface { protected $_attributeSet; protected $_eavSetupFactory; protected $_resourceProduct; public function __construct( AttributeSet $attributeSet, EavSetupFactory $eavSetupFactory, ResourceProduct $resourceProduct ) { $this->_attributeSet = $attributeSet; $this->_eavSetupFactory = $eavSetupFactory; $this->_resourceProduct = $resourceProduct; } public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { $eavSetup = $this->_eavSetupFactory->create(["setup"=>$setup]); $eavSetup->addAttribute( \Magento\Catalog\Model\Product::ENTITY, 'agreement_file', [ 'type' => 'varchar', 'label' => 'Agreement File', 'input' => 'file', 'backend' => 'Vendor\Module\Model\Product\Attribute\Backend\File', 'frontend' => '', 'class' => '', 'source' => '', 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, 'visible' => true, 'required' => false, 'user_defined' => true, 'default' => '', 'searchable' => false, 'filterable' => false, 'comparable' => false, 'visible_on_front' => false, 'unique' => false, 'apply_to' => 'simple,configurable', // applicable for simple and configurable product 'used_in_product_listing' => false ] ); // assign attribute to attribute set $entityType = $this->_resourceProduct->getEntityType(); $attributeSetCollection = $this->_attributeSet->setEntityTypeFilter($entityType); foreach ($attributeSetCollection as $attributeSet) { $eavSetup->addAttributeToSet("catalog_product", $attributeSet->getAttributeSetName(), "General", "agreement_file"); } } }
Step 2:
Then create backend model File.php(which we have defined in attribute options) in app/code/Vendor/Module/Model/Product/Attribute/Backend directory and copy below code.
<?php namespace Vendor\Module\Model\Product\Attribute\Backend; use Magento\Framework\App\Filesystem\DirectoryList; class File extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend { /** * @var \Magento\Framework\Filesystem\Driver\File */ protected $_file; /** * @var \Psr\Log\LoggerInterface */ protected $_logger; /** * @var \Magento\Framework\Filesystem */ protected $_filesystem; /** * @var \Magento\MediaStorage\Model\File\UploaderFactory */ protected $_fileUploaderFactory; /** * Construct * * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Filesystem $filesystem * @param \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory */ public function __construct( \Psr\Log\LoggerInterface $logger, \Magento\Framework\Filesystem $filesystem, \Magento\Framework\Filesystem\Driver\File $file, \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory ) { $this->_file = $file; $this->_filesystem = $filesystem; $this->_fileUploaderFactory = $fileUploaderFactory; $this->_logger = $logger; } public function afterSave($object) { $path = $this->_filesystem->getDirectoryRead( DirectoryList::MEDIA )->getAbsolutePath( 'catalog/product/file/' ); $delete = $object->getData($this->getAttribute()->getName() . '_delete'); if ($delete) { $fileName = $object->getData($this->getAttribute()->getName()); $object->setData($this->getAttribute()->getName(), ''); $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName()); if ($this->_file->isExists($path.$fileName)) { $this->_file->deleteFile($path.$fileName); } } if (empty($_FILES)) { return $this;// if no image is set then nothing to do } try { /** @var $uploader \Magento\MediaStorage\Model\File\Uploader */ $uploader = $this->_fileUploaderFactory->create(['fileId' => 'product['.$this->getAttribute()->getName().']']); $uploader->setAllowedExtensions(['pdf']); $uploader->setAllowRenameFiles(true); $result = $uploader->save($path); $object->setData($this->getAttribute()->getName(), $result['file']); $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName()); } catch (\Exception $e) { if ($e->getCode() != \Magento\MediaStorage\Model\File\Uploader::TMP_NAME_EMPTY) { $this->_logger->critical($e); } } return $this; } }
Step 3:
To display saved file, we need to define template for the attribute. So, first define modifier class of the attribute in app/code/Vendor/Module/etc/adminhtml/di.xml as mentioned below
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool"> <arguments> <argument name="modifiers" xsi:type="array"> <item name="agreement_file" xsi:type="array"> <item name="class" xsi:type="string">Vendor\Module\Ui\DataProvider\Product\Form\Modifier\File</item> <item name="sortOrder" xsi:type="number">10</item> </item> </argument> </arguments> </virtualType> </config>
Step 4:
Create modifier class File.php in app/code/Vendor/Module/Ui/DataProvider/Product/Form/Modifier directory and copy below code
<?php namespace Vendor\Module\Ui\DataProvider\Product\Form\Modifier; use Magento\Framework\Stdlib\ArrayManager; use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; class File extends AbstractModifier { /** * @var Magento\Framework\Stdlib\ArrayManager */ protected $arrayManager; /** * @param ArrayManager $arrayManager */ public function __construct( ArrayManager $arrayManager ) { $this->arrayManager = $arrayManager; } public function modifyMeta(array $meta) { $fieldCode = 'agreement_file'; $elementPath = $this->arrayManager->findPath($fieldCode, $meta, null, 'children'); $containerPath = $this->arrayManager->findPath(static::CONTAINER_PREFIX . $fieldCode, $meta, null, 'children'); if (!$elementPath) { return $meta; } $meta = $this->arrayManager->merge( $containerPath, $meta, [ 'children' => [ $fieldCode => [ 'arguments' => [ 'data' => [ 'config' => [ 'elementTmpl' => 'Vendor_Module/elements/file', ], ], ], ] ] ] ); return $meta; } /** * {@inheritdoc} */ public function modifyData(array $data) { return $data; } }
Step 5:
At last create template file file.html in /app/code/Vendor/Module/view/adminhtml/web/template/elements directory and write below code
<input class="admin__control-file" type="file" data-bind=" hasFocus: focused, attr: { name: inputName, placeholder: placeholder, 'aria-describedby': noticeId, id: uid, disabled: disabled, form: formId }" /> <!-- ko if: $parent.source.data.product[code] --> <span> <a attr="href: '/pub/media/catalog/product/file/'+$parent.source.data.product[code]" text="$parent.source.data.product[code]"></a> <label attr="for: uid+'_delete'"> <input type="checkbox" attr="name: 'product['+code + '_delete]', id: uid+'_delete', form: formId"> <span data-bind="i18n:'Delete'"></span> </label> </span> <!-- /ko -->
In this way we can create file type product attribute in magento 2. Thanks.. 🙂
For complete module please find at https://github.com/rani-webkul/product-file-attribute.
What if we want to integrate this into webkul marketplace and allow seller to add files when creating products in their dashboard (using the custom attribute add-on also)?