Magento 2.3.x Newsletter Module Add Extra Field

Magento 2.3.x Newsletter Module Add Extra Field

In this snippet, I will cover how can we add an extra field in the Newsletter module of Magento 2.3.x version.

Step 1: Create a module and rewrite newsletter controller using di.xml preference tag.

<preference for="Magento\Newsletter\Controller\Subscriber\NewAction" type="RLYD\Newsletter\Controller\Subscriber\NewAction"/>

Step 2: Create an install schema file as follows:

<?php

namespace RLYD\Newsletter\Setup;

use Magento\Framework\DB\Ddl\Table;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;

class InstallSchema implements InstallSchemaInterface {
    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) {
        $setup->startSetup();

        $table = $setup->getTable('newsletter_subscriber');

        $setup->getConnection()->addColumn(
            $table,
            'full_name',
            [
                'type' => Table::TYPE_TEXT,
                'nullable' => true,
                'comment' => 'Name',
            ]
        );

        $setup->endSetup();
    }
}

Step 3: Rewrite new controller file as follows:

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

namespace RLYD\Newsletter\Controller\Subscriber;

use Magento\Customer\Api\AccountManagementInterface as CustomerAccountManagement;
use Magento\Customer\Model\Session;
use Magento\Customer\Model\Url as CustomerUrl;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Phrase;
use Magento\Framework\Validator\EmailAddress as EmailValidator;
#use Magento\Newsletter\Controller\Subscriber as SubscriberController;
use Magento\Newsletter\Controller\Subscriber\NewAction as SubscriberNewController;
use Magento\Newsletter\Model\Subscriber;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Newsletter\Model\SubscriberFactory;

/**
 * New newsletter subscription action
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class NewAction extends SubscriberNewController implements HttpPostActionInterface
{
    /**
     * @var CustomerAccountManagement
     */
    protected $customerAccountManagement;

    /**
     * @var EmailValidator
     */
    private $emailValidator;

    /**
     * Initialize dependencies.
     *
     * @param Context $context
     * @param SubscriberFactory $subscriberFactory
     * @param Session $customerSession
     * @param StoreManagerInterface $storeManager
     * @param CustomerUrl $customerUrl
     * @param CustomerAccountManagement $customerAccountManagement
     * @param EmailValidator $emailValidator
     */
    public function __construct(
        Context $context,
        SubscriberFactory $subscriberFactory,
        Session $customerSession,
        StoreManagerInterface $storeManager,
        CustomerUrl $customerUrl,
        CustomerAccountManagement $customerAccountManagement,
        EmailValidator $emailValidator = null
    ) {
        $this->customerAccountManagement = $customerAccountManagement;
        $this->emailValidator = $emailValidator ?: ObjectManager::getInstance()->get(EmailValidator::class);
        parent::__construct(
            $context,
            $subscriberFactory,
            $customerSession,
            $storeManager,
            $customerUrl,
            $customerAccountManagement
        );
    }

    /**
     * Validates that the email address isn't being used by a different account.
     *
     * @param string $email
     * @throws LocalizedException
     * @return void
     */
    protected function validateEmailAvailable($email)
    {
        $websiteId = $this->_storeManager->getStore()->getWebsiteId();
        if ($this->_customerSession->isLoggedIn()
            && ($this->_customerSession->getCustomerDataObject()->getEmail() !== $email
            && !$this->customerAccountManagement->isEmailAvailable($email, $websiteId))
        ) {
            throw new LocalizedException(
                __('This email address is already assigned to another user.')
            );
        }
    }

    /**
     * Validates that if the current user is a guest, that they can subscribe to a newsletter.
     *
     * @throws LocalizedException
     * @return void
     */
    protected function validateGuestSubscription()
    {
        if ($this->_objectManager->get(ScopeConfigInterface::class)
                ->getValue(
                    Subscriber::XML_PATH_ALLOW_GUEST_SUBSCRIBE_FLAG,
                    ScopeInterface::SCOPE_STORE
                ) != 1
            && !$this->_customerSession->isLoggedIn()
        ) {
            throw new LocalizedException(
                __(
                    'Sorry, but the administrator denied subscription for guests. Please <a href="%1">register</a>.',
                    $this->_customerUrl->getRegisterUrl()
                )
            );
        }
    }

    /**
     * Validates the format of the email address
     *
     * @param string $email
     * @throws LocalizedException
     * @return void
     */
    protected function validateEmailFormat($email)
    {
        if (!$this->emailValidator->isValid($email)) {
            throw new LocalizedException(__('Please enter a valid email address.'));
        }
    }

    /**
     * New subscription action
     *
     * @return \Magento\Framework\Controller\Result\Redirect
     */
    public function execute()
    {
        if ($this->getRequest()->isPost() && $this->getRequest()->getPost('email')) {
            $email = (string)$this->getRequest()->getPost('email');
            $name = (string) $this->getRequest()->getPost('full_name');





            //$name = "test";

            try {
                $this->validateEmailFormat($email);
                $this->validateGuestSubscription();
                $this->validateEmailAvailable($email);

                $subscriber = $this->_subscriberFactory->create()->loadByEmail($email);
                if ($subscriber->getId()
                    && (int) $subscriber->getSubscriberStatus() === Subscriber::STATUS_SUBSCRIBED
                ) {
                    throw new LocalizedException(
                        __('This email address is already subscribed.')
                    );
                } else if ($subscriber->getId()
                    && (int) $subscriber->getSubscriberStatus() === 2
                ) {
                    throw new LocalizedException(
                        __('This email address is waiting for approval.')
                    );
                }



                $status = (int)$this->_subscriberFactory->create()->subscribe($email);


                $subscriber1 = $this->_subscriberFactory->create()->loadByEmail($email);                
                $subscriber1->setFullName($name)->save();                

                $this->messageManager->addSuccessMessage($this->getSuccessMessage($status));
            } catch (LocalizedException $e) {
                $this->messageManager->addErrorMessage($e->getMessage());
            } catch (\Exception $e) {                
                $this->messageManager->addExceptionMessage($e, __('Something went wrong with the subscription.'));
            }
        }
        /** @var \Magento\Framework\Controller\Result\Redirect $redirect */
        $redirect = $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT);
        $redirectUrl = $this->_redirect->getRedirectUrl();
        return $redirect->setUrl($redirectUrl);
    }

    /**
     * Get success message
     *
     * @param int $status
     * @return Phrase
     */
    private function getSuccessMessage(int $status): Phrase
    {
        if ($status === Subscriber::STATUS_NOT_ACTIVE) {
            return __('The confirmation request has been sent.');
        }

        return __('Thank you for your subscription.');
    }
}
?>

Step 4: In your theme file add the below code:

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

/** @var \Magento\Newsletter\Block\Subscribe $block */
?>
<div class="block newsletter">
    <div class="title"><strong><?= $block->escapeHtml(__('Newsletter')) ?></strong></div>
    <div class="content">
        <form class="form subscribe"
            novalidate
            action="<?= $block->escapeUrl($block->getFormActionUrl()) ?>"
            method="post"
            data-mage-init='{"validation": {"errorClass": "mage-error"}}'
            id="newsletter-validate-detail">


            <div class="field full_name">
                <label class="label" for="full_name"><span><?php echo $block->escapeHtml(__('Name')) ?></span></label>
                <div class="control">
                  <input name="full_name" type="text" id="full_name"
                         placeholder="<?php echo $block->escapeHtmlAttr(__('Name')) ?>"
                         data-validate="{required:true}"/>
                </div>
              </div>

            <div class="field newsletter">
                <div class="control">
                    <label for="newsletter">
                        <span class="label">
                            <?= $block->escapeHtml(__('Sign Up for Our Newsletter:')) ?>
                        </span>
                        <input name="email" type="email" id="newsletter"
                               placeholder="<?= $block->escapeHtmlAttr(__('Enter your email address')) ?>"
                               data-mage-init='{"mage/trim-input":{}}'
                               data-validate="{required:true, 'validate-email':true}"
                        />
                    </label>
                </div>
            </div>
            <div class="actions">
                <button class="action subscribe primary"
                        title="<?= $block->escapeHtmlAttr(__('Subscribe')) ?>"
                        type="submit"
                        aria-label="Subscribe">
                    <span><?= $block->escapeHtml(__('Subscribe')) ?></span>
                </button>
            </div>
        </form>
    </div>
</div>
?>