1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\Goals\Tracker;
use Piwik\Common;
use Piwik\Tracker\Action;
use Piwik\Tracker\GoalManager;
use Piwik\Tracker\Request;
use Piwik\Tracker\RequestProcessor;
use Piwik\Tracker\Visit\VisitProperties;
/**
* Handles conversion detection and tracking for tracker requests.
*
* ## Request Metadata
*
* This processor defines the following request metadata under the **Goals**
* plugin:
*
* * **goalsConverted**: The array of goals that were converted by this request. Each element
* will be an array of goal column value pairs. The ecommerce goal will
* only have the idgoal column set.
*
* Set in `processRequestParams()`.
*
* Plugins can set this to empty to skip conversion recording.
*
* * **visitIsConverted**: If `true`, the current visit should be marked as "converted". Note:
* some goal conversions (ie, ecommerce) do not mark the visit as
* "converted", so it is possible for goalsConverted to be non-empty
* while visitIsConverted is `false`.
*
* Set in `processRequestParams()`.
*/
class GoalsRequestProcessor extends RequestProcessor
{
/**
* @var GoalManager
*/
public $goalManager = null;
public function __construct(GoalManager $goalManager)
{
$this->goalManager = $goalManager;
}
public function processRequestParams(VisitProperties $visitProperties, Request $request)
{
$this->goalManager = new GoalManager();
if ($this->isManualGoalConversion($request)) {
// this request is from the JS call to piwikTracker.trackGoal()
$goal = $this->goalManager->detectGoalId($request->getIdSite(), $request);
$visitIsConverted = !empty($goal);
$request->setMetadata('Goals', 'visitIsConverted', $visitIsConverted);
$existingConvertedGoals = $request->getMetadata('Goals', 'goalsConverted') ?: array();
$request->setMetadata('Goals', 'goalsConverted', array_merge($existingConvertedGoals, array($goal)));
$request->setMetadata('Actions', 'action', null); // don't track actions when doing manual goal conversions
// if we find a idgoal in the URL, but then the goal is not valid, this is most likely a fake request
if (!$visitIsConverted) {
$idGoal = $request->getParam('idgoal');
Common::printDebug('Invalid goal tracking request for goal id = ' . $idGoal);
return true;
}
}
return false;
}
public function afterRequestProcessed(VisitProperties $visitProperties, Request $request)
{
$goalsConverted = $request->getMetadata('Goals', 'goalsConverted');
/** @var Action $action */
$action = $request->getMetadata('Actions', 'action');
// if the visit hasn't already been converted another way (ie, manual goal conversion or ecommerce conversion,
// try to convert based on the action)
if (empty($goalsConverted)
&& $action
) {
$goalsConverted = $this->goalManager->detectGoalsMatchingUrl($request->getIdSite(), $action, $visitProperties, $request);
$existingGoalsConverted = $request->getMetadata('Goals', 'goalsConverted') ?: array();
$request->setMetadata('Goals', 'goalsConverted', array_merge($existingGoalsConverted, $goalsConverted));
if (!empty($goalsConverted)) {
$request->setMetadata('Goals', 'visitIsConverted', true);
}
}
}
public function recordLogs(VisitProperties $visitProperties, Request $request)
{
// record the goals if there were conversions in this request (even if the visit itself was not converted)
$goalsConverted = $request->getMetadata('Goals', 'goalsConverted');
if (!empty($goalsConverted)) {
$this->goalManager->recordGoals($visitProperties, $request);
}
}
private function isManualGoalConversion(Request $request)
{
$idGoal = $request->getParam('idgoal');
return $idGoal > 0;
}
}
|