init
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
class AfterMigrationNotice {
|
||||
|
||||
const OPTION_NAME = 'mailpoet_display_after_migration_notice';
|
||||
|
||||
/** @var SettingsController */
|
||||
private $settings;
|
||||
|
||||
public function __construct() {
|
||||
$this->settings = SettingsController::getInstance();
|
||||
}
|
||||
|
||||
public function enable() {
|
||||
$this->settings->set(self::OPTION_NAME, true);
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
$this->settings->set(self::OPTION_NAME, false);
|
||||
}
|
||||
|
||||
public function init($shouldDisplay) {
|
||||
if ($shouldDisplay && $this->settings->get(self::OPTION_NAME, false)) {
|
||||
return $this->display();
|
||||
}
|
||||
}
|
||||
|
||||
private function display() {
|
||||
$message = Helpers::replaceLinkTags(
|
||||
__('Congrats! You’re progressing well so far. Complete your upgrade thanks to this [link]checklist[/link].', 'mailpoet'),
|
||||
'https://kb.mailpoet.com/article/199-checklist-after-migrating-to-mailpoet3',
|
||||
[
|
||||
'target' => '_blank',
|
||||
]
|
||||
);
|
||||
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
$dataNoticeName = self::OPTION_NAME;
|
||||
|
||||
\MailPoet\WP\Notice::displaySuccess($message, $extraClasses, $dataNoticeName);
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Config\ServicesChecker;
|
||||
use MailPoet\Util\License\Features\Subscribers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice as WPNotice;
|
||||
|
||||
class BlackFridayNotice {
|
||||
|
||||
const OPTION_NAME = 'dismissed-black-friday-notice';
|
||||
const DISMISS_NOTICE_TIMEOUT_SECONDS = 2592000; // 30 days
|
||||
const DATE_FROM = '2024-11-27 15:00:00 UTC';
|
||||
const DATE_TO = '2024-12-03 15:00:00 UTC';
|
||||
const PARAM_REF = 'sale-bfcm-2024-plugin';
|
||||
const PARAM_UTM_CAMPAIGN = 'sale_bfcm_2024';
|
||||
|
||||
/** @var ServicesChecker */
|
||||
private $servicesChecker;
|
||||
|
||||
/** @var Subscribers */
|
||||
private $subscribers;
|
||||
|
||||
public function __construct(
|
||||
ServicesChecker $servicesChecker,
|
||||
Subscribers $subscribers
|
||||
) {
|
||||
$this->servicesChecker = $servicesChecker;
|
||||
$this->subscribers = $subscribers;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay) {
|
||||
$shouldDisplay = $shouldDisplay
|
||||
&& !$this->servicesChecker->isBundledSubscription()
|
||||
&& (time() >= strtotime(self::DATE_FROM))
|
||||
&& (time() <= strtotime(self::DATE_TO))
|
||||
&& !get_transient(self::OPTION_NAME);
|
||||
if ($shouldDisplay) {
|
||||
$this->display();
|
||||
}
|
||||
}
|
||||
|
||||
private function display() {
|
||||
$header = '<h3 class="mailpoet-h3">' . __('Save 40% on all MailPoet annual plans and upgrades', 'mailpoet') . '</h3>';
|
||||
$body = '<h5 class="mailpoet-h5">' . __('For a limited time, save 40% when you switch to (or upgrade) an annual plan — no coupon needed. Offer ends at 3 pm UTC, December 3, 2024.', 'mailpoet') . '</h5>';
|
||||
$link = "<p><a href='" . $this->getSaleUrl() . "' class='mailpoet-button button-primary' target='_blank'>"
|
||||
// translators: a button on a sale banner
|
||||
. __('Pick a plan and save big', 'mailpoet')
|
||||
. '</a></p>';
|
||||
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
WPNotice::displaySuccess($header . $body . $link, $extraClasses, self::OPTION_NAME, false);
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
WPFunctions::get()->setTransient(self::OPTION_NAME, true, self::DISMISS_NOTICE_TIMEOUT_SECONDS);
|
||||
}
|
||||
|
||||
private function getSaleUrl(): string {
|
||||
$params = 'ref=' . self::PARAM_REF . '&utm_source=plugin&utm_medium=banner&utm_campaign=' . self::PARAM_UTM_CAMPAIGN;
|
||||
$partialApiKey = $this->servicesChecker->generatePartialApiKey();
|
||||
if ($partialApiKey) {
|
||||
return 'https://account.mailpoet.com/orders/upgrade/' . $partialApiKey . '?' . $params;
|
||||
}
|
||||
return 'https://account.mailpoet.com/?s=' . $this->subscribers->getSubscribersCount() . '&' . $params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class ChangedTrackingNotice {
|
||||
const OPTION_NAME = 'mailpoet-changed-tracking-settings-notice';
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay) {
|
||||
if ($shouldDisplay && $this->wp->getTransient(self::OPTION_NAME)) {
|
||||
return $this->display();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function display() {
|
||||
$text = __('Email open and click tracking is now enabled. You can change how MailPoet tracks your subscribers in [link]Settings[/link]', 'mailpoet');
|
||||
$text = Helpers::replaceLinkTags($text, 'admin.php?page=mailpoet-settings#advanced');
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
return Notice::displayWarning($text, $extraClasses, self::OPTION_NAME);
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
$this->wp->deleteTransient(self::OPTION_NAME);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Config\Env;
|
||||
use MailPoet\Doctrine\WPDB\Connection;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
use MailPoetVendor\Doctrine\ORM\EntityManager;
|
||||
|
||||
class DatabaseEngineNotice {
|
||||
const OPTION_NAME = 'database-engine-notice';
|
||||
const DISMISS_NOTICE_TIMEOUT_SECONDS = 15_552_000; // 6 months
|
||||
const CACHE_TIMEOUT_SECONDS = 86_400; // 1 day
|
||||
const MAX_TABLES_TO_DISPLAY = 2;
|
||||
|
||||
private WPFunctions $wp;
|
||||
|
||||
private EntityManager $entityManager;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp,
|
||||
EntityManager $entityManager
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay): ?Notice {
|
||||
if (!$shouldDisplay || Connection::isSQLite() || $this->wp->getTransient(self::OPTION_NAME)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$tablesWithIncorrectEngine = $this->checkTableEngines();
|
||||
if ($tablesWithIncorrectEngine === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->display($tablesWithIncorrectEngine);
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of table names that are not using the InnoDB engine.
|
||||
*/
|
||||
private function checkTableEngines(): array {
|
||||
$cacheKey = self::OPTION_NAME . '-cache';
|
||||
$cachedTables = $this->wp->getTransient($cacheKey);
|
||||
if (is_array($cachedTables)) {
|
||||
return $cachedTables;
|
||||
}
|
||||
|
||||
$tables = $this->loadTablesWithIncorrectEngines();
|
||||
|
||||
$this->wp->setTransient($cacheKey, $tables, self::CACHE_TIMEOUT_SECONDS);
|
||||
return $tables;
|
||||
}
|
||||
|
||||
private function loadTablesWithIncorrectEngines(): array {
|
||||
$data = $this->entityManager->getConnection()->executeQuery(
|
||||
'SHOW TABLE STATUS WHERE Name LIKE :prefix',
|
||||
[
|
||||
'prefix' => Env::$dbPrefix . '_%',
|
||||
]
|
||||
)->fetchAllAssociative();
|
||||
|
||||
return array_map(
|
||||
fn($row) => $row['Name'],
|
||||
array_filter(
|
||||
$data,
|
||||
fn($row) => isset($row['Engine']) && is_string($row['Engine']) && (strtolower($row['Engine']) !== 'innodb')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function display(array $tablesWithIncorrectEngine): Notice {
|
||||
// translators: %s is the list of the table names
|
||||
$errorString = __('Some of the MailPoet plugin’s tables are not using the InnoDB engine (%s). This may cause performance and compatibility issues. Please ensure all MailPoet tables are converted to use the InnoDB engine. For more information, check out [link]this guide[/link].', 'mailpoet');
|
||||
$tables = $this->formatTableNames($tablesWithIncorrectEngine);
|
||||
$errorString = sprintf($errorString, $tables);
|
||||
$error = Helpers::replaceLinkTags($errorString, 'https://kb.mailpoet.com/article/200-solving-database-connection-issues#database-configuration', [
|
||||
'target' => '_blank',
|
||||
]);
|
||||
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
return Notice::displayWarning($error, $extraClasses, self::OPTION_NAME);
|
||||
}
|
||||
|
||||
private function formatTableNames(array $tablesWithIncorrectEngine): string {
|
||||
sort($tablesWithIncorrectEngine);
|
||||
|
||||
$tables = array_map(
|
||||
fn($table) => "“{$table}”",
|
||||
array_slice($tablesWithIncorrectEngine, 0, self::MAX_TABLES_TO_DISPLAY)
|
||||
);
|
||||
|
||||
$remainingTablesCount = count($tablesWithIncorrectEngine) - count($tables);
|
||||
if ($remainingTablesCount > 0) {
|
||||
// translators: %d is the number of remaining tables, the whole string will be: "table1, table2 and 3 more"
|
||||
$tables[] = sprintf(__('and %d more', 'mailpoet'), $remainingTablesCount);
|
||||
}
|
||||
|
||||
return implode(', ', $tables);
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
$this->wp->setTransient(self::OPTION_NAME, true, self::DISMISS_NOTICE_TIMEOUT_SECONDS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
/**
|
||||
* This can be removed after 2022-12-01
|
||||
*/
|
||||
class DeprecatedFilterNotice {
|
||||
const DISMISS_NOTICE_TIMEOUT_SECONDS = 15552000; // 6 months
|
||||
const OPTION_NAME = 'dismissed-deprecated-filter-notice';
|
||||
|
||||
const DEPRECATED_FILTER_NAME = 'mailpoet_mailer_smtp_transport_agent';
|
||||
const NEW_FILTER_NAME = 'mailpoet_mailer_smtp_options';
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay): ?Notice {
|
||||
if ($shouldDisplay && !$this->wp->getTransient(self::OPTION_NAME) && $this->wp->hasFilter('mailpoet_mailer_smtp_transport_agent')) {
|
||||
return $this->display();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function display(): Notice {
|
||||
$message = Helpers::replaceLinkTags(
|
||||
__('The <i>mailpoet_mailer_smtp_transport_agent</i> filter no longer works. Please replace it with <i>mailpoet_mailer_smtp_options</i>. Read more in [link]documentation[/link].', 'mailpoet'),
|
||||
'https://kb.mailpoet.com/article/193-tls-encryption-does-not-work',
|
||||
['target' => '_blank']
|
||||
);
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
return Notice::displayWarning($message, $extraClasses, self::OPTION_NAME);
|
||||
}
|
||||
|
||||
public function disable(): void {
|
||||
$this->wp->setTransient(self::OPTION_NAME, true, self::DISMISS_NOTICE_TIMEOUT_SECONDS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Cron\Workers\SendingQueue\Tasks\Shortcodes;
|
||||
use MailPoet\Doctrine\WPDB\Connection;
|
||||
use MailPoet\Mailer\Mailer;
|
||||
use MailPoet\Mailer\MailerFactory;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class DisabledMailFunctionNotice {
|
||||
|
||||
const DISABLED_MAIL_FUNCTION_CHECK = 'disabled_mail_function_check';
|
||||
|
||||
const QUEUE_DISABLED_MAIL_FUNCTION_CHECK = 'queue_disabled_mail_function_check';
|
||||
|
||||
/** @var SettingsController */
|
||||
private $settings;
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
/** @var SubscribersFeature */
|
||||
private $subscribersFeature;
|
||||
|
||||
/** @var MailerFactory */
|
||||
private $mailerFactory;
|
||||
|
||||
private $isInQueueForChecking = false;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp,
|
||||
SettingsController $settings,
|
||||
SubscribersFeature $subscribersFeature,
|
||||
MailerFactory $mailerFactory
|
||||
) {
|
||||
$this->settings = $settings;
|
||||
$this->wp = $wp;
|
||||
$this->subscribersFeature = $subscribersFeature;
|
||||
$this->mailerFactory = $mailerFactory;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay): ?string {
|
||||
$shouldDisplay = $shouldDisplay && !Connection::isSQLite() && $this->shouldCheckMisconfiguredFunction() && $this->checkRequirements();
|
||||
if (!$shouldDisplay) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->display();
|
||||
}
|
||||
|
||||
private function checkRequirements(): bool {
|
||||
if ($this->isInQueueForChecking) {
|
||||
$this->settings->set(self::QUEUE_DISABLED_MAIL_FUNCTION_CHECK, false);
|
||||
}
|
||||
|
||||
$sendingMethod = $this->settings->get('mta.method', SettingsController::DEFAULT_SENDING_METHOD);
|
||||
$isPhpMailSendingMethod = $sendingMethod === Mailer::METHOD_PHPMAIL;
|
||||
|
||||
if (!$isPhpMailSendingMethod) {
|
||||
return false; // fails requirements check
|
||||
}
|
||||
|
||||
$functionName = 'mail';
|
||||
$isMailFunctionDisabled = $this->isFunctionDisabled($functionName);
|
||||
|
||||
if ($isMailFunctionDisabled) {
|
||||
$this->settings->set(DisabledMailFunctionNotice::DISABLED_MAIL_FUNCTION_CHECK, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
$isMailFunctionProperlyConfigured = $this->testMailFunctionIsCorrectlyConfigured();
|
||||
|
||||
return !$isMailFunctionProperlyConfigured;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check MisConfigured Function
|
||||
*
|
||||
* This method will cause this class to only display the notice if the settings option
|
||||
*
|
||||
* disabled_mail_function_check === true
|
||||
* or
|
||||
* queue_disabled_mail_function_check === true
|
||||
* or
|
||||
* Totally disabled when wp filter `mailpoet_display_disabled_mail_function_notice` === false
|
||||
*
|
||||
*/
|
||||
public function shouldCheckMisconfiguredFunction(): bool {
|
||||
$shouldCheck = $this->wp->applyFilters('mailpoet_display_disabled_mail_function_notice', true);
|
||||
$this->isInQueueForChecking = $this->settings->get(self::QUEUE_DISABLED_MAIL_FUNCTION_CHECK, false);
|
||||
|
||||
return $shouldCheck && (
|
||||
$this->settings->get(self::DISABLED_MAIL_FUNCTION_CHECK, false) ||
|
||||
$this->isInQueueForChecking
|
||||
);
|
||||
}
|
||||
|
||||
public function isFunctionDisabled(string $function): bool {
|
||||
$result = function_exists($function) && is_callable($function, false);
|
||||
return !$result;
|
||||
}
|
||||
|
||||
private function display(): string {
|
||||
$header = $this->getHeader();
|
||||
|
||||
$body = $this->getBody();
|
||||
|
||||
$button = $this->getConnectMailPoetButton();
|
||||
|
||||
$message = $header . $body . $button;
|
||||
|
||||
Notice::displayWarning($message, '', self::DISABLED_MAIL_FUNCTION_CHECK, false);
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
private function getHeader(): string {
|
||||
return '<h4>' . __('Get ready to send your first campaign.', 'mailpoet') . '</h4>';
|
||||
}
|
||||
|
||||
private function getBody(): string {
|
||||
$bodyText = __('Connect your website with MailPoet, and start sending for free. Reach inboxes, not spam boxes. [link]Why am I seeing this?[/link]', 'mailpoet');
|
||||
|
||||
$bodyWithReplacedLink = Helpers::replaceLinkTags($bodyText, 'https://kb.mailpoet.com/article/396-disabled-mail-function', [
|
||||
'target' => '_blank',
|
||||
]);
|
||||
|
||||
return '<p>' . $bodyWithReplacedLink . '</p>';
|
||||
}
|
||||
|
||||
private function getConnectMailPoetButton(): string {
|
||||
$subscribersCount = $this->subscribersFeature->getSubscribersCount();
|
||||
$buttonLink = "https://account.mailpoet.com/?s={$subscribersCount}&utm_source=mailpoet&utm_medium=plugin&utm_campaign=disabled_mail_function";
|
||||
$link = $this->wp->escAttr($buttonLink);
|
||||
return '<p><a target="_blank" href="' . $link . '" class="button button-primary">' . __('Connect MailPoet', 'mailpoet') . '</a></p>';
|
||||
}
|
||||
|
||||
/*
|
||||
* Test Mail Function Is Correctly Configured
|
||||
*
|
||||
* This is a workaround for detecting the user PHP mail() function is Correctly Configured and not disabled by the host
|
||||
*/
|
||||
private function testMailFunctionIsCorrectlyConfigured(): bool {
|
||||
if ($this->settings->get(DisabledMailFunctionNotice::DISABLED_MAIL_FUNCTION_CHECK, false)) {
|
||||
return false; // skip sending mail again
|
||||
}
|
||||
|
||||
$replyToAddress = $this->settings->get('reply_to.address');
|
||||
$senderAddress = $this->settings->get('sender.address');
|
||||
|
||||
$mailBody = "Hi there! \n
|
||||
|
||||
Your website ([site:homepage_link]) sent you this email to confirm that it can send emails.
|
||||
If you're reading this email, then it works! You can now continue sending marketing emails with MailPoet! \n
|
||||
|
||||
MailPoet on [site:homepage_link]";
|
||||
|
||||
$body = Shortcodes::process($mailBody, null, null, null, null);
|
||||
|
||||
$sendTestMailData = [
|
||||
'mailer' => $this->settings->get('mta'),
|
||||
'newsletter' => [
|
||||
'subject' => 'MailPoet can deliver your marketing emails!',
|
||||
'body' => [
|
||||
'html' => nl2br($body),
|
||||
'text' => $body,
|
||||
],
|
||||
],
|
||||
'subscriber' => empty($replyToAddress) ? $senderAddress : $replyToAddress,
|
||||
];
|
||||
|
||||
$sendMailResult = $this->sendTestMail($sendTestMailData);
|
||||
|
||||
if (!$sendMailResult) {
|
||||
// Error with PHP mail() function
|
||||
// keep displaying notice
|
||||
$this->settings->set(DisabledMailFunctionNotice::DISABLED_MAIL_FUNCTION_CHECK, true);
|
||||
}
|
||||
|
||||
return $sendMailResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send Test Mail
|
||||
* used to check for valid PHP mail()
|
||||
*
|
||||
* returns true if valid and okay
|
||||
* else returns false if invalid.
|
||||
*
|
||||
* We determine the mail function is invalid by checking against the Exception error thrown by PHPMailer
|
||||
* error message: Could not instantiate mail function.
|
||||
*
|
||||
* if the error is not equal to error message, we consider it okay.
|
||||
*/
|
||||
public function sendTestMail($data = []): bool {
|
||||
try {
|
||||
$mailer = $this->mailerFactory->buildMailer(
|
||||
$data['mailer'] ?? null,
|
||||
$data['sender'] ?? null,
|
||||
$data['reply_to'] ?? null
|
||||
);
|
||||
// report this as 'sending_test' in metadata since this endpoint is only used to test sending methods for now
|
||||
$extraParams = [
|
||||
'meta' => [
|
||||
'email_type' => 'sending_test',
|
||||
'subscriber_status' => 'unknown',
|
||||
'subscriber_source' => 'administrator',
|
||||
],
|
||||
];
|
||||
$result = $mailer->send($data['newsletter'], $data['subscriber'], $extraParams);
|
||||
|
||||
if ($result['response'] === false) {
|
||||
$errorMessage = $result['error']->getMessage();
|
||||
return !$this->checkForErrorMessage($errorMessage);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$errorMessage = $e->getMessage();
|
||||
return !$this->checkForErrorMessage($errorMessage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkForErrorMessage($errorMessage): bool {
|
||||
$phpmailerError = 'Could not instantiate mail function';
|
||||
$substringIndex = stripos($errorMessage, $phpmailerError);
|
||||
|
||||
return $substringIndex !== false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Cron\CronHelper;
|
||||
use MailPoet\Cron\CronTrigger;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class DisabledWPCronNotice {
|
||||
|
||||
const DISMISS_NOTICE_TIMEOUT_SECONDS = YEAR_IN_SECONDS;
|
||||
const OPTION_NAME = 'dismissed-wp-cron-disabled-notice';
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
/** @var CronHelper */
|
||||
private $cronHelper;
|
||||
|
||||
/** @var SettingsController */
|
||||
private $settings;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp,
|
||||
CronHelper $cronHelper,
|
||||
SettingsController $settings
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
$this->cronHelper = $cronHelper;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay) {
|
||||
if (!$shouldDisplay) {
|
||||
return null;
|
||||
}
|
||||
$isDismissed = $this->wp->getTransient(self::OPTION_NAME);
|
||||
$currentMethod = $this->settings->get(CronTrigger::SETTING_CURRENT_METHOD);
|
||||
$isWPCronMethodActive = $currentMethod === CronTrigger::METHOD_ACTION_SCHEDULER;
|
||||
$isCronFunctional = $this->isCronFunctional();
|
||||
if (!$isDismissed && $isWPCronMethodActive && $this->isWPCronDisabled() && !$isCronFunctional) {
|
||||
return $this->display();
|
||||
}
|
||||
}
|
||||
|
||||
public function isWPCronDisabled() {
|
||||
return defined('DISABLE_WP_CRON') && DISABLE_WP_CRON;
|
||||
}
|
||||
|
||||
public function isCronFunctional(): bool {
|
||||
// If a cron run was started/completed less than an hour ago, we consider it functional.
|
||||
$lastRunThreshold = time() - HOUR_IN_SECONDS;
|
||||
return ($this->cronHelper->getDaemon()['run_started_at'] ?? 0) > $lastRunThreshold
|
||||
|| ($this->cronHelper->getDaemon()['run_completed_at'] ?? 0) > $lastRunThreshold;
|
||||
}
|
||||
|
||||
public function display() {
|
||||
$errorString = __('WordPress built-in cron is disabled with the DISABLE_WP_CRON constant on your website, this prevents MailPoet sending from working. Please enable WordPress built-in cron or choose a different cron method in MailPoet Settings.', 'mailpoet');
|
||||
|
||||
$buttonString = __('[link]Go to Settings[/link]', 'mailpoet');
|
||||
$error = $errorString . '<br><br>' . Helpers::replaceLinkTags($buttonString, 'admin.php?page=mailpoet-settings#advanced', [
|
||||
'class' => 'button-primary',
|
||||
]);
|
||||
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
return Notice::displayError($error, $extraClasses, self::OPTION_NAME, true, false);
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
$this->wp->setTransient(self::OPTION_NAME, true, self::DISMISS_NOTICE_TIMEOUT_SECONDS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Cron\Workers\SendingQueue\SendingQueue;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class EmailWithInvalidSegmentNotice {
|
||||
const OPTION_NAME = SendingQueue::EMAIL_WITH_INVALID_SEGMENT_OPTION;
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay) {
|
||||
if (!$shouldDisplay || !$this->wp->getTransient(self::OPTION_NAME)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->display($this->wp->getTransient(self::OPTION_NAME));
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
$this->wp->deleteTransient(self::OPTION_NAME);
|
||||
}
|
||||
|
||||
private function display($newsletterSubject) {
|
||||
$notice = sprintf(
|
||||
// translators: %s is the subject of the newsletter.
|
||||
__('You are sending “%s“ to the deleted list. To continue sending, please restore the list. Alternatively, delete the newsletter if you no longer want to keep sending it.', 'mailpoet'),
|
||||
$this->wp->escHtml($newsletterSubject)
|
||||
);
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
Notice::displayError($notice, $extraClasses, self::OPTION_NAME, true);
|
||||
return $notice;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Captcha\CaptchaConstants;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Settings\TrackingConfig;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class HeadersAlreadySentNotice {
|
||||
|
||||
const DISMISS_NOTICE_TIMEOUT_SECONDS = YEAR_IN_SECONDS;
|
||||
const OPTION_NAME = 'dismissed-headers-already-sent-notice';
|
||||
|
||||
/** @var SettingsController */
|
||||
private $settings;
|
||||
|
||||
/** @var TrackingConfig */
|
||||
private $trackingConfig;
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
SettingsController $settings,
|
||||
TrackingConfig $trackingConfig,
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->settings = $settings;
|
||||
$this->trackingConfig = $trackingConfig;
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay) {
|
||||
if (!$shouldDisplay) {
|
||||
return null;
|
||||
}
|
||||
$captchaEnabled = $this->settings->get('captcha.type') === CaptchaConstants::TYPE_BUILTIN;
|
||||
$trackingEnabled = $this->trackingConfig->isEmailTrackingEnabled();
|
||||
if ($this->areHeadersAlreadySent()) {
|
||||
return $this->display($captchaEnabled, $trackingEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
public function areHeadersAlreadySent() {
|
||||
return !get_transient(self::OPTION_NAME)
|
||||
&& ($this->headersSent() || $this->isWhitespaceInBuffer());
|
||||
}
|
||||
|
||||
protected function headersSent() {
|
||||
return headers_sent();
|
||||
}
|
||||
|
||||
public function isWhitespaceInBuffer() {
|
||||
$content = ob_get_contents();
|
||||
if (!$content) {
|
||||
return false;
|
||||
}
|
||||
return preg_match('/^\s+$/', $content);
|
||||
}
|
||||
|
||||
public function display($captchaEnabled, $trackingEnabled) {
|
||||
if (!$captchaEnabled && !$trackingEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$errorString = __('It looks like there\'s an issue with some of the PHP files on your website which is preventing MailPoet from functioning correctly. If not resolved, you may experience:', 'mailpoet');
|
||||
$errorStringTracking = __('Inaccurate tracking of email opens and clicks', 'mailpoet');
|
||||
$errorStringCaptcha = __('CAPTCHA not rendering correctly', 'mailpoet');
|
||||
$errorString = $errorString . '<br>'
|
||||
. ($trackingEnabled ? ('<br> - ' . $errorStringTracking) : '')
|
||||
. ($captchaEnabled ? ('<br> - ' . $errorStringCaptcha) : '');
|
||||
|
||||
$howToResolveString = __('[link]Learn how to fix this issue and restore functionality[/link]', 'mailpoet');
|
||||
$error = $errorString . '<br><br>' . Helpers::replaceLinkTags($howToResolveString, 'https://kb.mailpoet.com/article/325-the-captcha-image-doesnt-show-up', [
|
||||
'target' => '_blank',
|
||||
'class' => 'button-primary',
|
||||
]);
|
||||
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
return Notice::displayError($error, $extraClasses, self::OPTION_NAME, true, false);
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
$this->wp->setTransient(self::OPTION_NAME, true, self::DISMISS_NOTICE_TIMEOUT_SECONDS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Subscribers\SubscribersRepository;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class InactiveSubscribersNotice {
|
||||
const OPTION_NAME = 'inactive-subscribers-notice';
|
||||
const MIN_INACTIVE_SUBSCRIBERS_COUNT = 50;
|
||||
|
||||
/** @var SettingsController */
|
||||
private $settings;
|
||||
|
||||
/** @var SubscribersRepository */
|
||||
private $subscribersRepository;
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
SettingsController $settings,
|
||||
SubscribersRepository $subscribersRepository,
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->settings = $settings;
|
||||
$this->wp = $wp;
|
||||
$this->subscribersRepository = $subscribersRepository;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay) {
|
||||
if (!$shouldDisplay || !$this->settings->get(self::OPTION_NAME, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// don't display notice if user has changed the default inactive time range
|
||||
$inactiveDays = (int)$this->settings->get('deactivate_subscriber_after_inactive_days');
|
||||
if ($inactiveDays !== SettingsController::DEFAULT_DEACTIVATE_SUBSCRIBER_AFTER_INACTIVE_DAYS) {
|
||||
return;
|
||||
}
|
||||
|
||||
$inactiveSubscribersCount = $this->subscribersRepository->countBy(['deletedAt' => null, 'status' => SubscriberEntity::STATUS_INACTIVE]);
|
||||
if ($inactiveSubscribersCount < self::MIN_INACTIVE_SUBSCRIBERS_COUNT) {
|
||||
return;
|
||||
}
|
||||
return $this->display($inactiveSubscribersCount);
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
$this->settings->set(self::OPTION_NAME, false);
|
||||
}
|
||||
|
||||
private function display($inactiveSubscribersCount) {
|
||||
$goToSettingsString = __('Go to the Advanced Settings', 'mailpoet');
|
||||
|
||||
$notice = sprintf(
|
||||
// translators: %d is the number of inactive subscribers.
|
||||
__('Good news! MailPoet won’t send emails to your %s inactive subscribers. This is a standard practice to maintain good deliverability and open rates. But if you want to disable it, you can do so in settings. [link]Read more.[/link]', 'mailpoet'),
|
||||
$this->wp->numberFormatI18n($inactiveSubscribersCount)
|
||||
);
|
||||
$notice = Helpers::replaceLinkTags($notice, 'https://kb.mailpoet.com/article/264-inactive-subscribers', [
|
||||
'target' => '_blank',
|
||||
]);
|
||||
$notice = "<p>$notice</p>";
|
||||
$notice .= '<p><a href="admin.php?page=mailpoet-settings#advanced" class="button button-primary">' . $goToSettingsString . '</a></p>';
|
||||
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
Notice::displaySuccess($notice, $extraClasses, self::OPTION_NAME, false);
|
||||
return $notice;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class PHPVersionWarnings {
|
||||
|
||||
const DISMISS_NOTICE_TIMEOUT_SECONDS = 2592000; // 30 days
|
||||
const OPTION_NAME = 'dismissed-php-version-outdated-notice';
|
||||
|
||||
public function init($phpVersion, $shouldDisplay) {
|
||||
if ($shouldDisplay && $this->isOutdatedPHPVersion($phpVersion)) {
|
||||
return $this->display($phpVersion);
|
||||
}
|
||||
}
|
||||
|
||||
public function isOutdatedPHPVersion($phpVersion) {
|
||||
return version_compare($phpVersion, '8.0', '<') && !get_transient(self::OPTION_NAME);
|
||||
}
|
||||
|
||||
public function display($phpVersion) {
|
||||
// translators: %s is the PHP version
|
||||
$errorString = __('Your website is running an outdated version of PHP (%1$s), on which MailPoet might stop working in the future. We recommend upgrading to %2$s or greater. Read our [link]simple PHP upgrade guide.[/link]', 'mailpoet');
|
||||
$errorString = sprintf($errorString, $phpVersion, '8.1');
|
||||
$error = Helpers::replaceLinkTags($errorString, 'https://kb.mailpoet.com/article/251-upgrading-the-websites-php-version', [
|
||||
'target' => '_blank',
|
||||
]);
|
||||
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
return Notice::displayWarning($error, $extraClasses, self::OPTION_NAME);
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
WPFunctions::get()->setTransient(self::OPTION_NAME, true, self::DISMISS_NOTICE_TIMEOUT_SECONDS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Mailer\Mailer;
|
||||
use MailPoet\Services\Bridge;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Notice as WPNotice;
|
||||
|
||||
class PendingApprovalNotice {
|
||||
|
||||
const OPTION_NAME = 'mailpoet-pending-approval-notice';
|
||||
|
||||
/** @var SettingsController */
|
||||
private $settings;
|
||||
|
||||
public function __construct(
|
||||
SettingsController $settings
|
||||
) {
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay): ?string {
|
||||
// We should display the notice if the user is using MSS and the subscription is not approved
|
||||
if (
|
||||
$shouldDisplay
|
||||
&& $this->settings->get('mta.method') === Mailer::METHOD_MAILPOET
|
||||
&& $this->settings->get('mta.mailpoet_api_key_state')
|
||||
&& $this->settings->get('mta.mailpoet_api_key_state.state', null) === Bridge::KEY_VALID
|
||||
&& !$this->settings->get('mta.mailpoet_api_key_state.data.is_approved', false)
|
||||
) {
|
||||
return $this->display();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPendingApprovalTitle(): string {
|
||||
$message = __("MailPoet is [link]reviewing your subscription[/link].", 'mailpoet');
|
||||
return Helpers::replaceLinkTags(
|
||||
$message,
|
||||
'https://kb.mailpoet.com/article/379-our-approval-process',
|
||||
[
|
||||
'target' => '_blank',
|
||||
'rel' => 'noreferrer',
|
||||
],
|
||||
'link'
|
||||
);
|
||||
}
|
||||
|
||||
public function getPendingApprovalBody(): string {
|
||||
// translators: %s is the email subject, which will always be in English
|
||||
$message = sprintf(__("You can use all MailPoet features and send [link1]email previews[/link1] to your [link2]authorized email addresses[/link2], but sending to your email list contacts is temporarily paused until we review your subscription. If you don't hear from us within 48 hours, please check the inbox and spam folders of your MailPoet account email for follow-up emails with the subject \"%s\" and reply, or [link3]contact us[/link3].", 'mailpoet'), 'Your MailPoet Subscription Review');
|
||||
$message = Helpers::replaceLinkTags(
|
||||
$message,
|
||||
'https://kb.mailpoet.com/article/290-check-your-newsletter-before-sending-it',
|
||||
[
|
||||
'target' => '_blank',
|
||||
'rel' => 'noreferrer',
|
||||
],
|
||||
'link1'
|
||||
);
|
||||
$message = Helpers::replaceLinkTags(
|
||||
$message,
|
||||
'https://kb.mailpoet.com/article/266-how-to-add-an-authorized-email-address-as-the-from-address#how-to-authorize-an-email-address',
|
||||
[
|
||||
'target' => '_blank',
|
||||
'rel' => 'noreferrer',
|
||||
],
|
||||
'link2'
|
||||
);
|
||||
$message = Helpers::replaceLinkTags(
|
||||
$message,
|
||||
'https://www.mailpoet.com/support/',
|
||||
[
|
||||
'target' => '_blank',
|
||||
'rel' => 'noreferrer',
|
||||
],
|
||||
'link3'
|
||||
);
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function getPendingApprovalMessage(): string {
|
||||
return sprintf('%s %s', $this->getPendingApprovalTitle(), $this->getPendingApprovalBody());
|
||||
}
|
||||
|
||||
private function display(): string {
|
||||
$message = $this->getPendingApprovalMessage();
|
||||
WPNotice::displayWarning($message, '', self::OPTION_NAME);
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Config\Menu;
|
||||
use MailPoet\Config\ServicesChecker;
|
||||
use MailPoet\Cron\CronHelper;
|
||||
use MailPoet\Mailer\MailerFactory;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Settings\TrackingConfig;
|
||||
use MailPoet\Subscribers\SubscribersRepository;
|
||||
use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoetVendor\Doctrine\ORM\EntityManager;
|
||||
|
||||
class PermanentNotices {
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
/** @var PHPVersionWarnings */
|
||||
private $phpVersionWarnings;
|
||||
|
||||
/** @var AfterMigrationNotice */
|
||||
private $afterMigrationNotice;
|
||||
|
||||
/** @var UnauthorizedEmailNotice */
|
||||
private $unauthorizedEmailsNotice;
|
||||
|
||||
/** @var UnauthorizedEmailInNewslettersNotice */
|
||||
private $unauthorizedEmailsInNewslettersNotice;
|
||||
|
||||
/** @var InactiveSubscribersNotice */
|
||||
private $inactiveSubscribersNotice;
|
||||
|
||||
/** @var BlackFridayNotice */
|
||||
private $blackFridayNotice;
|
||||
|
||||
/** @var HeadersAlreadySentNotice */
|
||||
private $headersAlreadySentNotice;
|
||||
|
||||
/** @var EmailWithInvalidSegmentNotice */
|
||||
private $emailWithInvalidListNotice;
|
||||
|
||||
/** @var ChangedTrackingNotice */
|
||||
private $changedTrackingNotice;
|
||||
|
||||
/** @var DeprecatedFilterNotice */
|
||||
private $deprecatedFilterNotice;
|
||||
|
||||
/** @var DisabledMailFunctionNotice */
|
||||
private $disabledMailFunctionNotice;
|
||||
|
||||
/** @var DisabledWPCronNotice */
|
||||
private $disabledWPCronNotice;
|
||||
|
||||
/** @var PendingApprovalNotice */
|
||||
private $pendingApprovalNotice;
|
||||
|
||||
/** @var WooCommerceVersionWarning */
|
||||
private $woocommerceVersionWarning;
|
||||
|
||||
/** @var PremiumFeaturesAvailableNotice */
|
||||
private $premiumFeaturesAvailableNotice;
|
||||
|
||||
/** @var SenderDomainAuthenticationNotices */
|
||||
private $senderDomainAuthenticationNotices;
|
||||
|
||||
/** @var WordPressPlaygroundNotice */
|
||||
private $wordPressPlaygroundNotice;
|
||||
|
||||
/** @var DatabaseEngineNotice */
|
||||
private $databaseEngineNotice;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp,
|
||||
CronHelper $cronHelper,
|
||||
EntityManager $entityManager,
|
||||
TrackingConfig $trackingConfig,
|
||||
SubscribersRepository $subscribersRepository,
|
||||
SettingsController $settings,
|
||||
SubscribersFeature $subscribersFeature,
|
||||
ServicesChecker $serviceChecker,
|
||||
MailerFactory $mailerFactory,
|
||||
SenderDomainAuthenticationNotices $senderDomainAuthenticationNotices
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
$this->phpVersionWarnings = new PHPVersionWarnings();
|
||||
$this->afterMigrationNotice = new AfterMigrationNotice();
|
||||
$this->unauthorizedEmailsNotice = new UnauthorizedEmailNotice($wp, $settings);
|
||||
$this->unauthorizedEmailsInNewslettersNotice = new UnauthorizedEmailInNewslettersNotice($settings, $wp);
|
||||
$this->inactiveSubscribersNotice = new InactiveSubscribersNotice($settings, $subscribersRepository, $wp);
|
||||
$this->blackFridayNotice = new BlackFridayNotice($serviceChecker, $subscribersFeature);
|
||||
$this->headersAlreadySentNotice = new HeadersAlreadySentNotice($settings, $trackingConfig, $wp);
|
||||
$this->emailWithInvalidListNotice = new EmailWithInvalidSegmentNotice($wp);
|
||||
$this->changedTrackingNotice = new ChangedTrackingNotice($wp);
|
||||
$this->deprecatedFilterNotice = new DeprecatedFilterNotice($wp);
|
||||
$this->disabledMailFunctionNotice = new DisabledMailFunctionNotice($wp, $settings, $subscribersFeature, $mailerFactory);
|
||||
$this->disabledWPCronNotice = new DisabledWPCronNotice($wp, $cronHelper, $settings);
|
||||
$this->pendingApprovalNotice = new PendingApprovalNotice($settings);
|
||||
$this->woocommerceVersionWarning = new WooCommerceVersionWarning($wp);
|
||||
$this->premiumFeaturesAvailableNotice = new PremiumFeaturesAvailableNotice($subscribersFeature, $serviceChecker, $wp);
|
||||
$this->databaseEngineNotice = new DatabaseEngineNotice($wp, $entityManager);
|
||||
$this->wordPressPlaygroundNotice = new WordPressPlaygroundNotice();
|
||||
$this->senderDomainAuthenticationNotices = $senderDomainAuthenticationNotices;
|
||||
}
|
||||
|
||||
public function init() {
|
||||
$excludeSetupWizard = [
|
||||
'mailpoet-welcome-wizard',
|
||||
'mailpoet-woocommerce-setup',
|
||||
'mailpoet-landingpage',
|
||||
];
|
||||
$this->wp->addAction('wp_ajax_dismissed_notice_handler', [
|
||||
$this,
|
||||
'ajaxDismissNoticeHandler',
|
||||
]);
|
||||
|
||||
$this->phpVersionWarnings->init(
|
||||
phpversion(),
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->afterMigrationNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->unauthorizedEmailsNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->unauthorizedEmailsInNewslettersNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->inactiveSubscribersNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->blackFridayNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->headersAlreadySentNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->emailWithInvalidListNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->changedTrackingNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->deprecatedFilterNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->disabledMailFunctionNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->disabledWPCronNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->pendingApprovalNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->woocommerceVersionWarning->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->premiumFeaturesAvailableNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->databaseEngineNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$this->wordPressPlaygroundNotice->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeSetupWizard)
|
||||
);
|
||||
$excludeDomainAuthenticationNotices = [
|
||||
'mailpoet-settings',
|
||||
'mailpoet-newsletter-editor',
|
||||
...$excludeSetupWizard,
|
||||
];
|
||||
$this->senderDomainAuthenticationNotices->init(
|
||||
Menu::isOnMailPoetAdminPage($excludeDomainAuthenticationNotices)
|
||||
);
|
||||
}
|
||||
|
||||
public function ajaxDismissNoticeHandler() {
|
||||
if (!isset($_POST['type'])) return;
|
||||
switch ($_POST['type']) {
|
||||
case (PHPVersionWarnings::OPTION_NAME):
|
||||
$this->phpVersionWarnings->disable();
|
||||
break;
|
||||
case (AfterMigrationNotice::OPTION_NAME):
|
||||
$this->afterMigrationNotice->disable();
|
||||
break;
|
||||
case (BlackFridayNotice::OPTION_NAME):
|
||||
$this->blackFridayNotice->disable();
|
||||
break;
|
||||
case (HeadersAlreadySentNotice::OPTION_NAME):
|
||||
$this->headersAlreadySentNotice->disable();
|
||||
break;
|
||||
case (InactiveSubscribersNotice::OPTION_NAME):
|
||||
$this->inactiveSubscribersNotice->disable();
|
||||
break;
|
||||
case (EmailWithInvalidSegmentNotice::OPTION_NAME):
|
||||
$this->emailWithInvalidListNotice->disable();
|
||||
break;
|
||||
case (ChangedTrackingNotice::OPTION_NAME):
|
||||
$this->changedTrackingNotice->disable();
|
||||
break;
|
||||
case (DisabledWPCronNotice::OPTION_NAME):
|
||||
$this->disabledWPCronNotice->disable();
|
||||
break;
|
||||
case (DeprecatedFilterNotice::OPTION_NAME):
|
||||
$this->deprecatedFilterNotice->disable();
|
||||
break;
|
||||
case (WooCommerceVersionWarning::OPTION_NAME):
|
||||
$this->woocommerceVersionWarning->disable();
|
||||
break;
|
||||
case (DatabaseEngineNotice::OPTION_NAME):
|
||||
$this->databaseEngineNotice->disable();
|
||||
break;
|
||||
case (PremiumFeaturesAvailableNotice::OPTION_NAME):
|
||||
$this->premiumFeaturesAvailableNotice->disable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Config\Installer;
|
||||
use MailPoet\Config\ServicesChecker;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class PremiumFeaturesAvailableNotice {
|
||||
|
||||
/** @var SubscribersFeature */
|
||||
private $subscribersFeature;
|
||||
|
||||
/** @var ServicesChecker */
|
||||
private $servicesChecker;
|
||||
|
||||
/** @var Installer */
|
||||
private $premiumInstaller;
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
const DISMISS_NOTICE_TIMEOUT_SECONDS = 2592000; // 30 days
|
||||
const OPTION_NAME = 'dismissed-premium-features-available-notice';
|
||||
|
||||
public function __construct(
|
||||
SubscribersFeature $subscribersFeature,
|
||||
ServicesChecker $servicesChecker,
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->subscribersFeature = $subscribersFeature;
|
||||
$this->servicesChecker = $servicesChecker;
|
||||
$this->premiumInstaller = new Installer(Installer::PREMIUM_PLUGIN_PATH);
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay): ?Notice {
|
||||
if (
|
||||
$shouldDisplay
|
||||
&& !$this->wp->getTransient(self::OPTION_NAME)
|
||||
&& $this->subscribersFeature->hasValidPremiumKey()
|
||||
&& (!Installer::isPluginInstalled(Installer::PREMIUM_PLUGIN_SLUG) || !$this->servicesChecker->isPremiumPluginActive())
|
||||
) {
|
||||
return $this->display();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function display(): Notice {
|
||||
$noticeString = __('Your current MailPoet plan includes advanced features, but they require the MailPoet Premium plugin to be installed and activated.', 'mailpoet');
|
||||
|
||||
// We reuse already existing translations from premium_messages.tsx
|
||||
if (!Installer::isPluginInstalled(Installer::PREMIUM_PLUGIN_SLUG)) {
|
||||
$noticeString .= ' [link]' . __('Download MailPoet Premium plugin', 'mailpoet') . '[/link]';
|
||||
$link = $this->premiumInstaller->generatePluginDownloadUrl();
|
||||
$attributes = ['target' => '_blank']; // Only download link should be opened in a new tab
|
||||
} else {
|
||||
$noticeString .= ' [link]' . __('Activate MailPoet Premium plugin', 'mailpoet') . '[/link]';
|
||||
$link = $this->premiumInstaller->generatePluginActivationUrl(Installer::PREMIUM_PLUGIN_PATH);
|
||||
$attributes = [];
|
||||
}
|
||||
|
||||
$noticeString = Helpers::replaceLinkTags($noticeString, $link, $attributes);
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
return Notice::displaySuccess($noticeString, $extraClasses, self::OPTION_NAME);
|
||||
}
|
||||
|
||||
public function disable(): void {
|
||||
WPFunctions::get()->setTransient(self::OPTION_NAME, true, self::DISMISS_NOTICE_TIMEOUT_SECONDS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Services\AuthorizedSenderDomainController;
|
||||
use MailPoet\Services\Bridge;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Util\FreeDomains;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\Util\License\Features\Subscribers;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class SenderDomainAuthenticationNotices {
|
||||
const FREE_MAIL_KB_URL = 'https://kb.mailpoet.com/article/259-your-from-address-cannot-be-yahoo-com-gmail-com-outlook-com';
|
||||
const SPF_DKIM_DMARC_KB_URL = 'https://kb.mailpoet.com/article/295-spf-dkim-dmarc';
|
||||
|
||||
private SettingsController $settingsController;
|
||||
|
||||
private Subscribers $subscribersFeatures;
|
||||
|
||||
private FreeDomains $freeDomains;
|
||||
|
||||
private AuthorizedSenderDomainController $authorizedSenderDomainController;
|
||||
|
||||
private Bridge $bridge;
|
||||
|
||||
public function __construct(
|
||||
SettingsController $settingsController,
|
||||
Subscribers $subscribersFeatures,
|
||||
FreeDomains $freeDomains,
|
||||
AuthorizedSenderDomainController $authorizedEmailsController,
|
||||
Bridge $bridge
|
||||
) {
|
||||
$this->settingsController = $settingsController;
|
||||
$this->subscribersFeatures = $subscribersFeatures;
|
||||
$this->freeDomains = $freeDomains;
|
||||
$this->authorizedSenderDomainController = $authorizedEmailsController;
|
||||
$this->bridge = $bridge;
|
||||
}
|
||||
|
||||
public function getDefaultFromAddress(): string {
|
||||
return $this->settingsController->get('sender.address', '');
|
||||
}
|
||||
|
||||
public function getDefaultFromDomain(): string {
|
||||
return Helpers::extractEmailDomain($this->getDefaultFromAddress());
|
||||
}
|
||||
|
||||
public function isFreeMailUser(): bool {
|
||||
return $this->freeDomains->isEmailOnFreeDomain($this->getDefaultFromDomain());
|
||||
}
|
||||
|
||||
public function init($shouldDisplay): ?Notice {
|
||||
if (
|
||||
!$shouldDisplay
|
||||
|| !$this->bridge->isMailpoetSendingServiceEnabled()
|
||||
|| in_array($this->getDefaultFromDomain(), $this->authorizedSenderDomainController->getFullyVerifiedSenderDomains(true))
|
||||
|| $this->authorizedSenderDomainController->isNewUser()
|
||||
|| $this->isFreeMailUser() && $this->subscribersFeatures->getSubscribersCount() <= AuthorizedSenderDomainController::LOWER_LIMIT
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->display();
|
||||
}
|
||||
|
||||
public function display(): Notice {
|
||||
$contactCount = $this->subscribersFeatures->getSubscribersCount();
|
||||
$isFreeMailUser = $this->isFreeMailUser();
|
||||
|
||||
$noticeContent = $isFreeMailUser
|
||||
? $this->getNoticeContentForFreeMailUsers($contactCount)
|
||||
: $this->getNoticeContentForBrandedDomainUsers($this->isPartiallyVerified(), $contactCount);
|
||||
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
if ($this->isErrorStyle()) {
|
||||
return Notice::displayError($noticeContent, $extraClasses, '', true, false);
|
||||
}
|
||||
|
||||
return Notice::displayWarning($noticeContent, $extraClasses);
|
||||
}
|
||||
|
||||
public function isErrorStyle(): bool {
|
||||
if (
|
||||
$this->subscribersFeatures->getSubscribersCount() < AuthorizedSenderDomainController::UPPER_LIMIT
|
||||
|| $this->isPartiallyVerified()
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isPartiallyVerified(): bool {
|
||||
return in_array($this->getDefaultFromDomain(), $this->authorizedSenderDomainController->getPartiallyVerifiedSenderDomains(true));
|
||||
}
|
||||
|
||||
public function getNoticeContentForFreeMailUsers(int $contactCount): string {
|
||||
if ($contactCount <= AuthorizedSenderDomainController::UPPER_LIMIT) {
|
||||
// translators: %1$s is the domain of the user's default from address, %2$s is a rewritten version of their default from address, %3$s is HTML for an 'update sender' button, and %4$s is HTML for a Learn More button
|
||||
return sprintf(
|
||||
__("<strong>Update your sender email address to a branded domain to continue sending your campaigns.</strong>
|
||||
<span>MailPoet can no longer send from email addresses on shared 3rd party domains like <strong>%1\$s</strong>. Please change your campaigns to send from an email address on your site's branded domain. Your existing scheduled and active emails will temporarily be sent from <strong>%2\$s</strong>.</span> <p>%3\$s %4\$s</p>", 'mailpoet'),
|
||||
"@" . $this->getDefaultFromDomain(),
|
||||
$this->authorizedSenderDomainController->getRewrittenEmailAddress($this->getDefaultFromAddress()),
|
||||
$this->getUpdateSenderButton(),
|
||||
$this->getLearnMoreAboutFreeMailButton()
|
||||
);
|
||||
}
|
||||
|
||||
// translators: %1$s is the domain of the user's default from address, %2$s is a rewritten version of their default from address, %3$s is HTML for an 'update sender' button, and %4$s is HTML for a Learn More button
|
||||
return sprintf(
|
||||
__("<strong>Your newsletters and post notifications have been paused. Update your sender email address to a branded domain to continue sending your campaigns.</strong>
|
||||
<span>MailPoet can no longer send from email addresses on shared 3rd party domains like <strong>%1\$s</strong>. Please change your campaigns to send from an email address on your site's branded domain. Your marketing automations and transactional emails will temporarily be sent from <strong>%2\$s</strong>.</span> <p>%3\$s %4\$s</p>", 'mailpoet'),
|
||||
"@" . $this->getDefaultFromDomain(),
|
||||
$this->authorizedSenderDomainController->getRewrittenEmailAddress($this->getDefaultFromAddress()),
|
||||
$this->getUpdateSenderButton(),
|
||||
$this->getLearnMoreAboutFreeMailButton()
|
||||
);
|
||||
}
|
||||
|
||||
public function getNoticeContentForBrandedDomainUsers(bool $isPartiallyVerified, int $contactCount): string {
|
||||
if ($isPartiallyVerified || $contactCount <= AuthorizedSenderDomainController::LOWER_LIMIT) {
|
||||
// translators: %1$s is HTML for an 'authenticate domain' button, %2$s is HTML for a Learn More button
|
||||
return sprintf(
|
||||
__("<strong>Authenticate your sender domain to improve email delivery rates.</strong>
|
||||
<span>Major mailbox providers require you to authenticate your sender domain to confirm you sent the emails, and may place unauthenticated emails in the “Spam” folder. Please authenticate your sender domain to ensure your marketing campaigns are compliant and will reach your contacts.</span><p>%1\$s %2\$s</p>", 'mailpoet'),
|
||||
$this->getAuthenticateDomainButton(),
|
||||
$this->getLearnMoreAboutSpfDkimDmarcButton()
|
||||
);
|
||||
}
|
||||
|
||||
if ($contactCount <= AuthorizedSenderDomainController::UPPER_LIMIT) {
|
||||
// translators: %1$s is a rewritten version of the user's default from address, %2$s is HTML for an 'authenticate domain' button, %3$s is HTML for a Learn More button
|
||||
return sprintf(
|
||||
__("<strong>Authenticate your sender domain to send new emails.</strong>
|
||||
<span>Major mailbox providers require you to authenticate your sender domain to confirm you sent the emails, and may place unauthenticated emails in the “Spam” folder. Please authenticate your sender domain to ensure your marketing campaigns are compliant and will reach your contacts. Your existing scheduled and active emails will temporarily be sent from <strong>%1\$s</strong>.</span> <p>%2\$s %3\$s</p>", 'mailpoet'),
|
||||
$this->authorizedSenderDomainController->getRewrittenEmailAddress($this->getDefaultFromAddress()),
|
||||
$this->getAuthenticateDomainButton(),
|
||||
$this->getLearnMoreAboutSpfDkimDmarcButton()
|
||||
);
|
||||
}
|
||||
|
||||
// translators: %1$s is a rewritten version of the user's default from address, %2$s is HTML for an 'authenticate domain' button, %3$s is HTML for a Learn More button
|
||||
return sprintf(
|
||||
__("<strong>Your newsletters and post notifications have been paused. Authenticate your sender domain to continue sending.</strong>
|
||||
<span>Major mailbox providers require you to authenticate your sender domain to confirm you sent the emails, and may place unauthenticated emails in the “Spam” folder. Please authenticate your sender domain to ensure your marketing campaigns are compliant and will reach your contacts. Your marketing automations and transactional emails will temporarily be sent from <strong>%1\$s</strong>.</span> <p>%2\$s %3\$s</p>", 'mailpoet'),
|
||||
$this->authorizedSenderDomainController->getRewrittenEmailAddress($this->getDefaultFromAddress()),
|
||||
$this->getAuthenticateDomainButton(),
|
||||
$this->getLearnMoreAboutSpfDkimDmarcButton()
|
||||
);
|
||||
}
|
||||
|
||||
public function getUpdateSenderButton(): string {
|
||||
$buttonClass = $this->subscribersFeatures->getSubscribersCount() > AuthorizedSenderDomainController::UPPER_LIMIT
|
||||
? 'button-primary'
|
||||
: 'button-secondary';
|
||||
$button = sprintf('<a href="admin.php?page=mailpoet-settings" class="button %1$s">%2$s</a>', $buttonClass, __('Update sender email', 'mailpoet'));
|
||||
return $button;
|
||||
}
|
||||
|
||||
public function getLearnMoreAboutFreeMailButton(): string {
|
||||
$button = '<a href="' . self::FREE_MAIL_KB_URL . '" rel="noopener noreferer" target="_blank" class="button button-link">' . __('Learn more', 'mailpoet') . '</a>';
|
||||
return $button;
|
||||
}
|
||||
|
||||
public function getLearnMoreAboutSpfDkimDmarcButton(): string {
|
||||
$button = '<a href="' . self::SPF_DKIM_DMARC_KB_URL . '" rel="noopener noreferer" target="_blank" class="button button-link">' . __('Learn more', 'mailpoet') . '</a>';
|
||||
return $button;
|
||||
}
|
||||
|
||||
public function getAuthenticateDomainButton() {
|
||||
$buttonClass = $this->isErrorStyle()
|
||||
? 'button-primary'
|
||||
: 'button-secondary';
|
||||
$button = sprintf(
|
||||
'<a href="#" class="button %s mailpoet-js-button-authorize-email-and-sender-domain" data-email="%s" data-type="domain">%s</a>',
|
||||
$buttonClass,
|
||||
esc_attr($this->getDefaultFromAddress()),
|
||||
__('Authenticate domain', 'mailpoet')
|
||||
);
|
||||
return $button;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Config\Menu;
|
||||
use MailPoet\Mailer\MailerError;
|
||||
use MailPoet\Mailer\MailerLog;
|
||||
use MailPoet\Newsletter\Renderer\EscapeHelper;
|
||||
use MailPoet\Services\AuthorizedEmailsController;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class UnauthorizedEmailInNewslettersNotice {
|
||||
|
||||
const OPTION_NAME = 'unauthorized-email-in-newsletters-addresses-notice';
|
||||
|
||||
/** @var SettingsController */
|
||||
private $settings;
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
SettingsController $settings,
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->settings = $settings;
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay) {
|
||||
$validationError = $this->settings->get(AuthorizedEmailsController::AUTHORIZED_EMAIL_ADDRESSES_ERROR_SETTING);
|
||||
if ($shouldDisplay && isset($validationError['invalid_senders_in_newsletters'])) {
|
||||
return $this->display($validationError);
|
||||
}
|
||||
}
|
||||
|
||||
public function display($validationError) {
|
||||
$message = $this->getMessageText();
|
||||
$message .= $this->getNewslettersLinks($validationError);
|
||||
$message .= $this->getFixThisButton();
|
||||
// Use Mailer log errors display system to display this notice
|
||||
$mailerLog = MailerLog::setError(MailerLog::getMailerLog(), MailerError::OPERATION_AUTHORIZATION, $message);
|
||||
MailerLog::updateMailerLog($mailerLog);
|
||||
}
|
||||
|
||||
private function getMessageText() {
|
||||
$message = __('<b>Your automatic emails have been paused</b> because some email addresses haven’t been authorized yet.', 'mailpoet');
|
||||
return "<p>$message</p>";
|
||||
}
|
||||
|
||||
private function getNewslettersLinks($validationError) {
|
||||
$links = '';
|
||||
foreach ($validationError['invalid_senders_in_newsletters'] as $error) {
|
||||
// translators: %s is the newsletter subject.
|
||||
$linkText = _x('Update the from address of %s', '%s will be replaced by a newsletter subject', 'mailpoet');
|
||||
$linkText = str_replace('%s', EscapeHelper::escapeHtmlText($error['subject']), $linkText);
|
||||
$linkUrl = $this->wp->adminUrl('admin.php?page=' . Menu::EMAILS_PAGE_SLUG . '#/send/' . $error['newsletter_id']);
|
||||
$link = Helpers::replaceLinkTags("[link]{$linkText}[/link]", $linkUrl, ['target' => '_blank']);
|
||||
$links .= "<p>$link</p>";
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
|
||||
private function getFixThisButton() {
|
||||
$button = '<button class="button button-primary mailpoet-js-button-fix-this">' . __('Fix this!', 'mailpoet') . '</button>';
|
||||
return "<p>$button</p>";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Newsletter\Renderer\EscapeHelper;
|
||||
use MailPoet\Services\AuthorizedEmailsController;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class UnauthorizedEmailNotice {
|
||||
|
||||
const OPTION_NAME = 'unauthorized-email-addresses-notice';
|
||||
|
||||
/** @var SettingsController|null */
|
||||
private $settings;
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp,
|
||||
SettingsController $settings = null
|
||||
) {
|
||||
$this->settings = $settings;
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay) {
|
||||
if (!$this->settings instanceof SettingsController) {
|
||||
throw new \Exception('This method can only be called if SettingsController is provided');
|
||||
}
|
||||
$validationError = $this->settings->get(AuthorizedEmailsController::AUTHORIZED_EMAIL_ADDRESSES_ERROR_SETTING);
|
||||
if ($shouldDisplay && isset($validationError['invalid_sender_address'])) {
|
||||
return $this->display($validationError);
|
||||
}
|
||||
}
|
||||
|
||||
public function display($validationError) {
|
||||
$message = $this->getMessage($validationError);
|
||||
$extraClasses = 'mailpoet-js-error-unauthorized-emails-notice';
|
||||
Notice::displayError($message, $extraClasses, self::OPTION_NAME, false, false);
|
||||
}
|
||||
|
||||
public function getMessage($validationError) {
|
||||
$message = $this->getMessageText($validationError);
|
||||
$message .= sprintf(
|
||||
'<p>%s %s %s</p>',
|
||||
$this->getAuthorizeEmailButton($validationError),
|
||||
$this->getDifferentEmailButton(),
|
||||
$this->getResumeSendingButton($validationError)
|
||||
);
|
||||
return $message;
|
||||
}
|
||||
|
||||
private function getMessageText($validationError) {
|
||||
// translators: %s is the email address.
|
||||
$text = _x(
|
||||
'<b>Sending all of your emails has been paused</b> because your email address <b>%s</b> hasn’t been authorized yet.',
|
||||
'Email addresses have to be authorized to be used to send emails. %s will be replaced by an email address.',
|
||||
'mailpoet'
|
||||
);
|
||||
$message = str_replace('%s', EscapeHelper::escapeHtmlText($validationError['invalid_sender_address']), $text);
|
||||
return "<p>$message</p>";
|
||||
}
|
||||
|
||||
private function getAuthorizeEmailButton($validationError) {
|
||||
$email = $this->wp->escAttr($validationError['invalid_sender_address']);
|
||||
$button = '<a target="_blank" href="https://account.mailpoet.com/authorization?email=' . $email . '" class="button button-primary mailpoet-js-button-authorize-email-and-sender-domain" data-type="email" data-email="' . $email . '">' . __('Authorize this email address', 'mailpoet') . '</a>';
|
||||
return $button;
|
||||
}
|
||||
|
||||
private function getDifferentEmailButton() {
|
||||
$button = '<button class="button button-secondary mailpoet-js-button-fix-this">' . __('Use a different email address', 'mailpoet') . '</button>';
|
||||
return $button;
|
||||
}
|
||||
|
||||
private function getResumeSendingButton($validationError) {
|
||||
$email = $this->wp->escAttr($validationError['invalid_sender_address']);
|
||||
$button = '<button class="button button-secondary mailpoet-js-button-resume-sending" value="' . $email . '">' . __('Resume sending', 'mailpoet') . '</button>';
|
||||
return $button;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Config\Env;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class WooCommerceVersionWarning {
|
||||
const OPTION_NAME = 'mailpoet-dismissed-woo-version-outdated-notice';
|
||||
const DISMISS_NOTICE_TIMEOUT_SECONDS = 2592000; // 30 days
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function init($shouldDisplay) {
|
||||
if (!is_plugin_active('woocommerce/woocommerce.php')) {
|
||||
return;
|
||||
}
|
||||
$woocommerceVersion = $this->getWoocommerceVersion();
|
||||
$requiredWooCommerceVersion = $this->getRequiredWooCommerceVersion();
|
||||
if ($shouldDisplay && $this->isOutdatedWooCommerceVersion($woocommerceVersion, $requiredWooCommerceVersion)) {
|
||||
$this->display($requiredWooCommerceVersion);
|
||||
}
|
||||
}
|
||||
|
||||
public function isOutdatedWooCommerceVersion($woocommerceVersion, $requiredWooCommerceVersion): bool {
|
||||
return version_compare($woocommerceVersion, $requiredWooCommerceVersion, '<') && !$this->wp->getTransient($this->getTransientKey());
|
||||
}
|
||||
|
||||
private function display($requiredWooCommerceVersion) {
|
||||
// translators: %s is the PHP version
|
||||
$errorString = __('MailPoet plugin requires WooCommerce version %s or newer. Please update your WooCommerce plugin version, or read our [link]instructions[/link] for additional options on how to resolve this issue.', 'mailpoet');
|
||||
$errorString = sprintf($errorString, $requiredWooCommerceVersion);
|
||||
$error = Helpers::replaceLinkTags($errorString, 'https://kb.mailpoet.com/article/152-minimum-requirements-for-mailpoet-3#woocommerce-version', [
|
||||
'target' => '_blank',
|
||||
]);
|
||||
|
||||
$extraClasses = 'mailpoet-dismissible-notice is-dismissible';
|
||||
|
||||
Notice::displayWarning($error, $extraClasses, self::OPTION_NAME);
|
||||
}
|
||||
|
||||
public function disable() {
|
||||
$this->wp->setTransient($this->getTransientKey(), true, self::DISMISS_NOTICE_TIMEOUT_SECONDS);
|
||||
}
|
||||
|
||||
private function getTransientKey() {
|
||||
$woocommerceVersion = $this->getWoocommerceVersion();
|
||||
return self::OPTION_NAME . '_' . $this->getRequiredWooCommerceVersion() . '_' . $woocommerceVersion;
|
||||
}
|
||||
|
||||
private function getWoocommerceVersion(): string {
|
||||
return $this->wp->getPluginData(WP_PLUGIN_DIR . '/woocommerce/woocommerce.php', false, false)['Version'];
|
||||
}
|
||||
|
||||
private function getRequiredWooCommerceVersion(): string {
|
||||
$pluginData = $this->wp->getFileData(
|
||||
Env::$file,
|
||||
[
|
||||
'RequiredWCVersion' => 'WC requires at least',
|
||||
]
|
||||
);
|
||||
return $pluginData['RequiredWCVersion'] ?? '100.0.0';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Util\Notices;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Doctrine\WPDB\Connection;
|
||||
use MailPoet\WP\Notice;
|
||||
|
||||
class WordPressPlaygroundNotice {
|
||||
const OPTION_NAME = 'wordpress-playground-notice';
|
||||
|
||||
public function init($shouldDisplay): ?Notice {
|
||||
if (!$shouldDisplay || !Connection::isSQLite()) {
|
||||
return null;
|
||||
}
|
||||
return $this->display();
|
||||
}
|
||||
|
||||
private function display(): Notice {
|
||||
return Notice::displayWarning(
|
||||
sprintf(
|
||||
'<p><strong>%s</strong></p><p>%s</p>',
|
||||
__('MailPoet Preview', 'mailpoet'),
|
||||
__('This is a preview of the MailPoet plugin. Please note that some functionality may be limited.', 'mailpoet')
|
||||
),
|
||||
null,
|
||||
self::OPTION_NAME,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
Reference in New Issue
Block a user