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