A lot of our users ask how to add a button in Magento 2 backend configuration section and call a simple PHP method when clicking on it.
In fact, that’s quite easy to do.
I’ll describe the solution on the example of our new free Others Also Bought extension for Magento 2, where MageWorx – is a vendor’s name and AlsoBought – is a name of the extension.
First, you need to add a button as a field in the Configuration file (mageworx_collect as an example):
app/code/MageWorx/AlsoBought/etc/adminhtml/system.xml
<?xml version="1.0"?> <!-- /** * Copyright © 2016 MageWorx. All rights reserved. * See LICENSE.txt for license details. */ --> <config xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd"> <system> <tab id="mageworx" sortOrder="2001"> <label>MageWorx</label> </tab> <section id="mageworx_alsobought" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="0"> <label>Also Bought</label> <tab>mageworx</tab> <resource>MageWorx_AlsoBought::config</resource> <group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1"> <label>General</label> <field id="mageworx_collect" translate="label comment" type="button" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0"> <frontend_model>MageWorx\AlsoBought\Block\System\Config\Collect</frontend_model> <label>Collect all available data (in separate table)</label> </field> </group> </section> </system> </config>
To draw this field-button, I use the frontend MageWorx\AlsoBought\Block\System\Config\Collect
model. This is how to create it:
app/code/MageWorx/AlsoBought/Block/System/Config/Collect.php
<?php /** * Copyright © 2016 MageWorx. All rights reserved. * See LICENSE.txt for license details. */ namespace MageWorx\AlsoBought\Block\System\Config; use Magento\Backend\Block\Template\Context; use Magento\Config\Block\System\Config\Form\Field; use Magento\Framework\Data\Form\Element\AbstractElement; class Collect extends Field { /** * @var string */ protected $_template = 'MageWorx_AlsoBought::system/config/collect.phtml'; /** * @param Context $context * @param array $data */ public function __construct( Context $context, array $data = [] ) { parent::__construct($context, $data); } /** * Remove scope label * * @param AbstractElement $element * @return string */ public function render(AbstractElement $element) { $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue(); return parent::render($element); } /** * Return element html * * @param AbstractElement $element * @return string */ protected function _getElementHtml(AbstractElement $element) { return $this->_toHtml(); } /** * Return ajax url for collect button * * @return string */ public function getAjaxUrl() { return $this->getUrl('mageworx_alsobought/system_config/collect'); } /** * Generate collect button html * * @return string */ public function getButtonHtml() { $button = $this->getLayout()->createBlock( 'Magento\Backend\Block\Widget\Button' )->setData( [ 'id' => 'collect_button', 'label' => __('Collect Data'), ] ); return $button->toHtml(); } }
This is a typical field model. The button is drawn using the getButtonHtml()
method.
To get a URL, you need to use the getAjaxUrl()
method.
Next, you will need to create a template:
app/code/MageWorx/AlsoBought/view/adminhtml/templates/system/config/collect.phtml
<?php /** * Copyright © 2016 MageWorx. All rights reserved. * See LICENSE.txt for license details. */ ?> <?php /* @var $block \MageWorx\AlsoBought\Block\System\Config\Collect */ ?> <script> require([ 'jquery', 'prototype' ], function(jQuery){ var collectSpan = jQuery('#collect_span'); jQuery('#collect_button').click(function () { var params = {}; new Ajax.Request('<?php echo $block->getAjaxUrl() ?>', { parameters: params, loaderArea: false, asynchronous: true, onCreate: function() { collectSpan.find('.collected').hide(); collectSpan.find('.processing').show(); jQuery('#collect_message_span').text(''); }, onSuccess: function(response) { collectSpan.find('.processing').hide(); var resultText = ''; if (response.status > 200) { resultText = response.statusText; } else { resultText = 'Success'; collectSpan.find('.collected').show(); } jQuery('#collect_message_span').text(resultText); var json = response.responseJSON; if (typeof json.time != 'undefined') { jQuery('#row_mageworx_alsobought_general_collect_time').find('.value .time').text(json.time); } } }); }); }); </script> <?php echo $block->getButtonHtml() ?> <span class="collect-indicator" id="collect_span"> <img class="processing" hidden="hidden" alt="Collecting" style="margin:0 5px" src="<?php echo $block->getViewFileUrl('images/process_spinner.gif') ?>"/> <img class="collected" hidden="hidden" alt="Collected" style="margin:-3px 5px" src="<?php echo $block->getViewFileUrl('images/rule_component_apply.gif') ?>"/> <span id="collect_message_span"></span> </span>
Note that in this case, you will have to rewrite a part of the code according to your needs. Below is an example of how you can do that.
The AJAX request method onCreate
and onSuccess
should suit your needs. Also, you can remove the <span class="collect-indicator" id="collect_span">
element. We use it to display the loading (spinner) process and the result of the action.
Also, you will need a controller (where all further operations will be processed) and a router.
app/code/MageWorx/AlsoBought/etc/adminhtml/routes.xml
<?xml version="1.0"?> <!-- /** * Copyright © 2016 MageWorx. All rights reserved. * See LICENSE.txt for license details. */ --> <config xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> <router id="admin"> <route id="mageworx_alsobought" frontName="mageworx_alsobought"> <module name="MageWorx_AlsoBought" before="Magento_Backend" /> </route> </router> </config>
app/code/MageWorx/AlsoBought/Controller/Adminhtml/System/Config/Collect.php
<?php /** * Copyright © 2016 MageWorx. All rights reserved. * See LICENSE.txt for license details. */ namespace MageWorx\AlsoBought\Controller\Adminhtml\System\Config; use Magento\Backend\App\Action; use Magento\Backend\App\Action\Context; use Magento\Framework\Controller\Result\JsonFactory; use MageWorx\AlsoBought\Helper\Data; class Collect extends Action { protected $resultJsonFactory; /** * @var Data */ protected $helper; /** * @param Context $context * @param JsonFactory $resultJsonFactory * @param Data $helper */ public function __construct( Context $context, JsonFactory $resultJsonFactory, Data $helper ) { $this->resultJsonFactory = $resultJsonFactory; $this->helper = $helper; parent::__construct($context); } /** * Collect relations data * * @return \Magento\Framework\Controller\Result\Json */ public function execute() { try { $this->_getSyncSingleton()->collectRelations(); } catch (\Exception $e) { $this->_objectManager->get('Psr\Log\LoggerInterface')->critical($e); } $lastCollectTime = $this->helper->getLastCollectTime(); /** @var \Magento\Framework\Controller\Result\Json $result */ $result = $this->resultJsonFactory->create(); return $result->setData(['success' => true, 'time' => $lastCollectTime]); } /** * Return product relation singleton * * @return \MageWorx\AlsoBought\Model\Relation */ protected function _getSyncSingleton() { return $this->_objectManager->get('MageWorx\AlsoBought\Model\Relation'); } protected function _isAllowed() { return $this->_authorization->isAllowed('MageWorx_AlsoBought::config'); } } ?>
That’s basically it.
As I mentioned above, this is a working example from our MageWorx Others Also Bought module for Magento 2. If you want to further explore it, you can download it from here for FREE.
Should you have any questions on the topic, feel free to drop me a line in the comments below.