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:
1 2 3 4 5 6 7 8 | <?php /** * Copyright © All rights reserved. * See COPYING.txt for license details. */ use Magento\Framework\Component\ComponentRegistrar; ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magelearn_CustomImage' , __DIR__); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | { "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" : "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:
1 2 3 4 5 | <? 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
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 <?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
123456789101112131415161718192021222324 <?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <? 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 > < type name = "Magento\Catalog\Model\Category\DataProvider" > < plugin name = "custom_category_data" type = "Magelearn\CustomImage\Plugin\CategoryDataProviderPlugin" /> </ type > < preference for = "Magento\Theme\Block\Html\Topmenu" type = "Magelearn\CustomImage\Block\Html\Topmenu" /> </ config > |
Magelearn/CustomImage/etc/adminhtml
12345678 <?
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 <?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
);
}
}
And now as per the code highlighted in etc/di.xml file, We will Create our Plugin file at Magelearn/CustomImage/Plugin/DataProvider.php file 12345678910111213141516171819202122232425 <?php
namespace
Magelearn\CustomImage\Plugin;
class
CategoryDataProviderPlugin
{
public
function
afterGetData(
\Magento\Catalog\Model\Category\DataProvider
$subject
,
$result
) {
// Modify the data here
if
(isset(
$result
[
'custom_image'
])) {
unset(
$result
[
'custom_image'
]);
}
return
$result
;
}
public
function
afterGetFieldsMap(
\Magento\Catalog\Model\Category\DataProvider
$subject
,
$result
) {
$result
[
'content'
][] =
'custom_image'
;
return
$result
;
}
}
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <? 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 > |
Now Create Block file Image.php file inside
Also Create Helper file Category.php file inside
And finally, Create templete file image.phtml inside
Magelearn/CustomImage/Block
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | <?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 ); } } |
Magelearn/CustomImage/Helper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <?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 ; } } |
Magelearn/CustomImage/view/frontend/templates1234567891011121314151617181920212223242526 <?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
12345678910111213141516171819202122 <?
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/Html123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 <?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"