This commit is contained in:
emmymayo
2025-02-05 23:15:46 +01:00
commit 7269c99357
16995 changed files with 3389680 additions and 0 deletions
@@ -0,0 +1,19 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Settings;
if (!defined('ABSPATH')) exit;
class Charsets {
public static function getAll() {
return [
'UTF-8', 'UTF-7', 'BIG5', 'ISO-2022-JP',
'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3',
'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6',
'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9',
'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14',
'ISO-8859-15', 'Windows-1251', 'Windows-1252',
];
}
}
@@ -0,0 +1,247 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Settings;
if (!defined('ABSPATH')) exit;
class Hosts {
private static $smtp = [
'AmazonSES' => [
'name' => 'Amazon SES',
'emails' => 100,
'interval' => 5,
'fields' => [
'region',
'access_key',
'secret_key',
],
'regions' => [
'US East (N. Virginia)' => 'us-east-1',
'US East (Ohio)' => 'us-east-2',
'US West (N. California)' => 'us-west-1',
'US West (Oregon)' => 'us-west-2',
'EU (Ireland)' => 'eu-west-1',
'EU (London)' => 'eu-west-2',
'EU (Paris)' => 'eu-west-3',
'EU (Milan)' => 'eu-south-1',
'EU (Frankfurt)' => 'eu-central-1',
'EU (Stockholm)' => 'eu-north-1',
'Canada (Central)' => 'ca-central-1',
'China (Beijing)' => 'cn-north-1',
'China (Ningxia)' => 'cn-northwest-1',
'Africa (Cape Town)' => 'af-south-1',
'Asia Pacific (Hong Kong)' => 'ap-east-1',
'Asia Pacific (Jakarta)' => 'ap-southeast-3',
'Asia Pacific (Mumbai)' => 'ap-south-1',
'Asia Pacific (Seoul)' => 'ap-northeast-2',
'Asia Pacific (Osaka)' => 'ap-northeast-3',
'Asia Pacific (Singapore)' => 'ap-southeast-1',
'Asia Pacific (Sydney)' => 'ap-southeast-2',
'Asia Pacific (Tokyo)' => 'ap-northeast-1',
'Middle East (Bahrain)' => 'me-south-1',
'South America (Sao Paulo)' => 'sa-east-1',
'AWS GovCloud (US)' => 'us-gov-west-1',
],
],
'SendGrid' => [
'name' => 'SendGrid',
'emails' => 100,
'interval' => 5,
'fields' => [
'api_key',
],
],
];
private static $web = [
'bluehost' => [
'name' => 'BlueHost',
'emails' => 70,
'interval' => 30,
],
'df' => [
'name' => 'Df.eu',
'emails' => 115,
'interval' => 15,
],
'dreamhost' => [
'name' => 'DreamHost',
'emails' => 25,
'interval' => 15,
],
'free' => [
'name' => 'Free.fr',
'emails' => 18,
'interval' => 15,
],
'froghost' => [
'name' => 'FrogHost.com',
'emails' => 490,
'interval' => 30,
],
'godaddy' => [
'name' => 'GoDaddy',
'emails' => 5,
'interval' => 30,
],
'goneo' => [
'name' => 'Goneo',
'emails' => 60,
'interval' => 15,
],
'googleapps' => [
'name' => 'Google Apps',
'emails' => 20,
'interval' => 60,
],
'greengeeks' => [
'name' => 'GreenGeeks',
'emails' => 45,
'interval' => 30,
],
'hawkhost' => [
'name' => 'Hawkhost.com',
'emails' => 500,
'interval' => 15,
],
'hivetec' => [
'name' => 'Hivetec',
'emails' => 20,
'interval' => 15,
],
'hostgator' => [
'name' => 'Host Gator',
'emails' => 115,
'interval' => 15,
],
'hosting2go' => [
'name' => 'Hosting 2GO',
'emails' => 45,
'interval' => 15,
],
'hostmonster' => [
'name' => 'Host Monster',
'emails' => 115,
'interval' => 15,
],
'infomaniak' => [
'name' => 'Infomaniak',
'emails' => 20,
'interval' => 15,
],
'1and1' => [
'name' => 'IONOS by 1&1',
'emails' => 30,
'interval' => 5,
],
'justhost' => [
'name' => 'JustHost',
'emails' => 70,
'interval' => 30,
],
'laughingsquid' => [
'name' => 'Laughing Squid',
'emails' => 20,
'interval' => 15,
],
'lunarpages' => [
'name' => 'Lunarpages',
'emails' => 19,
'interval' => 15,
],
'mediatemple' => [
'name' => 'Media Temple',
'emails' => 115,
'interval' => 15,
],
'netfirms' => [
'name' => 'Netfirms',
'emails' => 200,
'interval' => 60,
],
'netissime' => [
'name' => 'Netissime',
'emails' => 100,
'interval' => 15,
],
'one' => [
'name' => 'One.com',
'emails' => 100,
'interval' => 15,
],
'ovh' => [
'name' => 'OVH',
'emails' => 50,
'interval' => 15,
],
'phpnet' => [
'name' => 'PHPNet',
'emails' => 15,
'interval' => 15,
],
'planethoster' => [
'name' => 'PlanetHoster',
'emails' => 90,
'interval' => 30,
],
'rochen' => [
'name' => 'Rochen',
'emails' => 40,
'interval' => 15,
],
'site5' => [
'name' => 'Site5',
'emails' => 40,
'interval' => 15,
],
'siteground' => [
'name' => 'Siteground',
'emails' => 95,
'interval' => 15,
],
'synthesis' => [
'name' => 'Synthesis',
'emails' => 250,
'interval' => 15,
],
'techark' => [
'name' => 'Techark',
'emails' => 60,
'interval' => 15,
],
'vexxhost' => [
'name' => 'Vexxhost',
'emails' => 60,
'interval' => 15,
],
'vps' => [
'name' => 'VPS.net',
'emails' => 90,
'interval' => 30,
],
'webcity' => [
'name' => 'Webcity',
'emails' => 19,
'interval' => 15,
],
'westhost' => [
'name' => 'Westhost',
'emails' => 225,
'interval' => 15,
],
'wpwebhost' => [
'name' => 'Wpwebhost.com',
'emails' => 95,
'interval' => 30,
],
];
public static function getWebHosts() {
return static::$web;
}
public static function getSMTPHosts() {
return static::$smtp;
}
}
@@ -0,0 +1,123 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Settings;
if (!defined('ABSPATH')) exit;
use MailPoet\Subscription;
use MailPoet\WP\Functions as WPFunctions;
class Pages {
const PAGE_SUBSCRIPTIONS = 'subscriptions';
const PAGE_CAPTCHA = 'captcha';
public function __construct() {
}
public function init() {
WPFunctions::get()->registerPostType('mailpoet_page', [
'labels' => [
'name' => __('MailPoet Page', 'mailpoet'),
'singular_name' => __('MailPoet Page', 'mailpoet'),
],
'public' => true,
'has_archive' => false,
'show_ui' => false,
'show_in_menu' => false,
'rewrite' => false,
'show_in_nav_menus' => false,
'can_export' => false,
'publicly_queryable' => true,
'exclude_from_search' => true,
]);
}
public static function createMailPoetPage($postName) {
WPFunctions::get()->removeAllActions('pre_post_update');
WPFunctions::get()->removeAllActions('save_post');
WPFunctions::get()->removeAllActions('wp_insert_post');
$id = WPFunctions::get()->wpInsertPost([
'post_status' => 'publish',
'post_type' => 'mailpoet_page',
'post_author' => 1,
'post_content' => '[mailpoet_page]',
'post_title' => __('MailPoet Page', 'mailpoet'),
'post_name' => $postName,
]);
return ((int)$id > 0) ? (int)$id : false;
}
public static function getMailPoetPage($postName) {
$wp = WPFunctions::get();
$pages = $wp->getPosts([
'posts_per_page' => 1,
'orderby' => 'date',
'order' => 'DESC',
'post_type' => 'mailpoet_page',
'post_name__in' => [$postName],
]);
$page = null;
if (!empty($pages)) {
$page = array_shift($pages);
if (strpos($page->post_content, '[mailpoet_page]') === false) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
$page = null;
}
}
return $page;
}
public static function getMailPoetPages() {
return WPFunctions::get()->getPosts([
'post_type' => 'mailpoet_page',
'post_name__in' => [self::PAGE_SUBSCRIPTIONS],
]);
}
/**
* @param int $id
*
* @return bool
*/
public static function isMailpoetPage($id) {
$mailpoetPages = static::getMailPoetPages();
foreach ($mailpoetPages as $mailpoetPage) {
if ($mailpoetPage->ID === $id) {
return true;
}
}
return false;
}
public static function getAll() {
$allPages = array_merge(
static::getMailPoetPages(),
WPFunctions::get()->getPages()
);
$pages = [];
foreach ($allPages as $page) {
$pages[] = static::getPageData($page);
}
return $pages;
}
public static function getPageData($page) {
$subscriptionUrlFactory = Subscription\SubscriptionUrlFactory::getInstance();
return [
'id' => $page->ID,
'title' => $page->post_title, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
'url' => [
'unsubscribe' => $subscriptionUrlFactory->getSubscriptionUrl($page, 'unsubscribe'),
'manage' => $subscriptionUrlFactory->getSubscriptionUrl($page, 'manage'),
'confirm' => $subscriptionUrlFactory->getSubscriptionUrl($page, 'confirm'),
'confirm_unsubscribe' => $subscriptionUrlFactory->getSubscriptionUrl($page, 'confirm_unsubscribe'),
're_engagement' => $subscriptionUrlFactory->getSubscriptionUrl($page, 're_engagement'),
],
];
}
}
@@ -0,0 +1,116 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Settings;
if (!defined('ABSPATH')) exit;
use MailPoet\Cron\Workers\InactiveSubscribers;
use MailPoet\Cron\Workers\WooCommerceSync;
use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Mailer\Mailer;
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
use MailPoet\Services\Bridge;
use MailPoet\Services\SubscribersCountReporter;
use MailPoetVendor\Carbon\Carbon;
class SettingsChangeHandler {
/** @var ScheduledTasksRepository */
private $scheduledTasksRepository;
/** @var SettingsController */
private $settingsController;
/** @var Bridge */
private $bridge;
/** @var SubscribersCountReporter */
private $subscribersCountReporter;
public function __construct(
ScheduledTasksRepository $scheduledTasksRepository,
SettingsController $settingsController,
Bridge $bridge,
SubscribersCountReporter $subscribersCountReporter
) {
$this->scheduledTasksRepository = $scheduledTasksRepository;
$this->settingsController = $settingsController;
$this->bridge = $bridge;
$this->subscribersCountReporter = $subscribersCountReporter;
}
public function onSubscribeOldWoocommerceCustomersChange(): void {
$task = $this->scheduledTasksRepository->findOneBy([
'type' => WooCommerceSync::TASK_TYPE,
'status' => ScheduledTaskEntity::STATUS_SCHEDULED,
'deletedAt' => null,
], ['createdAt' => 'DESC']);
if (!($task instanceof ScheduledTaskEntity)) {
$task = $this->createScheduledTask(WooCommerceSync::TASK_TYPE);
}
$datetime = Carbon::now()->millisecond(0);
$task->setScheduledAt($datetime->subMinute());
$this->scheduledTasksRepository->persist($task);
$this->scheduledTasksRepository->flush();
}
public function onInactiveSubscribersIntervalChange(): void {
$task = $this->scheduledTasksRepository->findOneBy([
'type' => InactiveSubscribers::TASK_TYPE,
'status' => ScheduledTaskEntity::STATUS_SCHEDULED,
'deletedAt' => null,
], ['createdAt' => 'DESC']);
if (!($task instanceof ScheduledTaskEntity)) {
$task = $this->createScheduledTask(InactiveSubscribers::TASK_TYPE);
}
$datetime = Carbon::now()->millisecond(0);
$task->setScheduledAt($datetime->subMinute());
$this->scheduledTasksRepository->persist($task);
$this->scheduledTasksRepository->flush();
}
public function onMSSActivate($newSettings) {
// see mailpoet/assets/js/src/wizard/create_sender_settings.jsx:freeAddress
$httpHost = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : '';
$domain = str_replace('www.', '', $httpHost);
if (
isset($newSettings['sender']['address'])
&& !empty($newSettings['reply_to']['address'])
&& ($newSettings['sender']['address'] === ('wordpress@' . $domain))
) {
$sender = [
'name' => $newSettings['reply_to']['name'] ?? '',
'address' => $newSettings['reply_to']['address'],
];
$this->settingsController->set('sender', $sender);
$this->settingsController->set('reply_to', null);
}
}
private function createScheduledTask(string $type): ScheduledTaskEntity {
$task = new ScheduledTaskEntity();
$task->setType($type);
$task->setStatus(ScheduledTaskEntity::STATUS_SCHEDULED);
return $task;
}
public function updateApiKeyState($settings) {
$apiKey = $settings[Mailer::MAILER_CONFIG_SETTING_NAME]['mailpoet_api_key'] ?? null;
$premiumKey = $settings['premium']['premium_key'] ?? null;
if (!empty($apiKey)) {
$apiKeyState = $this->bridge->checkMSSKey($apiKey);
$this->bridge->storeMSSKeyAndState($apiKey, $apiKeyState);
}
if (!empty($premiumKey)) {
$premiumState = $this->bridge->checkPremiumKey($premiumKey);
$this->bridge->storePremiumKeyAndState($premiumKey, $premiumState);
}
if ($apiKey && !empty($apiKeyState) && in_array($apiKeyState['state'], [Bridge::KEY_VALID, Bridge::KEY_VALID_UNDERPRIVILEGED], true)) {
return $this->subscribersCountReporter->report($apiKey);
}
if ($premiumKey && !empty($premiumState) && in_array($premiumState['state'], [Bridge::KEY_VALID, Bridge::KEY_VALID_UNDERPRIVILEGED], true)) {
return $this->subscribersCountReporter->report($premiumKey);
}
}
}
@@ -0,0 +1,184 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Settings;
if (!defined('ABSPATH')) exit;
use MailPoet\Cron\CronTrigger;
use MailPoet\DI\ContainerWrapper;
class SettingsController {
const DEFAULT_SENDING_METHOD_GROUP = 'website';
const DEFAULT_SENDING_METHOD = 'PHPMail';
const DEFAULT_SENDING_FREQUENCY_EMAILS = 25;
const DEFAULT_SENDING_FREQUENCY_INTERVAL = 5; // in minutes
const DEFAULT_DEACTIVATE_SUBSCRIBER_AFTER_INACTIVE_DAYS = 365;
private $loaded = false;
private $settings = [];
private $defaults = null;
/** @var SettingsRepository */
private $settingsRepository;
private static $instance;
public function __construct(
SettingsRepository $settingsRepository
) {
$this->settingsRepository = $settingsRepository;
}
public function get($key, $default = null) {
$this->ensureLoaded();
$keyParts = explode('.', $key);
$setting = $this->settings;
if ($default === null) {
$default = $this->getDefaultValue($keyParts);
}
foreach ($keyParts as $keyPart) {
if (is_array($setting) && array_key_exists($keyPart, $setting)) {
$setting = $setting[$keyPart];
} else {
return $default;
}
}
if (is_array($setting) && is_array($default)) {
return array_replace_recursive($default, $setting);
}
return $setting;
}
public function getAllDefaults() {
if ($this->defaults === null) {
$this->defaults = [
'mta_group' => self::DEFAULT_SENDING_METHOD_GROUP,
'mta' => [
'method' => self::DEFAULT_SENDING_METHOD,
'frequency' => [
'emails' => self::DEFAULT_SENDING_FREQUENCY_EMAILS,
'interval' => self::DEFAULT_SENDING_FREQUENCY_INTERVAL,
],
],
CronTrigger::SETTING_NAME => [
'method' => CronTrigger::DEFAULT_METHOD,
],
'signup_confirmation' => [
'enabled' => true,
'use_mailpoet_editor' => true,
'subject' => __('Confirm your subscription to [site:title]', 'mailpoet'),
'body' => __("Hello [subscriber:firstname | default:there],\n\nYou've received this message because you subscribed to [site:title]. Please confirm your subscription to receive emails from us:\n\n[activation_link]Click here to confirm your subscription.[/activation_link] \n\nIf you received this email by mistake, simply delete it. You won't receive any more emails from us unless you confirm your subscription using the link above.\n\nThank you,\n\n<a target=\"_blank\" href=\"[site:homepage_url]\">[site:title]</a>", 'mailpoet'),
],
'tracking' => [
'level' => TrackingConfig::LEVEL_FULL,
],
'analytics' => [
'enabled' => false,
],
'display_nps_poll' => true,
'deactivate_subscriber_after_inactive_days' => self::DEFAULT_DEACTIVATE_SUBSCRIBER_AFTER_INACTIVE_DAYS,
];
}
return $this->defaults;
}
/**
* Fetches the value from DB and update in cache
* This is required for sync settings between parallel processes e.g. cron
*/
public function fetch($key, $default = null) {
$keys = explode('.', $key);
$mainKey = $keys[0];
$this->settings[$mainKey] = $this->fetchValue($mainKey);
return $this->get($key, $default);
}
public function getAll() {
$this->ensureLoaded();
return array_replace_recursive($this->getAllDefaults(), $this->settings);
}
public function set($key, $value) {
$this->ensureLoaded();
$keyParts = explode('.', $key);
$mainKey = $keyParts[0];
$lastKey = array_pop($keyParts);
$setting =& $this->settings;
foreach ($keyParts as $keyPart) {
$setting =& $setting[$keyPart];
if (!is_array($setting)) {
$setting = [];
}
}
$setting[$lastKey] = $value;
$this->settingsRepository->createOrUpdateByName($mainKey, $this->settings[$mainKey]);
}
public function delete($key) {
$setting = $this->settingsRepository->findOneByName($key);
if ($setting) {
$this->settingsRepository->remove($setting);
$this->settingsRepository->flush();
}
unset($this->settings[$key]);
}
/**
* Returns true if a value is stored in the database for the given key
*
* @param string $key
*
* @return bool
*/
public function hasSavedValue(string $key): bool {
return $this->get($key, 'unset') !== 'unset';
}
private function ensureLoaded() {
if ($this->loaded) {
return;
}
$this->settings = [];
foreach ($this->settingsRepository->findAll() as $setting) {
$this->settings[$setting->getName()] = $setting->getValue();
}
$this->loaded = true;
}
private function getDefaultValue($keys) {
$default = $this->getAllDefaults();
foreach ($keys as $key) {
if (array_key_exists($key, $default)) {
$default = $default[$key];
} else {
return null;
}
}
return $default;
}
private function fetchValue($key) {
$setting = $this->settingsRepository->findOneByName($key);
return $setting ? $setting->getValue() : null;
}
public function resetCache() {
$this->settings = [];
$this->loaded = false;
}
public static function setInstance($instance) {
self::$instance = $instance;
}
/** @return SettingsController */
public static function getInstance() {
if (isset(self::$instance)) return self::$instance;
return ContainerWrapper::getInstance()->get(SettingsController::class);
}
}
@@ -0,0 +1,54 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Settings;
if (!defined('ABSPATH')) exit;
use MailPoet\Doctrine\Repository;
use MailPoet\Entities\SettingEntity;
use MailPoetVendor\Carbon\Carbon;
use MailPoetVendor\Doctrine\ORM\Query;
/**
* @extends Repository<SettingEntity>
*/
class SettingsRepository extends Repository {
public function findOneByName(string $name): ?SettingEntity {
// Always fetch fresh entity data (= don't use "findOneBy()"). See also further below.
$result = (array)$this->doctrineRepository->createQueryBuilder('s')
->where('s.name = :name')
->setParameter('name', $name)
->getQuery()
->setHint(Query::HINT_REFRESH, true)
->getResult();
return isset($result[0]) && $result[0] instanceof SettingEntity ? $result[0] : null;
}
public function createOrUpdateByName($name, $value) {
// Temporarily use low-level INSERT ... ON DUPLICATE KEY UPDATE query to avoid race conditions
// between entity fetch and creation with multiple concurrent requests. This will be replaced
// by a code solving atomicity of create-or-update on entity (ORM) level in a follow-up ticket.
$now = Carbon::now()->millisecond(0);
$tableName = $this->entityManager->getClassMetadata(SettingEntity::class)->getTableName();
$this->entityManager->getConnection()->executeStatement("
INSERT INTO $tableName (name, value, created_at, updated_at)
VALUES (:name, :value, :now, :now)
ON DUPLICATE KEY UPDATE value = :value, updated_at = :now
", [
'name' => $name,
'value' => is_array($value) ? serialize($value) : $value,
'now' => $now,
]);
// Ensure entity data is up-to-date in memory.
// - We can't use "refresh()"; we don't have the entity instance, and it can be a new record.
// - We can't use "findOneBy()"; it could return a cached entity instance.
$this->findOneByName($name);
}
protected function getEntityClassName() {
return SettingEntity::class;
}
}
@@ -0,0 +1,54 @@
<?php declare(strict_types = 1);
namespace MailPoet\Settings;
if (!defined('ABSPATH')) exit;
class TrackingConfig {
const LEVEL_FULL = 'full';
const LEVEL_PARTIAL = 'partial';
const LEVEL_BASIC = 'basic';
const OPENS_MERGED = 'merged';
const OPENS_SEPARATED = 'separated';
/** @var SettingsController */
private $settings;
public function __construct(
SettingsController $settings
) {
$this->settings = $settings;
}
public function isEmailTrackingEnabled(string $level = null): bool {
$level = $level ?? $this->settings->get('tracking.level', self::LEVEL_FULL);
return in_array($level, [self::LEVEL_PARTIAL, self::LEVEL_FULL], true);
}
public function isCookieTrackingEnabled(string $level = null): bool {
$level = $level ?? $this->settings->get('tracking.level', self::LEVEL_FULL);
return $level === self::LEVEL_FULL;
}
public function areOpensMerged(string $opens = null): bool {
$opens = $opens ?? $this->settings->get('tracking.opens', self::OPENS_MERGED);
return $opens !== self::OPENS_SEPARATED;
}
public function areOpensSeparated(string $opens = null): bool {
return !$this->areOpensMerged($opens);
}
public function getConfig(): array {
return [
'level' => $this->settings->get('tracking.level', self::LEVEL_FULL),
'emailTrackingEnabled' => $this->isEmailTrackingEnabled(),
'cookieTrackingEnabled' => $this->isCookieTrackingEnabled(),
'opens' => $this->settings->get('tracking.opens', self::OPENS_MERGED),
'opensMerged' => $this->areOpensMerged(),
'opensSeparated' => $this->areOpensSeparated(),
];
}
}
@@ -0,0 +1,113 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Settings;
if (!defined('ABSPATH')) exit;
use MailPoet\Entities\UserFlagEntity;
use MailPoet\WP\Functions as WPFunctions;
class UserFlagsController {
const EMAIL_EDITOR_SURVEY = 'email_editor_survey_seen';
/** @var array|null */
private $data = null;
/** @var array */
private $defaults;
/** @var UserFlagsRepository */
private $userFlagsRepository;
public function __construct(
UserFlagsRepository $userFlagsRepository
) {
$this->defaults = [
'editor_tutorial_seen' => false,
'form_editor_tutorial_seen' => false,
'display_new_form_editor_nps_survey' => false,
'transactional_emails_opt_in_notice_dismissed' => false,
'legacy_automations_notice_dismissed' => false,
'legacy_automatic_emails_notice_dismissed' => false,
self::EMAIL_EDITOR_SURVEY => null,
];
$this->userFlagsRepository = $userFlagsRepository;
}
public function get($name) {
$this->ensureLoaded();
if (!isset($this->data[$name])) {
return $this->defaults[$name];
}
return $this->data[$name];
}
public function getAll() {
$this->ensureLoaded();
$data = $this->data;
if (!is_array($data)) {
$data = [];
}
return array_merge($this->defaults, $data);
}
public function set($name, $value) {
$currentUserId = WPFunctions::get()->getCurrentUserId();
$flag = $this->userFlagsRepository->findOneBy([
'userId' => $currentUserId,
'name' => $name,
]);
if (!$flag) {
$flag = new UserFlagEntity();
$flag->setUserId($currentUserId);
$flag->setName($name);
$this->userFlagsRepository->persist($flag);
}
$flag->setValue($value);
$this->userFlagsRepository->flush();
if ($this->isLoaded()) {
$this->data[$name] = $value;
}
}
public function delete($name) {
$currentUserId = WPFunctions::get()->getCurrentUserId();
$flag = $this->userFlagsRepository->findOneBy([
'userId' => $currentUserId,
'name' => $name,
]);
if (!$flag) {
return;
}
$this->userFlagsRepository->remove($flag);
$this->userFlagsRepository->flush();
if ($this->isLoaded()) {
unset($this->data[$name]);
}
}
private function load() {
$currentUserId = WPFunctions::get()->getCurrentUserId();
$flags = $this->userFlagsRepository->findBy(['userId' => $currentUserId]);
$this->data = [];
foreach ($flags as $flag) {
$this->data[$flag->getName()] = $flag->getValue();
}
}
private function isLoaded() {
return $this->data !== null;
}
private function ensureLoaded() {
if (!$this->isLoaded()) {
$this->load();
}
}
}
@@ -0,0 +1,18 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Settings;
if (!defined('ABSPATH')) exit;
use MailPoet\Doctrine\Repository;
use MailPoet\Entities\UserFlagEntity;
/**
* @extends Repository<UserFlagEntity>
*/
class UserFlagsRepository extends Repository {
protected function getEntityClassName() {
return UserFlagEntity::class;
}
}
@@ -0,0 +1 @@
<?php