In this tutorial, you will learn how to Creating a new category EAV attribute with image upload button.
Let's start it by creating custom module.
Find Complete Module on Github
Create folder in
app/code/
Magelearn/CustomImageStep 1: Create module registration file
Add registration.php file in it:
<?php /** * Copyright © All rights reserved. * See COPYING.txt for license details. */ use Magento\Framework\Component\ComponentRegistrar; ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magelearn_CustomImage', __DIR__);Add composer.json file in it:
{ "name": "magelearn/module-CustomImage", "description": "Magento2 image attachment in category add/edit admin form and display image on category page", "type": "magento2-module", "license": "OSL-3.0", "authors": [ { "email": "info@mage2gen.com", "name": "Mage2Gen" }, { "email": "vijaymrami@gmail.com", "name": "vijay rami" } ], "minimum-stability": "dev", "require": {}, "autoload": { "files": [ "registration.php" ], "psr-4": { "Magelearn\\CustomImage\\": "" } } }
Add etc/module.xml file in it:
<?xml version="1.0" ?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <module name="Magelearn_CustomImage" setup_version="1.0.0">
</module> </config>
Magelearn/CustomImage/Setup
<?php
namespace Magelearn\CustomImage\Setup;
use Magento\Eav\Setup\EavSetup;
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\ScopedAttributeInterface;
/**
* @codeCoverageIgnore
*/
class InstallData implements InstallDataInterface
{
/**
* EAV setup factory.
*
* @var EavSetupFactory
*/
private $_eavSetupFactory;
protected $categorySetupFactory;
/**
* Init.
*
* @param EavSetupFactory $eavSetupFactory
*/
public function __construct(EavSetupFactory $eavSetupFactory, \Magento\Catalog\Setup\CategorySetupFactory $categorySetupFactory)
{
$this->_eavSetupFactory = $eavSetupFactory;
$this->categorySetupFactory = $categorySetupFactory;
}
/**
* {@inheritdoc}
*
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function install(
ModuleDataSetupInterface $setup,
ModuleContextInterface $context
) {
/** @var EavSetup $eavSetup */
$eavSetup = $this->_eavSetupFactory->create(['setup' => $setup]);
$setup = $this->categorySetupFactory->create(['setup' => $setup]);
$setup->addAttribute(
\Magento\Catalog\Model\Category::ENTITY, 'custom_image', [
'type' => 'varchar',
'label' => 'Custom Image',
'input' => 'image',
'backend' => 'Magento\Catalog\Model\Category\Attribute\Backend\Image',
'visible' => true,
'required' => false,
'sort_order' => 9,
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
'group' => 'General Information'
]
);
}
}
Here we can use Backend option and Input type as Image itself, we can control that later in UI component and di(Dependency Injection).
Create category_form.xml inside Magelearn/CustomImage/view/adminhtml/ui_component
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<fieldset name="content">
<field name="custom_image">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">string</item>
<item name="source" xsi:type="string">category</item>
<item name="label" xsi:type="string" translate="true">Custom Category Image</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="formElement" xsi:type="string">fileUploader</item>
<item name="elementTmpl" xsi:type="string">ui/form/element/uploader/uploader</item>
<item name="previewTmpl" xsi:type="string">Magento_Catalog/image-preview</item>
<item name="required" xsi:type="boolean">false</item>
<item name="sortOrder" xsi:type="number">40</item>
<item name="uploaderConfig" xsi:type="array">
<item name="url" xsi:type="url" path="customimage/category_image/upload"/>
</item>
</item>
</argument>
</field>
</fieldset>
</form>
Create di.xml file inside
Magelearn/CustomImage/etc
Here we can include the file extension types inside allowedExtensions section.
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magelearn\CustomImage\Controller\Adminhtml\Category\Image\Upload">
<arguments>
<argument name="imageUploader" xsi:type="object">Magento\Catalog\CategoryImageUpload</argument>
</arguments>
</type>
<virtualType name="Magento\Catalog\CategoryImageUpload" type="Magento\Catalog\Model\ImageUploader">
<arguments>
<argument name="baseTmpPath" xsi:type="string">catalog/tmp/category</argument>
<argument name="basePath" xsi:type="string">catalog/category</argument>
<argument name="allowedExtensions" xsi:type="array">
<item name="jpg" xsi:type="string">jpg</item>
<item name="jpeg" xsi:type="string">jpeg</item>
<item name="gif" xsi:type="string">gif</item>
<item name="png" xsi:type="string">png</item>
</argument>
</arguments>
</virtualType>
<preference for="Magento\Catalog\Model\Category\DataProvider" type="Magelearn\CustomImage\Model\Category\DataProvider" />
</config>
Create routes.xml file inside Magelearn/CustomImage/etc/adminhtml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="admin">
<route id="customimage" frontName="customimage">
<module name="Magelearn_CustomImage" before="Magento_Backend" />
</route>
</router>
</config>
Create Upload.php file inside
Magelearn/CustomImage/
Controller/Adminhtml/Category/ImageThis is a Controller File Where we need to perform our Custom File Upload action
<?php
namespace Magelearn\CustomImage\Controller\Adminhtml\Category\Image;
use Magento\Framework\Controller\ResultFactory;
/**
* Category Image Upload Controller
*/
class Upload extends \Magento\Backend\App\Action
{
/**
* Image uploader
*
* @var \Magento\Catalog\Model\ImageUploader
*/
protected $imageUploader;
/**
* Uploader factory
*
* @var \Magento\MediaStorage\Model\File\UploaderFactory
*/
private $uploaderFactory;
/**
* Media directory object (writable).
*
* @var \Magento\Framework\Filesystem\Directory\WriteInterface
*/
protected $mediaDirectory;
/**
* Store manager
*
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManager;
/**
* Core file storage database
*
* @var \Magento\MediaStorage\Helper\File\Storage\Database
*/
protected $coreFileStorageDatabase;
/**
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* Upload constructor.
*
* @param \Magento\Backend\App\Action\Context $context
* @param \Magento\Catalog\Model\ImageUploader $imageUploader
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Catalog\Model\ImageUploader $imageUploader,
\Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
\Magento\Framework\Filesystem $filesystem,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase,
\Psr\Log\LoggerInterface $logger
) {
parent::__construct($context);
$this->imageUploader = $imageUploader;
$this->uploaderFactory = $uploaderFactory;
$this->mediaDirectory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA);
$this->storeManager = $storeManager;
$this->coreFileStorageDatabase = $coreFileStorageDatabase;
$this->logger = $logger;
}
/**
* Check admin permissions for this controller
*
* @return boolean
*/
protected function _isAllowed()
{
return $this->_authorization->isAllowed('Magelearn_CustomImage::category');
}
/**
* Upload file controller action
*
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
$imageId = $this->_request->getParam('param_name', 'custom_image');
try {
$result = $this->imageUploader->saveFileToTmpDir($imageId);
$result['cookie'] = [
'name' => $this->_getSession()->getName(),
'value' => $this->_getSession()->getSessionId(),
'lifetime' => $this->_getSession()->getCookieLifetime(),
'path' => $this->_getSession()->getCookiePath(),
'domain' => $this->_getSession()->getCookieDomain(),
];
} catch (\Exception $e) {
$result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
}
return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result);
}
}
Finally, Create DataProvider.php file inside Magelearn/CustomImage/Model/Category<?php
namespace Magelearn\CustomImage\Model\Category;
use Magento\Framework\App\ObjectManager;
use Magento\Catalog\Model\Category\FileInfo;
class DataProvider extends \Magento\Catalog\Model\Category\DataProvider
{
/**
* @var Filesystem
*/
private $fileInfo;
public function getData()
{
$data = parent::getData();
$category = $this->getCurrentCategory();
if ($category) {
$categoryData = $category->getData();
$categoryData = $this->addUseConfigSettings($categoryData);
$categoryData = $this->filterFields($categoryData);
//$categoryData = $this->convertValues($category, $categoryData);
$this->loadedData[$category->getId()] = $categoryData;
}
if (isset($data['custom_image'])) {
unset($data['custom_image']);
}
return $data;
}
protected function getFieldsMap()
{
$fields = parent::getFieldsMap();
$fields['content'][] = 'custom_image'; // custom image field
return $fields;
}
/**
* Get FileInfo instance
*
* @return FileInfo
*
* @deprecated 101.1.0
*/
private function getFileInfo()
{
if ($this->fileInfo === null) {
$this->fileInfo = ObjectManager::getInstance()->get(FileInfo::class);
}
return $this->fileInfo;
}
}
Now, we will check how to display this "custom_image" on Category view page.
Create catalog_category_view.xml file inside Magelearn/CustomImage/view/frontend/layout
<?xml version="1.0"?> <!-- /** * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceContainer name="category.view.container"> <block class="Magelearn\CustomImage\Block\Image" name="magelearn_category_image" template="Magelearn_CustomImage::image.phtml"> <arguments> <argument name="image_code" xsi:type="string">custom_image</argument> <argument name="css_class" xsi:type="string">custom_image</argument> </arguments> </block> </referenceContainer> </body> </page>Here we define our custom Block as well our custom template file.
Now Create Block file Image.php file inside
Magelearn/CustomImage/Block
<?php /** * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * Product description block * * @author Magento Core Team <core@magentocommerce.com> */ namespace Magelearn\CustomImage\Block; use Magento\Catalog\Model\Product; class Image extends \Magento\Framework\View\Element\Template { /** * @var Product */ protected $_category = null; /** * Core registry * * @var \Magento\Framework\Registry */ protected $_coreRegistry = null; /** * @var \SR\CategoryImage\Helper\Category */ protected $_categoryHelper; /** * @param \Magento\Framework\View\Element\Template\Context $context * @param \Magento\Framework\Registry $registry * @param array $data */ public function __construct( \Magento\Framework\View\Element\Template\Context $context, \Magento\Framework\Registry $registry, \Magelearn\CustomImage\Helper\Category $categoryHelper, array $data = [] ) { $this->_coreRegistry = $registry; $this->_categoryHelper = $categoryHelper; parent::__construct($context, $data); } /** * Retrieve current category model object * * @return \Magento\Catalog\Model\Category */ public function getCurrentCategory() { if (!$this->_category) { $this->_category = $this->_coreRegistry->registry('current_category'); if (!$this->_category) { throw new \Magento\Framework\Exception\LocalizedException(__('Category object could not be found in core registry')); } } return $this->_category; } public function getImageUrl() { $imageCode = $this->hasImageCode() ? $this->getImageCode() : 'image'; $image = $this->getCurrentCategory()->getData($imageCode); return $this->_categoryHelper->getImageUrl($image); } }Also Create Helper file Category.php file inside
Magelearn/CustomImage/Helper
<?php namespace Magelearn\CustomImage\Helper; use Magento\Framework\App\Helper\AbstractHelper; class Category extends AbstractHelper { /** * @return array */ public function getAdditionalImageTypes() { return array('custom_image'); } /** * Retrieve image URL * @param $image * @return string */ public function getImageUrl($image) { $url = false; //$image = $this->getImage(); if ($image) { if (is_string($image)) { $url = $this->_urlBuilder->getBaseUrl() . $image; //$url = $image; } else { throw new \Magento\Framework\Exception\LocalizedException( __('Something went wrong while getting the image url.') ); } } return $url; } }And finally, Create templete file image.phtml inside
Magelearn/CustomImage/view/frontend/templates<?php
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
// @codingStandardsIgnoreFile
?>
<?php
/**
* Category image template
*
* @var $block \Magelearn\CustomImage\Block\Image
*/
?>
<?php
$_helper = $this->helper('Magento\Catalog\Helper\Output');
$_category = $block->getCurrentCategory();
$_imgHtml = '';
if ($_imgUrl = $block->getImageUrl()) {
$_imgHtml = '<div class="' . $block->getCssClass() . '"><img src="' . $_imgUrl . '" alt="' . $block->escapeHtml($_category->getName()) . '" title="' . $block->escapeHtml($_category->getName()) . '"/></div>';
$_imgHtml = $_helper->categoryAttribute($_category, $_imgHtml, 'image');
/* @escapeNotVerified */ echo $_imgHtml;
}
?>
This will display on front end as per below:
Now we will check another interesting part of this blog.
Where we will display this custom image on Category Top Menu.
Modify di.xml file inside Magelearn/CustomImage/etc
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magelearn\CustomImage\Controller\Adminhtml\Category\Image\Upload">
<arguments>
<argument name="imageUploader" xsi:type="object">Magento\Catalog\CategoryImageUpload</argument>
</arguments>
</type>
<virtualType name="Magento\Catalog\CategoryImageUpload" type="Magento\Catalog\Model\ImageUploader">
<arguments>
<argument name="baseTmpPath" xsi:type="string">catalog/tmp/category</argument>
<argument name="basePath" xsi:type="string">catalog/category</argument>
<argument name="allowedExtensions" xsi:type="array">
<item name="jpg" xsi:type="string">jpg</item>
<item name="jpeg" xsi:type="string">jpeg</item>
<item name="gif" xsi:type="string">gif</item>
<item name="png" xsi:type="string">png</item>
</argument>
</arguments>
</virtualType>
<preference for="Magento\Catalog\Model\Category\DataProvider" type="Magelearn\CustomImage\Model\Category\DataProvider" />
<preference for="Magento\Theme\Block\Html\Topmenu" type="Magelearn\CustomImage\Block\Html\Topmenu" />
</config>
Create file Topmenu.php inside Magelearn/CustomImage/Block/Html<?php
namespace Magelearn\CustomImage\Block\Html;
use Magento\Framework\Data\Tree\Node;
use Magento\Framework\DataObject;
use Magento\Framework\View\Element\Template;
use Magento\Framework\Data\Tree\NodeFactory;
use Magento\Framework\Data\TreeFactory;
class Topmenu extends \Magento\Theme\Block\Html\Topmenu
{
protected $_categoryFactory;
protected $_storeManager;
public function __construct(
Template\Context $context,
NodeFactory $nodeFactory,
TreeFactory $treeFactory,
\Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $collecionFactory,
\Magento\Store\Model\StoreManagerInterface $storeManager,
array $data = []
) {
parent::__construct($context, $nodeFactory, $treeFactory, $data);
$this->_categoryFactory = $collecionFactory;
$this->_storeManager = $storeManager;
}
protected function _getHtml(
\Magento\Framework\Data\Tree\Node $menuTree,
$childrenWrapClass,
$limit,
array $colBrakes = []
) {
$html = '';
$children = $menuTree->getChildren();
$parentLevel = $menuTree->getLevel();
$childLevel = $parentLevel === null ? 0 : $parentLevel + 1;
$counter = 1;
$itemPosition = 1;
$childrenCount = $children->count();
$parentPositionClass = $menuTree->getPositionClass();
$itemPositionClassPrefix = $parentPositionClass ? $parentPositionClass . '-' : 'nav-';
/** @var \Magento\Framework\Data\Tree\Node $child */
foreach ($children as $child) {
if ($childLevel === 0 && $child->getData('is_parent_active') === false) {
continue;
}
$child->setLevel($childLevel);
$child->setIsFirst($counter == 1);
$child->setIsLast($counter == $childrenCount);
$child->setPositionClass($itemPositionClassPrefix . $counter);
$outermostClassCode = '';
$outermostClass = $menuTree->getOutermostClass();
if ($childLevel == 0 && $outermostClass) {
$outermostClassCode = ' class="' . $outermostClass . '" ';
$currentClass = $child->getClass();
if (empty($currentClass)) {
$child->setClass($outermostClass);
} else {
$child->setClass($currentClass . ' ' . $outermostClass);
}
}
if (is_array($colBrakes) && count($colBrakes) && $colBrakes[$counter]['colbrake']) {
$html .= '</ul></li><li class="column"><ul>';
}
$html .= '<li ' . $this->_getRenderedMenuItemAttributes($child) . '>';
$html .= '<a href="' . $child->getUrl() . '" ' . $outermostClassCode . '><span>' . $this->escapeHtml(
$child->getName()
) . $this->getCustomImage($child) . '</span></a>' . $this->_addSubMenu(
$child,
$childLevel,
$childrenWrapClass,
$limit
) . '</li>';
$itemPosition++;
$counter++;
}
if (is_array($colBrakes) && count($colBrakes) && $limit) {
$html = '<li class="column"><ul>' . $html . '</ul></li>';
}
return $html;
}
public function getCustomImage($childObj)
{
if (!($childObj->getIsCategory() && $childObj->getLevel() == 1)) {
return false;
}
$store = $this->_storeManager->getStore();
$mediaBaseUrl = $store->getBaseUrl();
$catNodeArr = explode('-', $childObj->getId());
$catId = end($catNodeArr);
$collection = $this->_categoryFactory
->create()
->addAttributeToSelect('custom_image')
->addAttributeToFilter('entity_id',['eq'=>$catId])
->setPageSize(1);
if ($collection->getSize() && $collection->getFirstItem()->getCustomImage()) {
$catCustomImageUrl = $mediaBaseUrl
. $collection->getFirstItem()->getCustomImage();
return '<span class="cat-thumbnail"><img src="'.$catCustomImageUrl.'"></span>';
}
}
}
It will display on Category top menu as per below:
Tag :
Magento2,
Magento2 Extensions
0 Comments On "Magento 2 create new category EAV Image attribute with file upload and Display Image on Category page as well as on Category Top Menu"