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->subscriberActivityTracker->registerCallback( 'mailpoet_abandoned_cart', [$this, 'handleSubscriberActivity'] ); } public function handleCartChange() { $cart = $this->wooCommerceHelper->WC()->cart; $currentAction = current_action(); if ($currentAction !== 'woocommerce_cart_emptied' && $cart && !$cart->is_empty()) { $this->scheduleAbandonedCartEmail($this->getCartProductIds($cart)); } else { $this->cancelAbandonedCartEmail(); } } public function handleSubscriberActivity(SubscriberEntity $subscriber) { // on subscriber activity on site 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->rescheduleAbandonedCartEmail($subscriber); } private function getCartProductIds($cart) { $cartItems = $cart->get_cart() ?: []; return array_column($cartItems, 'product_id'); } private function scheduleAbandonedCartEmail(array $cartProductIds = []) { $subscriber = $this->getSubscriber(); if (!$subscriber || $subscriber->getStatus() !== SubscriberEntity::STATUS_SUBSCRIBED) { return; } $this->wp->doAction(self::HOOK_SCHEDULE, $subscriber, $cartProductIds); $meta = [self::TASK_META_NAME => $cartProductIds]; $this->scheduler->scheduleOrRescheduleAutomaticEmail(WooCommerceEmail::SLUG, self::SLUG, $subscriber, $meta); } private function rescheduleAbandonedCartEmail(SubscriberEntity $subscriber) { $this->wp->doAction(self::HOOK_RE_SCHEDULE, $subscriber); $this->scheduler->rescheduleAutomaticEmail(WooCommerceEmail::SLUG, self::SLUG, $subscriber); } private function cancelAbandonedCartEmail() { $subscriber = $this->getSubscriber(); if (!$subscriber) { return; } $this->wp->doAction(self::HOOK_CANCEL, $subscriber); $this->scheduler->cancelAutomaticEmail(WooCommerceEmail::SLUG, self::SLUG, $subscriber); } private function getSubscriber(): ?SubscriberEntity { $wpUser = $this->wp->wpGetCurrentUser(); if ($wpUser->exists()) { return $this->subscribersRepository->findOneBy(['wpUserId' => $wpUser->ID]); } // if user not logged in, try to find subscriber by cookie $subscriberId = $this->subscriberCookie->getSubscriberId(); if ($subscriberId) { return $this->subscribersRepository->findOneById($subscriberId); } return null; } }