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": "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>app/code/Magelearn/CustomImage/Setup/Patch/Data<?php
declare(strict_types=1);
namespace Magelearn\CustomImage\Setup\Patch\Data;
use Magento\Catalog\Model\Category;
use Magento\Catalog\Model\Category\Attribute\Backend\Image;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
class CreateCustomImageAttribute implements DataPatchInterface
{
public function __construct(
private readonly ModuleDataSetupInterface $moduleDataSetup,
private readonly EavSetupFactory $eavSetupFactory
) {
}
public function apply(): void
{
/** @var EavSetup $eavSetup */
$eavSetup = $this->eavSetupFactory->create([
'setup' => $this->moduleDataSetup,
]);
$eavSetup->addAttribute(
Category::ENTITY,
'custom_image',
[
'type' => 'varchar',
'label' => 'Custom Image',
'input' => 'image',
'backend' => Image::class,
'required' => false,
'sort_order' => 10,
'global' => ScopedAttributeInterface::SCOPE_STORE,
'group' => 'Content',
]
);
}
public static function getDependencies(): array
{
return [];
}
public function getAliases(): array
{
return [];
}
}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" sortOrder="40" formElement="imageUploader">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="source" xsi:type="string">category</item>
</item>
</argument>
<settings>
<elementTmpl>ui/form/element/uploader/image</elementTmpl>
<dataType>string</dataType>
<label translate="true">Custom Category Image</label>
<visible>true</visible>
<required>false</required>
</settings>
<formElements>
<imageUploader>
<settings>
<required>false</required>
<uploaderConfig>
<param xsi:type="url" name="url" path="catalog/category_image/upload"/>
</uploaderConfig>
<previewTmpl>Magento_Catalog/image-preview</previewTmpl>
<openDialogTitle>Media Gallery</openDialogTitle>
<initialMediaGalleryOpenSubpath>catalog/category</initialMediaGalleryOpenSubpath>
<allowedExtensions>jpg jpeg gif png</allowedExtensions>
<maxFileSize>4194304</maxFileSize>
</settings>
</imageUploader>
</formElements>
</field>
</fieldset>
</form>Create di.xml file inside
Magelearn/CustomImage/etcHere 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">
<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\Theme\Block\Html\Topmenu" type="Magelearn\CustomImage\Block\Html\Topmenu" />
</config>
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="Magento\Framework\View\Element\Template" name="magelearn.custom.image" template="Magelearn_CustomImage::image.phtml">
<arguments>
<argument name="view_model" xsi:type="object">Magelearn\CustomImage\ViewModel\CategoryImage</argument>
<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 view model as well our custom template file.Now Create ViewModel file CategoryImage.php file inside
Magelearn/CustomImage/ViewModel<?php
declare(strict_types=1);
namespace Magelearn\CustomImage\ViewModel;
use Magelearn\CustomImage\Helper\Category as CategoryHelper;
use Magento\Catalog\Helper\Data as CatalogData;
use Magento\Catalog\Model\Category;
use Magento\Framework\View\Element\Block\ArgumentInterface;
class CategoryImage implements ArgumentInterface
{
public function __construct(
private readonly CatalogData $catalogData,
private readonly CategoryHelper $categoryHelper
) {
}
public function getCategory(): ?Category
{
$category = $this->catalogData->getCategory();
return $category instanceof Category ? $category : null;
}
public function getImageUrl(string $imageCode): ?string
{
$category = $this->getCategory();
if (!$category) {
return null;
}
$image = $category->getData($imageCode);
if (!$image) {
return null;
}
return $this->categoryHelper->getImageUrl($image);
1
}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
declare(strict_types=1);
/** @var \Magento\Framework\View\Element\Template $block */
/** @var \Magelearn\CustomImage\ViewModel\CategoryImage $viewModel */
$viewModel = $block->getViewModel();
$category = $viewModel->getCategory();
if (!$category) {
return;
}
$imageCode = (string) $block->getData('image_code');
$imageUrl = $viewModel->getImageUrl($imageCode);
$cssClass = (string) $block->getData('css_class');
if (!$imageUrl) {
return;
}
$categoryName = $block->escapeHtml($category->getName());
?>
<div class="<?= $block->escapeHtmlAttr($cssClass) ?>">
<img
src="<?= $block->escapeUrl($imageUrl) ?>"
alt="<?= $categoryName ?>"
title="<?= $categoryName ?>"
/>
</div>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">
<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\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"