Files
piratepoet/lib/AutomaticEmails/WooCommerce/Events/AbandonedCart.php
Jan Jakeš 8c848cfa28 Convert property names to camel case
[MAILPOET-1796]
2020-01-14 15:22:42 +01:00

190 lines
6.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace MailPoet\AutomaticEmails\WooCommerce\Events;
use MailPoet\AutomaticEmails\WooCommerce\WooCommerce as WooCommerceEmail;
use MailPoet\Models\Subscriber;
use MailPoet\Newsletter\Scheduler\AutomaticEmailScheduler;
use MailPoet\Statistics\Track\Clicks;
use MailPoet\Util\Cookies;
use MailPoet\WooCommerce\Helper as WooCommerceHelper;
use MailPoet\WP\Functions as WPFunctions;
class AbandonedCart {
const SLUG = 'woocommerce_abandoned_shopping_cart';
const LAST_VISIT_TIMESTAMP_OPTION_NAME = 'mailpoet_last_visit_timestamp';
/** @var WPFunctions */
private $wp;
/** @var WooCommerceHelper */
private $wooCommerceHelper;
/** @var Cookies */
private $cookies;
/** @var AbandonedCartPageVisitTracker */
private $pageVisitTracker;
/** @var AutomaticEmailScheduler */
private $scheduler;
public function __construct() {
$this->wp = WPFunctions::get();
$this->wooCommerceHelper = new WooCommerceHelper();
$this->cookies = new Cookies();
$this->pageVisitTracker = new AbandonedCartPageVisitTracker($this->wp, $this->wooCommerceHelper, $this->cookies);
$this->scheduler = new AutomaticEmailScheduler();
}
public function getEventDetails() {
return [
'slug' => self::SLUG,
'title' => WPFunctions::get()->_x('Abandoned Shopping Cart', 'This is the name of a type of automatic email for ecommerce. Those emails are sent automatically when a customer adds product to his shopping cart but never complete the checkout process.', 'mailpoet'),
'description' => WPFunctions::get()->__('Send an email to logged-in visitors who have items in their shopping carts but left your website without checking out. Can convert up to 5% of abandoned carts.', 'mailpoet'),
'listingScheduleDisplayText' => WPFunctions::get()->_x('Email sent when a customer abandons his cart.', 'Description of Abandoned Shopping Cart email', 'mailpoet'),
'badge' => [
'text' => WPFunctions::get()->__('Must-have', 'mailpoet'),
'style' => 'red',
],
'timeDelayValues' => [
'minutes' => [
'text' => _x('30 minutes after last page loaded', 'This is a trigger setting. It means that we will send an automatic email to a visitor 30 minutes after this visitor had left the website.', 'mailpoet'),
'displayAfterTimeNumberField' => false,
],
'hours' => [
'text' => __('hour(s) later', 'mailpoet'),
'displayAfterTimeNumberField' => true,
],
'days' => [
'text' => __('day(s) later', 'mailpoet'),
'displayAfterTimeNumberField' => true,
],
'weeks' => [
'text' => __('week(s) later', 'mailpoet'),
'displayAfterTimeNumberField' => true,
],
],
'defaultAfterTimeType' => 'minutes',
'schedulingReadMoreLink' => [
'link' => 'https://www.mailpoet.com/blog/abandoned-cart-woocommerce',
'text' => __('We recommend setting up 3 abandoned cart emails. Heres why.', 'mailpoet'),
],
];
}
public function init() {
if (!$this->wooCommerceHelper->isWooCommerceActive()) {
return;
}
// item added to cart (not fired on quantity changes)
$this->wp->addAction(
'woocommerce_add_to_cart',
[$this, 'handleCartChange'],
10
);
// item removed from cart (not fired on quantity changes, not even change to zero)
$this->wp->addAction(
'woocommerce_cart_item_removed',
[$this, 'handleCartChange'],
10
);
// item quantity updated (not fired when quantity updated to zero)
$this->wp->addAction(
'woocommerce_after_cart_item_quantity_update',
[$this, 'handleCartChange'],
10
);
// item quantity set to zero (it removes the item but does not fire remove event)
$this->wp->addAction(
'woocommerce_before_cart_item_quantity_zero',
[$this, 'handleCartChange'],
10
);
// cart emptied (not called when all items removed)
$this->wp->addAction(
'woocommerce_cart_emptied',
[$this, 'handleCartChange'],
10
);
// undo removal of item from cart or cart emptying (does not fire any other cart change hook)
$this->wp->addAction(
'woocommerce_cart_item_restored',
[$this, 'handleCartChange'],
10
);
$this->wp->addAction(
'wp',
[$this, 'trackPageVisit'],
10
);
}
public function handleCartChange() {
$cart = $this->wooCommerceHelper->WC()->cart;
if ($cart && !$cart->is_empty()) {
$this->scheduleAbandonedCartEmail();
} else {
$this->cancelAbandonedCartEmail();
$this->pageVisitTracker->stopTracking();
}
}
public function trackPageVisit() {
// on page visit reschedule all currently scheduled (not yet sent) emails for given subscriber
// (it tracks at most once per minute to avoid processing many calls at the same time, i.e. AJAX)
$this->pageVisitTracker->trackVisit(function () {
$this->rescheduleAbandonedCartEmail();
});
}
private function scheduleAbandonedCartEmail() {
$subscriber = $this->getSubscriber();
if (!$subscriber || $subscriber->status !== Subscriber::STATUS_SUBSCRIBED) {
return;
}
$this->scheduler->scheduleOrRescheduleAutomaticEmail(WooCommerceEmail::SLUG, self::SLUG, $subscriber->id);
// start tracking page visits to detect inactivity
$this->pageVisitTracker->startTracking();
}
private function rescheduleAbandonedCartEmail() {
$subscriber = $this->getSubscriber();
if (!$subscriber) {
return;
}
$this->scheduler->rescheduleAutomaticEmail(WooCommerceEmail::SLUG, self::SLUG, $subscriber->id);
}
private function cancelAbandonedCartEmail() {
$subscriber = $this->getSubscriber();
if (!$subscriber) {
return;
}
$this->scheduler->cancelAutomaticEmail(WooCommerceEmail::SLUG, self::SLUG, $subscriber->id);
}
private function getSubscriber() {
$wpUser = $this->wp->wpGetCurrentUser();
if ($wpUser->exists()) {
return Subscriber::where('wp_user_id', $wpUser->ID)->findOne() ?: null;
}
// if user not logged in, try to find subscriber by cookie
$cookieData = $this->cookies->get(Clicks::ABANDONED_CART_COOKIE_NAME);
if ($cookieData && isset($cookieData['subscriber_id'])) {
return Subscriber::findOne($cookieData['subscriber_id']) ?: null;
}
return null;
}
}