Move GA tracking to free
[MAILPOET-2397]
This commit is contained in:
committed by
Jack Kitterhing
parent
787cd8373a
commit
a42a971efd
@@ -13,6 +13,7 @@ use MailPoet\Models\SendingQueue as SendingQueueModel;
|
|||||||
use MailPoet\Newsletter\Links\Links as NewsletterLinks;
|
use MailPoet\Newsletter\Links\Links as NewsletterLinks;
|
||||||
use MailPoet\Newsletter\Renderer\PostProcess\OpenTracking;
|
use MailPoet\Newsletter\Renderer\PostProcess\OpenTracking;
|
||||||
use MailPoet\Settings\SettingsController;
|
use MailPoet\Settings\SettingsController;
|
||||||
|
use MailPoet\Statistics\GATracking;
|
||||||
use MailPoet\Util\Helpers;
|
use MailPoet\Util\Helpers;
|
||||||
use MailPoet\WP\Functions as WPFunctions;
|
use MailPoet\WP\Functions as WPFunctions;
|
||||||
|
|
||||||
@@ -26,10 +27,13 @@ class Newsletter {
|
|||||||
/** @var PostsTask */
|
/** @var PostsTask */
|
||||||
private $posts_task;
|
private $posts_task;
|
||||||
|
|
||||||
|
/** @var GATracking */
|
||||||
|
private $ga_tracking;
|
||||||
|
|
||||||
/** @var LoggerFactory */
|
/** @var LoggerFactory */
|
||||||
private $logger_factory;
|
private $logger_factory;
|
||||||
|
|
||||||
function __construct(WPFunctions $wp = null, PostsTask $posts_task = null) {
|
function __construct(WPFunctions $wp = null, PostsTask $posts_task = null, GATracking $ga_tracking = null) {
|
||||||
$settings = new SettingsController();
|
$settings = new SettingsController();
|
||||||
$this->tracking_enabled = (boolean)$settings->get('tracking.enabled');
|
$this->tracking_enabled = (boolean)$settings->get('tracking.enabled');
|
||||||
if ($wp === null) {
|
if ($wp === null) {
|
||||||
@@ -40,6 +44,10 @@ class Newsletter {
|
|||||||
$posts_task = new PostsTask;
|
$posts_task = new PostsTask;
|
||||||
}
|
}
|
||||||
$this->posts_task = $posts_task;
|
$this->posts_task = $posts_task;
|
||||||
|
if ($ga_tracking === null) {
|
||||||
|
$ga_tracking = new GATracking;
|
||||||
|
}
|
||||||
|
$this->ga_tracking = $ga_tracking;
|
||||||
$this->logger_factory = LoggerFactory::getInstance();
|
$this->logger_factory = LoggerFactory::getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +101,7 @@ class Newsletter {
|
|||||||
$rendered_newsletter,
|
$rendered_newsletter,
|
||||||
$newsletter
|
$newsletter
|
||||||
);
|
);
|
||||||
|
$rendered_newsletter = $this->ga_tracking->applyGATracking($rendered_newsletter, $newsletter);
|
||||||
// hash and save all links
|
// hash and save all links
|
||||||
$rendered_newsletter = LinksTask::process($rendered_newsletter, $newsletter, $sending_task);
|
$rendered_newsletter = LinksTask::process($rendered_newsletter, $newsletter, $sending_task);
|
||||||
} else {
|
} else {
|
||||||
@@ -103,6 +112,7 @@ class Newsletter {
|
|||||||
$rendered_newsletter,
|
$rendered_newsletter,
|
||||||
$newsletter
|
$newsletter
|
||||||
);
|
);
|
||||||
|
$rendered_newsletter = $this->ga_tracking->applyGATracking($rendered_newsletter, $newsletter);
|
||||||
}
|
}
|
||||||
// check if this is a post notification and if it contains at least 1 ALC post
|
// check if this is a post notification and if it contains at least 1 ALC post
|
||||||
if ($newsletter->type === NewsletterModel::TYPE_NOTIFICATION_HISTORY &&
|
if ($newsletter->type === NewsletterModel::TYPE_NOTIFICATION_HISTORY &&
|
||||||
|
@@ -39,6 +39,7 @@ use function MailPoet\Util\array_column;
|
|||||||
* @property string|null $schedule
|
* @property string|null $schedule
|
||||||
* @property boolean|null $isScheduled
|
* @property boolean|null $isScheduled
|
||||||
* @property string|null $scheduledAt
|
* @property string|null $scheduledAt
|
||||||
|
* @property string $ga_campaign
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Newsletter extends Model {
|
class Newsletter extends Model {
|
||||||
|
70
lib/Statistics/GATracking.php
Normal file
70
lib/Statistics/GATracking.php
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Statistics;
|
||||||
|
|
||||||
|
use MailPoet\Models\Newsletter;
|
||||||
|
use MailPoet\Newsletter\Links\Links as NewsletterLinks;
|
||||||
|
use MailPoet\Util\Helpers;
|
||||||
|
use MailPoet\WP\Functions as WPFunctions;
|
||||||
|
|
||||||
|
class GATracking {
|
||||||
|
|
||||||
|
function applyGATracking($rendered_newsletter, $newsletter, $internal_host = null) {
|
||||||
|
if ($newsletter instanceof Newsletter && $newsletter->type == Newsletter::TYPE_NOTIFICATION_HISTORY) {
|
||||||
|
$parent_newsletter = $newsletter->parent()->findOne();
|
||||||
|
$field = $parent_newsletter->ga_campaign;
|
||||||
|
} else {
|
||||||
|
$field = $newsletter->ga_campaign;
|
||||||
|
}
|
||||||
|
if (!empty($field)) {
|
||||||
|
$rendered_newsletter = $this->addGAParamsToLinks($rendered_newsletter, $field, $internal_host);
|
||||||
|
}
|
||||||
|
return $rendered_newsletter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addGAParamsToLinks($rendered_newsletter, $ga_campaign, $internal_host = null) {
|
||||||
|
// join HTML and TEXT rendered body into a text string
|
||||||
|
$content = Helpers::joinObject($rendered_newsletter);
|
||||||
|
$extracted_links = NewsletterLinks::extract($content);
|
||||||
|
$processed_links = $this->addParams($extracted_links, $ga_campaign, $internal_host);
|
||||||
|
list($content, $links) = NewsletterLinks::replace($content, $processed_links);
|
||||||
|
// split the processed body with hashed links back to HTML and TEXT
|
||||||
|
list($rendered_newsletter['html'], $rendered_newsletter['text'])
|
||||||
|
= Helpers::splitObject($content);
|
||||||
|
return $rendered_newsletter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addParams($extracted_links, $ga_campaign, $internal_host = null) {
|
||||||
|
$processed_links = [];
|
||||||
|
$params = [
|
||||||
|
'utm_source' => 'mailpoet',
|
||||||
|
'utm_medium' => 'email',
|
||||||
|
'utm_campaign' => urlencode($ga_campaign),
|
||||||
|
];
|
||||||
|
$internal_host = $internal_host ?: parse_url(home_url(), PHP_URL_HOST);
|
||||||
|
$internal_host = self::getSecondLevelDomainName($internal_host);
|
||||||
|
foreach ($extracted_links as $extracted_link) {
|
||||||
|
if ($extracted_link['type'] !== NewsletterLinks::LINK_TYPE_URL) {
|
||||||
|
continue;
|
||||||
|
} elseif (strpos(parse_url($extracted_link['link'], PHP_URL_HOST), $internal_host) === false) {
|
||||||
|
// Process only internal links (i.e. pointing to current site)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$processed_link = WPFunctions::get()->addQueryArg($params, $extracted_link['link']);
|
||||||
|
$link = $extracted_link['link'];
|
||||||
|
$processed_links[$link] = [
|
||||||
|
'type' => $extracted_link['type'],
|
||||||
|
'link' => $link,
|
||||||
|
'processed_link' => $processed_link,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $processed_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSecondLevelDomainName($host) {
|
||||||
|
if (preg_match('/[^.]*\.[^.]{2,3}(?:\.[^.]{2,3})?$/', $host, $matches)) {
|
||||||
|
return $matches[0];
|
||||||
|
}
|
||||||
|
return $host;
|
||||||
|
}
|
||||||
|
}
|
88
tests/integration/Statistics/GATrackingTest.php
Normal file
88
tests/integration/Statistics/GATrackingTest.php
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Statistics;
|
||||||
|
|
||||||
|
use MailPoet\Models\Newsletter;
|
||||||
|
|
||||||
|
class GATrackingTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $internal_host;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $ga_campaign;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $link;
|
||||||
|
|
||||||
|
/** @var string[] */
|
||||||
|
private $rendered_newsletter;
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->internal_host = 'newsletters.mailpoet.com';
|
||||||
|
$this->ga_campaign = 'Spring email';
|
||||||
|
$this->link = add_query_arg(['foo' => 'bar', 'baz' => 'xyz'], 'http://www.mailpoet.com/');
|
||||||
|
$this->rendered_newsletter = [
|
||||||
|
'html' => '<p><a href="' . $this->link . '">Click here</a>. <a href="http://somehost.com/fff/?abc=123">Do not process this</a> [link:some_link_shortcode]</p>',
|
||||||
|
'text' => '[Click here](' . $this->link . '). [Do not process this](http://somehost.com/fff/?abc=123) [link:some_link_shortcode]',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItConditionallyAppliesGATracking() {
|
||||||
|
// No process (empty GA campaign)
|
||||||
|
$newsletter = Newsletter::createOrUpdate(['id' => 123]);
|
||||||
|
$tracking = new GATracking();
|
||||||
|
$result = $tracking->applyGATracking($this->rendered_newsletter, $newsletter, $this->internal_host);
|
||||||
|
expect($result)->equals($this->rendered_newsletter);
|
||||||
|
// Process (filled GA campaign)
|
||||||
|
$newsletter->ga_campaign = $this->ga_campaign;
|
||||||
|
$newsletter->save();
|
||||||
|
$result = $tracking->applyGATracking($this->rendered_newsletter, $newsletter, $this->internal_host);
|
||||||
|
expect($result)->notEquals($this->rendered_newsletter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItGetsGACampaignFromParentNewsletterForPostNotifications() {
|
||||||
|
$tracking = new GATracking();
|
||||||
|
$notification = Newsletter::create();
|
||||||
|
$notification->hydrate([
|
||||||
|
'type' => Newsletter::TYPE_NOTIFICATION,
|
||||||
|
'ga_campaign' => $this->ga_campaign,
|
||||||
|
]);
|
||||||
|
$notification->save();
|
||||||
|
$notification_history = Newsletter::create();
|
||||||
|
$notification_history->hydrate([
|
||||||
|
'parent_id' => $notification->id,
|
||||||
|
'type' => Newsletter::TYPE_NOTIFICATION_HISTORY,
|
||||||
|
]);
|
||||||
|
$notification_history->save();
|
||||||
|
$result = $tracking->applyGATracking($this->rendered_newsletter, $notification_history, $this->internal_host);
|
||||||
|
expect($result)->notEquals($this->rendered_newsletter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItCanAddGAParamsToLinks() {
|
||||||
|
$tracking = new GATracking();
|
||||||
|
$newsletter = Newsletter::createOrUpdate([
|
||||||
|
'ga_campaign' => $this->ga_campaign,
|
||||||
|
]);
|
||||||
|
$result = $tracking->applyGATracking($this->rendered_newsletter, $newsletter, $this->internal_host);
|
||||||
|
expect($result['text'])->contains('utm_campaign=' . urlencode($this->ga_campaign));
|
||||||
|
expect($result['html'])->contains('utm_campaign=' . urlencode($this->ga_campaign));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItGetsSecondLevelDomainName() {
|
||||||
|
$cases = [
|
||||||
|
'mailpoet.com' => 'mailpoet.com',
|
||||||
|
'newsletters.mailpoet.com' => 'mailpoet.com',
|
||||||
|
'test.example.co.uk' => 'example.co.uk',
|
||||||
|
'example.co.uk' => 'example.co.uk',
|
||||||
|
'localhost' => 'localhost',
|
||||||
|
];
|
||||||
|
foreach ($cases as $subdomain => $domain) {
|
||||||
|
expect(GATracking::getSecondLevelDomainName($subdomain))->equals($domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . Newsletter::$_table);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user