get(TrackingConfig::class); $this->trackingEnabled = $trackingConfig->isEmailTrackingEnabled(); if ($wp === null) { $wp = new WPFunctions; } $this->wp = $wp; if ($postsTask === null) { $postsTask = new PostsTask; } $this->postsTask = $postsTask; if ($gaTracking === null) { $gaTracking = ContainerWrapper::getInstance()->get(GATracking::class); } $this->gaTracking = $gaTracking; $this->loggerFactory = LoggerFactory::getInstance(); if ($emoji === null) { $emoji = new Emoji(); } $this->emoji = $emoji; $this->renderer = ContainerWrapper::getInstance()->get(Renderer::class); $this->newslettersRepository = ContainerWrapper::getInstance()->get(NewslettersRepository::class); $this->linksTask = ContainerWrapper::getInstance()->get(LinksTask::class); $this->newsletterLinks = ContainerWrapper::getInstance()->get(NewsletterLinks::class); $this->sendingQueuesRepository = ContainerWrapper::getInstance()->get(SendingQueuesRepository::class); $this->subscribersRepository = ContainerWrapper::getInstance()->get(SubscribersRepository::class); } public function getNewsletterFromQueue($queue) { // get existing active or sending newsletter $newsletter = $queue->newsletter() ->whereNull('deleted_at') ->whereAnyIs( [ ['status' => NewsletterModel::STATUS_ACTIVE], ['status' => NewsletterModel::STATUS_SENDING], ] ) ->findOne(); if (!$newsletter) return false; // if this is a notification history, get existing active or sending parent newsletter if ($newsletter->type == NewsletterModel::TYPE_NOTIFICATION_HISTORY) { $parentNewsletter = $newsletter->parent() ->whereNull('deleted_at') ->whereAnyIs( [ ['status' => NewsletterModel::STATUS_ACTIVE], ['status' => NewsletterModel::STATUS_SENDING], ] ) ->findOne(); if (!$parentNewsletter) return false; } return $newsletter; } public function preProcessNewsletter(\MailPoet\Models\Newsletter $newsletter, $sendingTask) { // return the newsletter if it was previously rendered if (!is_null($sendingTask->getNewsletterRenderedBody())) { return (!$sendingTask->validate()) ? $this->stopNewsletterPreProcessing(sprintf('QUEUE-%d-RENDER', $sendingTask->id)) : $newsletter; } $this->loggerFactory->getLogger(LoggerFactory::TOPIC_NEWSLETTERS)->info( 'pre-processing newsletter', ['newsletter_id' => $newsletter->id, 'task_id' => $sendingTask->taskId] ); $newsletterEntity = $this->newslettersRepository->findOneById($newsletter->id); if (!$newsletterEntity) return false; // if tracking is enabled, do additional processing if ($this->trackingEnabled) { // hook to the newsletter post-processing filter and add tracking image $this->trackingImageInserted = OpenTracking::addTrackingImage(); // render newsletter $renderedNewsletter = $this->renderer->render($newsletterEntity, $sendingTask); $renderedNewsletter = $this->wp->applyFilters( 'mailpoet_sending_newsletter_render_after', $renderedNewsletter, $newsletter ); $renderedNewsletter = $this->gaTracking->applyGATracking($renderedNewsletter, $newsletter); // hash and save all links $renderedNewsletter = $this->linksTask->process($renderedNewsletter, $newsletter, $sendingTask); } else { // render newsletter $renderedNewsletter = $this->renderer->render($newsletterEntity, $sendingTask); $renderedNewsletter = $this->wp->applyFilters( 'mailpoet_sending_newsletter_render_after', $renderedNewsletter, $newsletter ); $renderedNewsletter = $this->gaTracking->applyGATracking($renderedNewsletter, $newsletter); } // check if this is a post notification and if it contains at least 1 ALC post if ( $newsletter->type === NewsletterModel::TYPE_NOTIFICATION_HISTORY && $this->postsTask->getAlcPostsCount($renderedNewsletter, $newsletter) === 0 ) { // delete notification history record since it will never be sent $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->info( 'no posts in post notification, deleting it', ['newsletter_id' => $newsletter->id, 'task_id' => $sendingTask->taskId] ); $this->newslettersRepository->bulkDelete([(int)$newsletter->id]); return false; } // extract and save newsletter posts $this->postsTask->extractAndSave($renderedNewsletter, $newsletterEntity); if ($sendingTask->queue() instanceof SendingQueueModel) { $sendingQueueEntity = $this->sendingQueuesRepository->findOneById($sendingTask->queue()->id); } else { $sendingQueueEntity = null; } // update queue with the rendered and pre-processed newsletter $sendingTask->newsletterRenderedSubject = ShortcodesTask::process( $newsletter->subject, $renderedNewsletter['html'], $newsletterEntity, null, $sendingQueueEntity ); // if the rendered subject is empty, use a default subject, // having no subject in a newsletter is considered spammy if (empty(trim((string)$sendingTask->newsletterRenderedSubject))) { $sendingTask->newsletterRenderedSubject = WPFunctions::get()->__('No subject', 'mailpoet'); } $renderedNewsletter = $this->emoji->encodeEmojisInBody($renderedNewsletter); $sendingTask->newsletterRenderedBody = $renderedNewsletter; $sendingTask->save(); // catch DB errors $queueErrors = $sendingTask->getErrors(); if (!$queueErrors) { // verify that the rendered body was successfully saved $sendingQueue = SendingQueueModel::findOne($sendingTask->id); if ($sendingQueue instanceof SendingQueueModel) { $queueErrors = ($sendingQueue->validate() !== true); } } if ($queueErrors) { $this->stopNewsletterPreProcessing(sprintf('QUEUE-%d-SAVE', $sendingTask->id)); } return $newsletter; } public function prepareNewsletterForSending($newsletter, $subscriber, $queue) { // shortcodes and links will be replaced in the subject, html and text body // to speed the processing, join content into a continuous string $renderedNewsletter = $queue->getNewsletterRenderedBody(); $renderedNewsletter = $this->emoji->decodeEmojisInBody($renderedNewsletter); $preparedNewsletter = Helpers::joinObject( [ $queue->newsletterRenderedSubject, $renderedNewsletter['html'], $renderedNewsletter['text'], ] ); if ($newsletter instanceof NewsletterModel) { $newsletterEntity = $this->newslettersRepository->findOneById($newsletter->id); } else { $newsletterEntity = null; } if ($subscriber instanceof SubscriberModel) { $subscriberEntity = $this->subscribersRepository->findOneById($subscriber->id); } else { $subscriberEntity = null; } if ($queue->queue() instanceof SendingQueueModel) { $sendingQueueEntity = $this->sendingQueuesRepository->findOneById($queue->queue()->id); } else { $sendingQueueEntity = null; } $preparedNewsletter = ShortcodesTask::process( $preparedNewsletter, null, $newsletterEntity, $subscriberEntity, $sendingQueueEntity ); if ($this->trackingEnabled) { $preparedNewsletter = $this->newsletterLinks->replaceSubscriberData( $subscriber->id, $queue->id, $preparedNewsletter ); } $preparedNewsletter = Helpers::splitObject($preparedNewsletter); return [ 'id' => $newsletter->id, 'subject' => $preparedNewsletter[0], 'body' => [ 'html' => $preparedNewsletter[1], 'text' => $preparedNewsletter[2], ], ]; } public function markNewsletterAsSent($newsletter, $queue) { // if it's a standard or notification history newsletter, update its status if ( $newsletter->type === NewsletterModel::TYPE_STANDARD || $newsletter->type === NewsletterModel::TYPE_NOTIFICATION_HISTORY ) { $newsletter->status = NewsletterModel::STATUS_SENT; $newsletter->sentAt = $queue->processedAt; $newsletter->save(); } } public function getNewsletterSegments($newsletter) { $segments = NewsletterSegmentModel::where('newsletter_id', $newsletter->id) ->select('segment_id') ->findArray(); return Helpers::flattenArray($segments); } public function stopNewsletterPreProcessing($errorCode = null) { MailerLog::processError( 'queue_save', WPFunctions::get()->__('There was an error processing your newsletter during sending. If possible, please contact us and report this issue.', 'mailpoet'), $errorCode ); } }