- Implements open tracking

This commit is contained in:
Vlad
2016-04-19 20:59:27 -04:00
parent 15cf087d40
commit 45b933d635
7 changed files with 47 additions and 40 deletions

View File

@ -84,6 +84,7 @@ class Initializer {
$newsletter_links = Env::$db_prefix . 'newsletter_links'; $newsletter_links = Env::$db_prefix . 'newsletter_links';
$statistics_newsletters = Env::$db_prefix . 'statistics_newsletters'; $statistics_newsletters = Env::$db_prefix . 'statistics_newsletters';
$statistics_clicks = Env::$db_prefix . 'statistics_clicks'; $statistics_clicks = Env::$db_prefix . 'statistics_clicks';
$statistics_opens = Env::$db_prefix . 'statistics_opens';
define('MP_SETTINGS_TABLE', $settings); define('MP_SETTINGS_TABLE', $settings);
define('MP_SEGMENTS_TABLE', $segments); define('MP_SEGMENTS_TABLE', $segments);
@ -101,6 +102,7 @@ class Initializer {
define('MP_NEWSLETTER_OPTION_TABLE', $newsletter_option); define('MP_NEWSLETTER_OPTION_TABLE', $newsletter_option);
define('MP_STATISTICS_NEWSLETTERS_TABLE', $statistics_newsletters); define('MP_STATISTICS_NEWSLETTERS_TABLE', $statistics_newsletters);
define('MP_STATISTICS_CLICKS_TABLE', $statistics_clicks); define('MP_STATISTICS_CLICKS_TABLE', $statistics_clicks);
define('MP_STATISTICS_OPENS_TABLE', $statistics_opens);
} }
function runMigrator() { function runMigrator() {

View File

@ -26,6 +26,7 @@ class Migrator {
'forms', 'forms',
'statistics_newsletters', 'statistics_newsletters',
'statistics_clicks', 'statistics_clicks',
'statistics_opens'
); );
} }
@ -293,6 +294,20 @@ class Migrator {
return $this->sqlify(__FUNCTION__, $attributes); 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) { private function sqlify($model, $attributes) {
$table = $this->prefix . $model; $table = $this->prefix . $model;

View File

@ -2,6 +2,7 @@
namespace MailPoet\Config; namespace MailPoet\Config;
use MailPoet\Cron\Daemon; use MailPoet\Cron\Daemon;
use MailPoet\Statistics\Track\Opens;
use MailPoet\Subscription; use MailPoet\Subscription;
use MailPoet\Statistics\Track\Clicks; use MailPoet\Statistics\Track\Clicks;
use MailPoet\Util\Helpers; use MailPoet\Util\Helpers;
@ -54,6 +55,9 @@ class PublicAPI {
if($this->action === 'click') { if($this->action === 'click') {
$track_class = new Clicks($this->data); $track_class = new Clicks($this->data);
} }
if($this->action === 'open') {
$track_class = new Opens($this->data);
}
if(!isset($track_class)) return; if(!isset($track_class)) return;
$track_class->track(); $track_class->track();
} catch(\Exception $e) { } catch(\Exception $e) {

View File

@ -9,6 +9,7 @@ use MailPoet\Models\Setting;
use MailPoet\Models\StatisticsNewsletters; use MailPoet\Models\StatisticsNewsletters;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
use MailPoet\Newsletter\Links\Links; use MailPoet\Newsletter\Links\Links;
use MailPoet\Newsletter\Renderer\PostProcess\OpenTracking;
use MailPoet\Newsletter\Renderer\Renderer; use MailPoet\Newsletter\Renderer\Renderer;
use MailPoet\Newsletter\Shortcodes\Shortcodes; use MailPoet\Newsletter\Shortcodes\Shortcodes;
use MailPoet\Util\Helpers; use MailPoet\Util\Helpers;
@ -74,6 +75,10 @@ class SendingQueue {
// check if newsletter has been rendered, in which case return its contents // check if newsletter has been rendered, in which case return its contents
// or render and save for future reuse // or render and save for future reuse
if($queue->newsletter_rendered_body === null) { if($queue->newsletter_rendered_body === null) {
// insert tracking code
add_filter('mailpoet_rendering_post_process', function($template) {
return OpenTracking::process($template);
});
// render newsletter // render newsletter
$rendered_newsletter = $this->renderNewsletter($newsletter); $rendered_newsletter = $this->renderNewsletter($newsletter);
if((boolean) Setting::getValue('tracking.enabled')) { if((boolean) Setting::getValue('tracking.enabled')) {

View File

@ -3,8 +3,8 @@ namespace MailPoet\Models;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class StatisticsClicks extends Model { class StatisticsOpens extends Model {
public static $_table = MP_STATISTICS_CLICKS_TABLE; public static $_table = MP_STATISTICS_OPENS_TABLE;
function __construct() { function __construct() {
parent::__construct(); parent::__construct();

View File

@ -2,12 +2,14 @@
namespace MailPoet\Newsletter\Renderer\PostProcess; namespace MailPoet\Newsletter\Renderer\PostProcess;
class OpenTracking { class OpenTracking {
static function process($template, $user_id) { static function process($template) {
$DOM = new \pQuery(); $DOM = new \pQuery();
$DOM = $DOM->parseStr($template);
$template = $DOM->query('body'); $template = $DOM->query('body');
$open_tracking_link = sprintf( $open_tracking_link = sprintf(
'<img alt="" src="%s/?mailpoet&endpoint=track&action=open&data=[mailpoet_data]', '<img alt="" class="" src="%s/%s"/>',
home_url() home_url(),
htmlentities('?mailpoet&endpoint=track&action=open&data=[mailpoet_data]')
); );
$template->html($template->html() . $open_tracking_link); $template->html($template->html() . $open_tracking_link);
return $DOM->__toString(); return $DOM->__toString();

View File

@ -1,60 +1,39 @@
<?php <?php
namespace MailPoet\Statistics\Track; namespace MailPoet\Statistics\Track;
use MailPoet\Models\NewsletterLink; use MailPoet\Models\StatisticsOpens;
use MailPoet\Models\StatisticsClicks;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
use MailPoet\Subscription\Url as SubscriptionUrl;
use MailPoet\Util\Helpers;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class Opens { class Opens {
public $url; public $data;
function __construct($url) { function __construct($data) {
$this->url = $url; $this->data = $data;
} }
function track($url = false) { function track($data = false) {
$url = ($url) ? $url : $this->url; $data = ($data) ? $data : $this->data;
if(!preg_match('/\d+-\d+-\d+$/', $url)) $this->abort(); if(!preg_match('/\d+-\d+-\d+/', $data)) $this->abort();
list ($newsletter_id, $subscriber_id, $queue_id) = explode('-', $url); list ($newsletter_id, $subscriber_id, $queue_id) = explode('-', $data);
$subscriber = Subscriber::findOne($subscriber_id); $subscriber = Subscriber::findOne($subscriber_id);
if(!$subscriber) return; if(!$subscriber) return;
$statistics = StatisticsOpens::where('link_id', $link->id) $statistics = StatisticsOpens::where('subscriber_id', $subscriber_id)
->where('subscriber_id', $subscriber_id)
->where('newsletter_id', $newsletter_id) ->where('newsletter_id', $newsletter_id)
->where('queue_id', $queue_id) ->where('queue_id', $queue_id)
->findOne(); ->findOne();
if(!$statistics) { if(!$statistics) {
$statistics = StatisticsClicks::create(); $statistics = StatisticsOpens::create();
$statistics->newsletter_id = $newsletter_id; $statistics->newsletter_id = $newsletter_id;
$statistics->link_id = $link->id;
$statistics->subscriber_id = $subscriber_id; $statistics->subscriber_id = $subscriber_id;
$statistics->queue_id = $queue_id; $statistics->queue_id = $queue_id;
$statistics->count = 1;
$statistics->save();
} else {
$statistics->count++;
$statistics->save(); $statistics->save();
} }
$url = (preg_match('/\[subscription:.*?\]/', $link->url)) ? header('Content-Type: image/gif');
$this->processSubscriptionUrl($link->url, $subscriber) : // return 1x1 pixel transparent gif image
$link->url; 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";
header('Location: ' . $url, true, 302); exit;
}
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;
} }
private function abort() { private function abort() {