Skip to main content

Custom Submission Functionality

Let's create observer function for WebForms that dumps submitted result into XML file.

We will be creating new extension called MageMe_WebFormsProcessResult.

File structure

├── etc
│ ├── events.xml
│ └── module.xml
├── Observer
│ └── WebformsResultSaveObserver.php
├── composer.json
└── registration.php


This file holds information for composer script

"name": "mage-me/web-forms-process-result",
"version": "1.0.0",
"description": "N/A",
"type": "magento2-module",
"require": {
"magento/framework": "*",
"mageme/module-webforms": "3.0.*"
"license": [
"autoload": {
"files": [
"psr-4": {
"MageMe\\WebFormsProcessResult\\": ""


This file registers module in the Magento system. The module is not visible without it.


use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'MageMe_WebFormsProcessResult', __DIR__);


This file holds basic description of our module. We need to set the sequence so that the module is loaded after the main WebForms extension.

<?xml version="1.0"?>
<config xmlns:xsi=""
<module name="MageMe_WebFormsProcessResult">
<module name="MageMe_WebForms"/>


This file registers our event handler function.

<?xml version="1.0"?>
<config xmlns:xsi=""
<event name="webforms_result_save">
<observer name="mageme_webformsprocessresult_webforms_result_save"
instance="MageMe\WebFormsProcessResult\Observer\WebformsResultSaveObserver" />


Here we define our model of the event observer class. It has some basic members to work with stores, system messages and logging.


namespace MageMe\WebFormsProcessResult\Observer;

use MageMe\WebForms\Model;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Message\ManagerInterface;
use Magento\Framework\Simplexml\Element;
use Magento\Store\Model\StoreManager;
use Psr\Log\LoggerInterface;

class WebformsResultSaveObserver implements ObserverInterface
/** @var StoreManager */
protected $_storeManager;

/** @var LoggerInterface */
protected $logger;

* @var ManagerInterface
protected $messageManager;

public function __construct(
StoreManager $storeManager,
ManagerInterface $messageManager,
LoggerInterface $logger
$this->_storeManager = $storeManager;
$this->messageManager = $messageManager;
$this->logger = $logger;

* @param Observer $observer
* @return $this
public function execute(Observer $observer)
/** @var Model\Result $result */
$result = $observer->getResult();

/** @var Model\Form $webform */
$webform = $result->getForm();

* Check web-form code
if($webform->getCode() != 'myform') return $this;

$xmlObject = new Element($result->toXml());

// generate unique filename
$mediaFolder = $this->_storeManager->getStore($result->getStoreId())->getBaseMediaDir();
$destinationFolder = $mediaFolder . '/' . 'webforms' . '/' . 'xml';
$filename = $destinationFolder . '/' . $result->getId() . '.xml';

// create folder
if (!(@is_dir($destinationFolder) || @mkdir($destinationFolder, 0755, true))) {
$this->messageManager->addErrorMessage("Unable to create directory '{$destinationFolder}'.");
} else {

// export to file
return $this;

$destinationFolder - variable that sets folder where result is being stored. We will be creating files in pub/media/webforms/xml folder.

$filename - is complete path to the file. For example pub/media/webforms/xml/123.xml.


Make sure pub/media folder is writable.

After the module is ready, please run following console commands:

php bin/magento module:enable MageMe_WebFormsProcessResult
php bin/magento setup:upgrade

Thats it! Feel free to modify this extension, experiment and add required post processing functionality to WebForms.

You can download sources here.