How to add image upload field to a CMS page and show this on top of my CMS page as Hero image like shown below?
Maybe there are simple solutions/tutorials, but I can't find right one.
-
You can upload image in the CMS and Block and than call this block on the CMS page which you want.mageDev0688– mageDev06882017年03月31日 11:48:57 +00:00Commented Mar 31, 2017 at 11:48
4 Answers 4
First you have to create your own module to override the save action and dataProvider for cms page. If you don't know how to create module Please refer this link http://inchoo.net/magento-2/how-to-create-a-basic-module-in-magento-2/.
After creating a module, follow the following steps:
Step 1. Add column for custom image on cms_page table
Create InstallSchema.php under [Vendor][Module]\Setup. Your file location will be [Vendor][Module]\Setup\InstallSchema.php
namespace [Vendor]\[Module]\Setup;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\DB\Ddl\Table;
class InstallSchema implements InstallSchemaInterface
{
public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
{
$installer = $setup;
$installer->startSetup();
$connection = $installer->getConnection();
$connection->addColumn('cms_page','your_image_field_name',['type' =>\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,'comment' => 'Your Image Field Name']);
$installer->endSetup();
}
}
If your module is already activated, please delete your module from setup_module table.
After Creating InstallSchema.php, open your terminal and hit following commands. It will add column to database table and clear caches.
php bin/magento cache:flush;
php bin/magento setup:upgrade;
php bin/magento setup:di:compile;
rm -rf var/generation/* var/di/* var/cache/* var/page_cache/* ;
rm -rf pub/static/frontend pub/static/_requirejs pub/static/adminhtml ;
Step 2. Add image field
Create cms_page_form.xml inside the folder [Vendor]/[Module]/view/adminhtml/ui_component . Your file location will be like [Vendor]/[Module]/view/adminhtml/ui_component/cms_page_form.xml. Add the following code.
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<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="your_image_field_name">
<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">Your image field Name</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="required" xsi:type="boolean">false</item>
<item name="uploaderConfig" xsi:type="array">
<item name="url" xsi:type="url" path="[module]/cms_heroimage/upload"/>
</item>
</item>
</argument>
</field>
</fieldset>
</form>
This will generate field under content tab.
Step 3. Add a route for upload action.
Create routes.xml under [Vendor]/[Module]/etc/adminhtml. Your file location will be [Vendor]/[Module]/etc/adminhtml/routes.xml.
Add the following code.
<?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="[module]" frontName="[module]">
<module name="[Vendor]_[Module]" />
</route>
</router>
</config>
Step 4. Create Controller for upload action.
Create Upload.php on [Vendor]/[Module]/Controller/Adminhtml/Cms/Heroimage. Your file location will be [Vendor]/[Module]/Controller/Adminhtml/Cms/Heroimage/Upload.php.
Add following code.
namespace [Vendor]\[Module]\Controller\Adminhtml\Cms\Heroimage;
use Magento\Framework\Controller\ResultFactory;
class Upload extends \Magento\Backend\App\Action
{
/**
* Image uploader
*
* @var \[Vendor]\[Module]\Model\ImageUploader
*/
protected $imageUploader;
/**
* @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
) {
parent::__construct($context);
$this->imageUploader = $imageUploader;
}
/**
* Upload file controller action
*
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
try {
$result = $this->imageUploader->saveFileToTmpDir('your_image_field_name');
$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);
}
}
?>
Step 5. Override Save action.
Create di.xml under [Vendor][Module]\etc\adminhtml. Your file location will be [Vendor][Module]\etc\adminhtml\di.xml add following line to override Save Action and DataProvider for cms page.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Cms\Controller\Adminhtml\Page\Save" type="[Vendor]\[Module]\Controller\Adminhtml\Cms\Page\Save" />
<preference for="Magento\Cms\Model\Page\DataProvider" type="[Vendor]\[Module]\Model\Cms\Page\DataProvider" />
</config>
Step 6. Create Save.php file. Create Save.php file under [Vendor][Module]\Controller\Adminhtml\Cms\Page. Your file location will be [Vendor][Module]\Controller\Adminhtml\Cms\Page\Save.php. Add Following code.
namespace [Vendor]\[Module]\Controller\Adminhtml\Cms\Page;
use Magento\Backend\App\Action;
use Magento\Cms\Model\Page;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\Exception\LocalizedException;
class Save extends \Magento\Cms\Controller\Adminhtml\Page\Save
{
/**
* Authorization level of a basic admin session
*
* @see _isAllowed()
*/
const ADMIN_RESOURCE = 'Magento_Cms::save';
/**
* @var PostDataProcessor
*/
protected $dataProcessor;
/**
* @var DataPersistorInterface
*/
protected $dataPersistor;
/**
* Save action
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
$data = $this->getRequest()->getPostValue();
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultRedirectFactory->create();
if ($data) {
$data = $this->dataProcessor->filter($data);
if (isset($data['is_active']) && $data['is_active'] === 'true') {
$data['is_active'] = Page::STATUS_ENABLED;
}
if (empty($data['page_id'])) {
$data['page_id'] = null;
}
/** @var \Magento\Cms\Model\Page $model */
$model = $this->_objectManager->create('Magento\Cms\Model\Page');
$id = $this->getRequest()->getParam('page_id');
if ($id) {
$model->load($id);
}
// Add custom image field to data
if(isset($data['your_image_field_name']) && is_array($data['your_image_field_name'])){
$data['your_image_field_name']=$data['your_image_field_name'][0]['name'];
}
$model->setData($data);
$this->_eventManager->dispatch(
'cms_page_prepare_save',
['page' => $model, 'request' => $this->getRequest()]
);
if (!$this->dataProcessor->validate($data)) {
return $resultRedirect->setPath('*/*/edit', ['page_id' => $model->getId(), '_current' => true]);
}
try {
$model->save();
$this->messageManager->addSuccess(__('You saved the page.'));
$this->dataPersistor->clear('cms_page');
if ($this->getRequest()->getParam('back')) {
return $resultRedirect->setPath('*/*/edit', ['page_id' => $model->getId(), '_current' => true]);
}
return $resultRedirect->setPath('*/*/');
} catch (LocalizedException $e) {
$this->messageManager->addError($e->getMessage());
} catch (\Exception $e) {
$this->messageManager->addException($e, __('Something went wrong while saving the page.'));
}
$this->dataPersistor->set('cms_page', $data);
return $resultRedirect->setPath('*/*/edit', ['page_id' => $this->getRequest()->getParam('page_id')]);
}
return $resultRedirect->setPath('*/*/');
}
}
?>
Step 7. Create DataProvider.php
Create DataProvider.php under [Vendor]\Module\Model\Cms\Page. Your File location will be [Vendor]\Module\Model\Cms\Page\DataProvider.php
<?php
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace [Vendor]\[Module]\Model\Cms\Page;
use Magento\Cms\Model\ResourceModel\Page\CollectionFactory;
use Magento\Framework\App\Request\DataPersistorInterface;
/**
* Class DataProvider
*/
class DataProvider extends \Magento\Cms\Model\Page\DataProvider
{
/**
* Get data
*
* @return array
*/
public function getData()
{
if (isset($this->loadedData)) {
return $this->loadedData;
}
$items = $this->collection->getItems();
/** @var $page \Magento\Cms\Model\Page */
foreach ($items as $page) {
$this->loadedData[$page->getId()] = $page->getData();
}
$data = $this->dataPersistor->get('cms_page');
if (!empty($data)) {
$page = $this->collection->getNewEmptyItem();
$page->setData($data);
$this->loadedData[$page->getId()] = $page->getData();
$this->dataPersistor->clear('cms_page');
}
/* For Modify You custom image field data */
if(!empty($this->loadedData[$page->getId()]['your_image_field_name'])){
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$storeManager = $objectManager->get('Magento\Store\Model\StoreManagerInterface');
$currentStore = $storeManager->getStore();
$media_url=$currentStore->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
$image_name=$this->loadedData[$page->getId()]['your_image_field_name'];
unset($this->loadedData[$page->getId()]['your_image_field_name']);
$this->loadedData[$page->getId()]['your_image_field_name'][0]['name']=$image_name;
$this->loadedData[$page->getId()]['your_image_field_name'][0]['url']=$media_url."cms/hero/tmp/".$image_name;
}
return $this->loadedData;
}
}
Note. Please Replace "your_image_field_name" with your field name.
-
1This is amazing. One thing though, don't put ?> at the end of your files, doing so could mean you accidentally include an extra character which would send headers before Magento does and cause you issues.Matthew Haworth– Matthew Haworth2019年08月06日 12:38:59 +00:00Commented Aug 6, 2019 at 12:38
-
can't upload the image @Nabin MaharjanNaresh Prajapati– Naresh Prajapati2019年12月02日 11:45:36 +00:00Commented Dec 2, 2019 at 11:45
-
@Nabin Thanks for the useful info, how do you print/show this custom fields on front-end?Sam– Sam2020年06月30日 17:35:20 +00:00Commented Jun 30, 2020 at 17:35
I would add to etc/adminhtml/di.xml
<virtualType name="Magento\Catalog\CategoryImageUpload" type="Magento\Catalog\Model\ImageUploader">
<arguments>
<argument name="baseTmpPath" xsi:type="string">your path here</argument>
<argument name="basePath" xsi:type="string">your path here</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="[Vendor]\[Module]\Controller\Adminhtml\Cms\Heroimage\Upload">
<arguments>
<argument name="imageUploader" xsi:type="object">Magento\Catalog\CategoryImageUpload</argument>
</arguments>
</type>
and
replace in DataProvider.php
if(!empty($this->loadedData[$page->getId()]['your_image_field_name']))
to
if (!empty($this->loadedData))
On frontend, as i was getting js error in file-uploader.js:79 Uncaught TypeError: value.map
I used this in DataProvider.php
namespace VENDOR\MODULE\Model\Cms\Page;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Cms\Model\ResourceModel\Page\CollectionFactory;
use Magento\Store\Model\StoreManagerInterface;
class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{
private $loadedData;
/**
* @var \Magento\Framework\App\Request\DataPersistorInterface
*/
private $dataPersistor;
/**
* @var Magento\Cms\Model\ResourceModel\Page\CollectionFactory
*/
public $collection;
/**
* Constructor
*
* @param string $name
* @param string $primaryFieldName
* @param string $requestFieldName
* @param CollectionFactory $blockCollectionFactory
* @param DataPersistorInterface $dataPersistor
* @param array $meta
* @param array $data
*/
public function __construct(
$name,
$primaryFieldName,
$requestFieldName,
CollectionFactory $collectionFactory,
DataPersistorInterface $dataPersistor,
StoreManagerInterface $storeManager,
array $meta = [],
array $data = []
) {
$this->collection = $collectionFactory->create();
$this->dataPersistor = $dataPersistor;
$this->storeManager = $storeManager;
parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
}
/**
* Get data
*
* @return array
*/
public function getData()
{
if (isset($this->loadedData)) {
return $this->loadedData;
}
$items = $this->collection->getItems();
foreach ($items as $model) {
$this->loadedData[$model->getId()] = $model->getData();
// echo $model->getCmsImage();exit();
if ($model->getCmsImage()) {
$m['cms_image'][0]['name'] = $model->getCmsImage();
$m['cms_image'][0]['url'] = $this->getMediaUrl().$model->getCmsImage();
$fullData = $this->loadedData;
$this->loadedData[$model->getId()] = array_merge($fullData[$model->getId()], $m);
}
}
$data = $this->dataPersistor->get('cms_page');
if (!empty($data)) {
$model = $this->collection->getNewEmptyItem();
$model->setData($data);
$this->loadedData[$model->getId()] = $model->getData();
$this->dataPersistor->clear('cms_page');
}
return $this->loadedData;
}
public function getMediaUrl()
{
$mediaUrl = $this->storeManager->getStore()
->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA).'cms/tmp/image/';
return $mediaUrl;
}
}
No need to overwrite Magento\Cms\Controller\Adminhtml\Page\Save
you can use an observer
create file <Venodr>/<ModueName>/etc/adminhtml/events.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="cms_page_prepare_save">
<observer name="custom_observer_cms_page_prepare_save" instance="<Venodr>\<ModueName>\Observer\SaveImageObserver" />
</event>
</config>
then create the observer file <Venodr>/<ModueName>/Observer/SaveImageObserver.php
namespace <Venodr>\<ModueName>\Observer;
class SaveImageObserver implements \Magento\Framework\Event\ObserverInterface
{
public function execute(\Magento\Framework\Event\Observer $observer)
{
$pageModel = $observer->getData('page');
$imageAttributes = ['custom_image'];
$data = $observer->getData('request')->getPostValue();
foreach($imageAttributes as $attributeCode){
if(
isset($data[$attributeCode])
&& is_array($data[$attributeCode])
) {
$pageModel->setData($attributeCode, $data[$attributeCode][0]['name']);
}
}
return $this;
}
}
Explore related questions
See similar questions with these tags.