From 45b933d6355f13e117a79aafb5bfd7c1c825f4e7 Mon Sep 17 00:00:00 2001 From: Vlad Date: Tue, 19 Apr 2016 20:59:27 -0400 Subject: [PATCH] - Implements open tracking --- lib/Config/Initializer.php | 2 + lib/Config/Migrator.php | 15 ++++++ lib/Config/PublicAPI.php | 4 ++ lib/Cron/Workers/SendingQueue.php | 5 ++ lib/Models/StatisticsOpens.php | 4 +- .../Renderer/PostProcess/OpenTracking.php | 8 +-- lib/Statistics/Track/Opens.php | 49 ++++++------------- 7 files changed, 47 insertions(+), 40 deletions(-) diff --git a/lib/Config/Initializer.php b/lib/Config/Initializer.php index e5d488614d..9145b996ec 100644 --- a/lib/Config/Initializer.php +++ b/lib/Config/Initializer.php @@ -84,6 +84,7 @@ class Initializer { $newsletter_links = Env::$db_prefix . 'newsletter_links'; $statistics_newsletters = Env::$db_prefix . 'statistics_newsletters'; $statistics_clicks = Env::$db_prefix . 'statistics_clicks'; + $statistics_opens = Env::$db_prefix . 'statistics_opens'; define('MP_SETTINGS_TABLE', $settings); define('MP_SEGMENTS_TABLE', $segments); @@ -101,6 +102,7 @@ class Initializer { define('MP_NEWSLETTER_OPTION_TABLE', $newsletter_option); define('MP_STATISTICS_NEWSLETTERS_TABLE', $statistics_newsletters); define('MP_STATISTICS_CLICKS_TABLE', $statistics_clicks); + define('MP_STATISTICS_OPENS_TABLE', $statistics_opens); } function runMigrator() { diff --git a/lib/Config/Migrator.php b/lib/Config/Migrator.php index 2f69d881e2..f9022cafab 100644 --- a/lib/Config/Migrator.php +++ b/lib/Config/Migrator.php @@ -26,6 +26,7 @@ class Migrator { 'forms', 'statistics_newsletters', 'statistics_clicks', + 'statistics_opens' ); } @@ -293,6 +294,20 @@ class Migrator { return $this->sqlify(__FUNCTION__, $attributes); } + function statistics_opens() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'newsletter_id mediumint(9) NOT NULL,', + 'subscriber_id mediumint(9) NOT NULL,', + 'queue_id mediumint(9) NOT NULL,', + 'created_at TIMESTAMP NOT NULL DEFAULT 0,', + 'deleted_at TIMESTAMP NULL DEFAULT NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id)', + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + private function sqlify($model, $attributes) { $table = $this->prefix . $model; diff --git a/lib/Config/PublicAPI.php b/lib/Config/PublicAPI.php index 2f6ef1b559..31fe8fe519 100644 --- a/lib/Config/PublicAPI.php +++ b/lib/Config/PublicAPI.php @@ -2,6 +2,7 @@ namespace MailPoet\Config; use MailPoet\Cron\Daemon; +use MailPoet\Statistics\Track\Opens; use MailPoet\Subscription; use MailPoet\Statistics\Track\Clicks; use MailPoet\Util\Helpers; @@ -54,6 +55,9 @@ class PublicAPI { if($this->action === 'click') { $track_class = new Clicks($this->data); } + if($this->action === 'open') { + $track_class = new Opens($this->data); + } if(!isset($track_class)) return; $track_class->track(); } catch(\Exception $e) { diff --git a/lib/Cron/Workers/SendingQueue.php b/lib/Cron/Workers/SendingQueue.php index 55c5000020..5470d727ad 100644 --- a/lib/Cron/Workers/SendingQueue.php +++ b/lib/Cron/Workers/SendingQueue.php @@ -9,6 +9,7 @@ use MailPoet\Models\Setting; use MailPoet\Models\StatisticsNewsletters; use MailPoet\Models\Subscriber; use MailPoet\Newsletter\Links\Links; +use MailPoet\Newsletter\Renderer\PostProcess\OpenTracking; use MailPoet\Newsletter\Renderer\Renderer; use MailPoet\Newsletter\Shortcodes\Shortcodes; use MailPoet\Util\Helpers; @@ -74,6 +75,10 @@ class SendingQueue { // check if newsletter has been rendered, in which case return its contents // or render and save for future reuse if($queue->newsletter_rendered_body === null) { + // insert tracking code + add_filter('mailpoet_rendering_post_process', function($template) { + return OpenTracking::process($template); + }); // render newsletter $rendered_newsletter = $this->renderNewsletter($newsletter); if((boolean) Setting::getValue('tracking.enabled')) { diff --git a/lib/Models/StatisticsOpens.php b/lib/Models/StatisticsOpens.php index c30e2db0d0..3d3786e9db 100644 --- a/lib/Models/StatisticsOpens.php +++ b/lib/Models/StatisticsOpens.php @@ -3,8 +3,8 @@ namespace MailPoet\Models; if(!defined('ABSPATH')) exit; -class StatisticsClicks extends Model { - public static $_table = MP_STATISTICS_CLICKS_TABLE; +class StatisticsOpens extends Model { + public static $_table = MP_STATISTICS_OPENS_TABLE; function __construct() { parent::__construct(); diff --git a/lib/Newsletter/Renderer/PostProcess/OpenTracking.php b/lib/Newsletter/Renderer/PostProcess/OpenTracking.php index b7c654acf8..e90e260ae8 100644 --- a/lib/Newsletter/Renderer/PostProcess/OpenTracking.php +++ b/lib/Newsletter/Renderer/PostProcess/OpenTracking.php @@ -2,12 +2,14 @@ namespace MailPoet\Newsletter\Renderer\PostProcess; class OpenTracking { - static function process($template, $user_id) { + static function process($template) { $DOM = new \pQuery(); + $DOM = $DOM->parseStr($template); $template = $DOM->query('body'); $open_tracking_link = sprintf( - '', + home_url(), + htmlentities('?mailpoet&endpoint=track&action=open&data=[mailpoet_data]') ); $template->html($template->html() . $open_tracking_link); return $DOM->__toString(); diff --git a/lib/Statistics/Track/Opens.php b/lib/Statistics/Track/Opens.php index 8c4179b650..6ef3d76544 100644 --- a/lib/Statistics/Track/Opens.php +++ b/lib/Statistics/Track/Opens.php @@ -1,60 +1,39 @@ url = $url; + function __construct($data) { + $this->data = $data; } - function track($url = false) { - $url = ($url) ? $url : $this->url; - if(!preg_match('/\d+-\d+-\d+$/', $url)) $this->abort(); - list ($newsletter_id, $subscriber_id, $queue_id) = explode('-', $url); + function track($data = false) { + $data = ($data) ? $data : $this->data; + if(!preg_match('/\d+-\d+-\d+/', $data)) $this->abort(); + list ($newsletter_id, $subscriber_id, $queue_id) = explode('-', $data); $subscriber = Subscriber::findOne($subscriber_id); if(!$subscriber) return; - $statistics = StatisticsOpens::where('link_id', $link->id) - ->where('subscriber_id', $subscriber_id) + $statistics = StatisticsOpens::where('subscriber_id', $subscriber_id) ->where('newsletter_id', $newsletter_id) ->where('queue_id', $queue_id) ->findOne(); if(!$statistics) { - $statistics = StatisticsClicks::create(); + $statistics = StatisticsOpens::create(); $statistics->newsletter_id = $newsletter_id; - $statistics->link_id = $link->id; $statistics->subscriber_id = $subscriber_id; $statistics->queue_id = $queue_id; - $statistics->count = 1; - $statistics->save(); - } else { - $statistics->count++; $statistics->save(); } - $url = (preg_match('/\[subscription:.*?\]/', $link->url)) ? - $this->processSubscriptionUrl($link->url, $subscriber) : - $link->url; - header('Location: ' . $url, true, 302); - } - - function processSubscriptionUrl($url, $subscriber) { - preg_match('/\[subscription:(.*?)\]/', $url, $match); - $action = $match[1]; - if(preg_match('/unsubscribe/', $action)) { - $url = SubscriptionUrl::getUnsubscribeUrl($subscriber); - } - if(preg_match('/manage/', $action)) { - $url = SubscriptionUrl::getManageUrl($subscriber); - } - return $url; + header('Content-Type: image/gif'); + // return 1x1 pixel transparent gif image + echo "\x47\x49\x46\x38\x37\x61\x1\x0\x1\x0\x80\x0\x0\xfc\x6a\x6c\x0\x0\x0\x2c\x0\x0\x0\x0\x1\x0\x1\x0\x0\x2\x2\x44\x1\x0\x3b"; + exit; } private function abort() {