PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.37.0
MailPoet – Newsletters, Email Marketing, and Automation v5.37.0
5.37.0 5.36.1 5.36.0 5.35.1 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 4 months ago AccessControl.php 2 years ago Activator.php 3 months ago AssetsLoader.php 3 weeks ago Capabilities.php 4 months ago Changelog.php 4 months ago DeactivationPoll.php 3 years ago DeferredAdminNotices.php 3 months ago Env.php 7 months ago Hooks.php 5 days ago HooksWooCommerce.php 2 months ago Initializer.php 5 days ago Installer.php 1 year ago Localizer.php 1 month ago Menu.php 2 months ago PersonalDataErasers.php 2 months ago PersonalDataExporters.php 2 months ago PluginActivatedHook.php 3 years ago Populator.php 1 month ago PrivacyPolicy.php 2 months ago Renderer.php 2 years ago RendererFactory.php 3 years ago RequirementsChecker.php 3 months ago Router.php 4 months ago ServicesChecker.php 3 years ago Shortcodes.php 1 month ago SilentUpgraderSkin.php 3 years ago SubscriberChangesNotifier.php 3 months ago TranslationUpdater.php 4 months ago TwigEnvironment.php 1 year ago TwigFileSystemCache.php 3 years ago Updater.php 1 month ago index.php 3 years ago
Hooks.php
922 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 'user_register',
396 [$this->subscriptionRegistration, 'applyTrackingConsentOnUserRegister'],
397 7
398 );
399 $this->wp->addAction(
400 'added_existing_user',
401 [$this->wpSegment, 'synchronizeUser'],
402 6
403 );
404 $this->wp->addAction(
405 'profile_update',
406 [$this->wpSegment, 'synchronizeUser'],
407 6,
408 2
409 );
410 $this->wp->addAction(
411 'add_user_role',
412 [$this->wpSegment, 'synchronizeUser'],
413 6,
414 1
415 );
416 $this->wp->addAction(
417 'set_user_role',
418 [$this->wpSegment, 'synchronizeUser'],
419 6,
420 1
421 );
422 $this->wp->addAction(
423 'delete_user',
424 [$this->wpSegment, 'synchronizeUser'],
425 1
426 );
427 // multisite
428 $this->wp->addAction(
429 'deleted_user',
430 [$this->wpSegment, 'synchronizeUser'],
431 1
432 );
433 $this->wp->addAction(
434 'remove_user_from_blog',
435 [$this->wpSegment, 'synchronizeUser'],
436 1
437 );
438
439 // Warn on the delete-user confirmation screen that the subscriber is kept.
440 $this->wpUserDeleteNotice->setupHooks();
441
442 // login
443 $this->wp->addAction(
444 'wp_login',
445 [$this->subscriberHandler, 'identifyByLogin'],
446 10,
447 1
448 );
449 }
450
451 public function setupWooCommerceSettings() {
452 $this->wp->addAction('woocommerce_settings_email_options_after', [
453 $this->hooksWooCommerce,
454 'disableWooCommerceSettings',
455 ]);
456
457 $this->wp->addAction('before_woocommerce_init', [
458 $this->hooksWooCommerce,
459 'declareWooCompatibility',
460 ]);
461
462 $this->wp->addAction('init', [
463 $this->hooksWooCommerce,
464 'addMailPoetTaskToWooHomePage',
465 ]);
466
467 $this->wp->addFilter(
468 'woocommerce_marketing_channels',
469 [$this->hooksWooCommerce, 'addMailPoetMarketingMultiChannel'],
470 10,
471 1
472 );
473 }
474
475 public function setupWoocommerceSystemInfo() {
476 $this->wp->addAction(
477 'woocommerce_system_status_report',
478 [
479 $this->wooSystemInfoController,
480 'render',
481 ]
482 );
483 $this->wp->addAction(
484 'woocommerce_rest_prepare_system_status',
485 [
486 $this->wooSystemInfoController,
487 'addFields',
488 ]
489 );
490 $this->wp->addAction(
491 'woocommerce_rest_system_status_schema',
492 [
493 $this->wooSystemInfoController,
494 'addSchema',
495 ]
496 );
497 }
498
499 public function setupWooCommerceUsers() {
500 // WooCommerce Customers synchronization
501 $this->wp->addAction(
502 'woocommerce_created_customer',
503 [$this->hooksWooCommerce, 'synchronizeRegisteredCustomer'],
504 7
505 );
506 $this->wp->addAction(
507 'woocommerce_new_customer',
508 [$this->hooksWooCommerce, 'synchronizeRegisteredCustomer'],
509 7
510 );
511 $this->wp->addAction(
512 'woocommerce_update_customer',
513 [$this->hooksWooCommerce, 'synchronizeRegisteredCustomer'],
514 7
515 );
516 $this->wp->addAction(
517 'woocommerce_delete_customer',
518 [$this->hooksWooCommerce, 'synchronizeRegisteredCustomer'],
519 7
520 );
521 $this->wp->addAction(
522 'woocommerce_checkout_update_order_meta',
523 [$this->hooksWooCommerce, 'synchronizeGuestCustomer'],
524 7
525 );
526 $this->wp->addAction(
527 'woocommerce_process_shop_order_meta',
528 [$this->hooksWooCommerce, 'synchronizeGuestCustomer'],
529 7
530 );
531 }
532
533 public function setupWooCommercePurchases() {
534 $this->wp->addAction(
535 'woocommerce_order_status_changed',
536 [$this->hooksWooCommerce, 'trackPurchase'],
537 10,
538 1
539 );
540
541 $this->wp->addAction(
542 'woocommerce_order_refunded',
543 [$this->hooksWooCommerce, 'trackRefund'],
544 10,
545 1
546 );
547 }
548
549 public function setupWooCommerceOrderAttribution() {
550 // The reconciliation boundary must be persisted before any post-activation
551 // order exists, and on the init hook because this setup runs on
552 // plugins_loaded, where WooCommerce may not be loaded yet
553 $this->wp->addAction(
554 'init',
555 [$this->hooksWooCommerce, 'markAttributionWritesStarted']
556 );
557 // After Woo's own priority-10 handler so the resolved values overwrite
558 // the empty placeholders Woo persists from the checkout form
559 $this->wp->addAction(
560 'woocommerce_order_save_attribution_data',
561 [$this->hooksWooCommerce, 'writeOrderAttribution'],
562 20
563 );
564 // Admin and REST orders; gated inside to stay out of storefront checkout
565 $this->wp->addAction(
566 'woocommerce_new_order',
567 [$this->hooksWooCommerce, 'writeOrderAttributionForNewOrder'],
568 20
569 );
570 $this->wp->addAction(
571 'woocommerce_order_status_changed',
572 [$this->hooksWooCommerce, 'writeOrderAttribution'],
573 10,
574 1
575 );
576 // After WC_Meta_Box_Order_Data::save (priority 40) so the billing email is saved
577 $this->wp->addAction(
578 'woocommerce_process_shop_order_meta',
579 [$this->hooksWooCommerce, 'writeOrderAttribution'],
580 50
581 );
582 }
583
584 public function setupWooCommerceSubscriberEngagement() {
585 $this->wp->addAction(
586 'woocommerce_new_order',
587 [$this->hooksWooCommerce, 'updateSubscriberEngagement'],
588 7
589 );
590 // See class-wc-order.php, which says this about this action
591 // "Fires when the order progresses from a pending payment status to a paid one"
592 $this->wp->addAction(
593 'woocommerce_order_payment_status_changed',
594 [$this->hooksWooCommerce, 'updateSubscriberLastPurchase']
595 );
596 }
597
598 public function setupWooCommerceTracking() {
599 $this->wp->addFilter(
600 'woocommerce_tracker_data',
601 [$this->hooksWooCommerce, 'addTrackingData'],
602 10
603 );
604 }
605
606 public function setupPostNotifications() {
607 $this->wp->addAction(
608 'transition_post_status',
609 [$this->postNotificationScheduler, 'transitionHook'],
610 10,
611 3
612 );
613 }
614
615 public function setupFooter() {
616 // Register AJAX handler on all admin pages (AJAX requests go to admin-ajax.php)
617 $this->wp->addAction(
618 'wp_ajax_mailpoet_rated',
619 [$this, 'setFooterRated']
620 );
621
622 // Register hooks that will check the page later
623 $this->wp->addFilter(
624 'admin_footer_text',
625 [$this, 'setFooter'],
626 1,
627 1
628 );
629 $this->wp->addAction(
630 'admin_enqueue_scripts',
631 [$this, 'enqueueFooterRatingScript']
632 );
633 }
634
635 public function enqueueFooterRatingScript(): void {
636 // Only show on MailPoet pages
637 if (!Menu::isOnMailPoetAdminPage()) {
638 return;
639 }
640
641 if (Menu::isOnMailPoetAutomationPage()) {
642 return;
643 }
644
645 if (!$this->wp->getOption(self::FOOTER_RATED_OPTION)) {
646 $handle = 'mailpoet-admin-footer-rating';
647 $this->wp->wpRegisterScript($handle, false, [], Env::$version, true);
648 $this->wp->wpEnqueueScript($handle);
649
650 $nonce = $this->wp->wpCreateNonce('mailpoet-rated');
651
652 $script = "(function() {
653 'use strict';
654 var ratingLink = document.querySelector('a.mailpoet-rating-link');
655 if (ratingLink) {
656 ratingLink.addEventListener('click', function(e) {
657 var link = e.currentTarget;
658 var formData = new FormData();
659 formData.append('action', 'mailpoet_rated');
660 formData.append('nonce', '" . esc_js($nonce) . "');
661
662 fetch('" . esc_js(admin_url('admin-ajax.php')) . "', {
663 method: 'POST',
664 body: formData,
665 credentials: 'same-origin'
666 });
667
668 if (link) {
669 link.textContent = link.getAttribute('data-rated');
670 }
671 });
672 }
673 })();";
674
675 $this->wp->wpAddInlineScript($handle, $script);
676 }
677 }
678
679 public function setFooter(): string {
680 // Only show footer on MailPoet pages
681 if (!Menu::isOnMailPoetAdminPage()) {
682 return '';
683 }
684
685 if (Menu::isOnMailPoetAutomationPage()) {
686 return '';
687 }
688
689 $feedbackLink = '<a href="https://feedback.mailpoet.com/" rel="noopener noreferrer" target="_blank">' . esc_html__('Give feedback', 'mailpoet') . '</a>';
690
691 if (!$this->wp->getOption(self::FOOTER_RATED_OPTION)) {
692 $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 �
693
694
695
696
697 MailPoet experience!', 'mailpoet') . '</a>';
698
699 return $reviewLink . ' | ' . $feedbackLink;
700 } else {
701 return esc_html__('Thank you for using MailPoet.', 'mailpoet') . ' | ' . $feedbackLink;
702 }
703 }
704
705 public function setFooterRated(): void {
706 if (!$this->wp->currentUserCan('manage_options')) {
707 $this->wp->wpDie(
708 esc_html__('You do not have permission to perform this action.', 'mailpoet'),
709 esc_html__('Unauthorized', 'mailpoet'),
710 ['response' => 403]
711 );
712 }
713
714 $nonce = isset($_POST['nonce']) && is_string($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
715
716 if (!$this->wp->wpVerifyNonce($nonce, 'mailpoet-rated')) {
717 $this->wp->wpDie(
718 esc_html__('Security check failed.', 'mailpoet'),
719 esc_html__('Error', 'mailpoet'),
720 ['response' => 403]
721 );
722 }
723
724 $this->wp->updateOption(self::FOOTER_RATED_OPTION, 1);
725 $this->wp->wpDie();
726 }
727
728 public function setupSettingsLinkInPluginPage() {
729 $this->wp->addFilter(
730 'plugin_action_links_' . Env::$pluginPath,
731 [$this, 'setSettingsLinkInPluginPage']
732 );
733 }
734
735 /**
736 * @param array<string, string> $actionLinks
737 * @return array<string, string>
738 */
739 public function setSettingsLinkInPluginPage(array $actionLinks): array {
740 $customLinks = [
741 '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>',
742 ];
743
744 return array_merge($customLinks, $actionLinks);
745 }
746
747 public function setupChangeNotifications(): void {
748 $this->wp->addAction(
749 'shutdown',
750 [$this->subscriberChangesNotifier, 'notify']
751 );
752 }
753
754 public function setupSubscriberLimitNotifications(): void {
755 $this->subscriberLimitNotificationScheduler->setupHooks();
756 }
757
758 public function setupLicenseProvisioning(): void {
759 $this->wp->addFilter(
760 'wpcom_marketplace_webhook_response_mailpoet-business',
761 [$this->dotcomLicenseProvisioner, 'provisionLicense'],
762 10,
763 3
764 );
765 }
766
767 // CAPTCHA on WP & WC registration forms
768 public function setupCaptchaOnRegisterForm(): void {
769 if ($this->captchaHooks->isEnabled()) {
770 $this->wp->addAction(
771 'register_form',
772 [$this->captchaHooks, 'renderInWPRegisterForm']
773 );
774
775 $this->wp->addAction(
776 'registration_errors',
777 [$this->captchaHooks, 'validate'],
778 10,
779 3
780 );
781
782 if ($this->wooHelper->isWooCommerceActive()) {
783 $this->wp->addAction(
784 'woocommerce_register_form',
785 [$this->captchaHooks, 'renderInWCRegisterForm']
786 );
787
788 $this->wp->addFilter(
789 'woocommerce_process_registration_errors',
790 [$this->captchaHooks, 'validate'],
791 10,
792 3
793 );
794 }
795 } else if ($this->reCaptchaHooks->isEnabled()) {
796 $this->wp->addAction(
797 'login_enqueue_scripts',
798 [$this->reCaptchaHooks, 'enqueueScripts']
799 );
800
801 $this->wp->addAction(
802 'register_form',
803 [$this->reCaptchaHooks, 'render']
804 );
805
806 $this->wp->addFilter(
807 'registration_errors',
808 [$this->reCaptchaHooks, 'validate'],
809 10,
810 3
811 );
812
813 if ($this->wooHelper->isWooCommerceActive()) {
814 $this->wp->addAction(
815 'woocommerce_before_customer_login_form',
816 [$this->reCaptchaHooks, 'enqueueScripts']
817 );
818
819 $this->wp->addAction(
820 'woocommerce_register_form',
821 [$this->reCaptchaHooks, 'render']
822 );
823
824 $this->wp->addAction(
825 'woocommerce_process_registration_errors',
826 [$this->reCaptchaHooks, 'validate']
827 );
828 }
829 } else if ($this->turnstileHooks->isEnabled()) {
830 $this->wp->addAction(
831 'login_enqueue_scripts',
832 [$this->turnstileHooks, 'enqueueScripts']
833 );
834
835 $this->wp->addAction(
836 'register_form',
837 [$this->turnstileHooks, 'render']
838 );
839
840 $this->wp->addFilter(
841 'registration_errors',
842 [$this->turnstileHooks, 'validate'],
843 10,
844 3
845 );
846
847 if ($this->wooHelper->isWooCommerceActive()) {
848 $this->wp->addAction(
849 'woocommerce_before_customer_login_form',
850 [$this->turnstileHooks, 'enqueueScripts']
851 );
852
853 $this->wp->addAction(
854 'woocommerce_register_form',
855 [$this->turnstileHooks, 'render']
856 );
857
858 $this->wp->addAction(
859 'woocommerce_process_registration_errors',
860 [$this->turnstileHooks, 'validate']
861 );
862 }
863 }
864 }
865
866 public function deactivateMailPoetCronBeforePluginUpgrade(): void {
867 $this->wp->addFilter(
868 'upgrader_pre_install',
869 [$this, 'deactivateCronActions'],
870 10,
871 2
872 );
873
874 $this->wp->addAction(
875 'action_scheduler_before_process_queue',
876 [$this, 'deactivateCronWhenInMaintenanceMode']
877 );
878 }
879
880 /**
881 * Deactivates the MailPoet Cron actions.
882 *
883 * Hooked to the 'upgrader_pre_install' filter
884 *
885 * The cron will be reactivated automatically later in Initializer::initialize -> setupCronTrigger()
886 *
887 * @param bool|\WP_Error $response The installation response before the installation has started.
888 * @param array $plugin Plugin package arguments.
889 * @return bool|\WP_Error The original `$response` parameter or WP_Error.
890 */
891 public function deactivateCronActions($response, array $plugin) {
892 if (is_wp_error($response)) { // skip
893 return $response;
894 }
895
896 $pluginId = $plugin['plugin'] ?? '';
897
898 if ($pluginId !== Env::$pluginPath) {
899 // not updating MailPoet;
900 return $response;
901 }
902
903 $this->cronTrigger->disable();
904
905 return $response;
906 }
907
908 public function deactivateCronWhenInMaintenanceMode(): void {
909 if (!$this->wp->wpIsMaintenanceMode()) {
910 return;
911 }
912
913 $this->wp->addFilter('action_scheduler_queue_runner_batch_size', function () {
914 // return 0 batch sizes to prevent the queue runner from running;
915 // this is the fastest way to stop the current running cron
916 return 0;
917 });
918
919 $this->cronTrigger->disable();
920 }
921 }
922