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>
?>