PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / Config / Menu.php
mailpoet / lib / Config Last commit date
PopulatorData 2 months ago AccessControl.php 2 years ago Activator.php 2 months ago AssetsLoader.php 2 weeks ago Capabilities.php 2 months ago Changelog.php 2 months ago DeactivationPoll.php 3 years ago DeferredAdminNotices.php 2 months ago Env.php 6 months ago Hooks.php 1 month ago HooksWooCommerce.php 1 month ago Initializer.php 1 month ago Installer.php 10 months ago Localizer.php 3 years ago Menu.php 1 month ago PersonalDataErasers.php 1 month ago PersonalDataExporters.php 1 month ago PluginActivatedHook.php 3 years ago Populator.php 2 weeks ago PrivacyPolicy.php 1 month ago Renderer.php 1 year ago RendererFactory.php 3 years ago RequirementsChecker.php 2 months ago Router.php 2 months ago ServicesChecker.php 3 years ago Shortcodes.php 1 month ago SilentUpgraderSkin.php 3 years ago SubscriberChangesNotifier.php 2 months ago TranslationUpdater.php 3 months ago TwigEnvironment.php 1 year ago TwigFileSystemCache.php 3 years ago Updater.php 5 days ago index.php 3 years ago
Menu.php
856 lines
1 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
2
3 namespace MailPoet\Config;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\AdminPages\Pages\Automation;
9 use MailPoet\AdminPages\Pages\AutomationAnalytics;
10 use MailPoet\AdminPages\Pages\AutomationEditor;
11 use MailPoet\AdminPages\Pages\AutomationFlowEmbed;
12 use MailPoet\AdminPages\Pages\AutomationPreviewEmbed;
13 use MailPoet\AdminPages\Pages\AutomationTemplates;
14 use MailPoet\AdminPages\Pages\CustomFields as CustomFieldsPage;
15 use MailPoet\AdminPages\Pages\DynamicSegments;
16 use MailPoet\AdminPages\Pages\ExperimentalFeatures;
17 use MailPoet\AdminPages\Pages\FormEditor;
18 use MailPoet\AdminPages\Pages\Forms;
19 use MailPoet\AdminPages\Pages\Help;
20 use MailPoet\AdminPages\Pages\Homepage;
21 use MailPoet\AdminPages\Pages\Landingpage;
22 use MailPoet\AdminPages\Pages\Logs;
23 use MailPoet\AdminPages\Pages\NewsletterEditor;
24 use MailPoet\AdminPages\Pages\Newsletters;
25 use MailPoet\AdminPages\Pages\Settings;
26 use MailPoet\AdminPages\Pages\StaticSegments;
27 use MailPoet\AdminPages\Pages\Subscribers;
28 use MailPoet\AdminPages\Pages\SubscribersExport;
29 use MailPoet\AdminPages\Pages\SubscribersImport;
30 use MailPoet\AdminPages\Pages\Tags as TagsPage;
31 use MailPoet\AdminPages\Pages\Upgrade;
32 use MailPoet\AdminPages\Pages\WelcomeWizard;
33 use MailPoet\AdminPages\Pages\WooCommerceSetup;
34 use MailPoet\DI\ContainerWrapper;
35 use MailPoet\EmailEditor\Integrations\MailPoet\EmailEditor;
36 use MailPoet\Form\Util\CustomFonts;
37 use MailPoet\Newsletter\NewslettersRepository;
38 use MailPoet\Util\License\Features\CapabilitiesManager;
39 use MailPoet\WP\Functions as WPFunctions;
40 use MailPoet\WPCOM\DotcomHelperFunctions;
41
42 class Menu {
43 const MAIN_PAGE_SLUG = self::HOMEPAGE_PAGE_SLUG;
44 const NO_PARENT_PAGE_SLUG = 'mailpoet-no-parent';
45
46 const EMAILS_PAGE_SLUG = 'mailpoet-newsletters';
47 const FORMS_PAGE_SLUG = 'mailpoet-forms';
48 const EMAIL_EDITOR_PAGE_SLUG = 'mailpoet-newsletter-editor';
49 const FORM_EDITOR_PAGE_SLUG = 'mailpoet-form-editor';
50 const HOMEPAGE_PAGE_SLUG = 'mailpoet-homepage';
51 const FORM_TEMPLATES_PAGE_SLUG = 'mailpoet-form-editor-template-selection';
52 const SUBSCRIBERS_PAGE_SLUG = 'mailpoet-subscribers';
53 const IMPORT_PAGE_SLUG = 'mailpoet-import';
54 const EXPORT_PAGE_SLUG = 'mailpoet-export';
55 const TAGS_PAGE_SLUG = 'mailpoet-tags';
56 const CUSTOM_FIELDS_PAGE_SLUG = 'mailpoet-custom-fields';
57 const LISTS_PAGE_SLUG = 'mailpoet-lists';
58 const SEGMENTS_PAGE_SLUG = 'mailpoet-segments';
59 const SETTINGS_PAGE_SLUG = 'mailpoet-settings';
60 const HELP_PAGE_SLUG = 'mailpoet-help';
61 const UPGRADE_PAGE_SLUG = 'mailpoet-upgrade';
62 const WELCOME_WIZARD_PAGE_SLUG = 'mailpoet-welcome-wizard';
63 const WOOCOMMERCE_SETUP_PAGE_SLUG = 'mailpoet-woocommerce-setup';
64 const EXPERIMENTS_PAGE_SLUG = 'mailpoet-experimental';
65 const LOGS_PAGE_SLUG = 'mailpoet-logs';
66 const AUTOMATIONS_PAGE_SLUG = 'mailpoet-automation';
67 const AUTOMATION_EDITOR_PAGE_SLUG = 'mailpoet-automation-editor';
68 const AUTOMATION_ANALYTICS_PAGE_SLUG = 'mailpoet-automation-analytics';
69 const AUTOMATION_TEMPLATES_PAGE_SLUG = 'mailpoet-automation-templates';
70 const AUTOMATION_PREVIEW_EMBED_PAGE_SLUG = 'mailpoet-automation-preview-embed';
71 const AUTOMATION_FLOW_EMBED_PAGE_SLUG = 'mailpoet-automation-flow-embed';
72
73 const LANDINGPAGE_PAGE_SLUG = 'mailpoet-landingpage';
74
75 const ICON_BASE64_SVG = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTIuMDIgMTU2LjQiPjxwYXRoIGZpbGw9IiNhN2FhYWQiIGQ9Ik0zNy43MSw4OS4xYzMuNSwwLDUuOS0uOCw3LjItMi4zYTgsOCwwLDAsMCwyLTUuNFYzNS43bDE3LDQ1LjFhMTIuNjgsMTIuNjgsMCwwLDAsMy43LDUuNGMxLjYsMS4zLDQsMiw3LjIsMmExMi41NCwxMi41NCwwLDAsMCw1LjktMS40LDguNDEsOC40MSwwLDAsMCwzLjktNWwxOC4xLTUwVjgxYTguNTMsOC41MywwLDAsMCwyLjEsNi4xYzEuNCwxLjQsMy43LDIuMiw2LjksMi4yLDMuNSwwLDUuOS0uOCw3LjItMi4zYTgsOCwwLDAsMCwyLTUuNFY4LjdhNy40OCw3LjQ4LDAsMCwwLTMuMy02LjZjLTIuMS0xLjQtNS0yLjEtOC42LTIuMWExOS4zLDE5LjMsMCwwLDAtOS40LDIsMTEuNjMsMTEuNjMsMCwwLDAtNS4xLDYuOEw3NC45MSw2Ny4xLDU0LjQxLDguNGExMi40LDEyLjQsMCwwLDAtNC41LTYuMmMtMi4xLTEuNS01LTIuMi04LjgtMi4yYTE2LjUxLDE2LjUxLDAsMCwwLTguOSwyLjFjLTIuMywxLjUtMy41LDMuOS0zLjUsNy4yVjgwLjhjMCwyLjguNyw0LjgsMiw2LjJDMzIuMjEsODguNCwzNC40MSw4OS4xLDM3LjcxLDg5LjFaIi8+PHBhdGggZmlsbD0iI2E3YWFhZCIgZD0iTTE0OSwxMTYuNmwtMi40LTEuOWE3LjQsNy40LDAsMCwwLTkuNC4zLDE5LjY1LDE5LjY1LDAsMCwxLTEyLjUsNC42aC0yMS40QTM3LjA4LDM3LjA4LDAsMCwwLDc3LDEzMC41bC0xLjEsMS4yLTEuMS0xLjFhMzcuMjUsMzcuMjUsMCwwLDAtMjYuMy0xMC45SDI3YTE5LjU5LDE5LjU5LDAsMCwxLTEyLjQtNC42LDcuMjgsNy4yOCwwLDAsMC05LjQtLjNsLTIuNCwxLjlBNy40Myw3LjQzLDAsMCwwLDAsMTIyLjJhNy4xNCw3LjE0LDAsMCwwLDIuNCw1LjdBMzcuMjgsMzcuMjgsMCwwLDAsMjcsMTM3LjRoMjEuNmExOS41OSwxOS41OSwwLDAsMSwxOC45LDE0LjR2LjJjLjEuNywxLjIsNC40LDguNSw0LjRzOC40LTMuNyw4LjUtNC40di0uMmExOS41OSwxOS41OSwwLDAsMSwxOC45LTE0LjRIMTI1YTM3LjI4LDM3LjI4LDAsMCwwLDI0LjYtOS41LDcuNDIsNy40MiwwLDAsMCwyLjQtNS43QTcuODYsNy44NiwwLDAsMCwxNDksMTE2LjZaIi8+PC9zdmc+';
76
77 public $mpApiKeyValid;
78 public $premiumKeyValid;
79
80 /** @var AccessControl */
81 private $accessControl;
82
83 /** @var WPFunctions */
84 private $wp;
85
86 /** @var ServicesChecker */
87 private $servicesChecker;
88
89 /** @var ContainerWrapper */
90 private $container;
91
92 /** @var Router */
93 private $router;
94
95 /** @var CustomFonts */
96 private $customFonts;
97
98 /** @var EmailEditor */
99 private $emailEditor;
100
101 private CapabilitiesManager $capabilitiesManager;
102
103 private DotcomHelperFunctions $dotcomHelperFunctions;
104
105 public function __construct(
106 AccessControl $accessControl,
107 WPFunctions $wp,
108 ServicesChecker $servicesChecker,
109 ContainerWrapper $container,
110 Router $router,
111 CustomFonts $customFonts,
112 CapabilitiesManager $capabilitiesManager,
113 EmailEditor $emailEditor,
114 DotcomHelperFunctions $dotcomHelperFunctions
115 ) {
116 $this->accessControl = $accessControl;
117 $this->wp = $wp;
118 $this->servicesChecker = $servicesChecker;
119 $this->container = $container;
120 $this->router = $router;
121 $this->customFonts = $customFonts;
122 $this->capabilitiesManager = $capabilitiesManager;
123 $this->emailEditor = $emailEditor;
124 $this->dotcomHelperFunctions = $dotcomHelperFunctions;
125 }
126
127 public function init() {
128 $this->checkPremiumKey();
129
130 $this->wp->addAction('admin_init', [$this, 'maybeRenderAutomationPreviewEmbed'], 1);
131 $this->wp->addAction('admin_init', [$this, 'maybeRenderAutomationFlowEmbed'], 1);
132
133 $this->wp->addAction(
134 'admin_menu',
135 [
136 $this,
137 'setup',
138 ]
139 );
140
141 $this->wp->addFilter('parent_file', [$this, 'highlightNestedMailPoetSubmenus']);
142 }
143
144 public function setup() {
145 global $parent_file;
146 $parent_file = self::EMAILS_PAGE_SLUG;
147 if (!$this->accessControl->validatePermission(AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN)) return;
148
149 $this->router->checkRedirects();
150
151 $this->registerMailPoetMenu();
152
153 if (!self::isOnMailPoetAdminPage()) {
154 return;
155 }
156 $this->wp->doAction('mailpoet_conflict_resolver_styles');
157 $this->wp->doAction('mailpoet_conflict_resolver_scripts');
158
159 if (
160 !isset($_REQUEST['page'])
161 || !is_string($_REQUEST['page'])
162 || sanitize_text_field(wp_unslash($_REQUEST['page'])) !== 'mailpoet-newsletter-editor'
163 ) {
164 return;
165 }
166 // Disable WP emojis to not interfere with the newsletter editor emoji handling
167 $this->disableWPEmojis();
168 if (!$this->customFonts->displayCustomFonts()) {
169 return;
170 }
171 $this->wp->addAction('admin_head', function () {
172 echo '<link href="https://fonts.googleapis.com/css?family='
173 . 'Arvo:400,400i,700,700i'
174 . '|Lato:400,400i,700,700i'
175 . '|Lora:400,400i,700,700i'
176 . '|Merriweather:400,400i,700,700i'
177 . '|Merriweather+Sans:400,400i,700,700i'
178 . '|Noticia+Text:400,400i,700,700i'
179 . '|Open+Sans:400,400i,700,700i'
180 . '|Playfair+Display:400,400i,700,700i'
181 . '|Roboto:400,400i,700,700i'
182 . '|Source+Sans+Pro:400,400i,700,700i'
183 . '|Oswald:400,400i,700,700i'
184 . '|Raleway:400,400i,700,700i'
185 . '|Permanent+Marker:400,400i,700,700i'
186 . '|Pacifico:400,400i,700,700i'
187 . '" rel="stylesheet">';
188 });
189 }
190
191 private function registerMailPoetMenu() {
192
193 // Main page
194 $this->wp->addMenuPage(
195 'MailPoet',
196 'MailPoet',
197 AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
198 self::MAIN_PAGE_SLUG,
199 '',
200 self::ICON_BASE64_SVG,
201 30
202 );
203
204 // Welcome wizard page
205 $this->wp->addSubmenuPage(
206 self::NO_PARENT_PAGE_SLUG,
207 $this->setPageTitle(__('Welcome Wizard', 'mailpoet')),
208 esc_html__('Welcome Wizard', 'mailpoet'),
209 AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
210 self::WELCOME_WIZARD_PAGE_SLUG,
211 [
212 $this,
213 'welcomeWizard',
214 ]
215 );
216
217 // Landingpage
218 $this->wp->addSubmenuPage(
219 self::NO_PARENT_PAGE_SLUG,
220 $this->setPageTitle(__('MailPoet', 'mailpoet')),
221 esc_html__('MailPoet', 'mailpoet'),
222 AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
223 self::LANDINGPAGE_PAGE_SLUG,
224 [
225 $this,
226 'landingPage',
227 ]
228 );
229
230 $this->registerMailPoetSubMenuEntries();
231 }
232
233 private function registerMailPoetSubMenuEntries() {
234 // Homepage
235 $this->wp->addSubmenuPage(
236 self::MAIN_PAGE_SLUG,
237 $this->setPageTitle(__('Home', 'mailpoet')),
238 esc_html__('Home', 'mailpoet'),
239 AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
240 self::HOMEPAGE_PAGE_SLUG,
241 [
242 $this,
243 'homepage',
244 ]
245 );
246
247 // Emails page
248 $this->wp->addSubmenuPage(
249 self::MAIN_PAGE_SLUG,
250 $this->setPageTitle(__('Emails', 'mailpoet')),
251 esc_html__('Emails', 'mailpoet'),
252 AccessControl::PERMISSION_MANAGE_EMAILS,
253 self::EMAILS_PAGE_SLUG,
254 [
255 $this,
256 'newsletters',
257 ]
258 );
259
260 // newsletter editor
261 $this->wp->addSubmenuPage(
262 self::EMAILS_PAGE_SLUG,
263 $this->setPageTitle(__('Newsletter', 'mailpoet')),
264 esc_html__('Newsletter Editor', 'mailpoet'),
265 AccessControl::PERMISSION_MANAGE_EMAILS,
266 self::EMAIL_EDITOR_PAGE_SLUG,
267 [
268 $this,
269 'newletterEditor',
270 ]
271 );
272
273 $this->registerAutomationMenu();
274
275 // Forms page
276 $this->wp->addSubmenuPage(
277 self::MAIN_PAGE_SLUG,
278 $this->setPageTitle(__('Forms', 'mailpoet')),
279 esc_html__('Forms', 'mailpoet'),
280 AccessControl::PERMISSION_MANAGE_FORMS,
281 self::FORMS_PAGE_SLUG,
282 [
283 $this,
284 'forms',
285 ]
286 );
287
288 // form editor
289 $formEditorPage = $this->wp->addSubmenuPage(
290 self::FORMS_PAGE_SLUG,
291 $this->setPageTitle(__('Form Editor', 'mailpoet')),
292 esc_html__('Form Editor', 'mailpoet'),
293 AccessControl::PERMISSION_MANAGE_FORMS,
294 self::FORM_EDITOR_PAGE_SLUG,
295 [
296 $this,
297 'formEditor',
298 ]
299 );
300
301 // add body class for form editor page
302 $this->wp->addAction('load-' . $formEditorPage, function() {
303 $this->wp->addFilter('admin_body_class', function ($classes) {
304 return ltrim($classes . ' block-editor-page');
305 });
306 });
307
308 // form editor templates
309 $formTemplateSelectionEditorPage = $this->wp->addSubmenuPage(
310 self::FORMS_PAGE_SLUG,
311 $this->setPageTitle(__('Select Form Template', 'mailpoet')),
312 esc_html__('Select Form Template', 'mailpoet'),
313 AccessControl::PERMISSION_MANAGE_FORMS,
314 self::FORM_TEMPLATES_PAGE_SLUG,
315 [
316 $this,
317 'formEditorTemplateSelection',
318 ]
319 );
320
321 // Subscribers page
322 $this->wp->addSubmenuPage(
323 self::MAIN_PAGE_SLUG,
324 $this->setPageTitle(__('Subscribers', 'mailpoet')),
325 esc_html__('Subscribers', 'mailpoet'),
326 AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
327 self::SUBSCRIBERS_PAGE_SLUG,
328 [
329 $this,
330 'subscribers',
331 ]
332 );
333
334 // import
335 $this->wp->addSubmenuPage(
336 self::SUBSCRIBERS_PAGE_SLUG,
337 $this->setPageTitle(__('Import', 'mailpoet')),
338 esc_html__('Import', 'mailpoet'),
339 AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
340 self::IMPORT_PAGE_SLUG,
341 [
342 $this,
343 'import',
344 ]
345 );
346
347 // export
348 $this->wp->addSubmenuPage(
349 self::SUBSCRIBERS_PAGE_SLUG,
350 $this->setPageTitle(__('Export', 'mailpoet')),
351 esc_html__('Export', 'mailpoet'),
352 AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
353 self::EXPORT_PAGE_SLUG,
354 [
355 $this,
356 'export',
357 ]
358 );
359
360 // tags
361 $this->wp->addSubmenuPage(
362 self::SUBSCRIBERS_PAGE_SLUG,
363 $this->setPageTitle(__('Tags', 'mailpoet')),
364 esc_html__('Tags', 'mailpoet'),
365 AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
366 self::TAGS_PAGE_SLUG,
367 [
368 $this,
369 'tags',
370 ]
371 );
372
373 // custom fields
374 $this->wp->addSubmenuPage(
375 self::SUBSCRIBERS_PAGE_SLUG,
376 $this->setPageTitle(__('Custom Fields', 'mailpoet')),
377 esc_html__('Custom Fields', 'mailpoet'),
378 AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
379 self::CUSTOM_FIELDS_PAGE_SLUG,
380 [
381 $this,
382 'customFields',
383 ]
384 );
385
386 // Lists page
387 $this->wp->addSubmenuPage(
388 self::MAIN_PAGE_SLUG,
389 $this->setPageTitle(__('Lists', 'mailpoet')),
390 esc_html__('Lists', 'mailpoet'),
391 AccessControl::PERMISSION_MANAGE_SEGMENTS,
392 self::LISTS_PAGE_SLUG,
393 [
394 $this,
395 'lists',
396 ]
397 );
398
399 // Segments page
400 $this->wp->addSubmenuPage(
401 self::MAIN_PAGE_SLUG,
402 $this->setPageTitle(__('Segments', 'mailpoet')),
403 esc_html__('Segments', 'mailpoet'),
404 AccessControl::PERMISSION_MANAGE_SEGMENTS,
405 self::SEGMENTS_PAGE_SLUG,
406 [
407 $this,
408 'segments',
409 ]
410 );
411
412 // Settings page
413 $this->wp->addSubmenuPage(
414 self::MAIN_PAGE_SLUG,
415 $this->setPageTitle(__('Settings', 'mailpoet')),
416 esc_html__('Settings', 'mailpoet'),
417 AccessControl::PERMISSION_MANAGE_SETTINGS,
418 self::SETTINGS_PAGE_SLUG,
419 [
420 $this,
421 'settings',
422 ]
423 );
424
425 // Help page
426 $this->wp->addSubmenuPage(
427 self::MAIN_PAGE_SLUG,
428 $this->setPageTitle(__('Help', 'mailpoet')),
429 esc_html__('Help', 'mailpoet'),
430 AccessControl::PERMISSION_MANAGE_HELP,
431 self::HELP_PAGE_SLUG,
432 [
433 $this,
434 'help',
435 ]
436 );
437
438 // Upgrade page
439 $this->wp->addSubmenuPage(
440 $this->capabilitiesManager->showUpgradePage() ? self::MAIN_PAGE_SLUG : self::HELP_PAGE_SLUG,
441 $this->setPageTitle(__('Upgrade', 'mailpoet')),
442 esc_html__('Upgrade', 'mailpoet'),
443 AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
444 self::UPGRADE_PAGE_SLUG,
445 [
446 $this,
447 'upgrade',
448 ]
449 );
450
451 // WooCommerce Setup
452 $this->wp->addSubmenuPage(
453 self::NO_PARENT_PAGE_SLUG,
454 $this->setPageTitle(__('WooCommerce Setup', 'mailpoet')),
455 esc_html__('WooCommerce Setup', 'mailpoet'),
456 AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
457 self::WOOCOMMERCE_SETUP_PAGE_SLUG,
458 [
459 $this,
460 'wooCommerceSetup',
461 ]
462 );
463
464 // Experimental page
465 $this->wp->addSubmenuPage(
466 self::SETTINGS_PAGE_SLUG,
467 $this->setPageTitle(__('Experimental Features', 'mailpoet')),
468 '',
469 AccessControl::PERMISSION_MANAGE_FEATURES,
470 self::EXPERIMENTS_PAGE_SLUG,
471 [$this, 'experimentalFeatures']
472 );
473
474 // display logs page
475 $this->wp->addSubmenuPage(
476 self::SETTINGS_PAGE_SLUG,
477 $this->setPageTitle(__('Logs', 'mailpoet')),
478 '',
479 AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
480 self::LOGS_PAGE_SLUG,
481 [$this, 'logs']
482 );
483 }
484
485 private function registerAutomationMenu() {
486 $automationPage = $this->wp->addSubmenuPage(
487 self::MAIN_PAGE_SLUG,
488 $this->setPageTitle(__('Automations', 'mailpoet')),
489 esc_html__('Automations', 'mailpoet'),
490 AccessControl::PERMISSION_MANAGE_EMAILS,
491 self::AUTOMATIONS_PAGE_SLUG,
492 [$this, 'automation']
493 );
494
495 // Automation editor
496 $automationEditorPage = $this->wp->addSubmenuPage(
497 self::AUTOMATIONS_PAGE_SLUG,
498 $this->setPageTitle(__('Automation Editor', 'mailpoet')),
499 esc_html__('Automation Editor', 'mailpoet'),
500 AccessControl::PERMISSION_MANAGE_AUTOMATIONS,
501 self::AUTOMATION_EDITOR_PAGE_SLUG,
502 [$this, 'automationEditor']
503 );
504
505 // Automation analytics
506 $this->wp->addSubmenuPage(
507 self::AUTOMATIONS_PAGE_SLUG,
508 $this->setPageTitle(__('Automation Analytics', 'mailpoet')),
509 esc_html__('Automation Analytics', 'mailpoet'),
510 AccessControl::PERMISSION_MANAGE_AUTOMATIONS,
511 self::AUTOMATION_ANALYTICS_PAGE_SLUG,
512 [$this, 'automationAnalytics']
513 );
514
515 // Automation templates
516 $this->wp->addSubmenuPage(
517 self::AUTOMATIONS_PAGE_SLUG,
518 $this->setPageTitle(__('Automation Templates', 'mailpoet')),
519 esc_html__('Automation Templates', 'mailpoet'),
520 AccessControl::PERMISSION_MANAGE_AUTOMATIONS,
521 self::AUTOMATION_TEMPLATES_PAGE_SLUG,
522 [$this, 'automationTemplates']
523 );
524
525 // Automation preview embed (hidden from menu, used for iframe embedding)
526 $this->wp->addSubmenuPage(
527 self::NO_PARENT_PAGE_SLUG,
528 $this->setPageTitle(__('Automation Preview', 'mailpoet')),
529 '',
530 AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
531 self::AUTOMATION_PREVIEW_EMBED_PAGE_SLUG,
532 [$this, 'automationPreviewEmbed']
533 );
534
535 // Automation flow embed (hidden from menu, used for iframe embedding)
536 $this->wp->addSubmenuPage(
537 self::NO_PARENT_PAGE_SLUG,
538 $this->setPageTitle(__('Automation Flow', 'mailpoet')),
539 '',
540 AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
541 self::AUTOMATION_FLOW_EMBED_PAGE_SLUG,
542 [$this, 'automationFlowEmbed']
543 );
544
545 // add body class for automation editor page
546 $this->wp->addAction('load-' . $automationPage, function() {
547 $this->wp->addFilter('admin_body_class', function ($classes) {
548 return ltrim($classes . ' mailpoet-automation-is-onboarding');
549 });
550 });
551 $this->wp->addAction('load-' . $automationEditorPage, function() {
552 $this->wp->addFilter('admin_body_class', function ($classes) {
553 $classes .= ' site-editor-php';
554 if ($this->dotcomHelperFunctions->isGarden()) {
555 $classes .= ' admin-color-modern';
556 }
557 return ltrim($classes);
558 });
559 });
560 }
561
562 public function disableWPEmojis() {
563 $this->wp->removeAction('admin_print_scripts', 'print_emoji_detection_script');
564 $this->wp->removeAction('admin_print_styles', 'print_emoji_styles');
565 }
566
567 public function welcomeWizard() {
568 $this->container->get(WelcomeWizard::class)->render();
569 }
570
571 public function landingPage() {
572 $this->container->get(Landingpage::class)->render();
573 }
574
575 public function wooCommerceSetup() {
576 $this->container->get(WooCommerceSetup::class)->render();
577 }
578
579 public function upgrade() {
580 $this->container->get(Upgrade::class)->render();
581 }
582
583 public function settings() {
584 $this->container->get(Settings::class)->render();
585 }
586
587 public function help() {
588 $this->container->get(Help::class)->render();
589 }
590
591 public function homepage() {
592 $this->container->get(Homepage::class)->render();
593 }
594
595 public function automation() {
596 $this->container->get(Automation::class)->render();
597 }
598
599 public function automationTemplates() {
600 $this->container->get(AutomationTemplates::class)->render();
601 }
602
603 public function automationEditor() {
604 $this->container->get(AutomationEditor::class)->render();
605 }
606
607 public function automationAnalytics() {
608 $this->container->get(AutomationAnalytics::class)->render();
609 }
610
611 public function automationPreviewEmbed() {
612 $this->container->get(AutomationPreviewEmbed::class)->render();
613 }
614
615 public function automationFlowEmbed() {
616 $this->container->get(AutomationFlowEmbed::class)->render();
617 }
618
619 /**
620 * Render automation preview embed page early, before WordPress outputs admin chrome.
621 * This allows the embed page to be a clean, standalone HTML page without menus/sidebars.
622 */
623 public function maybeRenderAutomationPreviewEmbed(): void {
624 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
625 if (!isset($_GET['page']) || $_GET['page'] !== self::AUTOMATION_PREVIEW_EMBED_PAGE_SLUG) {
626 return;
627 }
628
629 if (!$this->accessControl->validatePermission(AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN)) {
630 return;
631 }
632
633 $this->container->get(AutomationPreviewEmbed::class)->render();
634 }
635
636 /**
637 * Render automation flow embed page early, before WordPress outputs admin chrome.
638 * This allows the embed page to be a clean, standalone HTML page without menus/sidebars.
639 */
640 public function maybeRenderAutomationFlowEmbed(): void {
641 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
642 if (!isset($_GET['page']) || $_GET['page'] !== self::AUTOMATION_FLOW_EMBED_PAGE_SLUG) {
643 return;
644 }
645
646 if (!$this->accessControl->validatePermission(AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN)) {
647 return;
648 }
649
650 $this->container->get(AutomationFlowEmbed::class)->render();
651 }
652
653 public function experimentalFeatures() {
654 $this->container->get(ExperimentalFeatures::class)->render();
655 }
656
657 public function logs() {
658 $this->container->get(Logs::class)->render();
659 }
660
661 public function subscribers() {
662 $this->container->get(Subscribers::class)->render();
663 }
664
665 public function lists() {
666 $this->container->get(StaticSegments::class)->render();
667 }
668
669 public function segments() {
670 $this->container->get(DynamicSegments::class)->render();
671 }
672
673 public function forms() {
674 $this->container->get(Forms::class)->render();
675 }
676
677 public function newsletters() {
678 $this->container->get(Newsletters::class)->render();
679 }
680
681 public function newletterEditor() {
682 $this->container->get(NewsletterEditor::class)->render();
683 }
684
685 public function import() {
686 $this->container->get(SubscribersImport::class)->render();
687 }
688
689 public function export() {
690 $this->container->get(SubscribersExport::class)->render();
691 }
692
693 public function tags() {
694 $this->container->get(TagsPage::class)->render();
695 }
696
697 public function customFields() {
698 $this->container->get(CustomFieldsPage::class)->render();
699 }
700
701 public function formEditor() {
702 $this->container->get(FormEditor::class)->render();
703 }
704
705 public function formEditorTemplateSelection() {
706 $this->container->get(FormEditor::class)->renderTemplateSelection();
707 }
708
709 public function setPageTitle($title) {
710 return sprintf(
711 '%s - %s',
712 __('MailPoet', 'mailpoet'),
713 $title
714 );
715 }
716
717 public function highlightNestedMailPoetSubmenus($parentFile) {
718 global $plugin_page, $submenu, $submenu_file;
719
720 $page = $this->getPageFromContext();
721 if ($page) {
722 $plugin_page = $page;
723 return $parentFile;
724 }
725
726 // In case we are on the email editor page, we want to highlight the related MailPoet menu item
727 if ($this->emailEditor->isEditorPage(false)) {
728 $emailEditorMenuPageSlug = $this->getEmailEditorMenuPageSlug();
729 $plugin_page = $emailEditorMenuPageSlug;
730 $submenu_file = $emailEditorMenuPageSlug;
731 return $emailEditorMenuPageSlug;
732 }
733
734 if ($parentFile === self::MAIN_PAGE_SLUG || !self::isOnMailPoetAdminPage()) {
735 return $parentFile;
736 }
737
738 // find slug of the current submenu item
739 $parentSlug = null;
740 foreach ($submenu as $groupSlug => $group) {
741 foreach ($group as $item) {
742 if (($item[2] ?? null) === $plugin_page) {
743 $parentSlug = $groupSlug;
744 break 2;
745 }
746 }
747 }
748
749 if ($parentSlug && $parentSlug !== self::NO_PARENT_PAGE_SLUG) {
750 // highlight parent submenu item
751 $plugin_page = $parentSlug;
752 } else {
753 // no parent, hide MailPoet submenu for setup, wizards, error pages, etc.
754 unset($submenu[self::MAIN_PAGE_SLUG]);
755 $plugin_page = self::MAIN_PAGE_SLUG;
756 }
757 return $parentFile;
758 }
759
760 private function getEmailEditorMenuPageSlug(): string {
761 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- is_numeric guard plus int cast is the sanitization
762 $rawPostId = $_GET['post'] ?? null;
763 $postId = is_numeric($rawPostId) ? (int)$rawPostId : 0;
764 if (!$postId) {
765 return self::EMAILS_PAGE_SLUG;
766 }
767
768 $newslettersRepository = $this->container->get(NewslettersRepository::class);
769 $newsletter = $newslettersRepository->findOneBy(['wpPost' => $postId]);
770 if ($newsletter && ($newsletter->isAutomation() || $newsletter->isAutomationTransactional())) {
771 return self::AUTOMATIONS_PAGE_SLUG;
772 }
773 return self::EMAILS_PAGE_SLUG;
774 }
775
776 public static function isOnMailPoetAutomationPage(): bool {
777 $screenId = isset($_REQUEST['page']) && is_string($_REQUEST['page']) ? sanitize_text_field(wp_unslash($_REQUEST['page'])) : '';
778 $automationPages = [
779 'mailpoet-automation',
780 'mailpoet-automation-templates',
781 'mailpoet-automation-editor',
782 ];
783 return in_array(
784 $screenId,
785 $automationPages,
786 true
787 );
788 }
789
790 public static function isOnMailPoetAdminPage(?array $exclude = null, $screenId = null) {
791 if (is_null($screenId)) {
792 if (empty($_REQUEST['page']) || !is_string($_REQUEST['page'])) {
793 return false;
794 }
795 $screenId = sanitize_text_field(wp_unslash($_REQUEST['page']));
796 }
797 if (!empty($exclude)) {
798 foreach ($exclude as $slug) {
799 if (stripos($screenId, $slug) !== false) {
800 return false;
801 }
802 }
803 }
804 return (stripos($screenId, 'mailpoet-') !== false);
805 }
806
807 /**
808 * This error page is used when the initialization is failed
809 * to display admin notices only
810 */
811 public static function addErrorPage(AccessControl $accessControl) {
812 if (!self::isOnMailPoetAdminPage() || !isset($_REQUEST['page']) || !is_string($_REQUEST['page'])) {
813 return false;
814 }
815
816 $page = sanitize_text_field(wp_unslash($_REQUEST['page']));
817 // Check if page already exists
818 if (
819 get_plugin_page_hook($page, '')
820 || WPFunctions::get()->getPluginPageHook($page, self::MAIN_PAGE_SLUG)
821 ) {
822 return false;
823 }
824 WPFunctions::get()->addSubmenuPage(
825 self::NO_PARENT_PAGE_SLUG,
826 'MailPoet',
827 'MailPoet',
828 AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN,
829 $page,
830 [
831 __CLASS__,
832 'errorPageCallback',
833 ]
834 );
835 }
836
837 public static function errorPageCallback() {
838 // Used for displaying admin notices only
839 }
840
841 public function checkPremiumKey(?ServicesChecker $checker = null) {
842 $showNotices = self::isOnMailPoetAdminPage() || (isset($_SERVER['SCRIPT_NAME']) && is_string($_SERVER['SCRIPT_NAME'])
843 && stripos(sanitize_text_field(wp_unslash($_SERVER['SCRIPT_NAME'])), 'plugins.php') !== false);
844 $checker = $checker ?: $this->servicesChecker;
845 $this->premiumKeyValid = $checker->isPremiumKeyValid($showNotices);
846 }
847
848 public function getPageFromContext(): ?string {
849 $context = isset($_GET['context']) && is_string($_GET['context']) ? sanitize_text_field(wp_unslash($_GET['context'])) : null;
850 if ($context === 'automation') {
851 return self::AUTOMATIONS_PAGE_SLUG;
852 }
853 return null;
854 }
855 }
856