diff --git a/lib/Config/Hooks.php b/lib/Config/Hooks.php index bb63fcee03..a0ec6d25b4 100644 --- a/lib/Config/Hooks.php +++ b/lib/Config/Hooks.php @@ -8,6 +8,7 @@ use MailPoet\Subscription\Comment; use MailPoet\Subscription\Form; use MailPoet\Subscription\Registration; use MailPoet\Segments\WooCommerce as WooCommerceSegment; +use MailPoet\WooCommerce\Subscription as WooCommerceSubscription; use MailPoet\WP\Functions as WPFunctions; class Hooks { @@ -27,6 +28,9 @@ class Hooks { /** @var WPFunctions */ private $wp; + /** @var WooCommerceSubscription */ + private $woocommerce_subscription; + /** @var WooCommerceSegment */ private $woocommerce_segment; @@ -39,6 +43,7 @@ class Hooks { Registration $subscription_registration, SettingsController $settings, WPFunctions $wp, + WooCommerceSubscription $woocommerce_subscription, WooCommerceSegment $woocommerce_segment, WooCommercePurchases $woocommerce_purchases ) { @@ -47,6 +52,7 @@ class Hooks { $this->subscription_registration = $subscription_registration; $this->settings = $settings; $this->wp = $wp; + $this->woocommerce_subscription = $woocommerce_subscription; $this->woocommerce_segment = $woocommerce_segment; $this->woocommerce_purchases = $woocommerce_purchases; } @@ -58,6 +64,7 @@ class Hooks { $this->setupImageSize(); $this->setupListing(); $this->setupSubscriptionEvents(); + $this->setupWooCommerceSubscriptionEvents(); $this->setupPostNotifications(); } @@ -149,6 +156,25 @@ class Hooks { ); } + function setupWooCommerceSubscriptionEvents() { + + $woocommerce = $this->settings->get('woocommerce', []); + // WooCommerce: subscribe on checkout + if (!empty($woocommerce['optin_on_checkout']['enabled'])) { + $this->wp->addAction( + 'woocommerce_checkout_before_terms_and_conditions', + [$this->woocommerce_subscription, 'extendWooCommerceCheckoutForm'] + ); + } + + $this->wp->addAction( + 'woocommerce_checkout_update_order_meta', + [$this->woocommerce_subscription, 'subscribeOnCheckout'], + 10, // this should execute after the WC sync call on the same hook + 2 + ); + } + function setupWPUsers() { // WP Users synchronization $this->wp->addAction( diff --git a/lib/Config/Migrator.php b/lib/Config/Migrator.php index 5fdcea3b6e..f57c5d9cad 100644 --- a/lib/Config/Migrator.php +++ b/lib/Config/Migrator.php @@ -202,7 +202,7 @@ class Migrator { 'updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', 'deleted_at timestamp NULL,', 'unconfirmed_data longtext,', - "source enum('form','imported','administrator','api','wordpress_user','woocommerce_user','unknown') DEFAULT 'unknown',", + "source enum('form','imported','administrator','api','wordpress_user','woocommerce_user','woocommerce_checkout','unknown') DEFAULT 'unknown',", 'count_confirmations int(11) unsigned NOT NULL DEFAULT 0,', 'PRIMARY KEY (id),', 'UNIQUE KEY email (email),', diff --git a/lib/DI/ContainerConfigurator.php b/lib/DI/ContainerConfigurator.php index fb50228132..76f88e2a21 100644 --- a/lib/DI/ContainerConfigurator.php +++ b/lib/DI/ContainerConfigurator.php @@ -108,6 +108,7 @@ class ContainerConfigurator implements IContainerConfigurator { $container->autowire(\MailPoet\Newsletter\AutomatedLatestContent::class)->setPublic(true); // WooCommerce $container->autowire(\MailPoet\WooCommerce\Helper::class)->setPublic(true); + $container->autowire(\MailPoet\WooCommerce\Subscription::class)->setPublic(true); // WordPress $container->autowire(\MailPoet\WP\Functions::class)->setPublic(true); return $container; diff --git a/lib/Models/SubscriberSegment.php b/lib/Models/SubscriberSegment.php index 934ec7db6a..86260c969c 100644 --- a/lib/Models/SubscriberSegment.php +++ b/lib/Models/SubscriberSegment.php @@ -4,6 +4,13 @@ namespace MailPoet\Models; if (!defined('ABSPATH')) exit; +/** + * @property int $id + * @property int $subscriber_id + * @property int $segment_id + * @property string $status + */ + class SubscriberSegment extends Model { public static $_table = MP_SUBSCRIBER_SEGMENT_TABLE; diff --git a/lib/Subscribers/Source.php b/lib/Subscribers/Source.php index 5c34964204..5e6e6ee552 100644 --- a/lib/Subscribers/Source.php +++ b/lib/Subscribers/Source.php @@ -12,6 +12,7 @@ class Source { const API = 'api'; const WORDPRESS_USER = 'wordpress_user'; const WOOCOMMERCE_USER = 'woocommerce_user'; + const WOOCOMMERCE_CHECKOUT = 'woocommerce_checkout'; const UNKNOWN = 'unknown'; private static $allowed_sources = array( @@ -21,6 +22,7 @@ class Source { Source::API, Source::WORDPRESS_USER, Source::WOOCOMMERCE_USER, + Source::WOOCOMMERCE_CHECKOUT, Source::UNKNOWN, ); diff --git a/lib/WooCommerce/Subscription.php b/lib/WooCommerce/Subscription.php new file mode 100644 index 0000000000..87935d9323 --- /dev/null +++ b/lib/WooCommerce/Subscription.php @@ -0,0 +1,112 @@ +settings = $settings; + $this->wp = $wp; + } + + function extendWooCommerceCheckoutForm() { + $input_name = self::CHECKOUT_OPTIN_INPUT_NAME; + $checked = $this->isCurrentUserSubscribed(); + $label_string = $this->settings->get(self::OPTIN_MESSAGE_SETTING_NAME); + $template = $this->wp->applyFilters( + 'mailpoet_woocommerce_checkout_optin_template', + $this->getSubscriptionField($input_name, $checked, $label_string), + $input_name, + $checked, + $label_string + ); + echo $template; + } + + private function getSubscriptionField($input_name, $checked, $label_string) { + return '
+ +
'; + } + + private function isCurrentUserSubscribed() { + $subscriber = Subscriber::getCurrentWPUser(); + if ($subscriber instanceof Subscriber) { + $wc_segment = Segment::getWooCommerceSegment(); + $subscriber_segment = SubscriberSegment::where('subscriber_id', $subscriber->id) + ->where('segment_id', $wc_segment->id) + ->findOne(); + if ($subscriber_segment instanceof SubscriberSegment + && $subscriber_segment->status === Subscriber::STATUS_SUBSCRIBED + ) { + return true; + } + } + return false; + } + + function subscribeOnCheckout($order_id, $data) { + if (empty($data['billing_email'])) { + // no email in posted order data + return null; + } + + $subscriber = Subscriber::where('email', $data['billing_email']) + ->where('is_woocommerce_user', 1) + ->findOne(); + if (!$subscriber) { + // no subscriber: WooCommerce sync didn't work + return null; + } + + $checkout_optin_enabled = (bool)$this->settings->get(self::OPTIN_ENABLED_SETTING_NAME); + $wc_segment = Segment::getWooCommerceSegment(); + + if ($checkout_optin_enabled) { + if (!empty($_POST[self::CHECKOUT_OPTIN_INPUT_NAME])) { + // checkbox is checked + $subscriber->source = Source::WOOCOMMERCE_CHECKOUT; + $subscriber->status = Subscriber::STATUS_SUBSCRIBED; + if (empty($subscriber->confirmed_ip) && empty($subscriber->confirmed_at)) { + $subscriber->confirmed_ip = Helpers::getIP(); + $subscriber->setExpr('confirmed_at', 'NOW()'); + } + $subscriber->save(); + + SubscriberSegment::subscribeToSegments( + $subscriber, + array($wc_segment->id) + ); + return true; + } + } + + // Opt-in is disabled or checkbox is unchecked + SubscriberSegment::unsubscribeFromSegments( + $subscriber, + array($wc_segment->id) + ); + return false; + } +}