Skip to main content
1 of 2
akashmalik
  • 502
  • 3
  • 10

app/design/frontend/VENDER_NAME/YOUR_THEME/Magento_Contact/templates/form.phtml

-> add enctype="multipart/form-data" in form.phtml action

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

/** @var \Magento\Contact\Block\ContactForm $block */
?>
<form class="form contact"
      action="<?= $block->escapeUrl($block->getFormAction()) ?>"
      id="contact-form"
      method="post"
      data-hasrequired="<?= $block->escapeHtmlAttr(__('* Required Fields')) ?>"
      data-mage-init='{"validation":{}}'
      enctype="multipart/form-data">
    <fieldset class="fieldset">
        <legend class="legend"><span><?= $block->escapeHtml(__('Write Us')) ?></span></legend><br />
        <div class="field note no-label"><?= $block->escapeHtml(__('Jot us a note and we’ll get back to you as quickly as possible.')) ?></div>
        <div class="field name required">
            <label class="label" for="name"><span><?= $block->escapeHtml(__('Name')) ?></span></label>
            <div class="control">
                <input name="name" id="name" title="<?= $block->escapeHtmlAttr(__('Name')) ?>" value="<?= $block->escapeHtmlAttr($this->helper(\Magento\Contact\Helper\Data::class)->getPostValue('name') ?: $this->helper(\Magento\Contact\Helper\Data::class)->getUserName()) ?>" class="input-text" type="text" data-validate="{required:true}"/>
            </div>
        </div>
        <div class="field email required">
            <label class="label" for="email"><span><?= $block->escapeHtml(__('Email')) ?></span></label>
            <div class="control">
                <input name="email" id="email" title="<?= $block->escapeHtmlAttr(__('Email')) ?>" value="<?= $block->escapeHtmlAttr($this->helper(\Magento\Contact\Helper\Data::class)->getPostValue('email') ?: $this->helper(\Magento\Contact\Helper\Data::class)->getUserEmail()) ?>" class="input-text" type="email" data-validate="{required:true, 'validate-email':true}"/>
            </div>
        </div>
        <div class="field telephone">
            <label class="label" for="telephone"><span><?= $block->escapeHtml(__('Phone Number')) ?></span></label>
            <div class="control">
                <input name="telephone" id="telephone" title="<?= $block->escapeHtmlAttr(__('Phone Number')) ?>" value="<?= $block->escapeHtmlAttr($this->helper(\Magento\Contact\Helper\Data::class)->getPostValue('telephone')) ?>" class="input-text" type="text" />
            </div>
        </div>
        <div class="field comment required">
            <label class="label" for="comment"><span><?= $block->escapeHtml(__('What’s on your mind?')) ?></span></label>
            <div class="control">
                <textarea name="comment" id="comment" title="<?= $block->escapeHtmlAttr(__('What’s on your mind?')) ?>" class="input-text" cols="5" rows="3" data-validate="{required:true}"><?= $block->escapeHtml($this->helper(\Magento\Contact\Helper\Data::class)->getPostValue('comment')) ?></textarea>
            </div>
        </div>
        <?= $block->getChildHtml('form.additional.info') ?>
    </fieldset>
    <div class="actions-toolbar">
        <div class="primary">
            <input type="hidden" name="hideit" id="hideit" value="" />
            <button type="submit" title="<?= $block->escapeHtmlAttr(__('Submit')) ?>" class="action submit primary">
                <span><?= $block->escapeHtml(__('Submit')) ?></span>
            </button>
        </div>
    </div>
</form>

Vendor/Module/etc/di.xml

<?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
        <preference for="Magento\Contact\Controller\Index\Post" type="Vendor\Module\Rewrite\Magento\Contact\Controller\Index\Post"/>
    </config>

Vendor/Module/etc/email_templates.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Email:etc/email_templates.xsd">
    <template id="contact_email_attachment_email_template" label="Contact Form with Attachment" file="submitted_form.html" type="html" module="Vendor_Module" area="frontend"/>
</config> 

Vendor/Module/etc/frontend/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Contact\Block\ContactForm">
        <plugin name="contactus-attachment-form" type="Vendor\Module\Plugin\AddFieldToContactForm" />
    </type>
</config> 

Vendor/Module/view/frontend/email/submitted_form.html

<!--@subject {{trans "Contact Form with Attachment"}} @-->
<!--@vars {
"var data.comment":"Comment",
"var data.email":"Sender Email",
"var data.name":"Sender Name",
"var data.telephone":"Sender Telephone",
"var data.attachment":"Sender Attachment"
} @-->

{{template config_path="design/email/header_template"}}

<table class="message-details">
    <tr>
        <td><strong>{{trans "Name"}}</strong></td>
        <td>{{var data.name}}</td>
    </tr>
    <tr>
        <td><strong>{{trans "Email"}}</strong></td>
        <td>{{var data.email}}</td>
    </tr>
    <tr>
        <td><strong>{{trans "Phone"}}</strong></td>
        <td>{{var data.telephone}}</td>
    </tr>
    <tr>
        <td><strong>{{trans "Attachment"}}</strong></td>
        <td>{{var data.attachment}}</td>
    </tr>
</table>
<p><strong>{{trans "Message"}}</strong></p>
<p>{{var data.comment}}</p>

{{template config_path="design/email/footer_template"}} 

Vendor/Module/view/frontend/templates/contactus/attachment.phtml

<p style="font-size: 15px;">
    <b>Attachment</b>
    (Upload any relevant file e.g. screenshot of website error)
</p>
<p id="file_error" class="message-error error message" style="display:none;">
    File is too large
</p>
<p class="file">
    File must be less than 2MB and in any of these formats: .png, .jpg, .gif, .jpeg
</p>
<input id="attachment" accept=".png, .jpg, .gif, .jpeg/*" name="attachment" type="file" value="<?= $block->escapeHtmlAttr($this->helper('Magento\Contact\Helper\Data')->getPostValue('attachment')) ?>">

<script type="text/javascript" xml="space">
require(['jquery'], function ($) {
    jQuery(document).ready(function($){
        var uploadField = document.getElementById("attachment");
        uploadField.onchange = function() {
            if(this.files[0].size > 44362048){
               $('#file_error').show();
               this.value = "";
            }else{
                $('#file_error').hide();
            };
        };
    });
});
</script> 

Vendor/Module/Rewrite/Magento/Framework/Mail/Template/TransportBuilder.php

<?php

namespace Vendor\Module\Rewrite\Magento\Framework\Mail\Template;

use Magento\Framework\App\TemplateTypesInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\MailException;
use Magento\Framework\Mail\EmailMessageInterface;
use Magento\Framework\Mail\EmailMessageInterfaceFactory;
use Magento\Framework\Mail\AddressConverter;
use Magento\Framework\Mail\Exception\InvalidArgumentException;
use Magento\Framework\Mail\MessageInterface;
use Magento\Framework\Mail\MessageInterfaceFactory;
use Magento\Framework\Mail\MimeInterface;
use Magento\Framework\Mail\MimeMessageInterfaceFactory;
use Magento\Framework\Mail\MimePartInterfaceFactory;
use Magento\Framework\Mail\Template\FactoryInterface;
use Magento\Framework\Mail\Template\SenderResolverInterface;
use Magento\Framework\Mail\TemplateInterface;
use Magento\Framework\Mail\TransportInterface;
use Magento\Framework\Mail\TransportInterfaceFactory;
use Magento\Framework\ObjectManagerInterface;
use Magento\Framework\Phrase;
use Zend\Mime\Mime;
use Zend\Mime\PartFactory;

class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
{
    protected $templateIdentifier;
    protected $templateModel;
    protected $templateVars;
    protected $templateOptions;
    protected $transport;
    protected $templateFactory;
    protected $objectManager;
    protected $message;
    protected $_senderResolver;
    protected $mailTransportFactory;
    private $messageData = [];
    private $emailMessageInterfaceFactory;
    private $mimeMessageInterfaceFactory;
    private $mimePartInterfaceFactory;
    private $addressConverter;

    protected $attachments = [];

    protected $partFactory;

    public function __construct(
        FactoryInterface $templateFactory,
        MessageInterface $message,
        SenderResolverInterface $senderResolver,
        ObjectManagerInterface $objectManager,
        TransportInterfaceFactory $mailTransportFactory,
        MessageInterfaceFactory $messageFactory = null,
        EmailMessageInterfaceFactory $emailMessageInterfaceFactory = null,
        MimeMessageInterfaceFactory $mimeMessageInterfaceFactory = null,
        MimePartInterfaceFactory $mimePartInterfaceFactory = null,
        AddressConverter $addressConverter = null
    ) {
        $this->templateFactory = $templateFactory;
        $this->objectManager = $objectManager;
        $this->_senderResolver = $senderResolver;
        $this->mailTransportFactory = $mailTransportFactory;
        $this->emailMessageInterfaceFactory = $emailMessageInterfaceFactory ?: $this->objectManager
            ->get(EmailMessageInterfaceFactory::class);
        $this->mimeMessageInterfaceFactory = $mimeMessageInterfaceFactory ?: $this->objectManager
            ->get(MimeMessageInterfaceFactory::class);
        $this->mimePartInterfaceFactory = $mimePartInterfaceFactory ?: $this->objectManager
            ->get(MimePartInterfaceFactory::class);
        $this->addressConverter = $addressConverter ?: $this->objectManager
            ->get(AddressConverter::class);
        $this->partFactory = $objectManager->get(PartFactory::class);
        parent::__construct($templateFactory, $message, $senderResolver, $objectManager, $mailTransportFactory, $messageFactory, $emailMessageInterfaceFactory, $mimeMessageInterfaceFactory,
            $mimePartInterfaceFactory, $addressConverter);
    }

    public function addCc($address, $name = '')
    {
        $this->addAddressByType('cc', $address, $name);

        return $this;
    }
    public function addTo($address, $name = '')
    {
        $this->addAddressByType('to', $address, $name);

        return $this;
    }
    public function addBcc($address)
    {
        $this->addAddressByType('bcc', $address);

        return $this;
    }
    public function setReplyTo($email, $name = null)
    {
        $this->addAddressByType('replyTo', $email, $name);

        return $this;
    }
    public function setFrom($from)
    {
        return $this->setFromByScope($from);
    }
    public function setFromByScope($from, $scopeId = null)
    {
        $result = $this->_senderResolver->resolve($from, $scopeId);
        $this->addAddressByType('from', $result['email'], $result['name']);

        return $this;
    }
    public function setTemplateIdentifier($templateIdentifier)
    {
        $this->templateIdentifier = $templateIdentifier;

        return $this;
    }
    public function setTemplateModel($templateModel)
    {
        $this->templateModel = $templateModel;
        return $this;
    }
    public function setTemplateVars($templateVars)
    {
        $this->templateVars = $templateVars;

        return $this;
    }
    public function setTemplateOptions($templateOptions)
    {
        $this->templateOptions = $templateOptions;

        return $this;
    }
    public function getTransport()
    {
        try {
            $this->prepareMessage();
            $mailTransport = $this->mailTransportFactory->create(['message' => clone $this->message]);
        } finally {
            $this->reset();
        }

        return $mailTransport;
    }
    protected function reset()
    {
        $this->messageData = [];
        $this->templateIdentifier = null;
        $this->templateVars = null;
        $this->templateOptions = null;
        return $this;
    }
    protected function getTemplate()
    {
        return $this->templateFactory->get($this->templateIdentifier, $this->templateModel)
            ->setVars($this->templateVars)
            ->setOptions($this->templateOptions);
    }
    protected function prepareMessage()
    {
        $template = $this->getTemplate();
        $content = $template->processTemplate();
        switch ($template->getType()) {
            case TemplateTypesInterface::TYPE_TEXT:
                $part['type'] = MimeInterface::TYPE_TEXT;
                break;

            case TemplateTypesInterface::TYPE_HTML:
                $part['type'] = MimeInterface::TYPE_HTML;
                break;

            default:
                throw new LocalizedException(
                    new Phrase('Unknown template type')
                );
        }
        $mimePart = $this->mimePartInterfaceFactory->create(['content' => $content]);
        $parts = count($this->attachments) ? array_merge([$mimePart], $this->attachments) : [$mimePart];
        $this->messageData['body'] = $this->mimeMessageInterfaceFactory->create(
            ['parts' => $parts]
        );

        $this->messageData['subject'] = html_entity_decode(
            (string)$template->getSubject(),
            ENT_QUOTES
        );
        $this->message = $this->emailMessageInterfaceFactory->create($this->messageData);

        return $this;
    }

    private function addAddressByType(string $addressType, $email, ?string $name = null): void
    {
        if (is_string($email)) {
            $this->messageData[$addressType][] = $this->addressConverter->convert($email, $name);
            return;
        }
        $convertedAddressArray = $this->addressConverter->convertMany($email);
        if (isset($this->messageData[$addressType])) {
            $this->messageData[$addressType] = array_merge(
                $this->messageData[$addressType],
                $convertedAddressArray
            );
        }
    }

    public function addAttachment(?string $content, ?string $fileName, ?string $fileType)
    {
        $attachmentPart = $this->partFactory->create();
        $attachmentPart->setContent($content)
            ->setType($fileType)
            ->setFileName($fileName)
            ->setDisposition(Mime::DISPOSITION_ATTACHMENT)
            ->setEncoding(Mime::ENCODING_BASE64);
        $this->attachments[] = $attachmentPart;

        return $this;
    }
} 

Vendor/Module/Rewrite/Magento/Contact/Controller/Index/Post.php

<?php

namespace Vendor\Module\Rewrite\Magento\Contact\Controller\Index;

use Vendor\Module\Rewrite\Magento\Framework\Mail\Template\TransportBuilder; //replace vendor module

use Magento\Store\Model\StoreManagerInterface;
use Magento\Contact\Model\ConfigInterface;
use Magento\Contact\Model\MailInterface;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\Area;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\Controller\Result\Redirect;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem;
use Magento\Framework\Translate\Inline\StateInterface;
use Psr\Log\LoggerInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\DataObject;
use Magento\MediaStorage\Model\File\UploaderFactory;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Filesystem\Io\File;

/**
 * Post controller class
 */
class Post extends \Magento\Contact\Controller\Index\Post
{
    const FOLDER_LOCATION = 'contactattachment';

   
    private $dataPersistor;

    private $context;
    private $mail;
    private $logger;
    private $fileUploaderFactory;
    private $fileSystem;
    private $inlineTranslation;
    private $contactsConfig;
    private $transportBuilder;
    private $storeManager;

    public function __construct(
        Context $context,
        MailInterface $mail,
        DataPersistorInterface $dataPersistor,
        LoggerInterface $logger = null,
        UploaderFactory $fileUploaderFactory,
        Filesystem $fileSystem,
        StateInterface $inlineTranslation,
        ConfigInterface $contactsConfig,
        TransportBuilder $transportBuilder,
        StoreManagerInterface $storeManager,
        ScopeConfigInterface $scopeConfig,
        File $file
    ) {
        $this->context = $context;
        $this->mail = $mail;
        $this->dataPersistor = $dataPersistor;
        $this->logger = $logger ?: ObjectManager::getInstance()->get(LoggerInterface::class);
        $this->fileUploaderFactory = $fileUploaderFactory;
        $this->fileSystem = $fileSystem;
        $this->inlineTranslation = $inlineTranslation;
        $this->contactsConfig = $contactsConfig;
        $this->transportBuilder = $transportBuilder;
        $this->storeManager = $storeManager;
        $this->scopeConfig = $scopeConfig;
        $this->file = $file;
        parent::__construct($context, $contactsConfig, $mail, $dataPersistor, $logger);
    }

    public function execute()
    {
        if (!$this->getRequest()->isPost()) {
            return $this->resultRedirectFactory->create()->setPath('*/*/');
        }
        try {
            $this->sendEmail($this->validatedParams());
            $this->messageManager->addSuccessMessage(
                __('Thanks for contacting us with your comments and questions. We\'ll respond to you very soon.')
            );
            $this->dataPersistor->clear('contact_us');
        } catch (LocalizedException $e) {
            $this->messageManager->addErrorMessage($e->getMessage());
            $this->dataPersistor->set('contact_us', $this->getRequest()->getParams());
        } catch (\Exception $e) {
            $this->logger->critical($e);
            $this->messageManager->addErrorMessage(
                __('An error occurred while processing your form. Please try again later.')
            );
            $this->dataPersistor->set('contact_us', $this->getRequest()->getParams());
        }
        return $this->resultRedirectFactory->create()->setPath('contact/index');
    }

    private function sendEmail($post)
    {
        $this->send(
            $post['email'],
            ['data' => new DataObject($post)]
        );
    }

    public function send($replyTo, array $variables)
    {
        $filePath = null;
        $fileName = null;
        $uploaded = false;

        try {
            $fileCheck = $this->fileUploaderFactory->create(['fileId' => 'attachment']);
            $file = $fileCheck->validateFile();
            $attachment = $file['name'] ?? null;
        } catch (\Exception $e) {
            $attachment = null;
        }
        $filesData = $this->getRequest()->getFiles();
        if ($attachment) {
            $upload = $this->fileUploaderFactory->create(['fileId' => 'attachment']);
            $upload->setAllowRenameFiles(true);
            $upload->setFilesDispersion(true);
            $upload->setAllowCreateFolders(true);
            $upload->setAllowedExtensions(['txt', 'jpg', 'jpeg', 'gif', 'png']);

            $path = $this->fileSystem
                ->getDirectoryRead(DirectoryList::MEDIA)
                ->getAbsolutePath(self::FOLDER_LOCATION);
            $result = $upload->save($path);
            $uploaded = self::FOLDER_LOCATION . $upload->getUploadedFilename();
            $filePath = $result['path'] . $result['file'];
            $fileName = $result['name'];
        }

        /** @see \Magento\Contact\Controller\Index\Post::validatedParams() */
        $replyToName = !empty($variables['data']['name']) ? $variables['data']['name'] : null;

        $this->inlineTranslation->suspend();

        $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE;
        $transport = $this->transportBuilder
            ->setTemplateIdentifier($this->contactsConfig->emailTemplate())
            ->setTemplateOptions(
                [
                    'area' => Area::AREA_FRONTEND,
                    'store' => $this->storeManager->getStore()->getId(),
                ]
            )
            ->setTemplateVars($variables)
            ->setFrom($this->contactsConfig->emailSender())
            ->addTo($this->contactsConfig->emailRecipient())
            ->setReplyTo($replyTo, $replyToName)
            ->getTransport();

        if ($uploaded && !empty($filePath) && $this->file->fileExists($filePath)) {
            $mimeType = mime_content_type($filePath);

            $transport = $this->transportBuilder
                ->setTemplateIdentifier($this->contactsConfig->emailTemplate())
                ->setTemplateOptions(
                    [
                        'area' => Area::AREA_FRONTEND,
                        'store' => $this->storeManager->getStore()->getId(),
                    ]
                )
                ->addAttachment($this->file->read($filePath), $fileName, $mimeType)
                ->setTemplateVars($variables)
                ->setFrom($this->contactsConfig->emailSender())
                ->addTo($this->contactsConfig->emailRecipient())
                ->setReplyTo($replyTo, $replyToName)
                ->getTransport();
        }

        $transport->sendMessage();
        $this->inlineTranslation->resume();
    }

    private function validatedParams()
    {
        $request = $this->getRequest();
        // if (trim($request->getParam('hideit')) !== '') {
        //     throw new LocalizedException(__('Error'));
        // }
        return $request->getParams();
    }
} 

Vendor/Module/Plugin/AddFieldToContactForm.php

<?php
namespace Vendor\Module\Plugin;
use Vendor\Module\Block\Attachment as CommentBlock; //replace vendor module*emphasized text*
use Magento\Contact\Block\ContactForm as Subject;
use Magento\Framework\View\Element\Template;


/**
 * Class AddFieldToContactForm
 *
 */
class AddFieldToContactForm
{
    /**
     * @param Subject $subject
     * @param string $html
     *
     * @return string
     */
    public function afterToHtml(Subject $subject, string $html) : string
    {
        $commentBlock = $this->getChildBlock(CommentBlock::class, $subject);
        $commentBlock->setAddress($subject->getAddress());
        $html = $this->appendBlockBeforeFieldsetEnd($html, $commentBlock->toHtml());

        return $html;
    }

    /**
     * @param string $html
     * @param string $childHtml
     *
     * @return string
     */
    private function appendBlockBeforeFieldsetEnd(string $html, string $childHtml) : string
    {
        $pregMatch = '/\<\/fieldset>/';  
        $pregReplace = $childHtml . '\0';
        $html = preg_replace($pregMatch, $pregReplace, $html, 1);

        return $html;
    }

    /**
     * @param string $blockClass
     * @param Template $parentBlock
     *
     * @return mixed
     */
    private function getChildBlock(string $blockClass, Template $parentBlock)
    {
        $blockId = str_replace('\\', '_', $blockClass);
        return $parentBlock->getLayout()->createBlock($blockClass, $blockId);
    }
} 

Vendor/Module/Block/Attachment.php

<?php
namespace Vendor\Module\Block;

use Magento\Framework\View\Element\Template;

/**
 * Class Comment
 *
 */
class Attachment extends Template
{
    /**
     * @var string
     */
    protected $_template = 'contactus/attachment.phtml';
} 
akashmalik
  • 502
  • 3
  • 10