Skip to content

Commit

Permalink
Refs matomo-org#2624, add INI config options that will force a new vi…
Browse files Browse the repository at this point in the history
…sit if campaign/website referrer information changes between actions. Includes new tracker hook shouldForceNewVisit that dimensions can use to force a new visit during tracking. Also includes light refactoring to referrer dimensions. Testless.
  • Loading branch information
diosmosis committed Dec 10, 2014
1 parent 954e5e9 commit 0a0a0d2
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 33 deletions.
10 changes: 10 additions & 0 deletions config/global.ini.php
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,16 @@
; Includes by default the GA style campaign keyword parameter utm_term
campaign_keyword_var_name = "pk_kwd,pk_keyword,piwik_kwd,utm_term"

; if set to 1, actions that contain different campaign information from the last action in the current visit will
; be treated as the start of a new visit. This will include situations when campaign information was absent before,
; but is present now (or vice versa).
tracker_create_new_visit_when_campaign_changes = 1

; if set to 1, actions that contain different website referrer information from the last action in the current visit
; will be treatedas the start of a new visit. This will include situations when website referrer information was
; absent before, but is present now (or vice versa).
tracker_create_new_visit_when_website_referrer_changes = 0

; maximum length of a Page Title or a Page URL recorded in the log_action.name table
page_maximum_length = 1024;

Expand Down
22 changes: 22 additions & 0 deletions core/Columns/Dimension.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
use Piwik\Plugin\Dimension\ConversionDimension;
use Piwik\Plugin\Dimension\VisitDimension;
use Piwik\Plugin\Segment;
use Piwik\Tracker\Action;
use Piwik\Tracker\Request;
use Piwik\Tracker\Visitor;
use Piwik\Translate;

/**
Expand Down Expand Up @@ -166,6 +169,25 @@ public function getId()
return $pluginName . '.' . $dimensionName;
}

/**
* This hook is executed by the tracker when determining if an action is the start of a new visit
* or part of an existing one. Derived classes can use it to force new visits based on dimension
* data.
*
* For example, the Campaign dimension in the Referrers plugin will force a new visit if the
* campaign information for the current action is different from the last.
*
* @param Request $request The current tracker request information.
* @param Visitor $visitor The information for the currently recognized visitor.
* @param Action|null $action The current action information (if any).
* @return bool Return true to force a visit, false if otherwise.
* @api
*/
public function shouldForceNewVisit(Request $request, Visitor $visitor, Action $action = null)
{
return false;
}

/**
* Gets an instance of all available visit, action and conversion dimension.
* @return Dimension[]
Expand Down
66 changes: 55 additions & 11 deletions core/Tracker/Visit.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,7 @@ public function handle()

$this->visitorInfo = $visitor->getVisitorInfo();

$isLastActionInTheSameVisit = $this->isLastActionInTheSameVisit($visitor);

if (!$isLastActionInTheSameVisit) {
Common::printDebug("Visitor detected, but last action was more than 30 minutes ago...");
}
$isNewVisit = $this->isVisitNew($visitor, $action);

// Known visit when:
// ( - the visitor has the Piwik cookie with the idcookie ID used by Piwik to match the visitor
Expand All @@ -165,9 +161,7 @@ public function handle()
// )
// AND
// - the last page view for this visitor was less than 30 minutes ago @see isLastActionInTheSameVisit()
if ($visitor->isVisitorKnown()
&& $isLastActionInTheSameVisit
) {
if (!$isNewVisit) {
$idReferrerActionUrl = $this->visitorInfo['visit_exit_idaction_url'];
$idReferrerActionName = $this->visitorInfo['visit_exit_idaction_name'];

Expand Down Expand Up @@ -203,9 +197,7 @@ public function handle()
// - the visitor has the Piwik cookie but the last action was performed more than 30 min ago @see isLastActionInTheSameVisit()
// - the visitor doesn't have the Piwik cookie, and couldn't be matched in @see recognizeTheVisitor()
// - the visitor does have the Piwik cookie but the idcookie and idvisit found in the cookie didn't match to any existing visit in the DB
if (!$visitor->isVisitorKnown()
|| !$isLastActionInTheSameVisit
) {
if ($isNewVisit) {
$this->handleNewVisit($visitor, $action, $visitIsConverted);
if (!is_null($action)) {
$action->record($visitor, 0, 0);
Expand Down Expand Up @@ -550,6 +542,23 @@ private function triggerHookOnDimensions($dimensions, $hook, $visitor, $action,
return $valuesToUpdate;
}

private function triggerPredicateHookOnDimensions($dimensions, $hook, Visitor $visitor, Action $action = null, $returnFirstTrue = true)
{
$result = $returnFirstTrue ? false : array();
foreach ($dimensions as $dimension) {
$value = $dimension->$hook($this->request, $visitor, $action);

if ($returnFirstTrue) {
if ($value) {
return true;
}
} else {
$result[] = $value;
}
}
return $result;
}

protected function getAllVisitDimensions()
{
$dimensions = VisitDimension::getAllDimensions();
Expand Down Expand Up @@ -598,4 +607,39 @@ protected function insertNewVisit($visit)
{
return $this->getModel()->createVisit($visit);
}

/**
* Determines if the tracker if the current action should be treated as the start of a new visit or
* an action in an existing visit.
*
* @param Visitor $visitor The current visit/visitor information.
* @param Action|null $action The current action being tracked.
* @return bool
*/
private function isVisitNew(Visitor $visitor, Action $action = null)
{
$isLastActionInTheSameVisit = $this->isLastActionInTheSameVisit($visitor);

if (!$isLastActionInTheSameVisit) {
Common::printDebug("Visitor detected, but last action was more than 30 minutes ago...");

return true;
}

$shouldForceNewVisit = $this->triggerPredicateHookOnDimensions($this->getAllVisitDimensions(), 'shouldForceNewVisit', $visitor, $action);
if ($shouldForceNewVisit) {
return true;
}

// if we should create a new visit when the referrer changes, check if referrer changed
if ($this->createNewVisitWhenWebsiteReferrerChanges
&& $visitor->isReferrerInformationDifferent()
) {
Common::printDebug("Existing visit detected, but creating new visit because referrer information is different than last action");

return true;
}

return !$visitor->isVisitorKnown();
}
}
30 changes: 29 additions & 1 deletion plugins/Referrers/Columns/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ protected function getReferrerInformation($referrerUrl, $currentUrl, $idSite)
return $referrerInformation;
}

protected function getReferrerInformationFromRequest(Request $request)
{
$referrerUrl = $request->getParam('urlref');
$currentUrl = $request->getParam('url');

return $this->getReferrerInformation($referrerUrl, $currentUrl, $request->getIdSite());
}

/**
* Search engine detection
* @return bool
Expand Down Expand Up @@ -399,4 +407,24 @@ protected function setCampaignValuesToLowercase($type, &$name, &$keyword)
}
}

}
protected function hasReferrerInformationChanged(Visitor $visitor, $information)
{
foreach (array('referer_keyword', 'referer_name', 'referer_type') as $infoName) {
if ($this->hasReferrerColumnChanged($visitor, $information, $infoName)) {
return true;
}
}
return false;
}

protected function hasReferrerColumnChanged(Visitor $visitor, $information, $infoName)
{
return Common::mb_strtolower($visitor->getVisitorColumn($infoName)) != $information[$infoName];
}

protected function doesLastOrCurrentActionHaveSameReferrer(Visitor $visitor, $currentInformation, $referrerType)
{
return $visitor->getVisitorColumn('referer_type') == $referrerType
|| $currentInformation['referer_type'] == $referrerType;
}
}
51 changes: 48 additions & 3 deletions plugins/Referrers/Columns/Campaign.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,58 @@
*/
namespace Piwik\Plugins\Referrers\Columns;

use Piwik\Columns\Dimension;
use Piwik\Common;
use Piwik\Piwik;
use Piwik\Tracker\Action;
use Piwik\Tracker\Request;
use Piwik\Tracker\TrackerConfig;
use Piwik\Tracker\Visitor;

class Campaign extends Dimension
class Campaign extends Base
{
/**
* Obtained from the `[Tracker] tracker_create_new_visit_when_campaign_changes` INI config option.
* If true, will create new visits when campaign name changes.
*
* @var bool
*/
protected $createNewVisitWhenCampaignChanges;

public function __construct()
{
$this->createNewVisitWhenCampaignChanges = TrackerConfig::getConfigValue('tracker_create_new_visit_when_campaign_changes') == 1;
}

public function getName()
{
return Piwik::translate('Referrers_ColumnCampaign');
}
}

/**
* If we should create a new visit when the campaign changes, check if the campaign info changed and if so
* force the tracker to create a new visit.
*
* @param Request $request
* @param Visitor $visitor
* @param Action|null $action
* @return bool
*/
public function shouldForceNewVisit(Request $request, Visitor $visitor, Action $action = null)
{
if (!$this->createNewVisitWhenCampaignChanges) {
return false;
}

$information = $this->getReferrerInformationFromRequest($request);

if ($this->doesLastOrCurrentActionHaveSameReferrer($visitor, $information, Common::REFERRER_TYPE_CAMPAIGN)
&& $this->hasReferrerInformationChanged($visitor, $information)
) {
Common::printDebug("Existing visit detected, but creating new visit because campaign information is different than last action.");

return true;
}

return false;
}
}
5 changes: 1 addition & 4 deletions plugins/Referrers/Columns/Keyword.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ public function getName()
*/
public function onNewVisit(Request $request, Visitor $visitor, $action)
{
$referrerUrl = $request->getParam('urlref');
$currentUrl = $request->getParam('url');

$information = $this->getReferrerInformation($referrerUrl, $currentUrl, $request->getIdSite());
$information = $this->getReferrerInformationFromRequest($request);

if (!empty($information['referer_keyword'])) {
return substr($information['referer_keyword'], 0, 255);
Expand Down
5 changes: 1 addition & 4 deletions plugins/Referrers/Columns/ReferrerName.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ protected function configureSegments()
*/
public function onNewVisit(Request $request, Visitor $visitor, $action)
{
$referrerUrl = $request->getParam('urlref');
$currentUrl = $request->getParam('url');

$information = $this->getReferrerInformation($referrerUrl, $currentUrl, $request->getIdSite());
$information = $this->getReferrerInformationFromRequest($request);

if (!empty($information['referer_name'])) {

Expand Down
5 changes: 1 addition & 4 deletions plugins/Referrers/Columns/ReferrerType.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,7 @@ public function getName()
*/
public function onNewVisit(Request $request, Visitor $visitor, $action)
{
$referrerUrl = $request->getParam('urlref');
$currentUrl = $request->getParam('url');

$information = $this->getReferrerInformation($referrerUrl, $currentUrl, $request->getIdSite());
$information = $this->getReferrerInformationFromRequest($request);

return $information['referer_type'];
}
Expand Down
5 changes: 1 addition & 4 deletions plugins/Referrers/Columns/ReferrerUrl.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ protected function configureSegments()
*/
public function onNewVisit(Request $request, Visitor $visitor, $action)
{
$referrerUrl = $request->getParam('urlref');
$currentUrl = $request->getParam('url');

$information = $this->getReferrerInformation($referrerUrl, $currentUrl, $request->getIdSite());
$information = $this->getReferrerInformationFromRequest($request);

return $information['referer_url'];
}
Expand Down
41 changes: 39 additions & 2 deletions plugins/Referrers/Columns/Website.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,50 @@
*/
namespace Piwik\Plugins\Referrers\Columns;

use Piwik\Columns\Dimension;
use Piwik\Common;
use Piwik\Piwik;
use Piwik\Tracker\Action;
use Piwik\Tracker\Request;
use Piwik\Tracker\TrackerConfig;
use Piwik\Tracker\Visitor;

class Website extends Dimension
class Website extends Base
{
/**
* Set using the `[Tracker] tracker_create_new_visit_when_website_referrer_changes` INI config option.
* If true, will force new visits if the referrer website changes.
*
* @var bool
*/
protected $createNewVisitWhenWebsiteReferrerChanges;

public function __construct()
{
$this->createNewVisitWhenWebsiteReferrerChanges = TrackerConfig::getConfigValue('tracker_create_new_visit_when_website_referrer_changes') == 1;
}

public function getName()
{
return Piwik::translate('General_Website');
}

public function shouldForceNewVisit(Request $request, Visitor $visitor, Action $action = null)
{
if (!$this->createNewVisitWhenWebsiteReferrerChanges) {
return false;
}

$information = $this->getReferrerInformationFromRequest($request);

if ($this->doesLastOrCurrentActionHaveSameReferrer($visitor, $information, Common::REFERRER_TYPE_WEBSITE)
&& $this->hasReferrerInformationChanged($visitor, $information)
) {
Common::printDebug("Existing visit detected, but creating new visit because website referrer information is different than last action.");

return true;
}

return false;

}
}

0 comments on commit 0a0a0d2

Please sign in to comment.