- 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';
$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() {

View File

@ -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;

View File

@ -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) {

View File

@ -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')) {

View File

@ -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();

View File

@ -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(
'<img alt="" src="%s/?mailpoet&endpoint=track&action=open&data=[mailpoet_data]',
home_url()
'<img alt="" class="" src="%s/%s"/>',
home_url(),
htmlentities('?mailpoet&endpoint=track&action=open&data=[mailpoet_data]')
);
$template->html($template->html() . $open_tracking_link);
return $DOM->__toString();

View File

@ -1,60 +1,39 @@
<?php
namespace MailPoet\Statistics\Track;
use MailPoet\Models\NewsletterLink;
use MailPoet\Models\StatisticsClicks;
use MailPoet\Models\StatisticsOpens;
use MailPoet\Models\Subscriber;
use MailPoet\Subscription\Url as SubscriptionUrl;
use MailPoet\Util\Helpers;
if(!defined('ABSPATH')) exit;
class Opens {
public $url;
public $data;
function __construct($url) {
$this->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() {