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 / Hooks.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 4 weeks ago HooksWooCommerce.php 1 month ago Initializer.php 4 weeks 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 4 days ago index.php 3 years ago
Hooks.php
908 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\Captcha\CaptchaHooks;
9 use MailPoet\Captcha\ReCaptchaHooks;
10 use MailPoet\Captcha\TurnstileHooks;
11 use MailPoet\Cron\CronTrigger;
12 use MailPoet\EmailEditor\Integrations\MailPoet\Coupons\CouponBlockGenerator;
13 use MailPoet\EmailEditor\Integrations\MailPoet\ProductCollection\ProductCollectionEmailRendererRegistrar;
14 use MailPoet\Form\DisplayFormInWPContent;
15 use MailPoet\Mailer\WordPress\WordpressMailerReplacer;
16 use MailPoet\Newsletter\Scheduler\PostNotificationScheduler;
17 use MailPoet\Segments\WP;
18 use MailPoet\Settings\SettingsController;
19 use MailPoet\Statistics\Track\SubscriberHandler;
20 use MailPoet\Subscribers\SubscriberLimitNotificationScheduler;
21 use MailPoet\Subscription\AdminUserSubscription;
22 use MailPoet\Subscription\Comment;
23 use MailPoet\Subscription\Form;
24 use MailPoet\Subscription\Manage;
25 use MailPoet\Subscription\Registration;
26 use MailPoet\WooCommerce\Helper as WooHelper;
27 use MailPoet\WooCommerce\Integrations\AutomateWooHooks;
28 use MailPoet\WooCommerce\Subscription;
29 use MailPoet\WooCommerce\WooSystemInfoController;
30 use MailPoet\WP\Functions as WPFunctions;
31 use MailPoet\WPCOM\DotcomLicenseProvisioner;
32
33 class Hooks {
34 const OPTIN_POSITION_AFTER_BILLING_INFO = 'after_billing_info';
35 const OPTIN_POSITION_AFTER_ORDER_NOTES = 'after_order_notes';
36 const OPTIN_POSITION_AFTER_TERMS_AND_CONDITIONS = 'after_terms_and_conditions';
37 const OPTIN_POSITION_BEFORE_PAYMENT_METHODS = 'before_payment_methods';
38 const OPTIN_POSITION_BEFORE_TERMS_AND_CONDITIONS = 'before_terms_and_conditions';
39 const DEFAULT_OPTIN_POSITION = self::OPTIN_POSITION_AFTER_BILLING_INFO;
40 const OPTIN_HOOKS = [
41 self::OPTIN_POSITION_AFTER_BILLING_INFO => 'woocommerce_after_checkout_billing_form',
42 self::OPTIN_POSITION_AFTER_ORDER_NOTES => 'woocommerce_after_order_notes',
43 self::OPTIN_POSITION_AFTER_TERMS_AND_CONDITIONS => 'woocommerce_checkout_after_terms_and_conditions',
44 self::OPTIN_POSITION_BEFORE_PAYMENT_METHODS => 'woocommerce_review_order_before_payment',
45 self::OPTIN_POSITION_BEFORE_TERMS_AND_CONDITIONS => 'woocommerce_checkout_before_terms_and_conditions',
46 ];
47 const FOOTER_RATED_OPTION = 'mailpoet_admin_footer_text_rated';
48
49 /** @var Form */
50 private $subscriptionForm;
51
52 /** @var Comment */
53 private $subscriptionComment;
54
55 /** @var Manage */
56 private $subscriptionManage;
57
58 /** @var Registration */
59 private $subscriptionRegistration;
60
61 /** @var SettingsController */
62 private $settings;
63
64 /** @var WPFunctions */
65 private $wp;
66
67 /** @var PostNotificationScheduler */
68 private $postNotificationScheduler;
69
70 /** @var WordpressMailerReplacer */
71 private $wordpressMailerReplacer;
72
73 /** @var DisplayFormInWPContent */
74 private $displayFormInWPContent;
75
76 /** @var WP */
77 private $wpSegment;
78
79 /** @var SubscriberHandler */
80 private $subscriberHandler;
81
82 /** @var HooksWooCommerce */
83 private $hooksWooCommerce;
84
85 /** @var SubscriberChangesNotifier */
86 private $subscriberChangesNotifier;
87
88 /** @var SubscriberLimitNotificationScheduler */
89 private $subscriberLimitNotificationScheduler;
90
91 /** @var DotcomLicenseProvisioner */
92 private $dotcomLicenseProvisioner;
93
94 /** @var AutomateWooHooks */
95 private $automateWooHooks;
96
97 /** @var CaptchaHooks */
98 private $captchaHooks;
99
100 /** @var ReCaptchaHooks */
101 private $reCaptchaHooks;
102
103 /** @var TurnstileHooks */
104 private $turnstileHooks;
105
106 /** @var WooSystemInfoController */
107 private $wooSystemInfoController;
108
109 /** @var CronTrigger */
110 private $cronTrigger;
111
112 /** @var WooHelper */
113 private $wooHelper;
114
115 /** @var AdminUserSubscription */
116 private $adminUserSubscription;
117
118 private CouponBlockGenerator $couponBlockGenerator;
119
120 private ProductCollectionEmailRendererRegistrar $productCollectionEmailRendererRegistrar;
121
122 public function __construct(
123 Form $subscriptionForm,
124 Comment $subscriptionComment,
125 Manage $subscriptionManage,
126 Registration $subscriptionRegistration,
127 SettingsController $settings,
128 WPFunctions $wp,
129 PostNotificationScheduler $postNotificationScheduler,
130 WordpressMailerReplacer $wordpressMailerReplacer,
131 DisplayFormInWPContent $displayFormInWPContent,
132 WP $wpSegment,
133 SubscriberHandler $subscriberHandler,
134 HooksWooCommerce $hooksWooCommerce,
135 SubscriberChangesNotifier $subscriberChangesNotifier,
136 SubscriberLimitNotificationScheduler $subscriberLimitNotificationScheduler,
137 DotcomLicenseProvisioner $dotcomLicenseProvisioner,
138 AutomateWooHooks $automateWooHooks,
139 CaptchaHooks $captchaHooks,
140 ReCaptchaHooks $reCaptchaHooks,
141 TurnstileHooks $turnstileHooks,
142 WooSystemInfoController $wooSystemInfoController,
143 CronTrigger $cronTrigger,
144 WooHelper $wooHelper,
145 AdminUserSubscription $adminUserSubscription,
146 CouponBlockGenerator $couponBlockGenerator,
147 ProductCollectionEmailRendererRegistrar $productCollectionEmailRendererRegistrar
148 ) {
149 $this->subscriptionForm = $subscriptionForm;
150 $this->subscriptionComment = $subscriptionComment;
151 $this->subscriptionManage = $subscriptionManage;
152 $this->subscriptionRegistration = $subscriptionRegistration;
153 $this->settings = $settings;
154 $this->wp = $wp;
155 $this->postNotificationScheduler = $postNotificationScheduler;
156 $this->wordpressMailerReplacer = $wordpressMailerReplacer;
157 $this->displayFormInWPContent = $displayFormInWPContent;
158 $this->wpSegment = $wpSegment;
159 $this->subscriberHandler = $subscriberHandler;
160 $this->hooksWooCommerce = $hooksWooCommerce;
161 $this->captchaHooks = $captchaHooks;
162 $this->reCaptchaHooks = $reCaptchaHooks;
163 $this->turnstileHooks = $turnstileHooks;
164 $this->subscriberChangesNotifier = $subscriberChangesNotifier;
165 $this->subscriberLimitNotificationScheduler = $subscriberLimitNotificationScheduler;
166 $this->dotcomLicenseProvisioner = $dotcomLicenseProvisioner;
167 $this->automateWooHooks = $automateWooHooks;
168 $this->wooSystemInfoController = $wooSystemInfoController;
169 $this->cronTrigger = $cronTrigger;
170 $this->wooHelper = $wooHelper;
171 $this->adminUserSubscription = $adminUserSubscription;
172 $this->couponBlockGenerator = $couponBlockGenerator;
173 $this->productCollectionEmailRendererRegistrar = $productCollectionEmailRendererRegistrar;
174 }
175
176 public function init() {
177 $this->setupWPUsers();
178 $this->setupWooCommerceUsers();
179 $this->setupWooCommercePurchases();
180 $this->setupWooCommerceOrderAttribution();
181 $this->setupWooCommerceSubscriberEngagement();
182 $this->setupWooCommerceTracking();
183 $this->setupSubscriptionEvents();
184 $this->setupWooCommerceSubscriptionEvents();
185 $this->setupAutomateWooSubscriptionEvents();
186 $this->setupPostNotifications();
187 $this->setupWooCommerceSettings();
188 $this->couponBlockGenerator->init();
189 $this->productCollectionEmailRendererRegistrar->init();
190 $this->setupWoocommerceSystemInfo();
191 $this->setupFooter();
192 $this->setupSettingsLinkInPluginPage();
193 $this->setupChangeNotifications();
194 $this->setupSubscriberLimitNotifications();
195 $this->setupLicenseProvisioning();
196 $this->setupCaptchaOnRegisterForm();
197 $this->adminUserSubscription->setupHooks();
198 $this->deactivateMailPoetCronBeforePluginUpgrade();
199 }
200
201 public function initEarlyHooks() {
202 $this->setupMailer();
203 }
204
205 public function setupSubscriptionEvents() {
206 // In some cases on multisite instance, this code may run before DB migrator and settings table is not ready at that time
207 try {
208 $subscribe = $this->settings->get('subscribe', []);
209 } catch (\Exception $e) {
210 $subscribe = [];
211 }
212 // Subscribe in comments
213 if (
214 isset($subscribe['on_comment']['enabled'])
215 &&
216 (bool)$subscribe['on_comment']['enabled']
217 ) {
218 if ($this->wp->isUserLoggedIn()) {
219 $this->wp->addAction(
220 'comment_form_field_comment',
221 [$this->subscriptionComment, 'extendLoggedInForm']
222 );
223 } else {
224 $this->wp->addAction(
225 'comment_form_after_fields',
226 [$this->subscriptionComment, 'extendLoggedOutForm']
227 );
228 }
229
230 $this->wp->addAction(
231 'comment_post',
232 [$this->subscriptionComment, 'onSubmit'],
233 60,
234 2
235 );
236
237 $this->wp->addAction(
238 'wp_set_comment_status',
239 [$this->subscriptionComment, 'onStatusUpdate'],
240 60,
241 2
242 );
243 }
244
245 // Subscribe in registration form
246 if (
247 isset($subscribe['on_register']['enabled'])
248 &&
249 (bool)$subscribe['on_register']['enabled']
250 ) {
251 if (is_multisite()) {
252 $this->wp->addAction(
253 'signup_extra_fields',
254 [$this->subscriptionRegistration, 'extendForm']
255 );
256 $this->wp->addAction(
257 'wpmu_validate_user_signup',
258 [$this->subscriptionRegistration, 'onMultiSiteRegister'],
259 60,
260 1
261 );
262 } else {
263 $this->wp->addAction(
264 'register_form',
265 [$this->subscriptionRegistration, 'extendForm']
266 );
267 // we need to process new users while they are registered.
268 // We used `register_post` before but that is too soon
269 // because if registration fails during `registration_errors` we will keep the user as subscriber.
270 // So we are hooking to `registration_error` with a low priority.
271 $this->wp->addFilter(
272 'registration_errors',
273 [$this->subscriptionRegistration, 'onRegister'],
274 60,
275 3
276 );
277 }
278 $this->wp->addAction(
279 'woocommerce_register_form',
280 [$this->hooksWooCommerce, 'extendForm']
281 );
282 $this->wp->addFilter(
283 'woocommerce_registration_errors',
284 [$this->hooksWooCommerce, 'onRegister'],
285 60,
286 3
287 );
288 }
289
290 // Manage subscription
291 $this->wp->addAction(
292 'admin_post_mailpoet_subscription_update',
293 [$this->subscriptionManage, 'onSave']
294 );
295 $this->wp->addAction(
296 'admin_post_nopriv_mailpoet_subscription_update',
297 [$this->subscriptionManage, 'onSave']
298 );
299
300 // Subscription form
301 $this->wp->addAction(
302 'admin_post_mailpoet_subscription_form',
303 [$this->subscriptionForm, 'onSubmit']
304 );
305 $this->wp->addAction(
306 'admin_post_nopriv_mailpoet_subscription_form',
307 [$this->subscriptionForm, 'onSubmit']
308 );
309 $this->wp->addFilter(
310 'the_content',
311 [$this->displayFormInWPContent, 'contentDisplay']
312 );
313 $this->wp->addFilter(
314 'woocommerce_product_loop_end',
315 [$this->displayFormInWPContent, 'wooProductListDisplay']
316 );
317 $this->wp->addAction(
318 'wp_footer',
319 [$this->displayFormInWPContent, 'maybeRenderFormsInFooter']
320 );
321 }
322
323 public function setupMailer() {
324 $this->wp->addAction('plugins_loaded', [
325 $this->wordpressMailerReplacer,
326 'replaceWordPressMailer',
327 ]);
328 $this->wp->addAction('login_init', [
329 $this->wordpressMailerReplacer,
330 'replaceWordPressMailer',
331 ]);
332 $this->wp->addAction('lostpassword_post', [
333 $this->wordpressMailerReplacer,
334 'replaceWordPressMailer',
335 ]);
336 }
337
338 public function setupWooCommerceSubscriptionEvents() {
339 // In some cases on multisite instance, this code may run before DB migrator and settings table is not ready at that time
340 try {
341 $optInEnabled = (bool)$this->settings->get(Subscription::OPTIN_ENABLED_SETTING_NAME, false);
342 } catch (\Exception $e) {
343 $optInEnabled = false;
344 }
345 // WooCommerce: subscribe on checkout
346 if ($optInEnabled) {
347 $optInPosition = $this->settings->get(Subscription::OPTIN_POSITION_SETTING_NAME, self::DEFAULT_OPTIN_POSITION);
348 $optInHook = self::OPTIN_HOOKS[$optInPosition] ?? self::OPTIN_HOOKS[self::DEFAULT_OPTIN_POSITION];
349 $this->wp->addAction(
350 $optInHook,
351 [$this->hooksWooCommerce, 'extendWooCommerceCheckoutForm']
352 );
353
354 $this->wp->addAction(
355 'woocommerce_checkout_after_terms_and_conditions',
356 [$this->hooksWooCommerce, 'hideAutomateWooOptinCheckbox'],
357 5,
358 0
359 );
360 }
361
362 $this->wp->addAction(
363 'woocommerce_checkout_update_order_meta',
364 [$this->hooksWooCommerce, 'subscribeOnCheckout'],
365 10, // this should execute after the WC sync call on the same hook
366 2
367 );
368
369 $this->wp->addAction(
370 'woocommerce_before_pay_action',
371 [$this->hooksWooCommerce, 'subscribeOnOrderPay'],
372 10,
373 1
374 );
375 }
376
377 public function setupAutomateWooSubscriptionEvents() {
378 $this->automateWooHooks->setup();
379 }
380
381 public function setupWPUsers() {
382 // WP Users synchronization
383 $this->wp->addAction(
384 'user_register',
385 [$this->wpSegment, 'synchronizeUser'],
386 6
387 );
388 $this->wp->addAction(
389 'added_existing_user',
390 [$this->wpSegment, 'synchronizeUser'],
391 6
392 );
393 $this->wp->addAction(
394 'profile_update',
395 [$this->wpSegment, 'synchronizeUser'],
396 6,
397 2
398 );
399 $this->wp->addAction(
400 'add_user_role',
401 [$this->wpSegment, 'synchronizeUser'],
402 6,
403 1
404 );
405 $this->wp->addAction(
406 'set_user_role',
407 [$this->wpSegment, 'synchronizeUser'],
408 6,
409 1
410 );
411 $this->wp->addAction(
412 'delete_user',
413 [$this->wpSegment, 'synchronizeUser'],
414 1
415 );
416 // multisite
417 $this->wp->addAction(
418 'deleted_user',
419 [$this->wpSegment, 'synchronizeUser'],
420 1
421 );
422 $this->wp->addAction(
423 'remove_user_from_blog',
424 [$this->wpSegment, 'synchronizeUser'],
425 1
426 );
427
428 // login
429 $this->wp->addAction(
430 'wp_login',
431 [$this->subscriberHandler, 'identifyByLogin'],
432 10,
433 1
434 );
435 }
436
437 public function setupWooCommerceSettings() {
438 $this->wp->addAction('woocommerce_settings_email_options_after', [
439 $this->hooksWooCommerce,
440 'disableWooCommerceSettings',
441 ]);
442
443 $this->wp->addAction('before_woocommerce_init', [
444 $this->hooksWooCommerce,
445 'declareWooCompatibility',
446 ]);
447
448 $this->wp->addAction('init', [
449 $this->hooksWooCommerce,
450 'addMailPoetTaskToWooHomePage',
451 ]);
452
453 $this->wp->addFilter(
454 'woocommerce_marketing_channels',
455 [$this->hooksWooCommerce, 'addMailPoetMarketingMultiChannel'],
456 10,
457 1
458 );
459 }
460
461 public function setupWoocommerceSystemInfo() {
462 $this->wp->addAction(
463 'woocommerce_system_status_report',
464 [
465 $this->wooSystemInfoController,
466 'render',
467 ]
468 );
469 $this->wp->addAction(
470 'woocommerce_rest_prepare_system_status',
471 [
472 $this->wooSystemInfoController,
473 'addFields',
474 ]
475 );
476 $this->wp->addAction(
477 'woocommerce_rest_system_status_schema',
478 [
479 $this->wooSystemInfoController,
480 'addSchema',
481 ]
482 );
483 }
484
485 public function setupWooCommerceUsers() {
486 // WooCommerce Customers synchronization
487 $this->wp->addAction(
488 'woocommerce_created_customer',
489 [$this->hooksWooCommerce, 'synchronizeRegisteredCustomer'],
490 7
491 );
492 $this->wp->addAction(
493 'woocommerce_new_customer',
494 [$this->hooksWooCommerce, 'synchronizeRegisteredCustomer'],
495 7
496 );
497 $this->wp->addAction(
498 'woocommerce_update_customer',
499 [$this->hooksWooCommerce, 'synchronizeRegisteredCustomer'],
500 7
501 );
502 $this->wp->addAction(
503 'woocommerce_delete_customer',
504 [$this->hooksWooCommerce, 'synchronizeRegisteredCustomer'],
505 7
506 );
507 $this->wp->addAction(
508 'woocommerce_checkout_update_order_meta',
509 [$this->hooksWooCommerce, 'synchronizeGuestCustomer'],
510 7
511 );
512 $this->wp->addAction(
513 'woocommerce_process_shop_order_meta',
514 [$this->hooksWooCommerce, 'synchronizeGuestCustomer'],
515 7
516 );
517 }
518
519 public function setupWooCommercePurchases() {
520 $this->wp->addAction(
521 'woocommerce_order_status_changed',
522 [$this->hooksWooCommerce, 'trackPurchase'],
523 10,
524 1
525 );
526
527 $this->wp->addAction(
528 'woocommerce_order_refunded',
529 [$this->hooksWooCommerce, 'trackRefund'],
530 10,
531 1
532 );
533 }
534
535 public function setupWooCommerceOrderAttribution() {
536 // The reconciliation boundary must be persisted before any post-activation
537 // order exists, and on the init hook because this setup runs on
538 // plugins_loaded, where WooCommerce may not be loaded yet
539 $this->wp->addAction(
540 'init',
541 [$this->hooksWooCommerce, 'markAttributionWritesStarted']
542 );
543 // After Woo's own priority-10 handler so the resolved values overwrite
544 // the empty placeholders Woo persists from the checkout form
545 $this->wp->addAction(
546 'woocommerce_order_save_attribution_data',
547 [$this->hooksWooCommerce, 'writeOrderAttribution'],
548 20
549 );
550 // Admin and REST orders; gated inside to stay out of storefront checkout
551 $this->wp->addAction(
552 'woocommerce_new_order',
553 [$this->hooksWooCommerce, 'writeOrderAttributionForNewOrder'],
554 20
555 );
556 $this->wp->addAction(
557 'woocommerce_order_status_changed',
558 [$this->hooksWooCommerce, 'writeOrderAttribution'],
559 10,
560 1
561 );
562 // After WC_Meta_Box_Order_Data::save (priority 40) so the billing email is saved
563 $this->wp->addAction(
564 'woocommerce_process_shop_order_meta',
565 [$this->hooksWooCommerce, 'writeOrderAttribution'],
566 50
567 );
568 }
569
570 public function setupWooCommerceSubscriberEngagement() {
571 $this->wp->addAction(
572 'woocommerce_new_order',
573 [$this->hooksWooCommerce, 'updateSubscriberEngagement'],
574 7
575 );
576 // See class-wc-order.php, which says this about this action
577 // "Fires when the order progresses from a pending payment status to a paid one"
578 $this->wp->addAction(
579 'woocommerce_order_payment_status_changed',
580 [$this->hooksWooCommerce, 'updateSubscriberLastPurchase']
581 );
582 }
583
584 public function setupWooCommerceTracking() {
585 $this->wp->addFilter(
586 'woocommerce_tracker_data',
587 [$this->hooksWooCommerce, 'addTrackingData'],
588 10
589 );
590 }
591
592 public function setupPostNotifications() {
593 $this->wp->addAction(
594 'transition_post_status',
595 [$this->postNotificationScheduler, 'transitionHook'],
596 10,
597 3
598 );
599 }
600
601 public function setupFooter() {
602 // Register AJAX handler on all admin pages (AJAX requests go to admin-ajax.php)
603 $this->wp->addAction(
604 'wp_ajax_mailpoet_rated',
605 [$this, 'setFooterRated']
606 );
607
608 // Register hooks that will check the page later
609 $this->wp->addFilter(
610 'admin_footer_text',
611 [$this, 'setFooter'],
612 1,
613 1
614 );
615 $this->wp->addAction(
616 'admin_enqueue_scripts',
617 [$this, 'enqueueFooterRatingScript']
618 );
619 }
620
621 public function enqueueFooterRatingScript(): void {
622 // Only show on MailPoet pages
623 if (!Menu::isOnMailPoetAdminPage()) {
624 return;
625 }
626
627 if (Menu::isOnMailPoetAutomationPage()) {
628 return;
629 }
630
631 if (!$this->wp->getOption(self::FOOTER_RATED_OPTION)) {
632 $handle = 'mailpoet-admin-footer-rating';
633 $this->wp->wpRegisterScript($handle, false, [], Env::$version, true);
634 $this->wp->wpEnqueueScript($handle);
635
636 $nonce = $this->wp->wpCreateNonce('mailpoet-rated');
637
638 $script = "(function() {
639 'use strict';
640 var ratingLink = document.querySelector('a.mailpoet-rating-link');
641 if (ratingLink) {
642 ratingLink.addEventListener('click', function(e) {
643 var link = e.currentTarget;
644 var formData = new FormData();
645 formData.append('action', 'mailpoet_rated');
646 formData.append('nonce', '" . esc_js($nonce) . "');
647
648 fetch('" . esc_js(admin_url('admin-ajax.php')) . "', {
649 method: 'POST',
650 body: formData,
651 credentials: 'same-origin'
652 });
653
654 if (link) {
655 link.textContent = link.getAttribute('data-rated');
656 }
657 });
658 }
659 })();";
660
661 $this->wp->wpAddInlineScript($handle, $script);
662 }
663 }
664
665 public function setFooter(): string {
666 // Only show footer on MailPoet pages
667 if (!Menu::isOnMailPoetAdminPage()) {
668 return '';
669 }
670
671 if (Menu::isOnMailPoetAutomationPage()) {
672 return '';
673 }
674
675 $feedbackLink = '<a href="https://feedback.mailpoet.com/" rel="noopener noreferrer" target="_blank">' . esc_html__('Give feedback', 'mailpoet') . '</a>';
676
677 if (!$this->wp->getOption(self::FOOTER_RATED_OPTION)) {
678 $reviewLink = '<a href="https://wordpress.org/support/plugin/mailpoet/reviews/#new-post" rel="noopener noreferrer" target="_blank" class="mailpoet-rating-link" aria-label="' . esc_attr__('five star', 'mailpoet') . '" data-rated="' . esc_attr__('Thanks :)', 'mailpoet') . '">' . esc_html__('Help other businesses grow their email lists – share your �
679
680
681
682
683 MailPoet experience!', 'mailpoet') . '</a>';
684
685 return $reviewLink . ' | ' . $feedbackLink;
686 } else {
687 return esc_html__('Thank you for using MailPoet.', 'mailpoet') . ' | ' . $feedbackLink;
688 }
689 }
690
691 public function setFooterRated(): void {
692 if (!$this->wp->currentUserCan('manage_options')) {
693 $this->wp->wpDie(
694 esc_html__('You do not have permission to perform this action.', 'mailpoet'),
695 esc_html__('Unauthorized', 'mailpoet'),
696 ['response' => 403]
697 );
698 }
699
700 $nonce = isset($_POST['nonce']) && is_string($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
701
702 if (!$this->wp->wpVerifyNonce($nonce, 'mailpoet-rated')) {
703 $this->wp->wpDie(
704 esc_html__('Security check failed.', 'mailpoet'),
705 esc_html__('Error', 'mailpoet'),
706 ['response' => 403]
707 );
708 }
709
710 $this->wp->updateOption(self::FOOTER_RATED_OPTION, 1);
711 $this->wp->wpDie();
712 }
713
714 public function setupSettingsLinkInPluginPage() {
715 $this->wp->addFilter(
716 'plugin_action_links_' . Env::$pluginPath,
717 [$this, 'setSettingsLinkInPluginPage']
718 );
719 }
720
721 /**
722 * @param array<string, string> $actionLinks
723 * @return array<string, string>
724 */
725 public function setSettingsLinkInPluginPage(array $actionLinks): array {
726 $customLinks = [
727 'settings' => '<a href="' . $this->wp->adminUrl('admin.php?page=mailpoet-settings') . '" aria-label="' . $this->wp->escAttr(__('View MailPoet settings', 'mailpoet')) . '">' . $this->wp->escHtml(__('Settings', 'mailpoet')) . '</a>',
728 ];
729
730 return array_merge($customLinks, $actionLinks);
731 }
732
733 public function setupChangeNotifications(): void {
734 $this->wp->addAction(
735 'shutdown',
736 [$this->subscriberChangesNotifier, 'notify']
737 );
738 }
739
740 public function setupSubscriberLimitNotifications(): void {
741 $this->subscriberLimitNotificationScheduler->setupHooks();
742 }
743
744 public function setupLicenseProvisioning(): void {
745 $this->wp->addFilter(
746 'wpcom_marketplace_webhook_response_mailpoet-business',
747 [$this->dotcomLicenseProvisioner, 'provisionLicense'],
748 10,
749 3
750 );
751 }
752
753 // CAPTCHA on WP & WC registration forms
754 public function setupCaptchaOnRegisterForm(): void {
755 if ($this->captchaHooks->isEnabled()) {
756 $this->wp->addAction(
757 'register_form',
758 [$this->captchaHooks, 'renderInWPRegisterForm']
759 );
760
761 $this->wp->addAction(
762 'registration_errors',
763 [$this->captchaHooks, 'validate'],
764 10,
765 3
766 );
767
768 if ($this->wooHelper->isWooCommerceActive()) {
769 $this->wp->addAction(
770 'woocommerce_register_form',
771 [$this->captchaHooks, 'renderInWCRegisterForm']
772 );
773
774 $this->wp->addFilter(
775 'woocommerce_process_registration_errors',
776 [$this->captchaHooks, 'validate'],
777 10,
778 3
779 );
780 }
781 } else if ($this->reCaptchaHooks->isEnabled()) {
782 $this->wp->addAction(
783 'login_enqueue_scripts',
784 [$this->reCaptchaHooks, 'enqueueScripts']
785 );
786
787 $this->wp->addAction(
788 'register_form',
789 [$this->reCaptchaHooks, 'render']
790 );
791
792 $this->wp->addFilter(
793 'registration_errors',
794 [$this->reCaptchaHooks, 'validate'],
795 10,
796 3
797 );
798
799 if ($this->wooHelper->isWooCommerceActive()) {
800 $this->wp->addAction(
801 'woocommerce_before_customer_login_form',
802 [$this->reCaptchaHooks, 'enqueueScripts']
803 );
804
805 $this->wp->addAction(
806 'woocommerce_register_form',
807 [$this->reCaptchaHooks, 'render']
808 );
809
810 $this->wp->addAction(
811 'woocommerce_process_registration_errors',
812 [$this->reCaptchaHooks, 'validate']
813 );
814 }
815 } else if ($this->turnstileHooks->isEnabled()) {
816 $this->wp->addAction(
817 'login_enqueue_scripts',
818 [$this->turnstileHooks, 'enqueueScripts']
819 );
820
821 $this->wp->addAction(
822 'register_form',
823 [$this->turnstileHooks, 'render']
824 );
825
826 $this->wp->addFilter(
827 'registration_errors',
828 [$this->turnstileHooks, 'validate'],
829 10,
830 3
831 );
832
833 if ($this->wooHelper->isWooCommerceActive()) {
834 $this->wp->addAction(
835 'woocommerce_before_customer_login_form',
836 [$this->turnstileHooks, 'enqueueScripts']
837 );
838
839 $this->wp->addAction(
840 'woocommerce_register_form',
841 [$this->turnstileHooks, 'render']
842 );
843
844 $this->wp->addAction(
845 'woocommerce_process_registration_errors',
846 [$this->turnstileHooks, 'validate']
847 );
848 }
849 }
850 }
851
852 public function deactivateMailPoetCronBeforePluginUpgrade(): void {
853 $this->wp->addFilter(
854 'upgrader_pre_install',
855 [$this, 'deactivateCronActions'],
856 10,
857 2
858 );
859
860 $this->wp->addAction(
861 'action_scheduler_before_process_queue',
862 [$this, 'deactivateCronWhenInMaintenanceMode']
863 );
864 }
865
866 /**
867 * Deactivates the MailPoet Cron actions.
868 *
869 * Hooked to the 'upgrader_pre_install' filter
870 *
871 * The cron will be reactivated automatically later in Initializer::initialize -> setupCronTrigger()
872 *
873 * @param bool|\WP_Error $response The installation response before the installation has started.
874 * @param array $plugin Plugin package arguments.
875 * @return bool|\WP_Error The original `$response` parameter or WP_Error.
876 */
877 public function deactivateCronActions($response, array $plugin) {
878 if (is_wp_error($response)) { // skip
879 return $response;
880 }
881
882 $pluginId = $plugin['plugin'] ?? '';
883
884 if ($pluginId !== Env::$pluginPath) {
885 // not updating MailPoet;
886 return $response;
887 }
888
889 $this->cronTrigger->disable();
890
891 return $response;
892 }
893
894 public function deactivateCronWhenInMaintenanceMode(): void {
895 if (!$this->wp->wpIsMaintenanceMode()) {
896 return;
897 }
898
899 $this->wp->addFilter('action_scheduler_queue_runner_batch_size', function () {
900 // return 0 batch sizes to prevent the queue runner from running;
901 // this is the fastest way to stop the current running cron
902 return 0;
903 });
904
905 $this->cronTrigger->disable();
906 }
907 }
908